UNPKG

react-native-chart-kit

Version:

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

112 lines (111 loc) 6.16 kB
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; import { useMemo } from "react"; import { StyleSheet, Text, View } from "react-native"; import { useChartKitTheme } from "../../theme"; import { getLineChartRenderer as getProgressChartRenderer } from "../line/renderer"; import { getProgressChartAccessibilitySummary } from "./accessibility"; import { getAnimatedProgressRings, getAverageProgress, getProgressChartAnimationTargetKey, useProgressChartAnimation } from "./animation"; import { buildProgressChartModel } from "./model"; export { getProgressChartAccessibilitySummary, getProgressChartDataTable } from "./accessibility"; const defaultStrokeLinecap = "round"; const RendererLayer = ({ children }) => _jsx(_Fragment, { children: children }); export const ProgressChart = (props) => { const chartKitTheme = useChartKitTheme(); const model = useMemo(() => buildProgressChartModel({ chartKitTheme, props }), [chartKitTheme, props]); const { average, centerX, centerY, chartHeight, legendItems, legendVisible, resolvedTheme, rings } = model; const animationTargetKey = useMemo(() => getProgressChartAnimationTargetKey(rings), [rings]); const progressAnimation = useProgressChartAnimation({ animation: props.animation, targetKey: animationTargetKey }); const { progress: animationProgress, stagger: animationStagger } = progressAnimation; const animatedRings = useMemo(() => getAnimatedProgressRings({ centerX, centerY, progress: animationProgress, rings, stagger: animationStagger }), [animationProgress, animationStagger, centerX, centerY, rings]); const displayRings = props.animation ? animatedRings : rings; const animatedAverage = useMemo(() => getAverageProgress(displayRings), [displayRings]); const strokeLinecap = props.strokeLinecap ?? defaultStrokeLinecap; const centerLabel = typeof props.centerLabel === "function" ? props.centerLabel({ average: props.animation ? animatedAverage : average, rings: displayRings, theme: resolvedTheme }) : props.centerLabel; const accessibilityLabel = props.accessibilityLabel ?? getProgressChartAccessibilitySummary({ colorKey: props.colorKey, colors: props.colors, data: props.data, formatPercentage: props.formatPercentage, labelKey: props.labelKey, labels: props.labels, valueKey: props.valueKey }); const renderer = getProgressChartRenderer(props.renderer ?? chartKitTheme.renderer); const Layer = renderer.Layer ?? RendererLayer; const Path = renderer.Path; const Surface = renderer.Surface; const SvgText = renderer.Text; const canRenderText = renderer.capabilities?.text !== false; return (_jsxs(View, { accessible: true, accessibilityLabel: accessibilityLabel, accessibilityRole: "image", style: [ styles.container, { backgroundColor: resolvedTheme.background, height: props.height, width: props.width } ], testID: props.testID, children: [_jsxs(Surface, { width: props.width, height: chartHeight, children: [_jsx(Layer, { name: "background", children: rings.map((ring) => ring.backgroundPath.length > 0 ? (_jsx(Path, { d: ring.backgroundPath, fill: "none", stroke: resolvedTheme.grid, strokeLinecap: strokeLinecap, strokeWidth: ring.strokeWidth, testID: `${props.testID ?? "progress-chart"}-background.${ring.index}` }, `progress-background-${ring.index}`)) : null) }), _jsx(Layer, { name: "data", children: displayRings.map((ring) => ring.defined ? (_jsx(Path, { d: ring.path, fill: "none", stroke: ring.color ?? resolvedTheme.text, strokeLinecap: strokeLinecap, strokeLinejoin: "round", strokeWidth: ring.strokeWidth, testID: `${props.testID ?? "progress-chart"}-ring.${ring.index}` }, `progress-ring-${ring.index}`)) : null) }), typeof centerLabel === "string" && centerLabel.length > 0 && canRenderText ? (_jsx(Layer, { name: "overlays", children: _jsx(SvgText, { fill: resolvedTheme.text, fontSize: 18, fontWeight: "800", text: centerLabel, textAnchor: "middle", x: centerX, y: centerY + 6, ...(resolvedTheme.typography.fontFamily ? { fontFamily: resolvedTheme.typography.fontFamily } : {}), children: centerLabel }) })) : null] }), legendVisible && legendItems.length > 0 ? (_jsx(View, { style: styles.legend, children: legendItems.map((item) => (_jsxs(View, { style: styles.legendItem, children: [_jsx(View, { style: [styles.legendSwatch, { backgroundColor: item.color }] }), _jsx(Text, { numberOfLines: 1, style: [styles.legendText, { color: resolvedTheme.text }], children: item.label }), _jsx(Text, { numberOfLines: 1, style: [styles.legendValue, { color: resolvedTheme.mutedText }], children: item.percentageLabel })] }, item.key))) })) : null] })); }; export const ProgressRing = ({ color, label, value, ...props }) => { const row = { value, ...(label !== undefined ? { label } : {}), ...(color !== undefined ? { color } : {}) }; return (_jsx(ProgressChart, { ...props, data: [row], labelKey: "label", valueKey: "value", colorKey: "color", legend: props.legend ?? false })); }; const styles = StyleSheet.create({ container: { borderRadius: 8, overflow: "hidden" }, legend: { alignContent: "center", flexDirection: "row", flexWrap: "wrap", gap: 8, justifyContent: "center", paddingHorizontal: 8, paddingTop: 4 }, legendItem: { alignItems: "center", flexDirection: "row", gap: 5, maxWidth: "48%", minHeight: 18 }, legendSwatch: { borderRadius: 4, height: 8, width: 8 }, legendText: { flexShrink: 1, fontSize: 11, fontWeight: "700" }, legendValue: { fontSize: 10, fontWeight: "700" } });