UNPKG

react-native-chart-kit

Version:

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

134 lines (133 loc) 5.14 kB
import { buildProgressRings, normalizeLegacyProgressData } from "../../../core/index"; import { resolveCartesianChartThemeConfig } from "../../theme/presets"; const defaultValueKey = "value"; const defaultLabelKey = "label"; const defaultColorKey = "color"; const defaultStrokeWidth = 14; const defaultRingGap = 8; const defaultLegendHeight = 50; const defaultFormatPercentage = (value) => `${Math.round(value * 100)}%`; const isObjectRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value); const getStringValue = (value) => typeof value === "string" && value.length > 0 ? value : undefined; const getNumberLikeValue = (value) => { if (typeof value === "number") { return value; } if (value === null) { return null; } if (value === undefined) { return undefined; } return Number(value); }; const isObjectRowData = (data) => Array.isArray(data) && data.some(isObjectRecord); const normalizeProgressInput = ({ colorKey, colors, data, labelKey, labels, valueKey }) => { if (isObjectRowData(data)) { const resolvedValueKey = valueKey ?? defaultValueKey; const resolvedLabelKey = labelKey ?? defaultLabelKey; const resolvedColorKey = colorKey ?? defaultColorKey; return { data: data.map((item) => getNumberLikeValue(item[resolvedValueKey])), labels: data.map((item, index) => getStringValue(item[resolvedLabelKey]) ?? labels?.[index] ?? `Ring ${index + 1}`), colors: data.map((item, index) => getStringValue(item[resolvedColorKey]) ?? colors?.[index] ?? "") }; } if (Array.isArray(data)) { return { data, ...(labels !== undefined ? { labels } : {}), ...(colors !== undefined ? { colors } : {}) }; } const resolvedLabels = data.labels ?? labels; const resolvedColors = data.colors ?? colors; return { ...data, ...(resolvedLabels !== undefined ? { labels: resolvedLabels } : {}), ...(resolvedColors !== undefined ? { colors: resolvedColors } : {}) }; }; const getLegendVisible = ({ hideLegend, legend }) => { if (hideLegend || legend === false) { return false; } if (typeof legend === "object") { return legend.visible !== false; } return true; }; export const buildProgressChartModel = ({ chartKitTheme, props }) => { const { backgroundRingColor, colorKey, colors, data, formatPercentage = defaultFormatPercentage, height, hideLegend, labelKey, labels, legend, preset, radius, ringGap = defaultRingGap, strokeWidth = defaultStrokeWidth, theme, valueKey, width } = props; const resolvedTheme = resolveCartesianChartThemeConfig({ mode: typeof theme === "string" && theme !== "system" ? theme : chartKitTheme.mode, preset: preset ?? chartKitTheme.preset, presets: chartKitTheme.presets, theme: typeof theme === "object" ? theme : chartKitTheme.theme }); const legendVisible = getLegendVisible({ hideLegend, legend }); const chartHeight = Math.max(120, height - (legendVisible ? defaultLegendHeight : 0)); const centerX = width / 2; const centerY = chartHeight / 2; const resolvedStrokeWidth = Math.max(1, strokeWidth); const maxRadius = typeof radius === "number" && Number.isFinite(radius) ? Math.max(0, radius) : Math.max(0, Math.min(width, chartHeight) / 2 - resolvedStrokeWidth / 2 - 8); const normalized = normalizeLegacyProgressData(normalizeProgressInput({ colorKey, colors, data, labelKey, labels, valueKey })); const rings = buildProgressRings({ rings: normalized.rings, centerX, centerY, maxRadius, strokeWidth: resolvedStrokeWidth, ringGap }).map((ring, index) => { const customColor = typeof ring.color === "string" && ring.color.length > 0 ? ring.color : undefined; const color = customColor ?? resolvedTheme.series[index % resolvedTheme.series.length] ?? resolvedTheme.text; return { ...ring, color }; }); const definedRings = rings.filter((ring) => ring.value !== null); const average = definedRings.length > 0 ? definedRings.reduce((sum, ring) => sum + ring.clampedValue, 0) / definedRings.length : 0; const legendItems = rings.map((ring) => ({ index: ring.index, key: `${ring.index}-${ring.label ?? "Progress"}`, label: ring.label ?? `Ring ${ring.index + 1}`, percentageLabel: formatPercentage(ring.clampedValue), color: ring.color ?? resolvedTheme.series[0] ?? resolvedTheme.text, ring })); return { average, centerX, centerY, chartHeight, legendItems, legendVisible, resolvedTheme: { ...resolvedTheme, grid: backgroundRingColor ?? resolvedTheme.grid }, rings }; };