UNPKG

react-native-chart-kit

Version:

Beautiful React Native charts for dashboards, reports, and data-rich mobile apps.

152 lines (151 loc) 12.4 kB
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; import { View } from "react-native"; import { renderDefaultTooltip } from "./defaultTooltip"; import { renderLineChartDebugLayout } from "./debugOverlay"; import { renderConfiguredLegend } from "./legend"; import { renderDefaultDot } from "./markers"; import { getLineChartRenderer } from "./renderer"; import { getFontFamilyProps, measureLineChartText } from "./text"; import { getLineChartAreaGradientId, LineChartAreaPaths, LineChartLinePaths, LineChartThresholdClipDefs } from "./thresholdRendering"; import { useLineChartDebugLayout } from "./useDebugLayout"; export const LineChartSurface = ({ animatedTooltip, chartId, chartWidth, isScrollable, mainHeight, model, props, renderer: rendererProp, responderProps, yAxisLabels }) => { const { boxes, geometries, legendModel, referenceBandModels, referenceLineModels, resolvedTheme, showHorizontalGridLines, showVerticalGridLines, crosshairConfig, selectionModel, xLabelLayout, yScale, yTicks } = model; const { debugLayout, onLayoutDebug } = props; const debugLayoutModel = useLineChartDebugLayout({ enabled: Boolean(debugLayout || onLayoutDebug), model, onLayoutDebug, tooltip: animatedTooltip, yAxisLabels }); const renderer = getLineChartRenderer(rendererProp); const { Defs, Group, Line, Rect, Surface, Text } = renderer; const Layer = renderer.Layer ?? Group; const LinearGradient = renderer.LinearGradient; const canRenderText = renderer.capabilities?.text !== false; const supportsGradientDefs = renderer.capabilities?.gradients !== false && renderer.capabilities?.pathGradients !== true && Boolean(LinearGradient); const renderReferenceLabel = (key, label) => { const fontFamilyProps = getFontFamilyProps(resolvedTheme.typography.fontFamily); if (!label.container) { return (_jsx(Text, { x: label.x, y: label.y, fill: label.color, fontSize: label.fontSize, textAnchor: label.textAnchor, ...fontFamilyProps, children: label.text }, key)); } const labelSize = measureLineChartText(label.text, { fontFamily: resolvedTheme.typography.fontFamily, fontSize: label.fontSize }); const backgroundWidth = labelSize.width + label.container.paddingX * 2; const backgroundHeight = labelSize.height + label.container.paddingY * 2; const backgroundX = label.textAnchor === "end" ? label.x - backgroundWidth : label.textAnchor === "middle" ? label.x - backgroundWidth / 2 : label.x; const backgroundY = label.y - labelSize.height + 2 - label.container.paddingY; const textX = backgroundX + backgroundWidth / 2; return (_jsxs(Group, { children: [_jsx(Rect, { x: backgroundX, y: backgroundY, width: backgroundWidth, height: backgroundHeight, rx: label.container.borderRadius, fill: label.container.backgroundColor, opacity: label.container.opacity }), _jsx(Text, { x: textX, y: label.y, fill: label.color, fontSize: label.fontSize, textAnchor: "middle", ...fontFamilyProps, children: label.text })] }, key)); }; return (_jsx(View, { collapsable: false, style: { width: chartWidth, height: mainHeight }, ...responderProps, children: _jsxs(Surface, { width: chartWidth, height: mainHeight, children: [_jsx(Layer, { name: "background", children: _jsx(Rect, { x: 0, y: 0, width: chartWidth, height: mainHeight, rx: 8, fill: resolvedTheme.background }) }), _jsx(Layer, { name: "plot", children: _jsx(Rect, { x: boxes.plot.x, y: boxes.plot.y, width: boxes.plot.width, height: boxes.plot.height, rx: 6, fill: resolvedTheme.plotBackground }) }), _jsxs(Defs, { children: [supportsGradientDefs && LinearGradient ? geometries.map(({ style }, index) => (_jsx(LinearGradient, { id: getLineChartAreaGradientId(chartId, index), x1: "0%", x2: "0%", y1: "0%", y2: "100%", stops: [ { offset: "0%", color: style.areaFill.fromColor, opacity: style.areaFill.fromOpacity }, { offset: "100%", color: style.areaFill.toColor, opacity: style.areaFill.toOpacity } ] }, `area-gradient-${index}`))) : null, _jsx(LineChartThresholdClipDefs, { chartId: chartId, geometries: geometries, plot: boxes.plot, renderer: renderer, yScale: yScale })] }), _jsxs(Layer, { name: "grid", children: [showVerticalGridLines ? xLabelLayout.items.map((label) => (_jsx(Line, { x1: label.gridX, x2: label.gridX, y1: boxes.plot.y, y2: boxes.plot.y + boxes.plot.height, stroke: resolvedTheme.grid, strokeOpacity: 0.72, strokeWidth: 1 }, `grid-x-${label.index}`))) : null, showHorizontalGridLines ? yTicks.map((tick) => { const y = yScale.scale(tick); return (_jsx(Line, { x1: boxes.plot.x, x2: boxes.plot.x + boxes.plot.width, y1: y, y2: y, stroke: resolvedTheme.grid, strokeOpacity: 0.78, strokeWidth: 1 }, `grid-y-${tick}`)); }) : null] }), _jsxs(Layer, { name: "axes", children: [yAxisLabels.map((label) => { if (isScrollable || !canRenderText) { return null; } return (_jsx(Text, { x: boxes.plot.x - 8, y: label.y, fill: resolvedTheme.mutedText, fontSize: resolvedTheme.typography.axisLabelSize, opacity: label.opacity, textAnchor: "end", ...getFontFamilyProps(resolvedTheme.typography.fontFamily), children: label.text }, `label-y-${label.key}`)); }), canRenderText ? xLabelLayout.items.map((label) => (_jsx(Group, { transform: label.rotation !== 0 ? `rotate(${label.rotation} ${label.x} ${label.y})` : undefined, children: _jsx(Text, { x: label.x, y: label.y, fill: resolvedTheme.mutedText, fontSize: resolvedTheme.typography.axisLabelSize, textAnchor: label.textAnchor, ...getFontFamilyProps(resolvedTheme.typography.fontFamily), children: label.text }) }, `label-x-${label.index}`))) : null] }), _jsx(Layer, { name: "referenceBands", children: referenceBandModels.map((band) => (_jsx(Rect, { x: band.x, y: band.y, width: band.width, height: band.height, fill: band.color, opacity: band.opacity }, band.key))) }), _jsx(Layer, { name: "referenceLines", children: referenceLineModels.map((line) => (_jsx(Line, { x1: line.x1, x2: line.x2, y1: line.y, y2: line.y, stroke: line.color, strokeOpacity: line.opacity, strokeWidth: line.strokeWidth, ...(line.strokeDasharray ? { strokeDasharray: line.strokeDasharray } : {}) }, line.key))) }), _jsx(Layer, { name: "dataArea", children: _jsx(LineChartAreaPaths, { chartId: chartId, geometries: geometries, plot: boxes.plot, renderer: renderer, yScale: yScale }) }), _jsx(Layer, { name: "data", children: _jsx(LineChartLinePaths, { chartId: chartId, geometries: geometries, plot: boxes.plot, renderer: renderer, yScale: yScale }) }), _jsx(Layer, { name: "markers", children: geometries.flatMap(({ geometry, style }) => geometry.points .filter((point) => point.defined && style.dot.visible) .map((point) => { const dotProps = { point, seriesKey: geometry.key, seriesLabel: geometry.label, color: style.color, x: point.x, y: point.y, value: point.value, dataIndex: point.dataIndex, config: style.dot, theme: resolvedTheme }; const renderedDot = props.renderDot ? props.renderDot(dotProps) : renderDefaultDot(dotProps, renderer); return renderedDot ? (_jsx(Group, { children: renderedDot }, `dot-${geometry.key}-${point.index}`)) : null; })) }), _jsxs(Layer, { name: "referenceLabels", children: [referenceBandModels.map((band) => band.label && canRenderText ? renderReferenceLabel(`${band.key}-label`, band.label) : null), referenceLineModels.map((line) => line.label && canRenderText ? renderReferenceLabel(`${line.key}-label`, line.label) : null)] }), _jsxs(Layer, { name: "overlays", children: [selectionModel && crosshairConfig.visible ? (props.renderCrosshair ? (props.renderCrosshair({ chartHeight: mainHeight, chartWidth, config: crosshairConfig, plot: boxes.plot, series: selectionModel.series, theme: resolvedTheme, x: selectionModel.x, xLabel: selectionModel.xLabel, y: selectionModel.y })) : (_jsx(Line, { x1: selectionModel.x, x2: selectionModel.x, y1: boxes.plot.y, y2: boxes.plot.y + boxes.plot.height, stroke: crosshairConfig.color, strokeOpacity: crosshairConfig.opacity, strokeWidth: crosshairConfig.strokeWidth, ...(crosshairConfig.strokeDasharray ? { strokeDasharray: crosshairConfig.strokeDasharray } : {}) }, "selection-crosshair"))) : null, legendModel ? renderConfiguredLegend({ legend: legendModel.renderProps, config: legendModel.config, renderer }) : null] }), _jsxs(Layer, { name: "interaction", children: [selectionModel ? selectionModel.series .filter((item) => item.activeDot.visible) .map((item) => { const dotProps = { point: item.point, seriesKey: item.key, seriesLabel: item.label, color: item.color, x: item.point.x, y: item.point.y, value: item.value, dataIndex: item.point.dataIndex, config: item.activeDot, theme: resolvedTheme }; const renderedDot = props.renderActiveDot ? props.renderActiveDot(dotProps) : renderDefaultDot(dotProps, renderer); return renderedDot ? (_jsx(Group, { children: renderedDot }, `active-dot-${item.key}`)) : null; }) : null, animatedTooltip ? props.renderTooltip ? props.renderTooltip(animatedTooltip) : renderDefaultTooltip(animatedTooltip, renderer) : null] }), debugLayout && debugLayoutModel ? (_jsx(Layer, { name: "debug", children: renderLineChartDebugLayout({ fontFamily: resolvedTheme.typography.fontFamily, model: debugLayoutModel, renderer }) })) : null] }) })); };