UNPKG

react-native-chart-kit

Version:

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

104 lines (103 loc) 4.41 kB
import { useMemo } from "react"; import { resolveLineChartSeriesInput } from "./seriesInput"; import { defaultFormatXLabel, defaultFormatYLabel } from "./utils"; const pluralize = (count, singular, plural = `${singular}s`) => `${count} ${count === 1 ? singular : plural}`; const normalizeXValue = (value, fallback) => { return typeof value === "string" || (typeof value === "number" && Number.isFinite(value)) || value instanceof Date ? value : fallback; }; const normalizeYValue = (value) => typeof value === "number" && Number.isFinite(value) ? value : null; const getDefinedSeriesPoints = (series, rows) => rows.flatMap((row) => { const columnKey = String(series.key ?? series.yKey); const value = row.values[columnKey]; return typeof value === "number" ? [ { formattedValue: row.formattedValues[columnKey] ?? String(value), raw: row.raw, value, xLabel: row.xLabel } ] : []; }); const getMinPoint = (points) => points.reduce((min, point) => (!min || point.value < min.value ? point : min), undefined); const getMaxPoint = (points) => points.reduce((max, point) => (!max || point.value > max.value ? point : max), undefined); export const getLineChartDataTable = ({ data, formatXLabel = defaultFormatXLabel, formatYLabel = defaultFormatYLabel, series, xKey, yKey, yKeys }) => { const seriesInputs = resolveLineChartSeriesInput(yKey, yKeys, series); const columns = seriesInputs.map((item, index) => ({ key: String(item.key ?? item.yKey ?? `series-${index}`), label: String(item.label ?? item.key ?? item.yKey ?? `Series ${index + 1}`) })); return { columns, rows: data.map((row, index) => { const x = normalizeXValue(row[xKey], index); const values = {}; const formattedValues = {}; seriesInputs.forEach((item, seriesIndex) => { const key = String(item.key ?? item.yKey ?? `series-${seriesIndex}`); const value = normalizeYValue(row[item.yKey]); values[key] = value; formattedValues[key] = value === null ? "No value" : formatYLabel(value); }); return { index, x, xLabel: formatXLabel(x, index), values, formattedValues, raw: row }; }) }; }; export const getLineChartAccessibilitySummary = (input) => { const table = getLineChartDataTable(input); if (table.columns.length === 0 || table.rows.length === 0) { return "Line chart with no data."; } const seriesInputs = resolveLineChartSeriesInput(input.yKey, input.yKeys, input.series); const intro = table.columns.length === 1 ? `${table.columns[0].label} line chart with ${pluralize(table.rows.length, "point")}.` : `Line chart with ${pluralize(table.columns.length, "series", "series")} and ${pluralize(table.rows.length, "point")}.`; const seriesSummaries = seriesInputs.flatMap((series) => { const columnKey = String(series.key ?? series.yKey); const label = table.columns.find((column) => column.key === columnKey)?.label ?? columnKey; const points = getDefinedSeriesPoints(series, table.rows); const minPoint = getMinPoint(points); const maxPoint = getMaxPoint(points); const currentPoint = points[points.length - 1]; if (!minPoint || !maxPoint || !currentPoint) { return [`${label} has no defined values.`]; } return [ `${label} ranges from ${minPoint.formattedValue} in ${minPoint.xLabel} to ${maxPoint.formattedValue} in ${maxPoint.xLabel}. Current value is ${currentPoint.formattedValue}.` ]; }); return [intro, ...seriesSummaries].join(" "); }; export const useLineChartAccessibilityLabel = ({ accessibilityLabel, data, formatXLabel, formatYLabel, series, xKey, yKey, yKeys }) => useMemo(() => accessibilityLabel ?? getLineChartAccessibilitySummary({ data, formatXLabel, formatYLabel, series, xKey, yKey, yKeys }), [ accessibilityLabel, data, formatXLabel, formatYLabel, series, xKey, yKey, yKeys ]);