import { Group, Text as SkiaText, type SkFont, } from "@shopify/react-native-skia"; import { useDerivedValue } from "react-native-reanimated"; import type { ChartPadding } from "../draw/line"; import type { MultiEngineState } from "../core/useLiveChartEngine"; const LABEL_GAP = 8; function SeriesValueLabelAtIndex({ index, engine, padding, color, font, dotRadius, }: { index: number; engine: MultiEngineState; padding: ChartPadding; color: string; font: SkFont; dotRadius: number; }) { const labelX = useDerivedValue(() => { const w = engine.canvasWidth.value; if (w === 0) return -200; return w - padding.right + dotRadius + LABEL_GAP; }); const labelY = useDerivedValue(() => { const h = engine.canvasHeight.value; if (h === 0) return -200; const s = engine.series.value; const displays = engine.displaySeriesValues.value; if (index >= s.length) return -200; const chartH = h - padding.top - padding.bottom; const dMin = engine.displayMin.value; const dMax = engine.displayMax.value; const valRange = dMax - dMin; const v = displays[index] ?? s[index].value; const y = valRange === 0 ? padding.top + chartH / 2 : padding.top + ((dMax - v) / valRange) * chartH; const fm = font.getMetrics(); return y - (fm.ascent + fm.descent) / 2; }); const text = useDerivedValue(() => { const s = engine.series.value; if (index >= s.length) return ""; return s[index].label ?? s[index].id; }); const opacity = useDerivedValue(() => { const s = engine.series.value; const op = engine.seriesOpacities.value; if (index >= s.length || index >= op.length) return 0; return op[index] ?? 0; }); return ( ); } export function MultiSeriesValueLabels({ engine, padding, colors, font, dotRadius, seriesCount, }: { engine: MultiEngineState; padding: ChartPadding; colors: string[]; font: SkFont; dotRadius: number; /** Number of live series slots to mount. */ seriesCount: number; }) { return ( {Array.from({ length: seriesCount }, (_, i) => ( ))} ); }