UNPKG

react-native-chart-kit

Version:

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

230 lines (229 loc) 8.61 kB
import { createWarningCollector, getBeginningTimeForDate, millisecondsInOneDay, normalizeDateValue, normalizeNumberValue, normalizeXValue, shiftDate } from "./normalizeValues"; const getSeriesInputs = (input) => { if (input.series && input.series.length > 0) { return input.series; } if (input.yKeys && input.yKeys.length > 0) { return input.yKeys.map((yKey) => ({ yKey })); } if (input.yKey) { return [{ yKey: input.yKey }]; } return []; }; export const normalizeCartesianData = (input, options = {}) => { const collector = createWarningCollector(options); const seriesInputs = getSeriesInputs(input); const series = seriesInputs.map((seriesInput, seriesIndex) => { const key = seriesInput.key ?? seriesInput.yKey; const label = seriesInput.label ?? key; const points = input.data.map((row, rowIndex) => { const x = normalizeXValue(row[input.xKey], rowIndex, `data[${rowIndex}].${input.xKey}`, collector); const value = normalizeNumberValue(row[seriesInput.yKey], `data[${rowIndex}].${seriesInput.yKey}`, collector); return { index: rowIndex, x, value, defined: value !== null, raw: row }; }); const normalizedSeries = { key: String(key || `series-${seriesIndex}`), label: String(label || key || `Series ${seriesIndex + 1}`), points }; if (seriesInput.color !== undefined) { normalizedSeries.color = seriesInput.color; } return normalizedSeries; }); return { kind: "cartesian", xKey: input.xKey, series, rows: input.data, warnings: collector.warnings }; }; export const normalizeLegacyLineData = (data, options = {}) => { const collector = createWarningCollector(options); const maxPointCount = Math.max(data.labels?.length ?? 0, ...data.datasets.map((dataset) => dataset.data.length)); const rows = Array.from({ length: maxPointCount }, () => data); const series = data.datasets.map((dataset, datasetIndex) => { const key = String(dataset.key ?? `series-${datasetIndex}`); const label = data.legend?.[datasetIndex] ?? key; const points = Array.from({ length: maxPointCount }, (_, pointIndex) => { const value = normalizeNumberValue(dataset.data[pointIndex], `datasets[${datasetIndex}].data[${pointIndex}]`, collector); return { index: pointIndex, x: data.labels?.[pointIndex] ?? pointIndex, value, defined: value !== null, raw: data }; }); return { key, label, points }; }); return { kind: "cartesian", xKey: "labels", series, rows, warnings: collector.warnings }; }; export const normalizeLegacyPieData = (data, options = {}) => { const accessor = options.accessor ?? "population"; const collector = createWarningCollector(options); const slices = data.map((item, index) => { let value = normalizeNumberValue(item[accessor], `data[${index}].${accessor}`, collector); if (value !== null && value < 0) { collector.warn({ code: "negative-pie-value", message: `Expected non-negative pie value at data[${index}].${accessor}; normalized to null.`, path: `data[${index}].${accessor}` }); value = null; } const slice = { index, label: item.name ?? `Slice ${index + 1}`, value, defined: value !== null, raw: item }; if (item.color !== undefined) { slice.color = item.color; } return slice; }); return { kind: "pie", accessor, slices, warnings: collector.warnings }; }; export const normalizeLegacyProgressData = (input, options = {}) => { const collector = createWarningCollector(options); const data = Array.isArray(input) ? input : input.data; const labels = Array.isArray(input) ? undefined : input.labels; const colors = Array.isArray(input) ? undefined : input.colors; const rings = data.map((rawValue, index) => { const value = normalizeNumberValue(rawValue, `data[${index}]`, collector); if (value !== null && (value < 0 || value > 1)) { collector.warn({ code: "progress-out-of-range", message: `Expected progress value at data[${index}] to be between 0 and 1.`, path: `data[${index}]` }); } const ring = { index, value, defined: value !== null }; if (labels?.[index] !== undefined) { ring.label = labels[index]; } if (colors?.[index] !== undefined) { ring.color = colors[index]; } return ring; }); return { kind: "progress", rings, warnings: collector.warnings }; }; export const normalizeLegacyStackedBarData = (data, options = {}) => { const collector = createWarningCollector(options); const segmentCount = Math.max(data.legend.length, data.barColors.length, ...data.data.map((group) => group.length)); const groups = data.data.map((group, groupIndex) => { const segments = Array.from({ length: segmentCount }, (_, segmentIndex) => { const value = normalizeNumberValue(group[segmentIndex], `data[${groupIndex}][${segmentIndex}]`, collector); const segment = { index: groupIndex, seriesIndex: segmentIndex, label: data.legend[segmentIndex] ?? `Series ${segmentIndex + 1}`, value, defined: value !== null, raw: group }; if (data.barColors[segmentIndex] !== undefined) { segment.color = data.barColors[segmentIndex]; } return segment; }); return { index: groupIndex, label: data.labels[groupIndex] ?? String(groupIndex), total: segments.reduce((total, segment) => total + (segment.value ?? 0), 0), segments, raw: group }; }); return { kind: "stacked-bar", legend: data.legend, colors: data.barColors, percentile: options.percentile ?? false, groups, warnings: collector.warnings }; }; export const normalizeLegacyContributionData = (values, options) => { const collector = createWarningCollector(options); const accessor = options.accessor ?? "count"; const endDate = normalizeDateValue(options.endDate, "endDate", collector) ?? getBeginningTimeForDate(new Date(0)); const startDate = shiftDate(endDate, -Math.max(options.numDays, 0) + 1); const emptyValue = options.emptyValue === undefined ? 0 : options.emptyValue; const valuesByIndex = new Map(); values.forEach((value, valueIndex) => { const date = normalizeDateValue(value.date, `values[${valueIndex}].date`, collector); if (!date) { return; } const dayIndex = Math.floor((date.valueOf() - startDate.valueOf()) / millisecondsInOneDay); if (dayIndex < 0 || dayIndex >= options.numDays) { collector.warn({ code: "contribution-out-of-range", message: `Contribution date at values[${valueIndex}].date falls outside the configured range.`, path: `values[${valueIndex}].date` }); return; } valuesByIndex.set(dayIndex, value); }); const days = Array.from({ length: Math.max(options.numDays, 0) }, (_, dayIndex) => { const raw = valuesByIndex.get(dayIndex); const value = raw ? normalizeNumberValue(raw[accessor], `valuesByDate[${dayIndex}].${accessor}`, collector) : emptyValue; const day = { index: dayIndex, date: shiftDate(startDate, dayIndex), value, defined: value !== null }; if (raw !== undefined) { day.raw = raw; } return day; }); return { kind: "contribution", accessor, startDate, endDate, days, warnings: collector.warnings }; };