import { ResponsiveLine } from '@nivo/line'; import React, { useMemo } from 'react'; import { useAxisProps } from './hooks/useAxisProps'; import { useChartMargin } from './hooks/useChartMargin'; import { useChartTheme } from './hooks/useChartTheme'; import { useColorsAndGradients } from './hooks/useColorsAndGradients'; import { useMinMaxYSeries } from './hooks/useMinMaxYSeries'; import { useTooltips } from './hooks/useTooltips'; import { useXScaleConfig } from './hooks/useXScaleConfig'; import { useYMarkerProps } from './hooks/useYMarkerProps'; import { LineChartBox } from './LineChart.styled'; import { Tooltip } from './Tooltip/Tooltip'; import { LineChartProps, XDataType, YDataType } from './types'; export * from './types'; const yFormatterDefault = (y: YDataType) => parseFloat(y.toFixed(2)).toString(); const xFormatterDefault = (x: XDataType) => typeof x === 'number' ? parseFloat(x.toFixed(2)).toString() : x.toLocaleString(); const getYMaxExtended = ({ min, max, percentage = 0, }: { max: number; min: number; percentage: LineChartProps['yAxisTopOffsetPercentage']; }): number => { const diff = max - min; const multiplier = percentage / 100; return max + diff * multiplier; }; export const LineChart: React.FunctionComponent = ({ data, yMarker, axisBottomFormat, withoutAxis = false, withoutMargins = false, axisTypographyToken = 'bodyXSmallMedium', yScaleStacked = false, enablePoints = false, crosshairColorToken = 'primary500', axisTicksTextColorToken = 'white400', axisDomainLineColorToken = 'white900', visibleAxis = ['left', 'bottom'], axisTickPadding = 8, yAxisTopOffsetPercentage: yAxisTopOffsetPercentageProp = 15, yFormatter = yFormatterDefault, yScaleMax, yScaleMin, xFormatter = xFormatterDefault, xScaleMax, xScaleMin, curveType = 'linear', xScaleType = 'time', enableTooltip = true, }) => { const yAxisTopOffsetPercentage = Math.max(0, yAxisTopOffsetPercentageProp); const chartTheme = useChartTheme({ axisDomainLineColorToken, axisTicksTextColorToken, axisTypographyToken, crosshairColorToken, }); const axisFontFamily = chartTheme.axis.ticks.text.fontFamily; const axisFontSize = chartTheme.axis.ticks.text.fontSize; const { tooltips } = useTooltips(data); const { colorTokensMap, colors, gradients } = useColorsAndGradients(data); const minMaxYSeries = useMinMaxYSeries(data); const yMarkerProps = useYMarkerProps({ yMarker }); const chartMargin = useChartMargin({ axisFontFamily, axisFontSize, axisTickPadding, visibleAxis, yFormatter, yS: minMaxYSeries.yS, }); const axisProps = useAxisProps({ axisBottomFormat, axisTickPadding, visibleAxis, xFormatter, xScaleType, yFormatter, }); const xScaleProps = useXScaleConfig({ xScaleMax, xScaleMin, xScaleType, }); const yScaleMaxComputed = useMemo((): number | 'auto' => { if (yScaleMax) { return yScaleMax; } if (!yAxisTopOffsetPercentage) { return 'auto'; } return getYMaxExtended({ max: minMaxYSeries.max, min: minMaxYSeries.min, percentage: yAxisTopOffsetPercentage, }); }, [yScaleMax, yAxisTopOffsetPercentage, minMaxYSeries.min, minMaxYSeries.max]); return ( { const tooltip = tooltips[props.point.serieId]; if (!tooltip) { return null; } if (typeof tooltip === 'function') { const T = tooltip; return ; } const { tokenColorToken: tooltipTokenColorToken, token: tooltipToken } = tooltip || {}; return ( ); } : () => <> } useMesh={enableTooltip} xFormat={xScaleProps.xFormat} xScale={xScaleProps.xScale} yFormat={(c) => yFormatter(c as number)} yScale={{ max: yScaleMaxComputed, min: yScaleMin || 'auto', reverse: false, stacked: yScaleStacked, type: 'linear', }} /> ); };