@motionscript/charts 0.1.1-alpha.1 → 0.1.1-alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/README.md +19 -8
  3. package/dist/bar-chart/bar-chart.d.ts +97 -65
  4. package/dist/bar-chart/bar-chart.d.ts.map +1 -1
  5. package/dist/bar-chart/bar-chart.js +9 -5
  6. package/dist/bar-chart/bar-chart.js.map +1 -1
  7. package/dist/bar-chart/chart-bars.d.ts +29 -5
  8. package/dist/bar-chart/chart-bars.d.ts.map +1 -1
  9. package/dist/bar-chart/chart-bars.js +33 -8
  10. package/dist/bar-chart/chart-bars.js.map +1 -1
  11. package/dist/bar-chart/shared.d.ts +9 -4
  12. package/dist/bar-chart/shared.d.ts.map +1 -1
  13. package/dist/bar-chart/shared.js +10 -5
  14. package/dist/bar-chart/shared.js.map +1 -1
  15. package/dist/browser/chunks/chunk-7XCRX6GE.js +2 -0
  16. package/dist/browser/chunks/chunk-7XCRX6GE.js.map +7 -0
  17. package/dist/browser/index.js +1 -1
  18. package/dist/browser/index.js.map +3 -3
  19. package/dist/browser/kit.js +1 -1
  20. package/dist/browser/manifest.json +1 -1
  21. package/dist/kit/cartesian.d.ts +6 -4
  22. package/dist/kit/cartesian.d.ts.map +1 -1
  23. package/dist/kit/cartesian.js +5 -3
  24. package/dist/kit/cartesian.js.map +1 -1
  25. package/dist/kit/style.d.ts +339 -76
  26. package/dist/kit/style.d.ts.map +1 -1
  27. package/dist/kit/style.js +196 -101
  28. package/dist/kit/style.js.map +1 -1
  29. package/dist/line-chart/line-chart.d.ts +81 -57
  30. package/dist/line-chart/line-chart.d.ts.map +1 -1
  31. package/dist/line-chart/line-chart.js +9 -7
  32. package/dist/line-chart/line-chart.js.map +1 -1
  33. package/dist/pie-chart/pie-chart.d.ts +43 -43
  34. package/dist/pie-chart/pie-chart.d.ts.map +1 -1
  35. package/dist/pie-chart/pie-chart.js +2 -1
  36. package/dist/pie-chart/pie-chart.js.map +1 -1
  37. package/dist/pie-chart/shared.d.ts +15 -8
  38. package/dist/pie-chart/shared.d.ts.map +1 -1
  39. package/dist/pie-chart/shared.js +21 -20
  40. package/dist/pie-chart/shared.js.map +1 -1
  41. package/dist/radar-chart/index.d.ts +1 -1
  42. package/dist/radar-chart/index.d.ts.map +1 -1
  43. package/dist/radar-chart/index.js +1 -1
  44. package/dist/radar-chart/index.js.map +1 -1
  45. package/dist/radar-chart/radar-chart.d.ts +37 -43
  46. package/dist/radar-chart/radar-chart.d.ts.map +1 -1
  47. package/dist/radar-chart/radar-chart.js +12 -12
  48. package/dist/radar-chart/radar-chart.js.map +1 -1
  49. package/dist/radar-chart/radar-grid.d.ts +7 -1
  50. package/dist/radar-chart/radar-grid.d.ts.map +1 -1
  51. package/dist/radar-chart/radar-grid.js +17 -15
  52. package/dist/radar-chart/radar-grid.js.map +1 -1
  53. package/dist/radar-chart/shared.d.ts +7 -2
  54. package/dist/radar-chart/shared.d.ts.map +1 -1
  55. package/dist/radar-chart/shared.js +6 -0
  56. package/dist/radar-chart/shared.js.map +1 -1
  57. package/dist/radial-chart/radial-chart.d.ts +37 -43
  58. package/dist/radial-chart/radial-chart.d.ts.map +1 -1
  59. package/dist/radial-chart/radial-chart.js +2 -1
  60. package/dist/radial-chart/radial-chart.js.map +1 -1
  61. package/dist/radial-chart/shared.d.ts +13 -9
  62. package/dist/radial-chart/shared.d.ts.map +1 -1
  63. package/dist/radial-chart/shared.js +15 -16
  64. package/dist/radial-chart/shared.js.map +1 -1
  65. package/package.json +4 -4
  66. package/src/bar-chart/bar-chart.ts +17 -6
  67. package/src/bar-chart/chart-bars.ts +48 -9
  68. package/src/bar-chart/shared.ts +20 -5
  69. package/src/kit/cartesian.ts +10 -7
  70. package/src/kit/style.ts +214 -118
  71. package/src/line-chart/line-chart.ts +14 -8
  72. package/src/pie-chart/pie-chart.ts +3 -1
  73. package/src/pie-chart/shared.ts +30 -22
  74. package/src/radar-chart/index.ts +1 -1
  75. package/src/radar-chart/radar-chart.ts +16 -13
  76. package/src/radar-chart/radar-grid.ts +18 -13
  77. package/src/radar-chart/shared.ts +9 -2
  78. package/src/radial-chart/radial-chart.ts +3 -1
  79. package/src/radial-chart/shared.ts +30 -18
  80. package/dist/browser/chunks/chunk-R3Q5EE6E.js +0 -2
  81. package/dist/browser/chunks/chunk-R3Q5EE6E.js.map +0 -7
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/line-chart/line-chart.ts", "../../src/line-chart/chart-line.ts", "../../src/line-chart/shared.ts", "../../src/line-chart/chart-region.ts", "../../src/line-chart/x-scale.ts", "../../src/bar-chart/bar-chart.ts", "../../src/bar-chart/category-axis.ts", "../../src/bar-chart/chart-bars.ts", "../../src/bar-chart/shared.ts", "../../src/pie-chart/pie-chart.ts", "../../src/pie-chart/pie-ring.ts", "../../src/pie-chart/shared.ts", "../../src/radar-chart/radar-chart.ts", "../../src/radar-chart/radar-grid.ts", "../../src/radar-chart/shared.ts", "../../src/radar-chart/radar-series.ts", "../../src/radial-chart/radial-chart.ts", "../../src/radial-chart/radial-rings.ts", "../../src/radial-chart/shared.ts", "../../src/nodes.ts"],
4
- "sourcesContent": ["import {\n Rect,\n Text,\n Types,\n clamp,\n component2d,\n easeOut,\n type ChildView,\n type DataRecord,\n type NodeOf,\n type OutOf,\n // Named so this component's emitted type reaches `Node2D` and its props through the sdk, not core.\n type Node2D,\n type Node2DProps as _Node2DProps,\n type Fill as _Fill,\n type FillResolved as _FillResolved,\n type Stroke as _Stroke,\n type StrokeResolved as _StrokeResolved,\n type Size2D,\n type StyleInput as _StyleInput,\n type StyleValues as _StyleValues,\n type Vector2,\n} from \"@motionscript/sdk\"\nimport { formatNumber } from \"@motionscript/sdk/component\"\n\nimport { boundText, cartesianFrame, chartViews, columnGhost, fade, frameGap, headroom, laidOutSize, overhang } from \"../kit/cartesian\"\nimport { ChartCanvas } from \"../kit/chart-canvas\"\nimport { ChartLegend } from \"../kit/chart-legend\"\nimport { SERIES_ARG, asParts, fresh } from \"../kit/entries\"\nimport { HorizontalAxis } from \"../kit/horizontal-axis\"\nimport { DEFAULT_MARKERS, ENTER_SHARE, beats, legendAway, type AnyTimeline, type Beat } from \"../kit/motion\"\nimport {\n SPOTLIGHT_DIM,\n formatMarker,\n lerpAxisDomain,\n lerpAxisEntry,\n markerStep,\n markerValues,\n niceRange,\n niceTicks,\n resolveAxisDomain,\n settleAxisDomain,\n type AxisDomainConfig,\n type Range,\n type ResolvedAxisDomain,\n} from \"../kit/shared\"\nimport {\n CARTESIAN_GRID,\n CHART_COLORS,\n CHART_LEGEND,\n CHART_STYLE_FAMILY,\n CHART_STYLE_PRESETS,\n CHART_TEXT,\n axisConfigOf,\n legendConfigOf,\n seriesFill,\n valueText,\n} from \"../kit/style\"\nimport { VerticalAxis, axisPads } from \"../kit/vertical-axis\"\nimport { ChartArea, ChartLine, traceX } from \"./chart-line\"\nimport { ChartRegion } from \"./chart-region\"\nimport {\n LINE_LABELS,\n LINE_MARKS,\n resolveRegionBox,\n stackExtent,\n stackSeries,\n type LineSeries,\n type LineStack,\n type PlotRegion,\n type RegionBox,\n type StackedSeries,\n} from \"./shared\"\nimport { resolveXScale, type XScale } from \"./x-scale\"\n\nconst LINE_STYLE = Types.style(\n CHART_STYLE_FAMILY,\n { colors: CHART_COLORS, text: CHART_TEXT, grid: CARTESIAN_GRID, marks: LINE_MARKS, labels: LINE_LABELS, legend: CHART_LEGEND },\n { presets: CHART_STYLE_PRESETS }\n)\n\n/** A line chart's resolved style. */\nexport type LineChartStyle = OutOf<typeof LINE_STYLE>\n\n/** Both axes' domains with their ranges and ticks resolved. */\nexport interface LineChartDomains {\n readonly x: ResolvedAxisDomain\n readonly y: ResolvedAxisDomain\n}\n\n/** What a line chart plots, as its entries hold it. */\nexport interface LineChartValues {\n readonly data: DataRecord[]\n readonly xField: string\n readonly series: LineSeries[]\n readonly stack: LineStack\n readonly xAxis: AxisDomainConfig\n readonly yAxis: AxisDomainConfig\n /** Each series' share of a stack, `1` when missing. */\n readonly weights?: readonly number[]\n /** An area must reach its baseline, so a chart with areas keeps zero on the scale. */\n readonly style?: { readonly area: string }\n}\n\n/** One argument, two controls: the commands take a `PlotRegion`, so the x and y spans a host draws are declared inside it. */\nconst REGION_ARG = Types.custom<PlotRegion | undefined>(undefined, {\n kind: \"region\",\n properties: {\n x: { kind: \"range\", default: true, defaultMin: 0, defaultMax: 100 },\n y: { kind: \"range\", default: false, defaultMin: 0, defaultMax: 100 },\n },\n})\n\n/** What the chart's own commands read: its entries, and the private state they write. */\ninterface LineState extends LineChartValues {\n readonly style: LineChartStyle\n readonly region: PlotRegion | null\n readonly regionReveal: number\n readonly home: LineChartDomains | null\n readonly weights: number[]\n}\n\n/** The share of the y axis a percent stack reads to. */\nconst PERCENT: Range = [0, 100]\n\n/** What the x column is (a number, an instant, or a place in the file), and so how rows are positioned, ticked and captioned. */\nfunction columnOf(s: LineChartValues, format = s.xAxis.format): XScale {\n return resolveXScale(s.data, s.xField, format)\n}\n\n/** Every series as drawn; `weighted` false reads each at full share, as the scale does so the ticks hold still while a series sinks out. */\nfunction stacksOf(s: LineChartValues, weighted = true): StackedSeries[] {\n return stackSeries(s.data, columnOf(s), s.series, s.stack, weighted ? s.weights : undefined)\n}\n\n/** The explicit range and ticks, else the column's extent and ticks: only a numeric column has round numbers between its samples. */\nfunction drawnX(s: LineChartValues, domain: AxisDomainConfig): AxisDomainConfig {\n const column = columnOf(s, domain.format)\n const range = domain.range ?? column.extent\n return { ...domain, range, ticks: domain.ticks ?? column.ticks(range, DEFAULT_MARKERS - 1) }\n}\n\n/** The y range the data asks for: a percent stack reads to 100; areas and stacks keep zero on the scale. */\nfunction autoY(s: LineChartValues, divisions: number): Range {\n const [lo, hi] = stackExtent(stacksOf(s, false))\n if (s.stack === \"percent\" && lo >= 0) return PERCENT\n const zero = s.stack !== \"none\" || (s.style?.area ?? \"none\") !== \"none\"\n return niceRange(zero ? [Math.min(0, lo), Math.max(0, hi)] : [lo, hi], divisions)\n}\n\n/** Auto-ranging steps into one fewer segment than the marker count, so the tidy bounds frame the ticks drawn. */\nfunction drawnY(s: LineChartValues, domain: AxisDomainConfig): AxisDomainConfig {\n const divisions = (domain.ticks?.length ?? DEFAULT_MARKERS) - 1\n const range = domain.range ?? autoY(s, divisions)\n const even = domain.range !== undefined || (s.stack === \"percent\" && range === PERCENT)\n return { ...domain, range, ticks: domain.ticks ?? (even ? markerValues(range, DEFAULT_MARKERS - 1) : niceTicks(range, DEFAULT_MARKERS - 1)) }\n}\n\n/** The last domains worked out from each data array, and what else they were read from. */\nconst domainsDrawn = new WeakMap<DataRecord[], { readonly key: readonly unknown[]; readonly domains: LineChartDomains }>()\n\n/** Both axes as drawn now. */\nexport function lineChartDomains(s: LineChartValues): LineChartDomains {\n const key = [s.xField, s.xAxis, s.yAxis, s.series, s.stack, s.style?.area]\n const kept = domainsDrawn.get(s.data)\n if (kept && kept.key.every((value, i) => value === key[i])) return kept.domains\n const domains = {\n x: settleAxisDomain(s.xAxis, (d) => drawnX(s, d)) as LineChartDomains[\"x\"],\n y: settleAxisDomain(s.yAxis, (d) => drawnY(s, d)) as LineChartDomains[\"y\"],\n }\n domainsDrawn.set(s.data, { key, domains })\n return domains\n}\n\n/** Data to the plot's centred pixel space (origin at its centre, y-up). */\nfunction mapper(domains: LineChartDomains, plot: Size2D) {\n const [xMin, xMax] = domains.x.range\n const [yMin, yMax] = domains.y.range\n return {\n x: (x: number) => (xMax <= xMin ? 0 : ((x - xMin) / (xMax - xMin) - 0.5) * plot.width),\n y: (y: number) => (yMax === yMin ? 0 : ((y - yMin) / (yMax - yMin) - 0.5) * plot.height),\n }\n}\n\ninterface SeriesPixels {\n readonly points: Vector2[]\n /** The line under the series in a stack; empty when it fills to the baseline. */\n readonly base: Vector2[]\n /** What each point reads: its own value, or its share in a percent stack. */\n readonly values: number[]\n}\n\nconst NO_PIXELS: SeriesPixels = { points: [], base: [], values: [] }\n\n/** Series `index` in the plot's centred pixel space. */\nfunction seriesPixels(s: LineChartValues, domains: LineChartDomains, index: number, plot: Size2D): SeriesPixels {\n const stack = stacksOf(s)[index]\n if (!stack) return NO_PIXELS\n const map = mapper(domains, plot)\n const toPx = ([x, y]: [number, number]): Vector2 => ({ x: map.x(x), y: map.y(y) })\n return {\n points: stack.points.map(toPx),\n base: stack.base ? stack.base.map(toPx) : [],\n values: stack.points.map(([, y], k) => y - (stack.base?.[k]?.[1] ?? 0)),\n }\n}\n\n/** Where the areas fill down to: zero, held inside the scale. */\nfunction baselineValue(domains: LineChartDomains): number {\n const [lo, hi] = domains.y.range\n return clamp(0, Math.min(lo, hi), Math.max(lo, hi))\n}\n\n/** Whether anything plotted runs past the scale, so the plot clips it: a zoom, or an author's range narrower than the data. */\nfunction overflows(s: LineChartValues, domains: LineChartDomains): boolean {\n const [ylo, yhi] = stackExtent(stacksOf(s, false))\n const [xlo, xhi] = columnOf(s).extent\n const within = (v: number, [a, b]: Range) => v >= Math.min(a, b) - 1e-9 && v <= Math.max(a, b) + 1e-9\n return !(within(ylo, domains.y.range) && within(yhi, domains.y.range) && within(xlo, domains.x.range) && within(xhi, domains.x.range))\n}\n\n/** `region` in centred pixel space against the live scales, so it travels with a zoom. */\nfunction regionBox(s: LineChartValues & { readonly region: PlotRegion | null }, domains: LineChartDomains, plot: Size2D): RegionBox {\n const { width: w, height: h } = plot\n return resolveRegionBox(s.region, { left: -w / 2, right: w / 2, bottom: -h / 2, top: h / 2 }, domains.x.range, domains.y.range)\n}\n\n/** Whether a call-out is authored, not whether it resolves to pixels: a command is built before the first layout. A region bounding neither axis is none. */\nfunction hasCallout(s: { readonly region: PlotRegion | null }): boolean {\n const region = s.region\n return region != null && (region.x !== undefined || region.y !== undefined)\n}\n\n/** The `region` argument, or `{}`: a command is added before its arguments are filled in. */\nfunction regionArg(region: PlotRegion | null | undefined): PlotRegion {\n return region != null && typeof region === \"object\" ? region : {}\n}\n\n/** A range ordered low to high. */\nfunction span([a, b]: Range): Range {\n return a <= b ? [a, b] : [b, a]\n}\n\n/** Rescale to `range` keeping the tick count, so each marker slides rather than the row popping. */\nfunction rescale(range: Range, ticks: readonly number[]): AxisDomainConfig {\n const to = span(range)\n return { range: to, ticks: markerValues(to, Math.max(2, ticks.length) - 1) }\n}\n\nfunction axesAt(from: LineChartDomains, to: Partial<Record<\"x\" | \"y\", AxisDomainConfig>>, t: number) {\n return {\n ...(to.x && { xAxis: lerpAxisDomain(from.x, to.x, t) }),\n ...(to.y && { yAxis: lerpAxisDomain(from.y, to.y, t) }),\n }\n}\n\n/** A value as the y axis writes it: the author's pattern, a share in a percent stack, else the bare reading at the ticks' precision. */\nfunction yLabel(s: LineChartValues, value: number, ticks: readonly number[]): string {\n const format = s.yAxis.format\n if (format !== undefined) return formatNumber(value, format)\n const text = formatMarker(value, markerStep(ticks))\n return s.stack === \"percent\" ? `${text}%` : text\n}\n\nfunction weightOf(s: { readonly weights: readonly number[] }, index: number): number {\n return Math.max(0, s.weights[index] ?? 1)\n}\n\n/** The parts a line chart's commands drive, found through its children. */\nfunction partsOf(children: readonly ChildView[]) {\n const views = chartViews(children)\n return {\n vAxis: views.find(VerticalAxis.is) ?? null,\n hAxis: views.find(HorizontalAxis.is) ?? null,\n lines: views.filter(ChartLine.is),\n legend: views.find(ChartLegend.is) ?? null,\n }\n}\n\nfunction clearing(timeline: AnyTimeline, state: LineState) {\n const from = state.regionReveal\n const region = state.region\n // Nothing to retract, but the call still takes its slot.\n if (from === 0) return timeline.animate(() => ({ region: null, regionReveal: 0 }), { eased: false })\n // `region` is held until the retraction lands, or there would be nothing left to retract.\n return timeline.animate((t) => (t >= 1 ? { region: null, regionReveal: 0 } : { region, regionReveal: from * (1 - t) }))\n}\n\n/**\n * Show or hide series `index` with its legend entry. Apart, the line retraces;\n * in a stack it sinks into the series below as its share falls to nothing, so\n * the ones above settle rather than leaving a gap.\n */\nfunction toggling(timeline: AnyTimeline, state: LineState, children: readonly ChildView[], index: number, show: boolean) {\n const parts = partsOf(children)\n const line = parts.lines[index]\n if (!line) return timeline.wait(timeline.duration)\n const legend = parts.legend ? [parts.legend.run(show ? \"showSeries\" : \"hideSeries\", { index })] : []\n if (state.stack === \"none\") {\n return timeline.together([line.run(\"enter\", show ? { from: 0, to: 1 } : { from: 1, to: 0 }), ...legend])\n }\n const from = state.series.map((_, i) => weightOf(state, i))\n const start = from[index] ?? 1\n const target = show ? 1 : 0\n return timeline.together([\n timeline.animate((t) => {\n const weights = [...from]\n weights[index] = start + (target - start) * timeline.ease(t)\n return { weights }\n }, { eased: false }),\n line.run(\"hold\", { shown: show }),\n ...legend,\n ])\n}\n\n/**\n * A multi-series line or area chart composed of {@link ChartCanvas}, the value\n * and x axes, {@link ChartRegion}, a {@link ChartArea} and a {@link ChartLine}\n * per series, and {@link ChartLegend}. Every part reads the chart's entries\n * through bindings and maps against the plot panel's own laid-out box.\n *\n * Resting state is the finished chart; `enter` arms every part on its first\n * frame. A `to` of an axis `range` or `ticks` tweens from the domain as drawn\n * (see {@link lerpAxisEntry}), so an auto axis rescales continuously.\n */\nexport const LineChart = component2d({\n key: \"lineChart\",\n state: {\n data: fresh<DataRecord[]>(() => [], { kind: \"dataset\" }),\n // Not `x`: every node already has an `x`, its position.\n xField: \"\",\n series: fresh<LineSeries[]>(() => [], { kind: \"series\" }),\n /** `stacked`: each series sits on the sum of those before it; `percent`: every row reads as shares of 100. */\n stack: Types.oneOf([\"none\", \"stacked\", \"percent\"] as const),\n xAxis: Types.custom<AxisDomainConfig>({}, { resolve: resolveAxisDomain, lerp: lerpAxisEntry }),\n yAxis: Types.custom<AxisDomainConfig>({}, { resolve: resolveAxisDomain, lerp: lerpAxisEntry }),\n style: LINE_STYLE,\n /** The spotlit slice in data units, or `null`. The box snaps; {@link regionReveal} animates it. */\n region: Types.custom<PlotRegion | null>(null),\n /** How far the `region` call-out is drawn in, `[0, 1]`: rules grow, wash fades up, out-of-region stretches fade. */\n regionReveal: 0,\n /** The domain `zoomTo` first left, so `resetZoom` restores it, auto-derived ticks included. */\n home: Types.custom<LineChartDomains | null>(null, { private: true }),\n /** Each series' share of a stack, seeded from `enabled`: a weight rather than a switch, so a hidden series sinks out. */\n weights: Types.custom<number[]>([], { private: true }),\n /** Whether the plot clips its marks, from a zoom's first frame until a reset lands. */\n clipped: Types.boolean(false, { private: true }),\n },\n // A node made of parts that fill would otherwise hug them.\n defaults: {\n width: \"fill\",\n height: \"fill\",\n weights: (state) => state.series.map((s) => ((s.enabled ?? true) ? 1 : 0)),\n },\n allowedChildren: [],\n children: (state) => {\n const style = () => state.style\n const domains = () => lineChartDomains(state)\n let plot: Node2D | undefined\n const plotSize = () => laidOutSize(plot)\n const pixels = (i: number) => seriesPixels(state, domains(), i, plotSize())\n const enabled = state.series.map((s) => s.enabled ?? true)\n const built = state.style\n const yConfig = () => axisConfigOf(style(), \"y\")\n const xConfig = () => axisConfigOf(style(), \"x\")\n const yCaptions = () => {\n const ticks = domains().y.ticks\n return ticks.map((value) => yLabel(state, value, ticks))\n }\n\n // Bound, not snapshotted, so a rescale re-labels and re-places the row as it\n // tweens. The marker *count* is read once, which is why `zoomTo` keeps it.\n const vAxis = built.showYAxis\n ? (new VerticalAxis({\n range: () => domains().y.range,\n markers: () => domains().y.ticks,\n captions: yCaptions,\n axis: yConfig,\n label: state.yAxis.label ?? \"\",\n width: \"hug\",\n height: \"fill\",\n }) as unknown as Node2D)\n : undefined\n\n const hAxis = built.showXAxis\n ? (new HorizontalAxis({\n range: () => domains().x.range,\n markers: () => domains().x.ticks,\n // A month or category tick is captioned with its cell (`Jan`), not the instant it parsed to.\n captions: () => {\n const column = columnOf(state)\n return domains().x.ticks.map((value) => column.label(value))\n },\n axis: xConfig,\n label: state.xAxis.label ?? \"\",\n overhang: () => ({ left: overhang(style()), right: overhang(style()) }),\n width: \"fill\",\n height: \"hug\",\n }) as unknown as Node2D)\n : undefined\n\n const ghost = vAxis && hAxis\n ? columnGhost({\n captions: yCaptions,\n count: lineChartDomains(state).y.ticks.length,\n text: () => yConfig().labelStyle,\n title: state.yAxis.label ?? \"\",\n titleText: () => yConfig().titleStyle,\n tickPad: () => axisPads(yConfig(), \"right\").tick,\n titlePad: () => axisPads(yConfig(), \"right\").title,\n })\n : undefined\n\n const spotlight = () => regionBox(state, domains(), plotSize())\n const dimOpacity = () => 1 - (1 - SPOTLIGHT_DIM) * state.regionReveal\n const lines = state.series.map((s, i) =>\n new ChartLine({\n points: () => pixels(i).points,\n curve: () => style().curve,\n stroke: () => ({ weight: style().strokeWidth, fill: seriesFill(style(), s, i), align: \"center\", cap: \"round\", join: \"round\" }),\n dotSize: () => (style().dots ? style().dotSize : 0),\n dotFill: () => seriesFill(style(), s, i),\n enabled: enabled[i],\n spotlight,\n dimOpacity,\n })\n )\n const areas = state.series.map((s, i) =>\n new ChartArea({\n points: () => pixels(i).points,\n base: () => pixels(i).base,\n baseline: () => mapper(domains(), plotSize()).y(baselineValue(domains())),\n curve: () => style().curve,\n area: () => style().area,\n fill: () => seriesFill(style(), s, i),\n areaOpacity: () => style().areaOpacity,\n // The line's own trace, switch and fade, so the two arrive, leave and dim as one.\n progress: () => lines[i].progress,\n enabled: () => lines[i].enabled,\n opacity: () => lines[i].opacity,\n spotlight,\n dimOpacity,\n })\n )\n\n const labels: Node2D[] = []\n if (built.values !== \"none\") {\n const below = built.values === \"below\"\n state.series.forEach((_, i) => {\n state.data.forEach((_row, k) => {\n const line = lines[i]\n const label: Node2D = new Text({\n ...boundText(() => ({ ...valueText(style()), fontSize: Math.round(style().fontSize * 0.8) })),\n text: () => {\n const value = pixels(i).values[k]\n return value === undefined ? \"\" : yLabel(state, value, domains().y.ticks)\n },\n // Held inside the plot, so a figure on an end point does not run into the axis beside it.\n x: () => {\n const half = (plotSize().width - label.layoutBounds.width) / 2\n return clamp(pixels(i).points[k]?.x ?? 0, -Math.max(0, half), Math.max(0, half))\n },\n y: () => {\n const point = pixels(i).points[k]\n const clear = label.layoutBounds.height / 2 + (style().dots ? style().dotSize / 2 : style().strokeWidth / 2) + Math.round(style().fontSize * 0.25)\n return (point?.y ?? 0) + (below ? -clear : clear)\n },\n // In once the trace has passed its point.\n opacity: () => {\n const point = pixels(i).points[k]\n if (!line.enabled || !point) return 0\n const reach = traceX(pixels(i).points, line.progress)\n return line.opacity * (reach === Infinity ? 1 : clamp((reach - point.x) / 24, 0, 1))\n },\n }) as unknown as Node2D\n labels.push(label)\n })\n })\n }\n\n const legendAt = built.legend\n const legend = legendAt !== \"none\"\n ? (new ChartLegend({\n series: state.series,\n swatches: () => state.series.map((s, i) => seriesFill(style(), s, i)),\n legend: () => legendConfigOf(style()),\n flow: legendAt === \"right\" ? \"vertical\" : \"horizontal\",\n }) as unknown as Node2D)\n : undefined\n\n plot = new Rect({\n clip: () => state.clipped || overflows(state, domains()),\n children: [\n new ChartCanvas({\n fill: () => style().background,\n xGridStroke: () => style().verticalGrid,\n yGridStroke: () => style().horizontalGrid,\n xMarkers: () => domains().x.ticks,\n yMarkers: () => domains().y.ticks,\n xExtent: () => domains().x.range,\n yExtent: () => domains().y.range,\n axisStroke: () => style().axisStroke,\n xAxisAt: () => baselineValue(domains()),\n yAxisAt: () => domains().x.range[0],\n }),\n // Under the marks, so the highlight does not tint the stretch it picks out.\n new ChartRegion({\n box: spotlight,\n stroke: () => ({ weight: 2, fill: fade(style().foreground, 0.7), dash: [14, 12], cap: \"butt\", align: \"center\" }),\n fill: () => fade(style().foreground, 0.06),\n reveal: () => state.regionReveal,\n }),\n ...areas,\n ...lines,\n ...labels,\n ],\n }) as unknown as Node2D\n\n return asParts([\n cartesianFrame({\n left: vAxis,\n ghost,\n plot,\n bottom: hAxis,\n legend,\n legendAt,\n gap: () => frameGap(style()),\n padding: () => ({\n top: headroom(style()),\n right: hAxis ? overhang(style()) : 0,\n left: hAxis && !vAxis ? overhang(style()) : 0,\n bottom: 0,\n }),\n }),\n ])\n },\n commands: {\n /**\n * Axes stagger in, lines (and their areas) trace left to right, the legend\n * fades up last. `duration` is the whole entrance; a chart with a `region`\n * lands its call-out in the final quarter.\n */\n enter: {\n args: {},\n // Held from arrival, so it never shows finished ahead of its draw.\n entrance: true,\n easing: easeOut(),\n run: (timeline, state, children) => {\n const parts = partsOf(children)\n const duration = timeline.duration\n const revealing = hasCallout(state) && state.regionReveal === 0\n const body = revealing ? duration * 0.75 : duration\n const axes = body * ENTER_SHARE.axes\n const traced = body * ENTER_SHARE.marks\n const { legend } = parts\n const at0 = (piece: Beat[\"piece\"]): Beat => ({ at: 0, duration: 0, piece })\n const away = legendAway(state.style.legend)\n // The first frame arms what every later beat moves: a beat ahead of the\n // playhead writes nothing. A beat with nothing to do still takes its share.\n return beats(timeline, [\n ...(revealing ? [at0(timeline.animate(() => ({ regionReveal: 0 })))] : []),\n ...parts.lines.map((line) => at0(line.to({ progress: 0 }))),\n ...(legend ? [at0(legend.to({ opacity: 0, ...away }))] : []),\n ...(parts.vAxis ? [{ at: 0, duration: axes, piece: parts.vAxis.run(\"enter\", { slide: 24 }) }] : []),\n ...(parts.hAxis ? [{ at: 0, duration: axes, piece: parts.hAxis.run(\"enter\", { slide: 24 }) }] : []),\n ...parts.lines.map((line) => ({ at: axes, duration: traced, piece: line.run(\"enter\") })),\n ...(legend ? [{ at: axes + traced, duration: body * ENTER_SHARE.legend, piece: legend.to({ opacity: 1, x: 0, y: 0 }) }] : []),\n ...(revealing ? [{ at: body, duration: duration * 0.25, piece: timeline.animate((t) => ({ regionReveal: t })) }] : []),\n // Takes the whole slot even with no parts to move.\n { at: 0, duration, piece: timeline.wait(duration) },\n ])\n },\n },\n /**\n * Spotlight a slice of the plot in data units; either axis alone is a band.\n * Over a region already up, the old one retracts in the first half and the\n * new one draws in over the second, each half eased on its own.\n */\n spotlightRegion: {\n args: { region: REGION_ARG },\n easing: easeOut(),\n run: (timeline, state) => {\n const region = regionArg(timeline.args.region)\n const from = state.regionReveal\n const previous = state.region\n // A region bounding neither axis is no call-out: spotlighting it is a clear.\n if (region.x === undefined && region.y === undefined) return clearing(timeline, state)\n // Nothing up yet: the region is set from the first frame and just draws on.\n if (from <= 0 || !hasCallout(state)) return timeline.animate((t) => ({ region, regionReveal: from + (1 - from) * t }))\n return timeline.animate(\n (t) => (t < 0.5\n ? { region: previous, regionReveal: from * (1 - timeline.ease(t * 2)) }\n : { region, regionReveal: timeline.ease(t * 2 - 1) }),\n { eased: false }\n )\n },\n },\n /** Drop the call-out. A no-op when nothing is spotlit, which still takes its slot. */\n clearRegion: {\n args: {},\n easing: easeOut(),\n run: (timeline, state) => clearing(timeline, state),\n },\n /** Rescale the named axes so a slice (data units) fills the plot; an omitted axis is left. The first zoom remembers the domain for `resetZoom`. */\n zoomTo: {\n args: { region: REGION_ARG },\n easing: easeOut(),\n run: (timeline, state) => {\n const region = regionArg(timeline.args.region)\n if (!region.x && !region.y) return timeline.wait(timeline.duration)\n const from = lineChartDomains(state)\n const home = state.home ?? from\n const to = {\n ...(region.x && { x: { ...from.x, ...rescale(region.x, from.x.ticks) } }),\n ...(region.y && { y: { ...from.y, ...rescale(region.y, from.y.ticks) } }),\n }\n return timeline.animate((t) => ({ home, clipped: true, ...axesAt(from, to, t) }))\n },\n },\n /** Back to the domain the first zoom left; a hold if it never zoomed. */\n resetZoom: {\n args: {},\n easing: easeOut(),\n run: (timeline, state) => {\n const home = state.home\n if (!home) return timeline.wait(timeline.duration)\n const from = lineChartDomains(state)\n return timeline.animate((t) => ({ home: null, clipped: t < 1, ...axesAt(from, home, t) }))\n },\n },\n /** Bring series `index` in, with its legend entry growing in: traced, or in a stack risen out of the series below. */\n showSeries: {\n args: { seriesIndex: SERIES_ARG },\n easing: easeOut(),\n run: (timeline, state, children) => toggling(timeline, state, children, timeline.args.seriesIndex, true),\n },\n /** The mirror of `showSeries`. */\n hideSeries: {\n args: { seriesIndex: SERIES_ARG },\n easing: easeOut(),\n run: (timeline, state, children) => toggling(timeline, state, children, timeline.args.seriesIndex, false),\n },\n /** Fade every other series, line, area and legend entry, to focus on `index`. The legend dims in place, so the row does not reflow. */\n spotlightSeries: {\n args: { seriesIndex: SERIES_ARG },\n easing: easeOut(),\n run: (timeline, _state, children) => {\n const parts = partsOf(children)\n const index = timeline.args.seriesIndex\n return timeline.together([\n ...parts.lines.map((line, i) => line.to({ opacity: i === index ? 1 : SPOTLIGHT_DIM })),\n ...(parts.legend ? [parts.legend.run(\"spotlightSeries\", { index })] : []),\n timeline.wait(timeline.duration),\n ])\n },\n },\n },\n})\n\nexport type LineChart = NodeOf<typeof LineChart>\n", "import {\n Graphics2D,\n Types,\n clamp,\n component2d,\n fillOps,\n strokeOps,\n type Fill,\n type FillResolved,\n type NodeOf,\n // Named so this component's emitted type reaches `Node2D` and its props through the sdk, not core.\n type Node2D as _Node2D,\n type Node2DProps as _Node2DProps,\n type PathCommand,\n type RenderContext,\n type Stroke,\n type StrokeResolved,\n type Vector2,\n} from \"@motionscript/sdk\"\n\nimport { fade } from \"../kit/cartesian\"\nimport { fresh } from \"../kit/entries\"\nimport { frameEase } from \"../kit/motion\"\nimport { loadPaints } from \"../kit/paints\"\nimport { SPOTLIGHT_DIM } from \"../kit/shared\"\nimport {\n EMPTY_REGION_BOX,\n clipPolygonToBox,\n clipPolylineToBox,\n cutAt,\n curvePoints,\n hasRegion,\n type LineCurve,\n type RegionBox,\n} from \"./shared\"\n\n/** The x a trace at `progress` has reached, across `points` ordered along x. */\nexport function traceX(points: readonly Vector2[], progress: number): number {\n if (points.length === 0) return 0\n const first = points[0].x\n const last = points[points.length - 1].x\n return progress >= 1 ? Infinity : first + (last - first) * progress\n}\n\n/** The drawn path at `progress`: the whole curve once traced, else the part left of the trace. */\nfunction traced(points: readonly Vector2[], curve: LineCurve, progress: number): Vector2[] {\n const path = curvePoints(points, curve)\n return progress >= 1 ? path : cutAt(path, traceX(points, progress))\n}\n\nconst curveEntry = () => Types.custom<LineCurve>(\"smooth\")\n\n/** A closed outline as path commands. */\nfunction outlineCommands(points: readonly Vector2[]): PathCommand[] {\n return [...points.map((p, i): PathCommand => ({ type: i === 0 ? \"M\" : \"L\", x: p.x, y: p.y })), { type: \"Z\" }]\n}\n\nfunction fillOutline(ctx: RenderContext, outline: readonly Vector2[], fill: FillResolved[], opacity: number): void {\n if (outline.length < 3 || opacity <= 0) return\n const { width, height } = ctx.size\n // A frame symmetric about the origin, so the outline draws where its points say rather than re-centred on itself.\n const centerBounds: [number, number, number, number] = [-width / 2, -height / 2, width / 2, height / 2]\n ctx.draw(new Graphics2D().path({ data: outlineCommands(outline), centerBounds }).fill(fill).opacity(opacity))\n}\n\n/**\n * One series of a {@link LineChart}: its line through pre-mapped pixel `points`,\n * shaped by `curve`, and a dot on each point. `progress` traces it in from the\n * left; `enabled` shows or hides it wholesale.\n */\nexport const ChartLine = component2d({\n key: \"chartLine\",\n state: {\n /** In this node's pixel space (origin at centre, y-up), mapped by the parent and ordered along x. */\n points: fresh<Vector2[]>(() => []),\n curve: curveEntry(),\n stroke: Types.custom<Stroke, StrokeResolved[]>([], { resolve: strokeOps.resolve, lerp: strokeOps.lerp }),\n /** A dot of `dotSize` on each point, in `dotFill`; none at size 0. */\n dotSize: 0,\n dotFill: Types.custom<Fill, FillResolved[]>([], { resolve: fillOps.resolve, lerp: fillOps.lerp }),\n /** Trace from the left end, `[0, 1]`. Rests at 1 so a paused editor canvas paints the line; `enter` drives it from 0. */\n progress: 1,\n /** Whether the line is drawn at all, flipped alongside its legend entry. */\n enabled: true,\n /** In this node's pixel space; outside it the line drops to `dimOpacity`. */\n spotlight: fresh<RegionBox>(() => EMPTY_REGION_BOX),\n dimOpacity: SPOTLIGHT_DIM,\n },\n load: (loader, state) => loadPaints(loader, { fills: [state.dotFill], strokes: [state.stroke] }),\n commands: {\n /**\n * Trace the line from `from` to `to`; `showSeries`/`hideSeries` are this with\n * the ends stated. `enabled` rides along in the same value, so the line is\n * drawable for every `t` the trace covers and arriving backwards matches\n * arriving forwards.\n */\n enter: {\n args: { from: Types.number(0, { min: 0, max: 1 }), to: Types.number(1, { min: 0, max: 1 }) },\n run: (timeline) => {\n const { from, to } = timeline.args\n const ease = frameEase(timeline)\n return timeline.animate((t) => {\n const progress = from + (to - from) * ease(t)\n // Hidden only once fully retraced, so a hide does not vanish a frame early.\n return { progress, enabled: progress > 0 }\n })\n },\n },\n /** Hold the line fully traced while its chart moves it, switched on throughout a show and off once a hide lands. */\n hold: {\n args: { shown: Types.boolean(true) },\n run: (timeline) => {\n const { shown } = timeline.args\n return timeline.animate((t) => ({ progress: 1, enabled: shown || t < 1 }), { eased: false })\n },\n },\n },\n render: (ctx, state) => {\n if (!state.enabled) return\n const pts = state.points\n const p = clamp(state.progress, 0, 1)\n if (pts.length === 0 || p <= 0) return\n\n const box = state.spotlight\n const lit = hasRegion(box)\n const dim = clamp(state.dimOpacity, 0, 1)\n const stroke = state.stroke\n const weight = stroke[0]?.weight ?? 0\n const drawn = traced(pts, state.curve, p)\n\n if (drawn.length >= 2 && weight > 0) {\n // Rounded corners only where the line has corners to round.\n const radius = state.curve === \"linear\" ? weight * 2 : 0\n ctx.draw(new Graphics2D().line({ points: drawn, radius }).stroke(stroke).opacity(lit ? dim : 1))\n // One `draw` per run: shapes chained before `stroke()` combine into one surface, and stroking a union of disjoint open paths paints nothing.\n if (lit) for (const run of clipPolylineToBox(drawn, box)) ctx.draw(new Graphics2D().line({ points: run, radius }).stroke(stroke))\n }\n\n const size = state.dotSize\n if (size <= 0) return\n const reach = traceX(pts, p)\n const bright = new Graphics2D()\n const dimmed = new Graphics2D()\n let brightAny = false\n let dimAny = false\n for (const pt of pts) {\n // A dot grows in as the trace passes it.\n const grown = reach === Infinity ? 1 : clamp((reach - pt.x) / (size * 2), 0, 1)\n if (grown <= 0) continue\n const inside = !lit || (pt.x >= box.left && pt.x <= box.right && pt.y >= box.bottom && pt.y <= box.top)\n ;(inside ? bright : dimmed).ellipse({ x: pt.x, y: pt.y, width: size * grown, height: size * grown })\n if (inside) brightAny = true\n else dimAny = true\n }\n if (dimAny) ctx.draw(dimmed.fill(state.dotFill).opacity(dim))\n if (brightAny) ctx.draw(bright.fill(state.dotFill))\n },\n})\n\nexport type ChartLine = NodeOf<typeof ChartLine>\n\n/**\n * The fill under one series of a {@link LineChart}: down to `base` (the series\n * below it in a stack) or, without one, to the `baseline`. Drawn by its own node\n * so every area sits under every line; the chart binds its trace, switch and\n * opacity to its line's, so the two move as one.\n */\nexport const ChartArea = component2d({\n key: \"chartArea\",\n state: {\n /** The series' points, as its line has them. */\n points: fresh<Vector2[]>(() => []),\n /** The line the area fills down to, at the same x positions; empty for the baseline. */\n base: fresh<Vector2[]>(() => []),\n /** Pixel y of the baseline. */\n baseline: 0,\n curve: curveEntry(),\n area: Types.custom<\"none\" | \"solid\" | \"gradient\">(\"solid\"),\n /** The series colour; the area paints it at `areaOpacity`, a gradient fading it out towards the bottom. */\n fill: Types.custom<Fill, FillResolved[]>([], { resolve: fillOps.resolve, lerp: fillOps.lerp }),\n areaOpacity: 0.4,\n progress: 1,\n enabled: true,\n spotlight: fresh<RegionBox>(() => EMPTY_REGION_BOX),\n dimOpacity: SPOTLIGHT_DIM,\n },\n load: (loader, state) => loadPaints(loader, { fills: [state.fill] }),\n render: (ctx, state) => {\n const pts = state.points\n const p = clamp(state.progress, 0, 1)\n if (!state.enabled || state.area === \"none\" || pts.length < 2 || p <= 0 || state.fill.length === 0) return\n const outlineAt = (progress: number) => {\n const top = traced(pts, state.curve, progress)\n if (top.length < 2) return []\n const base = state.base.length === pts.length\n ? traced(state.base, state.curve, progress)\n : [{ x: top[0].x, y: state.baseline }, { x: top[top.length - 1].x, y: state.baseline }]\n return [...top, ...[...base].reverse()]\n }\n // The gradient spans the whole area's height, so it holds still while the area traces in and across a spotlight's cut.\n const span = verticalSpan(outlineAt(1))\n const paint = (outline: readonly Vector2[], opacity: number) =>\n fillOutline(ctx, outline, areaFill(state.fill, state.area, state.areaOpacity, span, verticalSpan(outline)), opacity)\n const outline = outlineAt(p)\n const box = state.spotlight\n if (!hasRegion(box)) {\n paint(outline, 1)\n return\n }\n paint(outline, clamp(state.dimOpacity, 0, 1))\n paint(clipPolygonToBox(outline, box), 1)\n },\n})\n\ninterface Span {\n readonly top: number\n readonly bottom: number\n}\n\nfunction verticalSpan(points: readonly Vector2[]): Span {\n let top = -Infinity\n let bottom = Infinity\n for (const p of points) {\n if (p.y > top) top = p.y\n if (p.y < bottom) bottom = p.y\n }\n return { top, bottom }\n}\n\n/**\n * The area's paint for an outline spanning `own`: the series colour at\n * `opacity`, or for a gradient that colour fading to nearly nothing across\n * `whole`. A gradient maps onto the bounds of the shape it fills, so its ends\n * are placed in `own`'s unit box (y-up) at `whole`'s top and bottom.\n */\nexport function areaFill(colour: FillResolved[], area: \"none\" | \"solid\" | \"gradient\", opacity: number, whole: Span, own: Span): FillResolved[] {\n const top = colour[colour.length - 1]\n if (area !== \"gradient\" || top?.type !== \"solid\" || !(own.top > own.bottom)) return fade(colour, opacity) as FillResolved[]\n const [r, g, b, a] = top.color\n const middle = (own.top + own.bottom) / 2\n const half = (own.top - own.bottom) / 2\n return fillOps.resolve({\n type: \"linear-gradient\",\n colors: [[r, g, b, a * opacity], [r, g, b, a * opacity * 0.04]],\n start: { x: 0, y: (whole.top - middle) / half },\n end: { x: 0, y: (whole.bottom - middle) / half },\n })\n}\n\nexport type ChartArea = NodeOf<typeof ChartArea>\n", "import { Types, type DataRecord, type Vector2 } from \"@motionscript/sdk\"\n\nimport { niceRange, num, type ChartSeries, type Range } from \"../kit/shared\"\nimport type { XScale } from \"./x-scale\"\n\n/** One polyline of a {@link LineChart}: {@link ChartSeries} under the name for what it draws here. */\nexport type LineSeries = ChartSeries\n\n/**\n * A rectangular slice of the plot in data units, the input to `spotlightRegion`\n * and `zoomTo`. Either axis may be omitted: `{ x: [60, 100] }` is a full-height\n * band. A reversed range reads the same as a forward one.\n */\nexport interface PlotRegion {\n /** Omit to span the full plot width. */\n x?: Range\n /** Omit to span the full plot height. */\n y?: Range\n}\n\n/**\n * A {@link PlotRegion} in the plot's centred pixel space (origin at the centre,\n * y-up), the frame the series points live in. An axis the author left unbounded\n * has its edges pinned to the plot's own and draws no rule.\n */\nexport interface RegionBox {\n left: number\n right: number\n bottom: number\n top: number\n xBounded: boolean\n yBounded: boolean\n}\n\n/** The \"no region\" resting value. */\nexport const EMPTY_REGION_BOX: RegionBox = {\n left: 0,\n right: 0,\n bottom: 0,\n top: 0,\n xBounded: false,\n yBounded: false,\n}\n\n/** Whether `box` is non-degenerate, so there is something to spotlight. */\nexport function hasRegion(box: RegionBox): boolean {\n return box.right > box.left && box.top > box.bottom\n}\n\n/**\n * Resolve a {@link PlotRegion} against the plot rectangle (centred pixel space)\n * and the data ranges its edges span. An omitted axis takes the plot's own\n * edges; a given one is clamped to the plot.\n */\nexport function resolveRegionBox(\n region: PlotRegion | null | undefined,\n plot: { left: number; right: number; bottom: number; top: number },\n xScale: Range,\n yScale: Range\n): RegionBox {\n if (!region || (region.x === undefined && region.y === undefined)) {\n return EMPTY_REGION_BOX\n }\n\n const span = (\n range: Range | undefined,\n [min, max]: Range,\n lo: number,\n hi: number\n ): [number, number, boolean] => {\n if (range === undefined || max <= min) return [lo, hi, false]\n const a = Math.min(range[0], range[1])\n const b = Math.max(range[0], range[1])\n const toPx = (v: number) => lo + ((v - min) / (max - min)) * (hi - lo)\n return [\n Math.max(lo, Math.min(hi, toPx(a))),\n Math.max(lo, Math.min(hi, toPx(b))),\n true,\n ]\n }\n\n const [left, right, xBounded] = span(region.x, xScale, plot.left, plot.right)\n const [bottom, top, yBounded] = span(region.y, yScale, plot.bottom, plot.top)\n return { left, right, bottom, top, xBounded, yBounded }\n}\n\n/**\n * The parts of `points` inside `box`, as contiguous sub-polylines: a series is\n * drawn dimmed in full, then these runs are re-drawn at full strength. Segments\n * are clipped, not filtered by endpoint, so a line entering mid-segment is cut\n * exactly on the boundary.\n */\nexport function clipPolylineToBox(\n points: Vector2[],\n box: RegionBox\n): Vector2[][] {\n if (points.length < 2 || !hasRegion(box)) return []\n\n const runs: Vector2[][] = []\n let run: Vector2[] = []\n\n for (let i = 1; i < points.length; i++) {\n const seg = clipSegment(points[i - 1], points[i], box)\n if (!seg) {\n // Misses the box: close the open run.\n if (run.length >= 2) runs.push(run)\n run = []\n continue\n }\n const [a, b] = seg\n // Continues the open run if it starts where the last ended; otherwise the line left and came back.\n if (run.length > 0 && samePoint(run[run.length - 1], a)) run.push(b)\n else {\n if (run.length >= 2) runs.push(run)\n run = [a, b]\n }\n }\n if (run.length >= 2) runs.push(run)\n return runs\n}\n\n/** Points within half a pixel are the same point, for run-joining purposes. */\nfunction samePoint(a: Vector2, b: Vector2): boolean {\n return Math.abs(a.x - b.x) < 0.5 && Math.abs(a.y - b.y) < 0.5\n}\n\n/** Liang-Barsky clip of one segment against `box`: the surviving `[start, end]`, or `null` when wholly outside. */\nfunction clipSegment(\n a: Vector2,\n b: Vector2,\n box: RegionBox\n): [Vector2, Vector2] | null {\n const dx = b.x - a.x\n const dy = b.y - a.y\n let t0 = 0\n let t1 = 1\n\n // Each edge as (p, q): the segment survives where p*t <= q.\n const edges: [number, number][] = [\n [-dx, a.x - box.left],\n [dx, box.right - a.x],\n [-dy, a.y - box.bottom],\n [dy, box.top - a.y],\n ]\n for (const [p, q] of edges) {\n if (p === 0) {\n // Parallel to this edge: outside it, the whole segment is out.\n if (q < 0) return null\n continue\n }\n const r = q / p\n if (p < 0) {\n if (r > t1) return null\n if (r > t0) t0 = r\n } else {\n if (r < t0) return null\n if (r < t1) t1 = r\n }\n }\n return [\n { x: a.x + t0 * dx, y: a.y + t0 * dy },\n { x: a.x + t1 * dx, y: a.y + t1 * dy },\n ]\n}\n\n/**\n * One series' `[x, y]` points, sorted along x so the polyline traces left to\n * right. A row missing its y contributes 0 rather than a gap, since dropping it\n * would silently bridge the hole.\n */\nexport function seriesPoints(\n data: DataRecord[],\n x: XScale,\n series: LineSeries\n): [x: number, y: number][] {\n return data\n .map((row, i): [number, number] => [x.at(i), num(row, series.field)])\n .sort((a, b) => a[0] - b[0])\n}\n\nexport function yExtent(data: DataRecord[], series: LineSeries[]): Range {\n let lo = Infinity\n let hi = -Infinity\n for (const row of data)\n for (const s of series) {\n const v = num(row, s.field)\n if (v < lo) lo = v\n if (v > hi) hi = v\n }\n return lo <= hi ? [lo, hi] : [0, 1]\n}\n\n/**\n * The explicit `range`, else the data's y extent nudged out to tidy step bounds.\n * `divisions` (one fewer than the marker count) only shapes the step when\n * `range` is omitted.\n */\nexport function resolveYScale(\n data: DataRecord[],\n series: LineSeries[],\n range: Range | undefined,\n divisions: number\n): Range {\n return range ?? niceRange(yExtent(data, series), divisions)\n}\n\n/** How the series sit on one another: apart, each on the sum of those before it, or as shares of the row's total. */\nexport type LineStack = \"none\" | \"stacked\" | \"percent\"\n\n/** One series as drawn: its `[x, y]` points along x, and the line its area fills down to (`null`: the baseline). */\nexport interface StackedSeries {\n readonly points: [x: number, y: number][]\n readonly base: [x: number, y: number][] | null\n}\n\n/**\n * Every series' points under `stack`, rows in x order. A series contributes its\n * values times its weight (`1` when missing), so a series sinking out of a stack\n * lowers the ones above it. `percent` reads each row as shares of its total\n * magnitude, so the top of a full stack is 100.\n */\nexport function stackSeries(\n data: DataRecord[],\n x: XScale,\n series: readonly LineSeries[],\n stack: LineStack,\n weights: readonly number[] = []\n): StackedSeries[] {\n const order = data.map((_, i) => i).sort((a, b) => x.at(a) - x.at(b))\n if (stack !== \"stacked\" && stack !== \"percent\") {\n return series.map((s) => ({ points: order.map((r): [number, number] => [x.at(r), num(data[r], s.field)]), base: null }))\n }\n const weight = (i: number) => Math.max(0, weights[i] ?? 1)\n const totals = order.map((r) => series.reduce((sum, s, i) => sum + Math.abs(num(data[r], s.field) * weight(i)), 0))\n const running = order.map(() => 0)\n return series.map((s, i) => {\n const base = order.map((r, k): [number, number] => [x.at(r), running[k]])\n const points = order.map((r, k): [number, number] => {\n const value = num(data[r], s.field) * weight(i)\n running[k] += stack === \"percent\" ? (totals[k] > 0 ? (value / totals[k]) * 100 : 0) : value\n return [x.at(r), running[k]]\n })\n return { points, base }\n })\n}\n\n/** The lowest and highest y anything in `stacks` reaches, its bases included. */\nexport function stackExtent(stacks: readonly StackedSeries[]): Range {\n let lo = Infinity\n let hi = -Infinity\n for (const { points, base } of stacks)\n for (const [, y] of [...points, ...(base ?? [])]) {\n if (y < lo) lo = y\n if (y > hi) hi = y\n }\n return lo <= hi ? [lo, hi] : [0, 1]\n}\n\n/** How a series' line runs between its points. */\nexport type LineCurve = \"smooth\" | \"linear\" | \"step\"\n\n/** Points along a cubic Bezier segment, its start left out. */\nconst SAMPLES = 16\n\n/**\n * The drawn path through `points` (ordered along x) as a polyline: the points\n * themselves for `linear`; for `step`, level runs that change at the midpoint\n * between neighbours; for `smooth`, a monotone cubic (Fritsch-Carlson, as d3's\n * `curveMonotoneX`), which never overshoots the data between two points.\n */\nexport function curvePoints(points: readonly Vector2[], curve: LineCurve): Vector2[] {\n if (curve === \"step\") {\n const out: Vector2[] = points.length > 0 ? [points[0]] : []\n for (let i = 1; i < points.length; i++) {\n const mid = (points[i - 1].x + points[i].x) / 2\n out.push({ x: mid, y: points[i - 1].y }, { x: mid, y: points[i].y }, points[i])\n }\n return out\n }\n if (curve !== \"smooth\" || points.length < 3) return [...points]\n const tangents = monotoneTangents(points)\n const out: Vector2[] = [points[0]]\n for (let i = 1; i < points.length; i++) {\n const a = points[i - 1]\n const b = points[i]\n const dx = (b.x - a.x) / 3\n const c1 = { x: a.x + dx, y: a.y + dx * tangents[i - 1] }\n const c2 = { x: b.x - dx, y: b.y - dx * tangents[i] }\n for (let k = 1; k <= SAMPLES; k++) {\n const t = k / SAMPLES\n const u = 1 - t\n out.push({\n x: u * u * u * a.x + 3 * u * u * t * c1.x + 3 * u * t * t * c2.x + t * t * t * b.x,\n y: u * u * u * a.y + 3 * u * u * t * c1.y + 3 * u * t * t * c2.y + t * t * t * b.y,\n })\n }\n }\n return out\n}\n\nfunction monotoneTangents(points: readonly Vector2[]): number[] {\n const n = points.length\n const slope = (i: number) => {\n const h = points[i + 1].x - points[i].x\n return h === 0 ? 0 : (points[i + 1].y - points[i].y) / h\n }\n const m = new Array<number>(n).fill(0)\n for (let i = 1; i < n - 1; i++) {\n const h0 = points[i].x - points[i - 1].x\n const h1 = points[i + 1].x - points[i].x\n const s0 = slope(i - 1)\n const s1 = slope(i)\n const p = h0 + h1 === 0 ? 0 : (s0 * h1 + s1 * h0) / (h0 + h1)\n m[i] = (Math.sign(s0) + Math.sign(s1)) * Math.min(Math.abs(s0), Math.abs(s1), 0.5 * Math.abs(p)) || 0\n }\n m[0] = endTangent(slope(0), m[1])\n m[n - 1] = endTangent(slope(n - 2), m[n - 2])\n return m\n}\n\n/** d3's one-sided end tangent, held to the end segment's own direction and to three times its slope, past which it would overshoot. */\nfunction endTangent(secant: number, inner: number): number {\n const t = (3 * secant - inner) / 2\n if (secant === 0 || Math.sign(t) !== Math.sign(secant)) return 0\n return Math.abs(t) > 3 * Math.abs(secant) ? 3 * secant : t\n}\n\n/** The part of `points` (ordered along x) left of `x`, ending on the point where it crosses `x`. */\nexport function cutAt(points: readonly Vector2[], x: number): Vector2[] {\n if (points.length === 0 || x < points[0].x) return []\n const out: Vector2[] = []\n for (let i = 0; i < points.length; i++) {\n const p = points[i]\n if (p.x <= x) {\n out.push(p)\n continue\n }\n const a = points[i - 1]\n if (a && p.x > a.x) out.push({ x, y: a.y + ((p.y - a.y) * (x - a.x)) / (p.x - a.x) })\n break\n }\n return out\n}\n\n/**\n * `polygon` clipped to `box` (Sutherland-Hodgman against each edge in turn).\n * The box is convex, so the result is the part inside, possibly with seams of\n * no width where a concave outline leaves and re-enters, which fill as nothing.\n */\nexport function clipPolygonToBox(polygon: readonly Vector2[], box: RegionBox): Vector2[] {\n if (polygon.length < 3 || !hasRegion(box)) return []\n const edges: ((p: Vector2) => number)[] = [\n (p) => p.x - box.left,\n (p) => box.right - p.x,\n (p) => p.y - box.bottom,\n (p) => box.top - p.y,\n ]\n let out: Vector2[] = [...polygon]\n for (const inside of edges) {\n const input = out\n out = []\n for (let i = 0; i < input.length; i++) {\n const cur = input[i]\n const prev = input[(i + input.length - 1) % input.length]\n const dc = inside(cur)\n const dp = inside(prev)\n if (dc >= 0) {\n if (dp < 0) out.push(crossing(prev, cur, dp, dc))\n out.push(cur)\n } else if (dp >= 0) out.push(crossing(prev, cur, dp, dc))\n }\n if (out.length === 0) return []\n }\n return out\n}\n\nfunction crossing(a: Vector2, b: Vector2, da: number, db: number): Vector2 {\n const t = da / (da - db)\n return { x: a.x + (b.x - a.x) * t, y: a.y + (b.y - a.y) * t }\n}\n\n/** A line chart's own look: how each series is stroked, dotted and filled. */\nexport const LINE_MARKS = {\n strokeWidth: Types.number(4, { min: 0, max: 24, step: 0.5, unit: \"px\" }),\n curve: Types.oneOf([\"smooth\", \"linear\", \"step\"] as const),\n dots: Types.boolean(false),\n /** Each dot's diameter. */\n dotSize: Types.number(12, { min: 0, max: 48, step: 1, unit: \"px\" }),\n /** Fill under each line: none, the series colour, or the colour fading to nothing at the baseline. */\n area: Types.oneOf([\"none\", \"solid\", \"gradient\"] as const),\n /** The fill's opacity at the line. */\n areaOpacity: Types.number(0.4, { min: 0, max: 1, step: 0.05 }),\n}\n\nexport const LINE_LABELS = {\n /** Read as the chart is built: each point's value printed above or below it, or none. */\n values: Types.oneOf([\"none\", \"above\", \"below\"] as const, { animatable: false }),\n}\n", "import {\n Graphics2D,\n Types,\n component2d,\n fillOps,\n strokeOps,\n type Fill,\n type FillResolved,\n type NodeOf,\n // Named so this component's emitted type reaches `Node2D` and its props through the sdk, not core.\n type Node2D as _Node2D,\n type Node2DProps as _Node2DProps,\n type Stroke,\n type StrokeResolved,\n} from \"@motionscript/sdk\"\n\nimport { rule } from \"../kit/chart-canvas\"\nimport { fresh } from \"../kit/entries\"\nimport { loadPaints } from \"../kit/paints\"\nimport {\n EMPTY_REGION_BOX,\n hasRegion,\n type RegionBox,\n} from \"./shared\"\n\n/**\n * The call-out of a {@link LineChart}: a washed rectangle with a dashed rule on\n * each bounded edge, drawn from the pre-mapped `box`. Dimming the series outside\n * is the line's and area's job, clipped against the same box so they agree on\n * the boundary. An unbounded edge is the plot's own border, and a rule there\n * would assert a limit the author did not set.\n */\nexport const ChartRegion = component2d({\n key: \"chartRegion\",\n state: {\n /** In this node's pixel space (origin at centre, y-up), mapped by the parent. A degenerate box draws nothing. */\n box: fresh<RegionBox>(() => EMPTY_REGION_BOX),\n stroke: Types.custom<Stroke, StrokeResolved[]>({ weight: 2, fill: \"white/70\", dash: [14, 12], cap: \"butt\", align: \"center\" }, { resolve: strokeOps.resolve, lerp: strokeOps.lerp }),\n fill: Types.custom<Fill, FillResolved[]>(\"white/6\", { resolve: fillOps.resolve, lerp: fillOps.lerp }),\n /** Driven by the chart's `regionReveal`, so the rules and the series' dimming move as one. */\n reveal: 0,\n },\n load: (loader, state) => loadPaints(loader, { fills: [state.fill], strokes: [state.stroke] }),\n render: (ctx, state) => {\n const box = state.box\n if (!hasRegion(box)) return\n\n const r = Math.max(0, Math.min(1, state.reveal))\n if (r <= 0) return\n\n const width = box.right - box.left\n const height = box.top - box.bottom\n const cx = (box.left + box.right) / 2\n const cy = (box.bottom + box.top) / 2\n\n if (state.fill.length > 0) {\n ctx.draw(new Graphics2D().rect({ x: cx, y: cy, width, height }).fill(state.fill).opacity(r))\n }\n\n if (state.stroke.length === 0) return\n\n if (box.xBounded) {\n const half = (height / 2) * r\n for (const x of [box.left, box.right]) rule(ctx, { x, y: cy - half }, { x, y: cy + half }, state.stroke, r)\n }\n if (box.yBounded) {\n const half = (width / 2) * r\n for (const y of [box.bottom, box.top]) rule(ctx, { x: cx - half, y }, { x: cx + half, y }, state.stroke, r)\n }\n },\n})\n\nexport type ChartRegion = NodeOf<typeof ChartRegion>\n", "/**\n * What a line chart's x column means: a number (plotted as is), an instant\n * (`Jan`, `2026-W12`; plotted by time, so a gap in the data reads as a gap), or\n * anything else (the row's position, evenly spaced).\n *\n * A tick on a time or ordinal scale is a sample, so its caption is the cell the\n * author wrote; only a tick that is not (an author-set range, a `zoomTo`\n * mid-flight) is formatted, by {@link formatInstant}.\n */\n\nimport type { DataRecord } from \"@motionscript/sdk\"\n\nimport {\n formatMarker,\n markerValues,\n num,\n text,\n type Range,\n} from \"../kit/shared\"\nimport { formatNumber } from \"@motionscript/sdk/component\"\n\n/** How an x column's cells become positions along the axis. */\nexport type XScaleKind = \"numeric\" | \"time\" | \"ordinal\"\n\n/** An x column resolved into positions, captions and ticks: three closures built once per (data, column), not a tag callers switch on. */\nexport interface XScale {\n kind: XScaleKind\n /** Position of row `index` along the axis, in this scale's own units. */\n at(index: number): number\n /** `[min, max]` across the rows: the scale when no range is set. */\n extent: Range\n label(value: number): string\n /** `divisions + 1` tick values spanning `range`, ends included. */\n ticks(range: Range, divisions: number): number[]\n}\n\nconst DAY = 86_400_000\n\nconst MONTHS = [\n \"january\",\n \"february\",\n \"march\",\n \"april\",\n \"may\",\n \"june\",\n \"july\",\n \"august\",\n \"september\",\n \"october\",\n \"november\",\n \"december\",\n]\n\n/** The year a cell naming none is dated into; a leap year, so February spaces the same as in a column that carries years. */\nconst NOMINAL_YEAR = 2024\n\n/** Month index for `jan`, `sept` or `january`, else -1: three letters minimum, then a prefix match, so `sept` passes and `janitor` does not. */\nfunction monthIndex(word: string): number {\n if (word.length < 3) return -1\n return MONTHS.findIndex((month) => month.startsWith(word))\n}\n\nfunction isoWeekStart(year: number, week: number): number {\n // ISO week 1 is the week containing 4 January, and weeks start on Monday.\n const jan4 = Date.UTC(year, 0, 4)\n const weekday = (new Date(jan4).getUTCDay() + 6) % 7 // Monday = 0\n return jan4 - weekday * DAY + (week - 1) * 7 * DAY\n}\n\n/**\n * One cell read as an instant, or `null`. Not `Date.parse`, which accepts `\"5\"`\n * and `\"Q3\"`, differs between engines off ISO, and reads `2026-03-14` as UTC but\n * `2026/03/14` as local. Every form is matched explicitly, and an ambiguous\n * all-numeric date (`03/04/2026`) is not one of them.\n */\nexport function parseInstant(raw: unknown): number | null {\n if (typeof raw !== \"string\") return null\n const s = raw.trim().toLowerCase()\n if (s === \"\") return null\n\n // 2026-03-14 · 2026/03/14 · 2026-03 · 2026/03\n const ymd = /^(\\d{4})[-/](\\d{1,2})(?:[-/](\\d{1,2}))?$/.exec(s)\n if (ymd) {\n const month = Number(ymd[2])\n const day = ymd[3] === undefined ? 1 : Number(ymd[3])\n if (month < 1 || month > 12 || day < 1 || day > 31) return null\n return Date.UTC(Number(ymd[1]), month - 1, day)\n }\n\n // 2026-W12 · 2026W12 · w12 · week 12\n const week = /^(?:(\\d{4})[-\\s]?)?w(?:ee)?k?[-\\s]?(\\d{1,2})$/.exec(s)\n if (week) {\n const n = Number(week[2])\n if (n < 1 || n > 53) return null\n return isoWeekStart(\n week[1] === undefined ? NOMINAL_YEAR : Number(week[1]),\n n\n )\n }\n\n // jan · january · jan 2026 · january-2026 · 2026 jan\n const named = /^(?:(\\d{4})[-\\s]+)?([a-z]+)(?:[-\\s]+(\\d{4}))?$/.exec(s)\n if (named) {\n const month = monthIndex(named[2])\n if (month >= 0) {\n const year = named[1] ?? named[3]\n const y = year === undefined ? NOMINAL_YEAR : Number(year)\n return Date.UTC(y, month, 1)\n }\n }\n\n // 14 mar 2026 · mar 14 2026 · mar 14, 2026\n const dayNamed =\n /^(?:(\\d{1,2})[-\\s]+([a-z]+)|([a-z]+)[-\\s]+(\\d{1,2}),?)[-\\s]+(\\d{4})$/.exec(\n s\n )\n if (dayNamed) {\n const month = monthIndex(dayNamed[2] ?? dayNamed[3])\n const day = Number(dayNamed[1] ?? dayNamed[4])\n if (month >= 0 && day >= 1 && day <= 31) {\n return Date.UTC(Number(dayNamed[5]), month, day)\n }\n }\n\n return null\n}\n\n/** An instant captioned at the coarsest granularity the span tells apart: a decade reads as years, a year as months. */\nexport function formatInstant(value: number, span: number): string {\n const date = new Date(value)\n const year = date.getUTCFullYear()\n const month = MONTHS[date.getUTCMonth()].slice(0, 3)\n const label = month.charAt(0).toUpperCase() + month.slice(1)\n if (span > 4 * 365 * DAY) return String(year)\n if (span > 60 * DAY) return `${label} ${year}`\n return `${label} ${date.getUTCDate()}`\n}\n\n/** `numericFields`' rule for one column: a single text cell takes it off the numeric scale rather than plot that row at 0. */\nfunction isNumericColumn(data: DataRecord[], field: string): boolean {\n let sawValue = false\n for (const row of data) {\n const v = row[field]\n if (v === undefined || v === null || v === \"\") continue\n if (typeof v !== \"number\") return false\n sawValue = true\n }\n return sawValue\n}\n\n/**\n * Every non-empty cell as an instant, or `null` if any is not one. A blank cell\n * keeps its slot and takes the nearest known instant: stacking it on the epoch\n * would drag the whole scale back fifty years.\n */\nfunction instantColumn(data: DataRecord[], field: string): number[] | null {\n const parsed: (number | null)[] = []\n let sawValue = false\n for (const row of data) {\n const raw = row[field]\n if (raw === undefined || raw === null || raw === \"\") {\n parsed.push(null)\n continue\n }\n const t = parseInstant(raw)\n if (t === null) return null\n parsed.push(t)\n sawValue = true\n }\n if (!sawValue) return null\n\n const first = parsed.find((t): t is number => t !== null) as number\n let last = first\n return parsed.map((t) => (t === null ? last : (last = t)))\n}\n\n/** `[min, max]` of `values`, or `[0, 1]` when there is nothing to span. */\nfunction extentOf(values: number[]): Range {\n let lo = Infinity\n let hi = -Infinity\n for (const v of values) {\n if (v < lo) lo = v\n if (v > hi) hi = v\n }\n return lo <= hi ? [lo, hi] : [0, 1]\n}\n\n/** Up to this many samples in view, every one is a tick. */\nexport const EVERY_SAMPLE = 12\n\n/**\n * Ticks spanning `range`, each a sample, nearest to where an evenly spaced tick\n * would go. They must be samples (a caption between two has nothing to say) and\n * spread (every nth sample would print five dates on top of each other across a\n * burst of rows), so this walks the evenly spaced targets, not the samples.\n * Targets that pick the same sample collapse to one tick, so a gappy column\n * draws fewer honest ticks rather than overlapping ones.\n */\nfunction sampledTicks(\n positions: number[],\n [min, max]: Range,\n divisions: number\n): number[] {\n const inside = positions.filter((v) => v >= min && v <= max)\n const unique = [...new Set(inside)].sort((a, b) => a - b)\n if (unique.length === 0) return markerValues([min, max], divisions)\n // Few and even enough to caption every one: a month left out reads as missing data.\n if (unique.length <= EVERY_SAMPLE && evenlySpaced(unique)) return unique\n\n const nearest = (target: number) =>\n unique.reduce((best, v) =>\n Math.abs(v - target) < Math.abs(best - target) ? v : best\n )\n\n const out: number[] = []\n for (const target of markerValues([min, max], divisions)) {\n const tick = nearest(target)\n if (out[out.length - 1] !== tick) out.push(tick)\n }\n return out\n}\n\n/** Whether no two neighbouring samples sit much closer than the average gap: months do, a burst of days between weeks of nothing does not. */\nfunction evenlySpaced(sorted: readonly number[]): boolean {\n if (sorted.length < 3) return true\n const mean = (sorted[sorted.length - 1] - sorted[0]) / (sorted.length - 1)\n for (let i = 1; i < sorted.length; i++) if (sorted[i] - sorted[i - 1] < mean * 0.75) return false\n return true\n}\n\n/** The cell of the row a tick came from, or `fallback` when it is not a sample. */\nfunction labelBySample(\n positions: number[],\n captions: string[],\n value: number,\n fallback: (value: number) => string\n): string {\n const i = positions.indexOf(value)\n return i >= 0 ? captions[i] : fallback(value)\n}\n\n/** Resolved scales by data array, then by field and pattern. */\nconst scales = new WeakMap<DataRecord[], Map<string, XScale>>()\n\n/** Kept per `data` array: bound props ask a dozen times a frame, and parsing every row's instant each time was most of a frame. */\nexport function resolveXScale(\n data: DataRecord[],\n field: string,\n pattern?: string\n): XScale {\n let byKey = scales.get(data)\n if (!byKey) scales.set(data, (byKey = new Map()))\n const key = JSON.stringify([field, pattern ?? null])\n let scale = byKey.get(key)\n if (!scale) byKey.set(key, (scale = xScaleOf(data, field, pattern)))\n return scale\n}\n\nfunction xScaleOf(\n data: DataRecord[],\n field: string,\n /** Number-format pattern for a numeric column only; ticks on the other kinds are the author's cells. */\n pattern?: string\n): XScale {\n if (field !== \"\" && isNumericColumn(data, field)) {\n const positions = data.map((row) => num(row, field))\n return {\n kind: \"numeric\",\n at: (i) => positions[i] ?? 0,\n extent: extentOf(positions),\n label: (value) =>\n pattern === undefined ? formatMarker(value) : formatNumber(value, pattern),\n // A continuous axis is read by its scale, not by which samples are on it.\n ticks: markerValues,\n }\n }\n\n const captions = data.map((row) => text(row, field))\n const instants = field === \"\" ? null : instantColumn(data, field)\n\n if (instants) {\n const extent = extentOf(instants)\n const span = extent[1] - extent[0]\n return {\n kind: \"time\",\n at: (i) => instants[i] ?? 0,\n extent,\n label: (value) =>\n labelBySample(instants, captions, value, (v) =>\n formatInstant(v, span)\n ),\n ticks: (range, divisions) => sampledTicks(instants, range, divisions),\n }\n }\n\n const positions = data.map((_, i) => i)\n return {\n kind: \"ordinal\",\n at: (i) => i,\n // `[0, n-1]`, not `[0, n]`: the first and last rows sit on the plot's edges.\n extent: positions.length > 0 ? [0, positions.length - 1] : [0, 1],\n label: (value) => captions[Math.round(value)] ?? \"\",\n ticks: (range, divisions) => sampledTicks(positions, range, divisions),\n }\n}\n", "import {\n Rect,\n Types,\n clamp,\n component2d,\n easeOut,\n type ChildView,\n type DataRecord,\n type NodeOf,\n type OutOf,\n // Named so this component's emitted type reaches `Node2D` and its props through the sdk, not core.\n type Node2D,\n type Node2DProps as _Node2DProps,\n type Fill as _Fill,\n type FillResolved as _FillResolved,\n type Stroke as _Stroke,\n type StrokeResolved as _StrokeResolved,\n type Size2D,\n type StyleInput as _StyleInput,\n type StyleValues as _StyleValues,\n} from \"@motionscript/sdk\"\nimport { formatNumber } from \"@motionscript/sdk/component\"\n\nimport { cartesianFrame, chartViews, columnGhost, frameGap, headroom, laidOutSize, overhang } from \"../kit/cartesian\"\nimport { ChartCanvas } from \"../kit/chart-canvas\"\nimport { ChartLegend } from \"../kit/chart-legend\"\nimport { SERIES_ARG, asParts, fresh } from \"../kit/entries\"\nimport { HorizontalAxis } from \"../kit/horizontal-axis\"\nimport { DEFAULT_MARKERS, ENTER_SHARE, beats, legendAway, type AnyTimeline, type Beat } from \"../kit/motion\"\nimport {\n SPOTLIGHT_DIM,\n formatMarker,\n lerpAxisDomain,\n lerpAxisEntry,\n markerStep,\n markerValues,\n niceTicks,\n num,\n resolveAxisDomain,\n settleAxisDomain,\n type AxisDomainConfig,\n type Range,\n type ResolvedAxisDomain,\n} from \"../kit/shared\"\nimport {\n CARTESIAN_GRID,\n CHART_COLORS,\n CHART_LEGEND,\n CHART_STYLE_FAMILY,\n CHART_STYLE_PRESETS,\n CHART_TEXT,\n axisConfigOf,\n legendConfigOf,\n seriesFill,\n valueText,\n} from \"../kit/style\"\nimport { VerticalAxis, axisPads } from \"../kit/vertical-axis\"\nimport { CategoryAxis, slotCentre } from \"./category-axis\"\nimport { ChartBars, type BarGeometry } from \"./chart-bars\"\nimport {\n BAR_LABELS,\n BAR_MARKS,\n barCategories,\n barSpans,\n resolveBarScale,\n type BarOrientation,\n type BarSeries,\n type BarStack,\n} from \"./shared\"\n\nconst BAR_STYLE = Types.style(\n CHART_STYLE_FAMILY,\n { colors: CHART_COLORS, text: CHART_TEXT, grid: CARTESIAN_GRID, marks: BAR_MARKS, labels: BAR_LABELS, legend: CHART_LEGEND },\n { presets: CHART_STYLE_PRESETS }\n)\n\n/** A bar chart's resolved style. */\nexport type BarChartStyle = OutOf<typeof BAR_STYLE>\n\n/** What a bar chart plots, as its entries hold it. */\nexport interface BarChartValues {\n readonly data: DataRecord[]\n readonly series: BarSeries[]\n readonly stack: BarStack\n readonly valueAxis: AxisDomainConfig\n}\n\n/** The value axis's domain with its range and ticks resolved. */\nexport type BarChartDomain = ResolvedAxisDomain\n\ninterface BarState extends BarChartValues {\n readonly categoryField: string\n readonly orientation: BarOrientation\n readonly style: BarChartStyle\n readonly weights: number[]\n readonly showing: boolean[]\n readonly spotlight: number | null\n readonly spotlightReveal: number\n}\n\nfunction drawnValue(s: BarChartValues, domain: AxisDomainConfig): AxisDomainConfig {\n const divisions = (domain.ticks?.length ?? DEFAULT_MARKERS) - 1\n const range = resolveBarScale(s.data, s.series, s.stack, domain.range, divisions)\n const even = domain.range !== undefined || s.stack === \"percent\"\n return { ...domain, range, ticks: domain.ticks ?? (even ? markerValues(range, DEFAULT_MARKERS - 1) : niceTicks(range, DEFAULT_MARKERS - 1)) }\n}\n\n/** The last domain worked out from each data array, and what it was read from. */\nconst domainsDrawn = new WeakMap<DataRecord[], { readonly key: readonly unknown[]; readonly domain: BarChartDomain }>()\n\n/** The value axis as drawn now. A series being hidden keeps its room, so the ticks hold still while it goes. */\nexport function barChartDomain(s: BarChartValues): BarChartDomain {\n const key = [s.series, s.stack, s.valueAxis]\n const kept = domainsDrawn.get(s.data)\n if (kept && kept.key.every((value, i) => value === key[i])) return kept.domain\n const domain = settleAxisDomain(s.valueAxis, (d) => drawnValue(s, d)) as BarChartDomain\n domainsDrawn.set(s.data, { key, domain })\n return domain\n}\n\n/** Ticks and the figures printed by bars both read through here, so they cannot disagree about how a number looks. */\nfunction valueLabel(s: BarChartValues, domain: BarChartDomain, value: number): string {\n const pattern = s.valueAxis.format\n if (pattern !== undefined) return formatNumber(value, pattern)\n const text = formatMarker(value, markerStep(domain.ticks))\n return s.stack === \"percent\" ? `${text}%` : text\n}\n\n/** A value along the value axis, a run of `length` px centred on 0. */\nfunction valueToPx(domain: BarChartDomain, length: number, value: number): number {\n const [min, max] = domain.range\n if (max === min) return -length / 2\n return ((value - min) / (max - min) - 0.5) * length\n}\n\n/** Where bars grow from: zero held on the scale, so a cropped axis grows them from the plot's edge. */\nfunction baselineValue(domain: BarChartDomain): number {\n const [lo, hi] = domain.range\n return clamp(0, Math.min(lo, hi), Math.max(lo, hi))\n}\n\nfunction weightAt(s: { readonly weights: readonly number[] }, index: number): number {\n return Math.max(0, s.weights[index] ?? 1)\n}\n\n/** The plot's run along the value axis and across the categories. */\nfunction runs(s: BarState, plot: Size2D): { along: number; across: number } {\n return s.orientation === \"horizontal\" ? { along: plot.width, across: plot.height } : { along: plot.height, across: plot.width }\n}\n\n/** Category `row`'s slot centre across the plot: left to right, or top to bottom. */\nfunction slotAt(s: BarState, row: number, across: number): number {\n const centre = slotCentre(row, s.data.length, across)\n return s.orientation === \"horizontal\" ? -centre : centre\n}\n\n/**\n * Series `index`'s bars in centred pixel space. Side by side, a series divides\n * the slot with its siblings by live weight; stacked, it takes the whole slot\n * and its weight scales its length, so hiding a series reflows rather than\n * punching a hole.\n */\nfunction seriesBars(s: BarState, index: number, plot: Size2D): BarGeometry[] {\n const series = s.series[index]\n if (!series) return []\n const domain = barChartDomain(s)\n const { along, across } = runs(s, plot)\n const n = s.data.length\n const slot = n > 0 ? across / n : 0\n const inner = slot * clamp(s.style.barWidth, 0, 1)\n const stacked = s.stack !== \"none\"\n let total = 0\n for (let i = 0; i < s.series.length; i++) total += weightAt(s, i)\n const unit = inner / (total > 0 ? total : 1)\n const weight = weightAt(s, index)\n let before = 0\n for (let i = 0; i < index; i++) before += weightAt(s, i)\n const gap = s.series.length > 1 ? s.style.barGap : 0\n const values = s.style.values\n\n return s.data.map((row, rowIndex) => {\n // Built from live contributions, so a fading series lowers the segments beyond it.\n const spans = barSpans(row, s.series, s.stack, s.weights)\n const span = spans[index] ?? { from: 0, to: 0, value: 0, outer: false }\n const centre = slotAt(s, rowIndex, across)\n const offset = -inner / 2 + unit * before + (unit * weight) / 2\n let caption = \"\"\n if (values !== \"none\" && span.value !== 0) {\n if (!stacked || values === \"inside\" || s.stack === \"percent\") caption = valueLabel(s, domain, stacked ? span.value : num(row, series.field))\n else if (span.outer) caption = valueLabel(s, domain, span.to)\n }\n return {\n center: stacked ? centre : centre + (s.orientation === \"horizontal\" ? -offset : offset),\n thickness: stacked ? inner : Math.max(0, unit * weight - gap),\n from: valueToPx(domain, along, span.from),\n to: valueToPx(domain, along, span.to),\n round: span.outer,\n caption,\n }\n })\n}\n\n/** Per-row opacity: 1 while nothing is spotlit, falling to {@link SPOTLIGHT_DIM} for all but the chosen category. */\nfunction categoryDims(s: BarState): number[] {\n const focus = clamp(s.spotlightReveal, 0, 1)\n const chosen = s.spotlight\n return s.data.map((_, i) => (focus <= 0 || chosen === i ? 1 : 1 - (1 - SPOTLIGHT_DIM) * focus))\n}\n\n/** The parts a bar chart's commands drive, found through its children. */\nfunction partsOf(children: readonly ChildView[]) {\n const views = chartViews(children)\n return {\n valueAxis: views.find((view) => VerticalAxis.is(view) || HorizontalAxis.is(view)) ?? null,\n categoryAxis: views.find(CategoryAxis.is) ?? null,\n bars: views.filter(ChartBars.is),\n legend: views.find(ChartLegend.is) ?? null,\n }\n}\n\n/**\n * Move series `index`'s share to `target` with its legend entry. Its bars stay\n * drawn for every frame the move covers and switch off only once a hide has\n * landed, so arriving at a time backwards matches arriving forwards.\n */\nfunction toggling(timeline: AnyTimeline, state: BarState, children: readonly ChildView[], index: number, target: number) {\n const parts = partsOf(children)\n if (!parts.bars[index]) return timeline.wait(timeline.duration)\n const from = state.series.map((_, i) => weightAt(state, i))\n const start = from[index] ?? 1\n const showing = state.series.map((s, i) => state.showing[i] ?? (s.enabled ?? true))\n return timeline.together([\n timeline.animate((t) => {\n const weights = [...from]\n weights[index] = start + (target - start) * timeline.ease(t)\n const shown = [...showing]\n shown[index] = target > 0 || t < 1\n return { weights, showing: shown }\n }, { eased: false }),\n ...(parts.legend ? [parts.legend.run(target > 0 ? \"showSeries\" : \"hideSeries\", { index })] : []),\n ])\n}\n\n/**\n * A bar chart, vertical or horizontal, its series side by side, stacked, or\n * stacked as shares of 100. Built like the line chart from `ChartCanvas`, a\n * value axis, a {@link CategoryAxis}, one {@link ChartBars} per series and\n * `ChartLegend`. Zero is always on the scale and bars grow about it, so a\n * negative value draws the other way from the same `growth` signal.\n *\n * Resting state is the finished chart; `enter` arms every part on its first\n * frame. A `to` of the value axis's `range` or `ticks` tweens from the domain as\n * drawn, so an auto axis rescales the bars continuously.\n */\nexport const BarChart = component2d({\n key: \"barChart\",\n state: {\n data: fresh<DataRecord[]>(() => [], { kind: \"dataset\" }),\n // Names a column, not a value, like the line chart's `xField`.\n categoryField: \"\",\n series: fresh<BarSeries[]>(() => [], { kind: \"series\" }),\n /** `vertical`: columns rise from a row of categories; `horizontal`: bars grow right from a column of them. */\n orientation: Types.oneOf([\"vertical\", \"horizontal\"] as const, { animatable: false }),\n /** `stacked`: each series sits on the sum of those before it; `percent`: every category reads as shares of 100. */\n stack: Types.oneOf([\"none\", \"stacked\", \"percent\"] as const),\n valueAxis: Types.custom<AxisDomainConfig>({}, { resolve: resolveAxisDomain, lerp: lerpAxisEntry }),\n categoryAxis: Types.custom<AxisDomainConfig>({}, { resolve: resolveAxisDomain, lerp: lerpAxisDomain }),\n style: BAR_STYLE,\n /** Rise of every bar about the baseline, `[0, 1]`: 0 collapses them onto it. */\n growth: 1,\n /** The category spotlit, or `null`. The choice snaps; `spotlightReveal` animates it. */\n spotlight: Types.custom<number | null>(null),\n spotlightReveal: 0,\n /** Each series' share of the slot, seeded from `enabled`: a weight rather than a switch, so hiding one widens the others. */\n weights: Types.custom<number[]>([], { private: true }),\n /** Whether each series' bars are drawn: on for every frame a show or hide covers, off once a hide lands. */\n showing: Types.custom<boolean[]>([], { private: true }),\n },\n defaults: {\n // A node made of parts that fill would otherwise hug them.\n width: \"fill\",\n height: \"fill\",\n weights: (state) => state.series.map((s) => ((s.enabled ?? true) ? 1 : 0)),\n showing: (state) => state.series.map((s) => s.enabled ?? true),\n },\n allowedChildren: [],\n children: (state) => {\n const style = () => state.style\n const domain = () => barChartDomain(state)\n let plot: Node2D | undefined\n const plotSize = () => laidOutSize(plot)\n const built = state.style\n const horizontal = state.orientation === \"horizontal\"\n const categories = barCategories(state.data, state.categoryField)\n const valueConfig = () => axisConfigOf(style(), horizontal ? \"x\" : \"y\")\n const categoryConfig = () => axisConfigOf(style(), horizontal ? \"y\" : \"x\")\n const valueCaptions = () => {\n const d = domain()\n return d.ticks.map((value) => valueLabel(state, d, value))\n }\n const showValue = horizontal ? built.showXAxis : built.showYAxis\n const showCategory = horizontal ? built.showYAxis : built.showXAxis\n\n const valueAxis = showValue\n ? (horizontal\n ? new HorizontalAxis({\n range: () => domain().range,\n markers: () => domain().ticks,\n captions: valueCaptions,\n axis: valueConfig,\n label: state.valueAxis.label ?? \"\",\n overhang: () => ({ left: overhang(style()), right: overhang(style()) }),\n width: \"fill\",\n height: \"hug\",\n })\n : new VerticalAxis({\n range: () => domain().range,\n markers: () => domain().ticks,\n captions: valueCaptions,\n axis: valueConfig,\n label: state.valueAxis.label ?? \"\",\n width: \"hug\",\n height: \"fill\",\n })) as unknown as Node2D\n : undefined\n\n const categoryAxis = showCategory\n ? (new CategoryAxis({\n categories,\n axis: categoryConfig,\n label: state.categoryAxis.label ?? \"\",\n orientation: horizontal ? \"vertical\" : \"horizontal\",\n dims: () => categoryDims(state),\n width: horizontal ? \"hug\" : \"fill\",\n height: horizontal ? \"fill\" : \"hug\",\n }) as unknown as Node2D)\n : undefined\n\n const left = horizontal ? categoryAxis : valueAxis\n const bottom = horizontal ? valueAxis : categoryAxis\n const leftConfig = horizontal ? categoryConfig : valueConfig\n const ghost = left && bottom\n ? columnGhost({\n captions: horizontal ? () => categories : valueCaptions,\n count: horizontal ? categories.length : barChartDomain(state).ticks.length,\n text: () => leftConfig().labelStyle,\n title: (horizontal ? state.categoryAxis.label : state.valueAxis.label) ?? \"\",\n titleText: () => leftConfig().titleStyle,\n tickPad: () => axisPads(leftConfig(), \"right\").tick,\n titlePad: () => axisPads(leftConfig(), \"right\").title,\n })\n : undefined\n\n const barSets = state.series.map(\n (s, i) =>\n new ChartBars({\n bars: () => seriesBars(state, i, plotSize()),\n baseline: () => valueToPx(domain(), runs(state, plotSize()).along, baselineValue(domain())),\n horizontal,\n fill: () => seriesFill(style(), s, i),\n cornerRadius: () => style().barRadius,\n growth: () => state.growth,\n dims: () => categoryDims(state),\n // A figure past a stack's end prints the stack's total; a percent stack has none worth printing, so prints its shares inside.\n values: () => (built.values === \"end\" && state.stack === \"percent\" ? \"inside\" : built.values),\n valueStyle: () => ({ ...valueText(style()), fontSize: Math.round(style().fontSize * 0.85) }),\n enabled: () => state.showing[i] ?? (s.enabled ?? true),\n }) as unknown as Node2D\n )\n\n const legendAt = built.legend\n const legend = legendAt !== \"none\"\n ? (new ChartLegend({\n series: state.series,\n swatches: () => state.series.map((s, i) => seriesFill(style(), s, i)),\n legend: () => legendConfigOf(style()),\n flow: legendAt === \"right\" ? \"vertical\" : \"horizontal\",\n }) as unknown as Node2D)\n : undefined\n\n const n = state.data.length\n // Category lines fall between the slots, never through a bar.\n const boundaries = () => Array.from({ length: Math.max(0, n - 1) }, (_, i) => i + 1)\n const slots = (): Range => [0, Math.max(1, n)]\n plot = new Rect({\n children: [\n new ChartCanvas({\n fill: () => style().background,\n xGridStroke: () => style().verticalGrid,\n yGridStroke: () => style().horizontalGrid,\n xMarkers: horizontal ? () => domain().ticks : boundaries,\n yMarkers: horizontal ? boundaries : () => domain().ticks,\n xExtent: horizontal ? () => domain().range : slots,\n yExtent: horizontal ? slots : () => domain().range,\n axisStroke: () => style().axisStroke,\n xAxisAt: () => (horizontal ? 0 : baselineValue(domain())),\n yAxisAt: () => (horizontal ? baselineValue(domain()) : 0),\n }),\n ...barSets,\n ],\n }) as unknown as Node2D\n\n return asParts([\n cartesianFrame({\n left,\n ghost,\n plot,\n bottom,\n legend,\n legendAt,\n gap: () => frameGap(style()),\n padding: () => ({\n top: headroom(style()),\n right: horizontal && bottom ? overhang(style()) : 0,\n left: horizontal && bottom && !left ? overhang(style()) : 0,\n bottom: 0,\n }),\n }),\n ])\n },\n commands: {\n /** Axes stagger in, bars rise from the baseline, the legend fades up last. `duration` is the whole entrance. */\n enter: {\n args: {},\n // Held from arrival, so it never shows finished ahead of its draw.\n entrance: true,\n easing: easeOut(),\n run: (timeline, state, children) => {\n const parts = partsOf(children)\n const duration = timeline.duration\n const axes = duration * ENTER_SHARE.axes\n const rise = duration * ENTER_SHARE.marks\n const { legend } = parts\n const at0 = (piece: Beat[\"piece\"]): Beat => ({ at: 0, duration: 0, piece })\n return beats(timeline, [\n at0(timeline.animate(() => ({ growth: 0 }))),\n ...(legend ? [at0(legend.to({ opacity: 0, ...legendAway(state.style.legend) }))] : []),\n ...(parts.valueAxis ? [{ at: 0, duration: axes, piece: parts.valueAxis.run(\"enter\", { slide: 24 }) }] : []),\n ...(parts.categoryAxis ? [{ at: 0, duration: axes, piece: parts.categoryAxis.run(\"enter\", { slide: 24 }) }] : []),\n // No priming to 0 first: the value at `t` is a function of `t`.\n { at: axes, duration: rise, piece: timeline.animate((t) => ({ growth: t })) },\n ...(legend ? [{ at: axes + rise, duration: duration * ENTER_SHARE.legend, piece: legend.to({ opacity: 1, x: 0, y: 0 }) }] : []),\n ])\n },\n },\n /** Bring series `index` back, the group reflowing to make room, with its legend entry. */\n showSeries: {\n args: { seriesIndex: SERIES_ARG },\n easing: easeOut(),\n run: (timeline, state, children) => toggling(timeline, state, children, timeline.args.seriesIndex, 1),\n },\n /** The mirror of `showSeries`: bars narrow away (stacked, sink out) while the rest widen into the space. */\n hideSeries: {\n args: { seriesIndex: SERIES_ARG },\n easing: easeOut(),\n run: (timeline, state, children) => toggling(timeline, state, children, timeline.args.seriesIndex, 0),\n },\n /** Fade every other series, bars and legend entry, to focus on `index`. Nothing moves, so the group does not reflow. */\n spotlightSeries: {\n args: { seriesIndex: SERIES_ARG },\n easing: easeOut(),\n run: (timeline, _state, children) => {\n const parts = partsOf(children)\n const index = timeline.args.seriesIndex\n return timeline.together([\n ...parts.bars.map((bars, i) => bars.to({ opacity: i === index ? 1 : SPOTLIGHT_DIM })),\n ...(parts.legend ? [parts.legend.run(\"spotlightSeries\", { index })] : []),\n timeline.wait(timeline.duration),\n ])\n },\n },\n /**\n * Fade every other category's bars and caption to {@link SPOTLIGHT_DIM}. While\n * another is lit the focus moves directly. A missing category takes its slot\n * and changes nothing.\n */\n spotlightCategory: {\n args: { categoryIndex: Types.number(0, { min: 0, step: 1 }) },\n easing: easeOut(),\n run: (timeline, state) => {\n const index = timeline.args.categoryIndex\n if (index < 0 || index >= state.data.length) return timeline.wait(timeline.duration)\n const from = state.spotlightReveal\n return timeline.animate((t) => ({ spotlight: index, spotlightReveal: from + (1 - from) * t }))\n },\n },\n /** Every category back to full; the lit one is held until the fade lands. A no-op when nothing is lit, which still takes its slot. */\n clearCategory: {\n args: {},\n easing: easeOut(),\n run: (timeline, state) => {\n const from = state.spotlightReveal\n if (from === 0) return timeline.wait(timeline.duration)\n const lit = state.spotlight\n return timeline.animate((t) => (t >= 1 ? { spotlight: null, spotlightReveal: 0 } : { spotlight: lit, spotlightReveal: from * (1 - t) }))\n },\n },\n },\n})\n\nexport type BarChart = NodeOf<typeof BarChart>\n", "import {\n Rect,\n Text,\n Types,\n clamp,\n component2d,\n type NodeOf,\n // Named so this component's emitted type reaches `Node2D` and its props through the sdk, not core.\n type Node2D,\n type Node2DProps as _Node2DProps,\n} from \"@motionscript/sdk\"\nimport { enterBudget } from \"@motionscript/sdk/component\"\n\nimport { boundText } from \"../kit/cartesian\"\nimport { asParts, fresh } from \"../kit/entries\"\nimport { armed, arrival, arrivalOf, arrivalsEntry, beats, frameEase, type Arrival } from \"../kit/motion\"\nimport { DEFAULT_X_AXIS, type AxisConfig } from \"../kit/shared\"\nimport { axisPads, captionColumn } from \"../kit/vertical-axis\"\n\nconst SLIDE = 24\n\n/** Slot `index`'s centre along a run of `length` px divided into `count` equal slots, first slot at `-length / 2`. */\nexport function slotCentre(index: number, count: number, length: number): number {\n return count <= 0 ? 0 : -length / 2 + (length / count) * (index + 0.5)\n}\n\n/**\n * The categorical axis of a {@link BarChart}: one {@link Text} caption per row,\n * centred on its slot. `horizontal` is a row under the plot, first category on\n * the left; `vertical` a right-aligned column beside it, first category at the\n * top. It is laid out to exactly the plot's length, so each caption lands by its\n * bars with neither side told about the other. The resting state is landed.\n */\nexport const CategoryAxis = component2d({\n key: \"categoryAxis\",\n state: {\n categories: fresh<string[]>(() => []),\n axis: Types.custom<AxisConfig>(DEFAULT_X_AXIS),\n label: \"\",\n orientation: Types.oneOf([\"horizontal\", \"vertical\"] as const),\n /** Per-category opacity multiplier, so the caption by a dimmed bar dims with it. Missing reads as 1. */\n dims: fresh<number[]>(() => []),\n arrivals: arrivalsEntry(),\n },\n // A node made of captions would otherwise hug them.\n defaults: { width: \"fill\", height: \"fill\" },\n children: (state) => {\n const n = state.categories.length\n const dim = (i: number) => clamp(state.dims[i] ?? 1, 0, 1)\n if (state.orientation === \"vertical\") {\n return asParts([\n captionColumn({\n count: n,\n axis: () => state.axis,\n text: (i) => state.categories[i] ?? \"\",\n // y-up: the first category takes the top slot.\n place: (i, height) => -slotCentre(i, state.categories.length, height),\n arrivals: () => state.arrivals,\n opacity: dim,\n label: state.label,\n }),\n ])\n }\n\n const pads = () => axisPads(state.axis, \"top\")\n // The spotlight dim sits on a hug box around each caption, so the entrance animates the text's own opacity without the two fighting over one value.\n const captions = state.categories.map((caption, i) => {\n const slot: Node2D = new Rect({\n width: \"hug\",\n height: \"hug\",\n flow: \"freeform\",\n opacity: () => dim(i),\n x: () => slotCentre(i, state.categories.length, (slot.parent as Node2D | null)?.layoutBounds.width ?? 0),\n children: [\n new Text({\n ...boundText(() => state.axis.labelStyle),\n text: caption,\n opacity: () => arrivalOf(state.arrivals, i).opacity,\n y: () => arrivalOf(state.arrivals, i).shift,\n }),\n ],\n }) as unknown as Node2D\n return slot\n })\n const children: Node2D[] = [new Rect({ width: \"fill\", height: \"hug\", padding: () => ({ top: pads().tick }), children: captions }) as unknown as Node2D]\n if (state.label !== \"\") {\n children.push(\n new Text({\n ...boundText(() => state.axis.titleStyle),\n text: state.label,\n opacity: () => arrivalOf(state.arrivals, \"label\").opacity,\n y: () => arrivalOf(state.arrivals, \"label\").shift,\n }) as unknown as Node2D\n )\n }\n return asParts([new Rect({ flow: \"vertical\", gap: () => pads().title, height: \"hug\", width: \"fill\", children }) as unknown as Node2D])\n },\n commands: {\n /**\n * Slide and fade captions in, first category first, then the title. The\n * duration is the whole entrance ({@link enterBudget}). `stagger` is seconds\n * between captions (derived when omitted); `slide` is the starting offset in px.\n */\n enter: {\n args: {\n stagger: Types.custom<number | undefined>(undefined),\n slide: Types.number(SLIDE),\n },\n run: (timeline, state) => {\n const { stagger, slide } = timeline.args\n const count = state.categories.length\n const captioned = state.label !== \"\"\n const from: Arrival = { opacity: 0, shift: slide }\n const keys = [...state.categories.keys(), ...(captioned ? [\"label\"] : [])]\n const arm = timeline.animate(() => ({ arrivals: armed(keys, from) }))\n if (count === 0) return arm\n const { step, per, caption } = enterBudget(timeline.duration, count, captioned, stagger)\n const ease = frameEase(timeline)\n const captions = state.categories.map((_, i) => ({ at: i * step, duration: per, piece: arrival(timeline, i, from, ease) }))\n const label = captioned ? [{ at: (count - 1) * step + per, duration: caption, piece: arrival(timeline, \"label\", from, ease) }] : []\n return timeline.together([arm, beats(timeline, [...captions, ...label])])\n },\n },\n },\n})\n\nexport type CategoryAxis = NodeOf<typeof CategoryAxis>\n", "import {\n Graphics2D,\n Text,\n Types,\n clamp,\n component2d,\n fillOps,\n type Fill,\n type FillResolved,\n type NodeOf,\n // Named so this component's emitted type reaches `Node2D` and its props through the sdk, not core.\n type Node2D,\n type Node2DProps as _Node2DProps,\n type TextStyle,\n} from \"@motionscript/sdk\"\n\nimport { boundText } from \"../kit/cartesian\"\nimport { asParts, fresh } from \"../kit/entries\"\nimport { frameEase } from \"../kit/motion\"\nimport { loadPaints } from \"../kit/paints\"\nimport { formatMarker } from \"../kit/shared\"\nimport { inkOn } from \"./shared\"\n\n/**\n * One drawn bar in the plot's centred pixel space (origin at the centre, y-up),\n * mapped by the parent {@link BarChart}: `center` and `thickness` across the\n * category slot, `from` and `to` along the value axis (y for a column, x for a\n * horizontal bar). Two ends rather than a base and a length, like `BarSpan`:\n * one shape fits grouped, stacked and negative.\n */\nexport interface BarGeometry {\n center: number\n thickness: number\n /** The base: the baseline when grouped, the running stack end when stacked. */\n from: number\n /** The far end at full growth. */\n to: number\n /** Whether the far end takes the corner radius (the stack's last segment on its side). */\n round: boolean\n /** The figure printed by the bar; empty for none. */\n caption: string\n}\n\n/** A figure inside a bar needs this much room around it, in multiples of the type size. */\nconst INSIDE_ROOM = 0.6\n\ninterface Bars {\n readonly bars: readonly BarGeometry[]\n readonly baseline: number\n readonly horizontal: boolean\n readonly growth: number\n readonly dims: readonly number[]\n readonly enabled: boolean\n readonly values: \"none\" | \"end\" | \"inside\"\n readonly valueStyle: TextStyle\n}\n\n/** Bar `i`'s dimming: the category spotlight, then the series switch. */\nfunction dimAt(s: Bars, index: number): number {\n if (!s.enabled) return 0\n return clamp(s.dims[index] ?? 1, 0, 1)\n}\n\n/** Bar `i`'s two ends as grown so far, along the value axis. */\nfunction endsAt(s: Bars, index: number): { base: number; end: number } | null {\n const bar = s.bars[index]\n if (!bar) return null\n const g = clamp(s.growth, 0, 1)\n return { base: s.baseline + (bar.from - s.baseline) * g, end: s.baseline + (bar.to - s.baseline) * g }\n}\n\nfunction sizeOf(style: TextStyle): number {\n return typeof style.fontSize === \"number\" ? style.fontSize : 24\n}\n\n/** Where bar `i`'s figure sits along the value axis: past its end, or in its middle. */\nfunction captionAlong(s: Bars, index: number, extent: number): number {\n const ends = endsAt(s, index)\n if (!ends) return 0\n if (s.values === \"inside\") return (ends.base + ends.end) / 2\n const direction = ends.end >= ends.base ? 1 : -1\n return ends.end + direction * (sizeOf(s.valueStyle) * 0.4 + extent / 2)\n}\n\n/** Whether bar `i` has room for a figure `extent` long inside it. */\nfunction fitsInside(s: Bars, index: number, extent: number, across: number): boolean {\n const bar = s.bars[index]\n const ends = endsAt(s, index)\n if (!bar || !ends) return false\n const room = sizeOf(s.valueStyle) * INSIDE_ROOM\n return Math.abs(ends.end - ends.base) >= extent + room && bar.thickness >= across\n}\n\n/**\n * One series of a {@link BarChart}: its bar in every category plus the printed\n * figures. A node per series, like `ChartLine`, so `showSeries` and\n * `spotlightSeries` mean the same on both: enable the node or tween its opacity.\n * Positions come from the parent, which owns the slot arithmetic.\n */\nexport const ChartBars = component2d({\n key: \"chartBars\",\n state: {\n bars: fresh<BarGeometry[]>(() => []),\n /** Pixel position of value 0 along the value axis, where every bar grows from. */\n baseline: 0,\n /** Bars grow along x from a category column rather than along y from a row. */\n horizontal: false,\n fill: Types.custom<Fill, FillResolved[]>([], { resolve: fillOps.resolve, lerp: fillOps.lerp }),\n cornerRadius: 8,\n /**\n * Rise of every bar in `[0, 1]` about the baseline, not each bar's own base:\n * every segment travels by the same factor, so a stack stays flush\n * mid-animation and a negative bar grows the other way.\n */\n growth: 1,\n /** Per-bar opacity by row index, how the category spotlight reaches one bar. Missing reads as 1. */\n dims: fresh<number[]>(() => []),\n /** Read as built: whether each bar prints its figure, and where. */\n values: Types.custom<\"none\" | \"end\" | \"inside\">(\"none\"),\n valueStyle: Types.custom<TextStyle>({ fontSize: 24, fill: \"white\" }),\n /** The wholesale switch behind `showSeries`/`hideSeries`; off skips the bars and their figures. */\n enabled: true,\n },\n // A node made of its figures would otherwise hug them.\n defaults: { width: \"fill\", height: \"fill\" },\n // One figure per bar, built once (the row count is fixed at construction)\n // and bound to the live geometry so it travels with its bar.\n children: (state) => {\n if (state.values === \"none\") return []\n return asParts(state.bars.map((_, i) => {\n const caption: Node2D = new Text({\n ...boundText(() => ({ ...state.valueStyle, ...(state.values === \"inside\" && { fill: inkOn(state.fill) }) })),\n text: () => state.bars[i]?.caption ?? \"\",\n x: () => (state.horizontal ? captionAlong(state, i, caption.layoutBounds.width) : (state.bars[i]?.center ?? 0)),\n y: () => (state.horizontal ? (state.bars[i]?.center ?? 0) : captionAlong(state, i, caption.layoutBounds.height)),\n opacity: () => {\n const box = caption.layoutBounds\n const along = state.horizontal ? box.width : box.height\n const across = state.horizontal ? box.height : box.width\n if (state.values === \"inside\" && !fitsInside(state, i, along, across)) return 0\n // A figure past the end rises in with its bar's last stretch.\n return dimAt(state, i) * clamp((state.growth - 0.6) / 0.4, 0, 1)\n },\n }) as unknown as Node2D\n return caption\n }))\n },\n load: (loader, state) => loadPaints(loader, { fills: [state.fill] }),\n commands: {\n /** Raise every bar from the baseline (`growth` 0 to 1). The resting state is the finished one; the chart arms it back to 0. */\n enter: (timeline) => {\n const ease = frameEase(timeline)\n return timeline.animate((t) => ({ growth: ease(t) }))\n },\n },\n render: (ctx, state) => {\n if (state.enabled) {\n for (let i = 0; i < state.bars.length; i++) {\n const bar = state.bars[i]\n const ends = endsAt(state, i)\n if (!ends || bar.thickness <= 0) continue\n // A segment inside a stack reaches a pixel under the next, so no seam of background shows between them.\n const seam = bar.round ? 0 : 1\n const length = Math.abs(ends.end - ends.base) + seam\n if (length <= seam) continue\n const radius = bar.round ? Math.max(0, Math.min(state.cornerRadius, length, bar.thickness / 2)) : 0\n const forward = ends.end >= ends.base\n const mid = (ends.base + ends.end) / 2 + (forward ? seam : -seam) / 2\n // Corner keys are visual (y-up): only the far end rounds.\n const far = state.horizontal\n ? (forward ? { topRight: radius, bottomRight: radius, topLeft: 0, bottomLeft: 0 } : { topLeft: radius, bottomLeft: radius, topRight: 0, bottomRight: 0 })\n : (forward ? { topLeft: radius, topRight: radius, bottomLeft: 0, bottomRight: 0 } : { bottomLeft: radius, bottomRight: radius, topLeft: 0, topRight: 0 })\n // One `Graphics2D` per bar: opacity belongs to the command list, and the spotlight dims single bars.\n const g = new Graphics2D().rect(state.horizontal\n ? { x: mid, y: bar.center, width: length, height: bar.thickness, cornerRadius: radius > 0 ? far : 0 }\n : { x: bar.center, y: mid, width: bar.thickness, height: length, cornerRadius: radius > 0 ? far : 0 })\n g.fill(state.fill)\n ctx.draw(g.opacity(dimAt(state, i)))\n }\n }\n ctx.children()\n },\n})\n\nexport type ChartBars = NodeOf<typeof ChartBars>\n\n/** A figure as the bar prints it when the chart gives no caption. */\nexport function barCaption(value: number): string {\n return value === 0 ? \"\" : formatMarker(value)\n}\n", "import { Types, fillOps, type DataRecord, type Fill } from \"@motionscript/sdk\"\n\nimport { niceRange, num, text, type ChartSeries, type Range } from \"../kit/shared\"\n\n/** One bar per row, beside its siblings in the category slot or stacked on them: {@link ChartSeries} under the name for what it draws here. */\nexport type BarSeries = ChartSeries\n\n/** How the series share a category: side by side, stacked, or stacked as shares of 100. */\nexport type BarStack = \"none\" | \"stacked\" | \"percent\"\n\n/** Which way the bars grow: up from a category row, or right from a category column. */\nexport type BarOrientation = \"vertical\" | \"horizontal\"\n\n/**\n * One bar's span in data units. A span rather than a height because every mode\n * fits it, and a negative value just runs the other way with no special case.\n */\nexport interface BarSpan {\n /** Where the base sits: 0 apart, the running total below (or above, for a negative) when stacked. */\n from: number\n to: number\n /** `to - from`. */\n value: number\n /** Whether it ends its stack on its side of zero, so its far end is rounded. */\n outer: boolean\n}\n\n/**\n * One row's spans, in series order. Stacking keeps a running sum on each side\n * of zero, so a negative value stacks downward from the baseline rather than\n * eating into the positives. In `percent` each value is its share of the row's\n * total magnitude. A zero value still yields a degenerate span, keeping the list\n * index-aligned with the series. `weights` scale each series' contribution.\n */\nexport function barSpans(row: DataRecord, series: readonly BarSeries[], stack: BarStack, weights: readonly number[] = []): BarSpan[] {\n const weight = (i: number) => Math.max(0, weights[i] ?? 1)\n if (stack !== \"stacked\" && stack !== \"percent\") {\n return series.map((s) => {\n const value = num(row, s.field)\n return { from: 0, to: value, value, outer: true }\n })\n }\n const values = series.map((s, i) => num(row, s.field) * weight(i))\n const total = values.reduce((sum, v) => sum + Math.abs(v), 0)\n const scaled = stack === \"percent\" ? values.map((v) => (total > 0 ? (v / total) * 100 : 0)) : values\n let lastUp = -1\n let lastDown = -1\n scaled.forEach((v, i) => {\n if (v > 0) lastUp = i\n else if (v < 0) lastDown = i\n })\n let up = 0\n let down = 0\n return scaled.map((value, i) => {\n if (value < 0) {\n const from = down\n down += value\n return { from, to: down, value, outer: i === lastDown }\n }\n const from = up\n up += value\n return { from, to: up, value, outer: i === lastUp }\n })\n}\n\nexport function barCategories(data: DataRecord[], field: string): string[] {\n return data.map((row) => text(row, field))\n}\n\n/**\n * The `[min, max]` of everything drawn, zero always included: a scale starting\n * at 40 draws a bar three times its neighbour for a 10% difference. A cropped\n * axis takes an explicit range.\n */\nexport function barValueExtent(data: DataRecord[], series: readonly BarSeries[], stack: BarStack, weights?: readonly number[]): Range {\n let lo = 0\n let hi = 0\n for (const row of data) {\n for (const span of barSpans(row, series, stack, weights)) {\n lo = Math.min(lo, span.from, span.to)\n hi = Math.max(hi, span.from, span.to)\n }\n }\n return lo < hi ? [lo, hi] : [0, 1]\n}\n\n/** The explicit `range`, else the data's extent nudged to tidy bounds (a percent stack reads to 100); `divisions` (one fewer than the marker count) makes the drawn ticks land on them. */\nexport function resolveBarScale(\n data: DataRecord[],\n series: readonly BarSeries[],\n stack: BarStack,\n range: Range | undefined,\n divisions: number,\n weights?: readonly number[]\n): Range {\n if (range) return range\n const [lo, hi] = barValueExtent(data, series, stack, weights)\n if (stack === \"percent\") return [lo < 0 ? -100 : 0, hi > 0 ? 100 : 0]\n return niceRange([lo, hi], divisions)\n}\n\n/** Black or white, whichever reads on `fill`: a figure printed inside a bar. */\nexport function inkOn(fill: Fill): string {\n const layers = fillOps.resolve(fill)\n const top = layers[layers.length - 1]\n if (top?.type !== \"solid\") return \"white\"\n const [r, g, b] = top.color\n const lift = (c: number) => (c <= 0.03928 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4)\n const luminance = 0.2126 * lift(r) + 0.7152 * lift(g) + 0.0722 * lift(b)\n return luminance > 0.4 ? \"#0a0a0a\" : \"white\"\n}\n\n/** A bar chart's own look: how round and how wide the bars are. */\nexport const BAR_MARKS = {\n /** Radius of each bar's far corners; a stacked segment inside the stack stays square. */\n barRadius: Types.number(10, { min: 0, max: 64, step: 1, unit: \"px\" }),\n /** How much of its category slot a bar group fills, the rest spacing the groups. */\n barWidth: Types.number(0.7, { min: 0.05, max: 1, step: 0.05 }),\n /** Space between the bars of one group, side by side. */\n barGap: Types.number(6, { min: 0, max: 40, step: 1, unit: \"px\" }),\n}\n\nexport const BAR_LABELS = {\n /** Read as the chart is built: each bar's value past its end, inside it, or none. */\n values: Types.oneOf([\"none\", \"end\", \"inside\"] as const, { animatable: false }),\n}\n", "import {\n Rect,\n Types,\n clamp,\n component2d,\n easeOut,\n type ChildView,\n type DataRecord,\n type NodeOf,\n // Named so this component's emitted type reaches `Node2D` and its props through the sdk, not core.\n type Node2D,\n type Node2DProps as _Node2DProps,\n type Fill as _Fill,\n type FillResolved as _FillResolved,\n} from \"@motionscript/sdk\"\n\nimport { asParts, fresh } from \"../kit/entries\"\nimport { beats, type AnyTimeline, type Beat } from \"../kit/motion\"\nimport { PieLegend } from \"../kit/pie-legend\"\nimport { PieRing } from \"./pie-ring\"\nimport { CHART_STYLE_FAMILY, CHART_STYLE_PRESETS, paletteFill } from \"../kit/style\"\nimport {\n PIE_SPOTLIGHT_DIM,\n PIE_STYLE_GROUPS,\n centerConfigOf,\n labelConfigOf,\n legendOf,\n resolvePieSlices,\n ringConfigOf,\n selectionFade,\n type PieLabelMode,\n type PieSlice,\n type PieStyle,\n} from \"./shared\"\n\nexport interface PieChartValues {\n readonly data: DataRecord[]\n readonly categoryField: string\n readonly valueField: string\n readonly style: PieStyle\n readonly pops: number[]\n}\n\n/** How `enter` divides its duration: wedges sweeping in, then labels and legend together. Sums to 1. */\nconst SWEEP_SHARE = 0.65\nconst LABEL_SHARE = 0.35\n\nconst SLICE_ARG = Types.number(0, { min: 0, step: 1 })\n\nfunction slicesOf(s: PieChartValues): PieSlice[] {\n return resolvePieSlices(\n s.data,\n s.categoryField,\n s.valueField,\n s.data.map((_, i) => paletteFill(s.style, i))\n )\n}\n\nfunction popAt(s: PieChartValues, index: number): number {\n return clamp(s.pops[index] ?? 0, 0, 1)\n}\n\n/** Whether slice `index` is past half way out, so a slice mid-swell is not yet counted. */\nexport function isSliceSelected(s: PieChartValues, index: number): boolean {\n return popAt(s, index) > 0.5\n}\n\n/** Per-slice opacity: 1 while nothing is out and for the selected slice, falling toward `dimOpacity` for the rest as the selection grows. */\nfunction sliceDims(s: PieChartValues): number[] {\n let focus = 0\n for (let i = 0; i < s.data.length; i++) focus = Math.max(focus, popAt(s, i))\n return s.data.map((_, i) => selectionFade(focus, PIE_SPOTLIGHT_DIM, popAt(s, i)))\n}\n\n/** Every slice's pop eased to what `pop` asks for. A move that changes nothing still takes its slot. */\nfunction popping(timeline: AnyTimeline, s: PieChartValues, pop: (index: number) => number) {\n const from = s.data.map((_, i) => popAt(s, i))\n const targets = s.data.map((_, i) => clamp(pop(i), 0, 1))\n if (from.every((value, i) => value === targets[i])) return timeline.wait(timeline.duration)\n return timeline.animate((t) => ({ pops: from.map((value, i) => value + (targets[i] - value) * t) }))\n}\n\n/** The ring and legend among the children; the last row is the one the chart built. */\nfunction partsOf(children: readonly ChildView[]) {\n for (let i = children.length - 1; i >= 0; i--) {\n const row = children[i]\n const ring = Rect.is(row) ? row.children.find(PieRing.is) : undefined\n if (ring) return { ring, legend: row.children.find(PieLegend.is) ?? null }\n }\n return null\n}\n\n/**\n * A pie or donut chart: a {@link PieRing} filling what the hugging {@link PieLegend}\n * leaves. One mark per row, not per column, and nothing to hide, since dropping\n * a slice would re-cut every other wedge; `selectSlice` and its siblings swell\n * a slice and dim the rest instead.\n *\n * Resting state is the finished chart, except the hole's summary, which\n * `showCenter: false` holds back for `revealCenter`.\n */\nexport const PieChart = component2d({\n key: \"pieChart\",\n state: {\n data: fresh<DataRecord[]>(() => [], { kind: \"dataset\" }),\n /** Slice caption, used on the labels and the legend. */\n categoryField: \"\",\n /** Slice magnitude: the wedge's share of the ring. */\n valueField: \"\",\n style: Types.style(CHART_STYLE_FAMILY, PIE_STYLE_GROUPS, { presets: CHART_STYLE_PRESETS }),\n /** What the ring's labels say. */\n labelMode: Types.custom<PieLabelMode>(\"percent\"),\n /** Gap between the ring and the legend, in px. */\n gap: 40,\n /** Text set in the ring's hole. */\n centerLabel: \"\",\n /** Smaller second line under `centerLabel`. */\n centerCaption: \"\",\n /** How far each slice is pushed out, `0`-`1` per index. Here, not on the ring, because the wedges and the legend both read it. */\n pops: fresh<number[]>(() => []),\n /** Read as the chart is built: whether the hole's summary is drawn at rest. A scene that wants it to land later sets `false` and runs `revealCenter`. */\n showCenter: Types.boolean(true, { animatable: false }),\n },\n defaults: {\n // A node made of parts that fill would otherwise hug them.\n width: \"fill\",\n height: \"fill\",\n pops: (state) => slicesOf(state).map(() => 0),\n },\n allowedChildren: [],\n // The structure (a label and legend row per row) is read once; slices, paint and selection are bound, so a theme tween re-paints and a `set` of `data` re-cuts.\n children: (state) => {\n const style = () => state.style\n const slices = () => slicesOf(state)\n const parts: Node2D[] = [\n new PieRing({\n width: \"fill\",\n height: \"fill\",\n slices,\n ring: () => ringConfigOf(style()),\n label: () => labelConfigOf(style()),\n centerStyle: () => centerConfigOf(style()),\n labelMode: state.labelMode,\n labelPlacement: state.style.labelPlacement,\n pops: () => state.pops,\n dimOpacity: PIE_SPOTLIGHT_DIM,\n centerLabel: state.centerLabel,\n centerCaption: state.centerCaption,\n centerReveal: state.showCenter === false ? 0 : 1,\n }) as unknown as Node2D,\n ]\n const position = state.style.legend\n if (position !== \"none\") {\n const side = position === \"right\"\n const legend = new PieLegend({\n slices,\n legend: () => legendOf(style()),\n dims: () => sliceDims(state),\n flow: side ? \"vertical\" : \"horizontal\",\n align: \"center\",\n // Spacing is fixed as built.\n gap: side ? legendOf(state.style).itemGap / 3 : legendOf(state.style).itemGap,\n padding: 0,\n }) as unknown as Node2D\n if (position === \"top\") parts.unshift(legend)\n else parts.push(legend)\n }\n const row = new Rect({\n flow: position === \"right\" || position === \"none\" ? \"horizontal\" : \"vertical\",\n width: \"fill\",\n height: \"fill\",\n gap: state.gap,\n padding: 24,\n align: \"center\",\n fill: () => state.style.background,\n children: parts,\n })\n return asParts([row as unknown as Node2D])\n },\n commands: {\n /** Wedges sweep in clockwise from `startAngle`, then labels fade up and the legend staggers in. `duration` is the whole entrance; the hole's summary keeps its own signal. */\n enter: {\n args: {},\n // Held from arrival, so it never shows finished ahead of its draw.\n entrance: true,\n easing: easeOut(),\n run: (timeline, _state, children) => {\n const parts = partsOf(children)\n if (!parts) return timeline.wait(timeline.duration)\n const { ring, legend } = parts\n const sweep = timeline.duration * SWEEP_SHARE\n const labels = timeline.duration * LABEL_SHARE\n const at0 = (piece: Beat[\"piece\"]): Beat => ({ at: 0, duration: 0, piece })\n return beats(timeline, [\n at0(ring.to({ growth: 0, labelReveal: 0 })),\n ...(legend ? [at0(legend.run(\"arm\"))] : []),\n { at: 0, duration: sweep, piece: ring.run(\"sweep\") },\n { at: sweep, duration: labels, piece: ring.run(\"revealLabels\") },\n ...(legend ? [{ at: sweep, duration: labels, piece: legend.run(\"enter\") }] : []),\n ])\n },\n },\n /** Fade the hole's summary up. Not part of `enter`: it is usually the conclusion, which a scene lands on its own beat. */\n revealCenter: {\n args: {},\n easing: easeOut(),\n run: (timeline, _state, children) => partsOf(children)?.ring.run(\"revealCenter\") ?? timeline.wait(timeline.duration),\n },\n /** Grow slice `index` out past the ring's rim and dim the rest, leaving any other selected slice where it is. */\n selectSlice: {\n args: { sliceIndex: SLICE_ARG },\n easing: easeOut(),\n run: (timeline, state) => {\n const index = timeline.args.sliceIndex\n return popping(timeline, state, (i) => (i === index ? 1 : popAt(state, i)))\n },\n },\n /** Settle slice `index` back flush with the ring. */\n deselectSlice: {\n args: { sliceIndex: SLICE_ARG },\n easing: easeOut(),\n run: (timeline, state) => {\n const index = timeline.args.sliceIndex\n return popping(timeline, state, (i) => (i === index ? 0 : popAt(state, i)))\n },\n },\n /** Move the focus to slice `index` alone, settling whatever else was out. */\n selectOnlySlice: {\n args: { sliceIndex: SLICE_ARG },\n easing: easeOut(),\n run: (timeline, state) => {\n const index = timeline.args.sliceIndex\n return popping(timeline, state, (i) => (i === index ? 1 : 0))\n },\n },\n /** Settle every slice flush and bring the whole chart back to full. */\n clearSelection: {\n args: {},\n easing: easeOut(),\n run: (timeline, state) => popping(timeline, state, () => 0),\n },\n },\n})\n\nexport type PieChart = NodeOf<typeof PieChart>\n", "import {\n Graphics2D,\n PathBuilder,\n Rect,\n Text,\n Types,\n clamp,\n component2d,\n strokeOps,\n textOps,\n type Fill,\n type NodeOf,\n // Named so this component's emitted type reaches `Node2D` and its props through the sdk, not core.\n type Node2D,\n type Node2DProps as _Node2DProps,\n type TextStyle,\n type Vector2,\n} from \"@motionscript/sdk\"\n\nimport { asParts, fresh } from \"../kit/entries\"\nimport { frameEase } from \"../kit/motion\"\nimport { loadPaints } from \"../kit/paints\"\nimport { resolvedFill, ringFills } from \"../kit/polar\"\nimport { formatPercent } from \"../kit/shared\"\n\nimport {\n PIE_SPOTLIGHT_DIM,\n pieArcs,\n relaxLabels,\n ringPoint,\n selectionFade,\n type CenterConfig,\n type LabelConfig,\n type PieArc,\n type PieLabelMode,\n type PieLabelPlacement,\n type PieSlice,\n type RingConfig,\n} from \"./shared\"\n\nconst DEFAULT_RING: RingConfig = { gap: 3, holeRadius: 0, startAngle: 0, selectedGrow: 1.08, cornerRadius: 4 }\nconst DEFAULT_LABEL: LabelConfig = {\n textStyle: { fontSize: 28, fontWeight: 500, textAlign: \"center\", fill: \"#a1a1aa\" },\n percentStyle: { fontSize: 28, fontWeight: 700, textAlign: \"center\", fill: \"#f4f4f5\" },\n insideStyle: { fontSize: 52, fontWeight: 700, textAlign: \"center\", fill: \"#111113\" },\n leaderStroke: { weight: 2, fill: \"#a1a1aa\" },\n}\nconst DEFAULT_CENTER: CenterConfig = {\n labelStyle: { fontSize: 50, fontWeight: 800, textAlign: \"center\", fill: \"#f4f4f5\" },\n captionStyle: { fontSize: 22, fontWeight: 500, textAlign: \"center\", fill: \"#a1a1aa\" },\n}\n\n/** Black or white, whichever reads better on a solid `fill`; black for any other paint. */\nexport function onFill(fill: Fill): string {\n const layers = resolvedFill(fill)\n const solid = layers.find((layer) => layer.type === \"solid\") as { color: [number, number, number, number] } | undefined\n if (!solid) return \"#111113\"\n const [r, g, b] = solid.color\n return 0.2126 * r + 0.7152 * g + 0.0722 * b > 0.45 ? \"#111113\" : \"#ffffff\"\n}\n\nconst LABEL_GAP = 12\nconst LABEL_PAD = 14\n/** Rough glyph width as a fraction of the font size, for gutter sizing. */\nconst GLYPH_RATIO = 0.62\nconst LEADER_LIFTOFF = 6\nconst LEADER_LENGTH = 34\nconst LABEL_STUB = 26\nconst TEXT_INSET = 8\n/** Floor on the elbow's distance from the ring's axis, as a fraction of the leader radius, so a label pushed above or below the ring still elbows out sideways. */\nconst MIN_ELBOW = 0.18\nconst ARC_STEPS = 240\nconst ELBOW_RADIUS = 8\nconst BARE_PAD = 2\nconst INSIDE_CAPTION_RATIO = 0.44\n/** Where an inside label sits on a solid pie, as a fraction of the radius: far enough out to clear the point every wedge converges on. */\nconst PIE_LABEL_RADIUS = 0.62\nconst CENTER_LABEL_FIT = 0.78\nconst INSIDE_LABEL_FIT = 0.9\n/** Below this a wedge's bisector counts as axis-aligned and that bound stops binding. */\nconst AXIS_EPSILON = 1e-3\n/** Type size when a theme style leaves it unset or on autofit. */\nconst FALLBACK_SIZE = 26\n\nfunction sizeOf(style: TextStyle, fallback = FALLBACK_SIZE): number {\n const size = style.fontSize\n return typeof size === \"number\" ? size : fallback\n}\n\ninterface LabelPlacement {\n index: number\n /** +1 right, -1 left. */\n side: 1 | -1\n /** Wedge edge, elbow, label. */\n leader: Vector2[]\n /** Where the label's inner edge is pinned. */\n text: Vector2\n}\n\n/**\n * A wedge over `a0`..`a1` (radians clockwise from 12 o'clock) from `rInner` to\n * `rOuter`, centred on `cx`; with `rInner <= 0` it closes at an apex pulled\n * off the centre by the gap. `halfGap` is half the px gap to the neighbour,\n * converted to an angle per radius so the channel keeps one width across the\n * band; the inset is capped at the wedge's half-span so a sliver narrows to\n * nothing rather than turning inside out. Corners are rounded by `corner` px\n * (clamped to what the wedge can hold), except a pie's apex.\n */\nexport function wedgePath(a0: number, a1: number, rInner: number, rOuter: number, halfGap: number, corner: number, cx: number): PathBuilder {\n const path = new PathBuilder()\n const span = a1 - a0\n const steps = Math.max(2, Math.ceil((Math.abs(span) / (Math.PI * 2)) * ARC_STEPS))\n const insetAt = (r: number): number => (r <= 0 ? 0 : Math.min(halfGap / r, span / 2.2))\n const at = (r: number, a: number): Vector2 => {\n const p = ringPoint(r, a)\n return { x: p.x + cx, y: p.y }\n }\n const hasHole = rInner > 0\n const oa0 = a0 + insetAt(rOuter)\n const oa1 = a1 - insetAt(rOuter)\n const ia0 = a0 + insetAt(rInner)\n const ia1 = a1 - insetAt(rInner)\n const O0 = at(rOuter, oa0)\n const O1 = at(rOuter, oa1)\n const half = Math.max(1e-3, Math.min(span / 2, Math.PI / 2))\n const apex = at(halfGap > 0 ? Math.min(halfGap / Math.sin(half), rOuter * 0.8) : 0, (a0 + a1) / 2)\n const I0 = hasHole ? at(rInner, ia0) : apex\n const I1 = hasHole ? at(rInner, ia1) : apex\n\n const band = hasHole ? rOuter - rInner : rOuter\n const rho = Math.max(0, Math.min(corner, band / 2.2, ((oa1 - oa0) * rOuter) / 2.2, hasHole ? ((ia1 - ia0) * rInner) / 2.2 : Infinity))\n const rounded = rho >= 0.5\n const toward = (from: Vector2, to: Vector2, d: number): Vector2 => {\n const len = Math.hypot(to.x - from.x, to.y - from.y) || 1\n const k = Math.min(0.5, d / len)\n return { x: from.x + (to.x - from.x) * k, y: from.y + (to.y - from.y) * k }\n }\n const dOuter = rounded ? rho / Math.max(1, rOuter) : 0\n const dInner = rounded && hasHole ? rho / rInner : 0\n\n const arc = (r: number, from: number, to: number) => {\n for (let i = 0; i <= steps; i++) {\n const p = at(r, from + ((to - from) * i) / steps)\n path.lineTo(p.x, p.y)\n }\n }\n const round = (corner: Vector2, next: Vector2) => {\n if (rounded) path.quadraticCurveTo(corner.x, corner.y, next.x, next.y)\n else path.lineTo(corner.x, corner.y)\n }\n\n const first = at(rOuter, oa0 + dOuter)\n path.moveTo(first.x, first.y)\n arc(rOuter, oa0 + dOuter, oa1 - dOuter)\n round(O1, toward(O1, I1, rho))\n if (hasHole) {\n const beforeI1 = toward(I1, O1, rho)\n path.lineTo(beforeI1.x, beforeI1.y)\n round(I1, at(rInner, ia1 - dInner))\n arc(rInner, ia1 - dInner, ia0 + dInner)\n round(I0, toward(I0, O0, rho))\n } else {\n path.lineTo(apex.x, apex.y)\n }\n const beforeO0 = toward(O0, I0, rounded ? rho : 0)\n path.lineTo(beforeO0.x, beforeO0.y)\n round(O0, first)\n path.close()\n return path\n}\n\ninterface RingState {\n readonly slices: PieSlice[]\n readonly ring: RingConfig\n readonly label: LabelConfig\n readonly centerStyle: CenterConfig\n readonly labelMode: PieLabelMode\n readonly labelPlacement: PieLabelPlacement\n readonly pops: readonly number[]\n readonly dimOpacity: number\n readonly centerLabel: string\n readonly centerCaption: string\n}\n\n/** Every radius, gutter and label position for one box, derived afresh wherever read so the drawing and the labels' bound positions cannot disagree. */\nexport class RingGeometry {\n constructor(\n private readonly s: RingState,\n private readonly box: { readonly width: number; readonly height: number }\n ) { }\n\n /** Re-read every frame so a value tween re-cuts them. */\n get arcs(): PieArc[] {\n return pieArcs(this.s.slices, this.s.ring.startAngle)\n }\n\n /** Leader labels are the only thing that costs a gutter. */\n get hasLeaderLabels(): boolean {\n return this.s.labelPlacement === \"outside\" && this.s.labelMode !== \"none\" && this.arcs.length > 0\n }\n\n /**\n * Px a horizontal label centred in `arc`'s band can run before leaving the\n * wedge: bound by the band's thickness near 3 o'clock, by its arc near 12.\n * Measured off the unpopped radius, so a slice growing out of the ring does not\n * resize its own text mid-animation.\n */\n insideRoom(arc: PieArc): number {\n const outer = this.outerRadius\n const hole = this.holeRadius\n const band = hole > 0 ? outer - hole : outer * (1 - PIE_LABEL_RADIUS) * 2\n const mid = hole > 0 ? (hole + outer) / 2 : outer * PIE_LABEL_RADIUS\n const sin = Math.abs(Math.sin(arc.mid))\n const cos = Math.abs(Math.cos(arc.mid))\n const acrossBand = sin > AXIS_EPSILON ? band / sin : Infinity\n const alongArc = cos > AXIS_EPSILON ? ((arc.a1 - arc.a0) * mid) / cos : Infinity\n return Math.max(0, Math.min(acrossBand, alongArc))\n }\n\n /** Widest line, in glyphs at the leading line's size, an inside label runs to. */\n insideGlyphs(arc: PieArc): number {\n const mode = this.s.labelMode\n const category = this.s.slices[arc.index]?.category.length ?? 0\n const percent = mode === \"both\" || mode === \"percent\" ? formatPercent(arc.fraction).length : 0\n // The caption is a fraction of the leading line, unless it is the leading line.\n const caption = mode === \"category\" ? category : mode === \"both\" ? category * INSIDE_CAPTION_RATIO : 0\n return Math.max(1, percent, caption)\n }\n\n /** The theme's `insideStyle.fontSize` shrunk to fit, an upper bound. One size across every inside label (the smallest any needs): mismatched sizes read as a mistake. */\n get insideFont(): number {\n let size = sizeOf(this.s.label.insideStyle, FALLBACK_SIZE * 1.9)\n for (const arc of this.arcs) {\n const fits = (this.insideRoom(arc) * INSIDE_LABEL_FIT) / (this.insideGlyphs(arc) * GLYPH_RATIO)\n size = Math.min(size, fits)\n }\n return Math.max(1, size)\n }\n\n /** The configured size capped to fit across the hole, which derives from the box: a smaller reflow would otherwise push the summary through the ring. */\n get centerFont(): number {\n const { centerStyle, centerLabel, centerCaption } = this.s\n const wanted = sizeOf(centerStyle.labelStyle, 46)\n const hole = this.holeRadius\n if (hole <= 0) return wanted\n const captionRatio = sizeOf(centerStyle.captionStyle, 22) / Math.max(1, wanted)\n // Both lines must clear the hole; the caption is a fraction of this size, so the wider once drawn binds, not the longer.\n const glyphs = Math.max(1, centerLabel.length, centerCaption.length * captionRatio)\n return Math.min(wanted, (hole * 2 * CENTER_LABEL_FIT) / (glyphs * GLYPH_RATIO))\n }\n\n /** Rim radius of a fully selected slice as a multiple of the ring's. */\n get growFactor(): number {\n return Math.max(1, Math.min(1.6, this.s.ring.selectedGrow))\n }\n\n get maxPop(): number {\n return this.outerRadius * (this.growFactor - 1)\n }\n\n /** Height of one leader label block, the unit the columns are spaced by. Inside labels cost no vertical reserve. */\n get labelRowHeight(): number {\n if (!this.hasLeaderLabels) return 0\n const caption = sizeOf(this.s.label.textStyle) * 1.25\n const percent = sizeOf(this.s.label.percentStyle) * 1.25\n if (this.s.labelMode === \"both\") return caption + percent + 2\n return this.s.labelMode === \"category\" ? caption : percent\n }\n\n /** Widest line in glyphs a leader label for slice `index` runs to. */\n captionGlyphs(index: number): number {\n const mode = this.s.labelMode\n // \"100%\" is the widest a percentage gets; captions are their own length.\n const percent = mode === \"percent\" || mode === \"both\" ? 4 : 0\n const category = mode === \"category\" || mode === \"both\" ? (this.s.slices[index]?.category.length ?? 0) : 0\n return Math.max(percent, category)\n }\n\n /** Room reserved per side for leaders and labels, from the slices that leader out that way. Excludes selection growth, which scales with the radius and is divided out in {@link outerRadius}. */\n get labelGutters(): { left: number; right: number } {\n const gutters = { left: BARE_PAD, right: BARE_PAD }\n if (!this.hasLeaderLabels) return gutters\n const glyph = sizeOf(this.s.label.textStyle) * GLYPH_RATIO\n for (const arc of this.arcs) {\n const room = LEADER_LENGTH + LABEL_STUB + TEXT_INSET + this.captionGlyphs(arc.index) * glyph + LABEL_PAD\n const key = sideOf(arc.mid) > 0 ? \"right\" : \"left\"\n gutters[key] = Math.max(gutters[key], room)\n }\n return gutters\n }\n\n /** Slides the ring into the empty half when labels all fall one way, keeping the ring-plus-labels group centred. */\n get centerX(): number {\n const { left, right } = this.labelGutters\n return (left - right) / 2\n }\n\n /** Fitted to what the gutters leave. The divisor keeps a fully selected slice (`radius * growFactor`) inside the box, and the ring one size whether or not anything is selected. */\n get outerRadius(): number {\n const { left, right } = this.labelGutters\n const room = Math.min((this.box.width - left - right) / 2, this.box.height / 2 - this.labelRowHeight - 4)\n return Math.max(0, room / this.growFactor)\n }\n\n get holeRadius(): number {\n const configured = this.s.ring.holeRadius\n if (configured <= 0) return 0\n const px = configured < 1 ? configured * this.outerRadius : configured\n return Math.min(px, this.outerRadius * 0.95)\n }\n\n /** The circle every leader elbows on, clear of even a popped-out slice. */\n get elbowRadius(): number {\n return this.outerRadius + this.maxPop + LEADER_LENGTH\n }\n\n popOf(index: number): number {\n return clamp(this.s.pops[index] ?? 0, 0, 1)\n }\n\n anchorRadius(index: number): number {\n return this.outerRadius + this.maxPop * this.popOf(index)\n }\n\n /** Halfway across the band on a donut, further out on a solid pie, where halfway would crowd the point the wedges converge on. Rides the slice's pop. */\n bandMidRadius(index: number): number {\n const rim = this.anchorRadius(index)\n const hole = this.holeRadius\n return hole > 0 ? (hole + rim) / 2 : rim * PIE_LABEL_RADIUS\n }\n\n insideAnchor(index: number): Vector2 {\n const arc = this.arcs.find((a) => a.index === index)\n if (arc === undefined) return { x: this.centerX, y: 0 }\n const point = ringPoint(this.bandMidRadius(index), arc.mid)\n return { x: point.x + this.centerX, y: point.y }\n }\n\n /** The most-grown slice, so the dim in {@link sliceOpacity} rides the pops' tween. */\n get selectionStrength(): number {\n let strongest = 0\n for (let i = 0; i < this.s.slices.length; i++) strongest = Math.max(strongest, this.popOf(i))\n return strongest\n }\n\n /** Opacity of slice `index` with its leader and label. */\n sliceOpacity(index: number): number {\n return selectionFade(this.selectionStrength, this.s.dimOpacity, this.popOf(index))\n }\n\n percentText(index: number): string {\n const arc = this.arcs.find((a) => a.index === index)\n return formatPercent(arc?.fraction ?? 0)\n }\n\n /** Labels split into left and right columns by their slice's bisector, each spread so nothing overlaps or leaves the box, then a leader built to each. */\n placements(): LabelPlacement[] {\n if (!this.hasLeaderLabels) return []\n const arcs = this.arcs\n if (arcs.length === 0 || this.outerRadius <= 0) return []\n\n const radius = this.elbowRadius\n const rowHeight = this.labelRowHeight\n const top = this.box.height / 2 - rowHeight / 2\n const bottom = -top\n const cx = this.centerX\n\n interface Slot {\n index: number\n side: 1 | -1\n mid: number\n ideal: number\n y: number\n }\n const right: Slot[] = []\n const left: Slot[] = []\n for (const arc of arcs) {\n const side = sideOf(arc.mid)\n const ideal = ringPoint(radius, arc.mid).y\n ;(side > 0 ? right : left).push({ index: arc.index, side, mid: arc.mid, ideal, y: ideal })\n }\n relaxLabels(right, rowHeight + LABEL_GAP, top, bottom)\n relaxLabels(left, rowHeight + LABEL_GAP, top, bottom)\n\n return [...right, ...left].map((slot) => {\n const start = ringPoint(this.anchorRadius(slot.index) + LEADER_LIFTOFF, slot.mid)\n // The elbow sits where the label's y crosses the leader circle. Solving\n // x^2 + y^2 = radius^2 for x keeps it on that circle (never inside the\n // ring); a label pushed past the circle's top or bottom falls back to the\n // sideways floor so its leader still reads as pointing outward.\n const onCircle = Math.sqrt(Math.max(0, radius * radius - slot.y * slot.y))\n const elbowX = cx + slot.side * Math.max(onCircle, radius * MIN_ELBOW)\n const endX = cx + slot.side * (radius + LABEL_STUB)\n\n return {\n index: slot.index,\n side: slot.side,\n leader: [\n { x: start.x + cx, y: start.y },\n { x: elbowX, y: slot.y },\n { x: endX, y: slot.y },\n ],\n text: { x: endX + slot.side * TEXT_INSET, y: slot.y },\n }\n })\n }\n\n placementFor(index: number): LabelPlacement | undefined {\n return this.placements().find((placement) => placement.index === index)\n }\n}\n\nfunction sideOf(mid: number): 1 | -1 {\n return Math.sin(mid) >= 0 ? 1 : -1\n}\n\nconst NO_BOX = { width: 0, height: 0 }\n\n/** Fills resolved once per paint, not per frame: a theme tween hands over new paint, but a frame that moves nothing must not re-resolve. Keyed by the paint, so it needs no node. */\n/** One label per drawn slice (a zero-valued slice has no wedge), then the hole's summary. Only the choice of form is settled here; the pinned points stay reactive. */\nfunction ringLabels(s: RingState & { readonly labelReveal: number; readonly centerReveal: number }) {\n const blocks: Node2D[] = []\n // A label block's parent is the ring, whose box it was laid out at.\n const geometry = () => new RingGeometry(s, (blocks[0]?.parent as Node2D | null | undefined)?.layoutBounds ?? NO_BOX)\n\n const label = (arc: PieArc): Node2D => {\n const opacity = () => clamp(s.labelReveal, 0, 1) * geometry().sliceOpacity(arc.index)\n const wantsCategory = s.labelMode === \"both\" || s.labelMode === \"category\"\n const wantsPercent = s.labelMode === \"both\" || s.labelMode === \"percent\"\n\n if (s.labelPlacement === \"inside\") {\n // The number leads: inside a wedge the reader knows which slice it is. Sizes are bound because the fitted size derives from a radius unknown until layout.\n const inside: Node2D[] = []\n if (wantsPercent) {\n inside.push(new Text({\n ...textOps.styleProps(s.label.insideStyle),\n text: () => geometry().percentText(arc.index),\n fill: () => onFill(s.slices[arc.index]?.fill ?? \"white\"),\n fontSize: () => geometry().insideFont,\n }))\n }\n if (wantsCategory) {\n inside.push(new Text({\n ...textOps.styleProps(s.label.insideStyle),\n text: () => s.slices[arc.index]?.category ?? \"\",\n fill: () => onFill(s.slices[arc.index]?.fill ?? \"white\"),\n fontSize: () => (s.labelMode === \"category\" ? geometry().insideFont : geometry().insideFont * INSIDE_CAPTION_RATIO),\n }))\n }\n return new Rect({\n flow: \"vertical\",\n width: \"hug\",\n height: \"hug\",\n gap: 0,\n align: \"center\",\n opacity,\n center: () => geometry().insideAnchor(arc.index),\n children: inside,\n })\n }\n\n const side = sideOf(arc.mid)\n const at = () => geometry().placementFor(arc.index)?.text ?? { x: 0, y: 0 }\n const children: Node2D[] = []\n if (wantsCategory) {\n children.push(new Text({\n ...textOps.styleProps(s.label.textStyle),\n text: () => s.slices[arc.index]?.category ?? \"\",\n textAlign: side > 0 ? \"left\" : \"right\",\n }))\n }\n if (wantsPercent) {\n children.push(new Text({\n ...textOps.styleProps(s.label.percentStyle),\n text: () => geometry().percentText(arc.index),\n textAlign: side > 0 ? \"left\" : \"right\",\n }))\n }\n return new Rect({\n flow: \"vertical\",\n width: \"hug\",\n height: \"hug\",\n gap: 2,\n align: side > 0 ? \"centerLeft\" : \"centerRight\",\n opacity,\n centerLeft: side > 0 ? at : undefined,\n centerRight: side > 0 ? undefined : at,\n children,\n })\n }\n\n if (s.labelPlacement !== \"none\" && s.labelMode !== \"none\") {\n for (const arc of pieArcs(s.slices, s.ring.startAngle)) blocks.push(label(arc))\n }\n\n // Pinned to the ring's centre, so it tracks the sideways shift a one-sided label column causes.\n if (s.centerLabel !== \"\" || s.centerCaption !== \"\") {\n const children: Node2D[] = []\n if (s.centerLabel !== \"\") {\n children.push(new Text({\n ...textOps.styleProps(s.centerStyle.labelStyle),\n text: s.centerLabel,\n fontSize: () => geometry().centerFont,\n }))\n }\n if (s.centerCaption !== \"\") {\n children.push(new Text({\n ...textOps.styleProps(s.centerStyle.captionStyle),\n text: s.centerCaption,\n fontSize: () =>\n geometry().centerFont * (sizeOf(s.centerStyle.captionStyle, 22) / sizeOf(s.centerStyle.labelStyle, 46)),\n }))\n }\n blocks.push(new Rect({\n flow: \"vertical\",\n width: \"hug\",\n height: \"hug\",\n gap: 2,\n align: \"center\",\n opacity: () => clamp(s.centerReveal, 0, 1) * clamp(geometry().holeRadius / 20, 0, 1),\n center: () => ({ x: geometry().centerX, y: 0 }),\n children,\n }))\n }\n return asParts(blocks)\n}\n\n/**\n * The ring: one wedge per {@link PieSlice} swept clockwise from `startAngle`,\n * with a constant-width `gap` (see {@link wedgePath}). A selected slice swells\n * out while its hole edge stays put, and the rest dims, leaders and labels\n * included. The only path-drawing part of the chart family; labels are real\n * {@link Text} nodes, so no glyph-width guesswork places a caption. Only the\n * sides that carry a leader reserve a gutter, and the ring slides into the rest.\n */\nexport const PieRing = component2d({\n key: \"pieRing\",\n state: {\n slices: fresh<PieSlice[]>(() => []),\n ring: Types.custom<RingConfig>(DEFAULT_RING),\n label: Types.custom<LabelConfig>(DEFAULT_LABEL),\n // Not `center`: every node already has one, the anchor its position is measured from.\n centerStyle: Types.custom<CenterConfig>(DEFAULT_CENTER),\n labelMode: Types.custom<PieLabelMode>(\"percent\"),\n labelPlacement: Types.custom<PieLabelPlacement>(\"outside\"),\n /** Sweep `[0, 1]`: the wedges grow clockwise from `startAngle` as it rises. */\n growth: 1,\n /** Fade of leaders and labels, separate from `growth` so they arrive after the sweep. */\n labelReveal: 1,\n /** Per-slice pop `[0, 1]`, owned by the chart so the ring and legend read one signal. */\n pops: fresh<number[]>(() => []),\n /** Opacity everything unselected falls back to while any slice is selected. */\n dimOpacity: PIE_SPOTLIGHT_DIM,\n /** Empty leaves the hole clear; ignored when there is no hole. */\n centerLabel: \"\",\n centerCaption: \"\",\n /** The hole's summary fade, untouched by the entrance: a scene that wants the conclusion on a later beat sets 0 and calls `revealCenter`. */\n centerReveal: 1,\n },\n // A plain node filled its parent; one made of its labels would hug them.\n defaults: { width: \"fill\", height: \"fill\" },\n children: (state) => ringLabels(state),\n // The paints sit past the paint entries: a fill per slice, the wedge outline and shadow, and the leader stroke.\n load: (loader, state) =>\n loadPaints(loader, {\n fills: ringFills(state.slices),\n strokes: [strokeOps.resolve(state.label.leaderStroke)],\n }),\n commands: {\n /** Wipe the wedges in around the ring (`growth` 0 to 1). */\n sweep: (timeline) => {\n const ease = frameEase(timeline)\n return timeline.animate((t) => ({ growth: ease(t) }))\n },\n /** Fade the leaders and captions up. */\n revealLabels: (timeline) => {\n const ease = frameEase(timeline)\n return timeline.animate((t) => ({ labelReveal: ease(t) }))\n },\n /** Fade the hole's summary up; not part of the entrance, since it is usually the conclusion. */\n revealCenter: (timeline, state) => {\n const ease = frameEase(timeline)\n const from = clamp(state.centerReveal, 0, 1)\n return timeline.animate((t) => ({ centerReveal: from + (1 - from) * ease(t) }))\n },\n },\n render: (ctx, state) => {\n const g = new RingGeometry(state, ctx.size)\n const rOuter = g.outerRadius\n const arcs = rOuter > 0 ? g.arcs : []\n if (arcs.length > 0) {\n const sweep = clamp(state.growth, 0, 1)\n const revealEnd = state.ring.startAngle * (Math.PI / 180) + Math.PI * 2 * sweep\n const hole = g.holeRadius\n const halfGap = Math.max(0, state.ring.gap) / 2\n\n // One shared frame (the whole ring square, grown slices included) pinned onto\n // every wedge path, so `Graphics2D.path()` doesn't re-centre each wedge on its\n // own bbox and collapse them all onto the origin. It stays symmetric about the\n // node's origin, so path coordinates land exactly in node space, and is grown\n // by the ring's sideways offset rather than moved with it, which would undo\n // the very shift it has to contain.\n const cx = g.centerX\n const half = rOuter + g.maxPop + 1 + Math.abs(cx)\n const centerBounds: [number, number, number, number] = [-half, -half, half, half]\n // Explicit width/height alongside centerBounds: a wedge path's command list\n // carries no implied extent, so a slice filled with an image or a video needs\n // this to size its decode.\n const span = half * 2\n\n const fills = ringFills(state.slices)\n for (const arc of arcs) {\n // Clipped to the revealed arc, so the ring draws in as one clockwise wipe.\n const a1 = Math.min(arc.a1, revealEnd)\n if (a1 <= arc.a0) continue\n\n const path = wedgePath(arc.a0, a1, hole, g.anchorRadius(arc.index), halfGap, Math.max(0, state.ring.cornerRadius), cx)\n const wedge = new Graphics2D().path(path.toPathState({ centerBounds, width: span, height: span }))\n wedge.fill(fills[arc.index] ?? [])\n ctx.draw(wedge.opacity(g.sliceOpacity(arc.index)))\n }\n\n // One `Graphics2D` per leader: open polylines chained into one command list\n // are combined into a single surface before the stroke, which closes each\n // contour and paints the leaders as thin triangles.\n const reveal = clamp(state.labelReveal, 0, 1)\n if (reveal > 0.001) {\n for (const placement of g.placements()) {\n ctx.draw(\n new Graphics2D()\n .line({ points: placement.leader, radius: ELBOW_RADIUS })\n .stroke(state.label.leaderStroke)\n .opacity(reveal * g.sliceOpacity(placement.index))\n )\n }\n }\n }\n ctx.children()\n },\n})\n\nexport type PieRing = NodeOf<typeof PieRing>\n", "import { Types, type Fill, type TextStyle, type Stroke, type FillResolved as _FillResolved } from \"@motionscript/sdk\"\n\nimport {\n CHART_COLORS,\n CHART_LEGEND,\n CHART_TEXT,\n legendConfigOf,\n type ChartStyleBase,\n} from \"../kit/style\"\nimport { num, text, type LegendConfig } from \"../kit/shared\"\nimport { DEG, PIE_SPOTLIGHT_DIM, ringPoint, selectionFade, type CenterConfig, type PieSlice } from \"../kit/polar\"\n\nexport { DEG, PIE_SPOTLIGHT_DIM, ringPoint, selectionFade, type CenterConfig, type PieSlice }\n\n/**\n * One slice per row, painted from `palette` by row order (cycling). Paint comes\n * from the palette, not the rows, because a pie's mark is a row where a line's\n * colour belongs to a column; that lets a pie be fed a CSV of plain numbers.\n */\nexport function resolvePieSlices(data: readonly Record<string, unknown>[], category: string, value: string, palette: readonly Fill[]): PieSlice[] {\n return data.map((row, i) => ({\n category: text(row as never, category),\n value: num(row as never, value),\n fill: palette.length > 0 ? palette[i % palette.length] : (\"white\" as Fill),\n }))\n}\n\n/** What a {@link PieChart}'s labels say. */\nexport type PieLabelMode =\n /** Two lines, whose order flips with placement: an outside label reads category over percentage, an inside label reads the percentage big over a small category. */\n | \"both\"\n | \"category\"\n | \"percent\"\n /** No labels and no leader lines. */\n | \"none\"\n\n/** `\"inside\"` centres the label in the wedge's band with no leader or gutter, so the ring draws bigger; `\"outside\"` sets it on a leader, which a sliver too narrow for text needs. */\nexport type PieLabelPlacement = \"inside\" | \"outside\" | \"none\"\n\n\n/** A slice's plotted value: negatives and non-finite values count as 0. */\nexport function sliceValue(slice: PieSlice): number {\n return slice.value > 0 && Number.isFinite(slice.value) ? slice.value : 0\n}\n\n/** Sum of every slice's plotted value, the denominator of every share. */\nexport function sliceTotal(slices: PieSlice[]): number {\n let sum = 0\n for (const slice of slices) sum += sliceValue(slice)\n return sum\n}\n\n/** One slice's resolved angular span on the ring. */\nexport interface PieArc {\n /** Index of the slice in the source list. */\n index: number\n /** Radians clockwise from 12 o'clock. */\n a0: number\n a1: number\n /** Where the slice's label and pop-out point. */\n mid: number\n /** Share of the total, `[0, 1]`. */\n fraction: number\n}\n\n/**\n * One arc per positive slice, walking clockwise from `startDegrees` and abutting.\n * Arcs are the undivided shares: a fixed angular gap would pinch shut at the\n * hole, so the gap is applied when the wedge is drawn, as a constant-width inset\n * off both ends.\n */\nexport function pieArcs(slices: PieSlice[], startDegrees: number): PieArc[] {\n const total = sliceTotal(slices)\n if (total <= 0) return []\n\n const arcs: PieArc[] = []\n let cursor = startDegrees * DEG\n slices.forEach((slice, index) => {\n const value = sliceValue(slice)\n if (value <= 0) return\n const fraction = value / total\n const a0 = cursor\n const a1 = a0 + fraction * Math.PI * 2\n cursor = a1\n arcs.push({ index, a0, a1, mid: (a0 + a1) / 2, fraction })\n })\n return arcs\n}\n\ninterface LabelSlot {\n /** Where the label would sit if nothing else were in the way. */\n ideal: number\n /** Written by {@link relaxLabels}. */\n y: number\n}\n\n/**\n * Spread one column of labels so none overlap, each near its `ideal` y and all\n * inside `[bottom, top]`. A top-down pass clears each label from the one above\n * by `minGap`; a reverse pass lifts a tail pushed past `bottom`. When the column\n * cannot hold them all, the reverse pass wins and the crowding is shared evenly.\n * Mutates each `y` and returns `slots` ordered top to bottom.\n */\nexport function relaxLabels<T extends LabelSlot>(slots: T[], minGap: number, top: number, bottom: number): T[] {\n slots.sort((a, b) => b.ideal - a.ideal)\n\n let ceiling = top\n for (const slot of slots) {\n slot.y = Math.min(slot.ideal, ceiling)\n ceiling = slot.y - minGap\n }\n\n let floor = bottom\n for (let i = slots.length - 1; i >= 0; i--) {\n slots[i].y = Math.max(slots[i].y, floor)\n floor = slots[i].y + minGap\n }\n\n return slots\n}\n\n/** The ring's geometry: everything about the wedges but their colour. */\nexport interface RingConfig {\n /** Channel between adjacent slices in px, constant across the band (an angular gap would splay open toward the rim). */\n gap: number\n /** Below 1 a fraction of the outer radius (`0.6` leaves a band 40% thick); 1 and up a pixel radius; `0` draws solid wedges. */\n holeRadius: number\n /** Degrees clockwise from 12 o'clock where the first slice begins. */\n startAngle: number\n /** How far a selected slice's rim reaches, as a multiple of the outer radius so the emphasis scales with the chart. Clamped to `[1, 1.6]`. */\n selectedGrow: number\n /** Rounding of each wedge corner, px. */\n cornerRadius: number\n}\n\n/** How the ring's labels are set, and the leader lines that point at them. */\nexport interface LabelConfig {\n /** The category caption outside the ring. */\n textStyle: TextStyle\n /** The percentage outside the ring. */\n percentStyle: TextStyle\n /** Both lines of a label inside its wedge; its fill is set per wedge, for contrast against the paint. */\n insideStyle: TextStyle\n /** Runs from a wedge out to its label. */\n leaderStroke: Stroke\n}\n\n/** What a pie's `style` resolves to. */\nexport interface PieStyle extends ChartStyleBase {\n readonly innerRadius: number\n readonly sliceGap: number\n readonly sliceRadius: number\n readonly labelPlacement: PieLabelPlacement\n}\n\n/** The groups of a pie's `style`: no grid, as nothing is ruled. */\nexport const PIE_STYLE_GROUPS = {\n colors: CHART_COLORS,\n text: CHART_TEXT,\n marks: {\n /** Hole radius as a fraction of the outer radius: 0 is a pie, about 0.6 a donut. */\n innerRadius: Types.number(0, { min: 0, max: 0.9, step: 0.05 }),\n /** Channel between neighbouring wedges, px. */\n sliceGap: Types.number(3, { min: 0, max: 40, step: 1, unit: \"px\" }),\n /** Rounding of each wedge corner, px. */\n sliceRadius: Types.number(4, { min: 0, max: 60, step: 1, unit: \"px\" }),\n },\n labels: {\n /** Read as the chart is built: inside the wedge, outside on a leader, or none. */\n labelPlacement: Types.oneOf([\"inside\", \"outside\", \"none\"] as const, { animatable: false }),\n },\n legend: CHART_LEGEND,\n}\n\nexport function legendOf(style: PieStyle): LegendConfig {\n return legendConfigOf(style)\n}\n\nfunction face(style: PieStyle): Pick<TextStyle, \"fontFamily\"> {\n return style.fontFamily ? { fontFamily: style.fontFamily } : {}\n}\n\nexport function ringConfigOf(style: PieStyle): RingConfig {\n return { gap: style.sliceGap, holeRadius: style.innerRadius, startAngle: 0, selectedGrow: 1.08, cornerRadius: style.sliceRadius }\n}\n\nexport function labelConfigOf(style: PieStyle): LabelConfig {\n const base: TextStyle = { ...face(style), fontSize: style.fontSize, fontWeight: style.fontWeight, textAlign: \"center\", fill: style.muted }\n const bold = Math.min(900, style.fontWeight + 200)\n return {\n textStyle: base,\n percentStyle: { ...base, fontWeight: bold, fill: style.foreground },\n insideStyle: { ...base, fontSize: Math.round(style.fontSize * 1.9), fontWeight: bold, fill: \"#111113\" },\n leaderStroke: { weight: 2, fill: style.muted },\n }\n}\n\nexport function centerConfigOf(style: PieStyle): CenterConfig {\n return {\n labelStyle: {\n ...face(style),\n fontSize: Math.round(style.fontSize * 1.8),\n fontWeight: Math.min(900, style.fontWeight + 300),\n textAlign: \"center\",\n fill: style.foreground,\n },\n captionStyle: { ...face(style), fontSize: Math.round(style.fontSize * 0.8), fontWeight: style.fontWeight, textAlign: \"center\", fill: style.muted },\n }\n}\n", "import {\n Rect,\n Text,\n Types,\n component2d,\n easeOut,\n textOps,\n type ChildView,\n type DataRecord,\n type NodeOf,\n // Named so this component's emitted type reaches `Node2D` and its props through the sdk, not core.\n type Node2D,\n type Node2DProps as _Node2DProps,\n type Fill as _Fill,\n type FillResolved as _FillResolved,\n type Stroke as _Stroke,\n type StrokeResolved as _StrokeResolved,\n type Size2D,\n type Vector2,\n} from \"@motionscript/sdk\"\n\nimport { laidOutSize } from \"../kit/cartesian\"\nimport { ChartLegend } from \"../kit/chart-legend\"\nimport { SERIES_ARG, asParts, fresh } from \"../kit/entries\"\nimport { ENTER_SHARE, LEGEND_SLIDE, beats, type AnyTimeline, type Beat } from \"../kit/motion\"\nimport { SPOTLIGHT_DIM, type ChartSeries } from \"../kit/shared\"\nimport {\n CHART_COLORS,\n CHART_LEGEND,\n CHART_STYLE_FAMILY,\n CHART_STYLE_PRESETS,\n CHART_TEXT,\n legendConfigOf,\n markerText,\n seriesFill,\n} from \"../kit/style\"\nimport { RadarGrid } from \"./radar-grid\"\nimport { RadarSeries } from \"./radar-series\"\nimport {\n RADAR_GRID,\n RADAR_MARKS,\n categoriesOf,\n fitRadius,\n fractionOf,\n labelAnchor,\n labelPoint,\n scaleOf,\n valuesOf,\n} from \"./shared\"\n\n/** What a radar chart plots, as its entries hold it. */\nexport interface RadarValues {\n readonly data: DataRecord[]\n readonly categoryField: string\n readonly series: ChartSeries[]\n readonly min: number\n readonly max: number\n}\n\n/** The scale the web is drawn to, whether `max` was given or left to the data. */\nexport function radarScale(state: RadarValues): { min: number; max: number } {\n return scaleOf(valuesOf(state.data, state.series), state.min, state.max)\n}\n\n/** Series `index`'s values as fractions of the rim, in spoke order. */\nexport function radarFractions(state: RadarValues, index: number): number[] {\n const series = state.series[index]\n if (!series) return []\n const scale = radarScale(state)\n return state.data.map((row) => {\n const v = row[series.field]\n return fractionOf(typeof v === \"number\" && Number.isFinite(v) ? v : 0, scale)\n })\n}\n\n/** The grid, series, label layer and legend among the children; the last row holding a grid is the one the chart built. */\nfunction partsOf(children: readonly ChildView[]) {\n for (let i = children.length - 1; i >= 0; i--) {\n const row = children[i]\n if (!Rect.is(row)) continue\n const plot = row.children.find((part) => Rect.is(part) && part.children.some(RadarGrid.is))\n if (!plot) continue\n return {\n grid: plot.children.find(RadarGrid.is)!,\n series: plot.children.filter(RadarSeries.is),\n labels: plot.children.find(Rect.is) ?? null,\n legend: row.children.find(ChartLegend.is) ?? null,\n }\n }\n return null\n}\n\nfunction toggling(timeline: AnyTimeline, children: readonly ChildView[], index: number, show: boolean) {\n const parts = partsOf(children)\n const series = parts?.series[index]\n if (!parts || !series) return timeline.wait(timeline.duration)\n return timeline.together([\n series.run(\"enter\", show ? { from: 0, to: 1 } : { from: 1, to: 0 }),\n ...(parts.legend ? [parts.legend.run(show ? \"showSeries\" : \"hideSeries\", { index })] : []),\n ])\n}\n\n/** The share of one series' growth that passes before the next starts. */\nconst STAGGER = 0.3\n\n/**\n * A radar (spider) chart: one spoke per data row, one closed polygon per\n * series, over a web of rings. Composed of a {@link RadarGrid}, a\n * {@link RadarSeries} per series, the category labels and a {@link ChartLegend}.\n *\n * Resting state is the finished chart; `enter` arms every part on its first\n * frame. `max` of 0 (or one not above `min`) is the largest value rounded up.\n */\nexport const RadarChart = component2d({\n key: \"radarChart\",\n state: {\n data: fresh<DataRecord[]>(() => [], { kind: \"dataset\" }),\n /** The column that names each spoke. */\n categoryField: \"\",\n series: fresh<ChartSeries[]>(() => [], { kind: \"series\" }),\n /** The value at the centre of the web. */\n min: 0,\n /** The value at the rim; 0 rounds the largest value up. */\n max: 0,\n style: Types.style(\n CHART_STYLE_FAMILY,\n {\n colors: CHART_COLORS,\n text: CHART_TEXT,\n grid: RADAR_GRID,\n marks: RADAR_MARKS,\n legend: CHART_LEGEND,\n },\n { presets: CHART_STYLE_PRESETS }\n ),\n },\n // A node made of parts that fill would otherwise hug them.\n defaults: { width: \"fill\", height: \"fill\" },\n allowedChildren: [],\n children: (state) => {\n const style = () => state.style\n let plot: Node2D | undefined\n const plotSize = (): Size2D => laidOutSize(plot)\n const radius = () => fitRadius(plotSize(), categoriesOf(state.data, state.categoryField), style().fontSize, style().spokeLabels)\n const count = state.data.length\n const enabled = state.series.map((s) => s.enabled ?? true)\n\n const grid = new RadarGrid({\n count: () => state.data.length,\n radius,\n levels: () => style().gridLevels,\n shape: () => style().gridShape,\n stroke: () => style().gridStroke,\n spokeStroke: () => style().spokeStroke,\n }) as unknown as Node2D\n\n const series = state.series.map(\n (s, i) =>\n new RadarSeries({\n fractions: () => radarFractions(state, i),\n radius,\n fill: () => seriesFill(style(), s, i),\n stroke: () => {\n const weight = style().strokeWidth\n return weight > 0 ? { weight, fill: seriesFill(style(), s, i), align: \"center\", join: \"round\" } : []\n },\n areaOpacity: () => style().areaOpacity,\n dots: () => style().dots,\n dotSize: () => style().dotSize,\n enabled: enabled[i],\n }) as unknown as Node2D\n )\n\n const parts: Node2D[] = [grid, ...series]\n\n if (state.style.spokeLabels) {\n const labels: Node2D[] = []\n for (let i = 0; i < count; i++) {\n const anchor = labelAnchor(i, count)\n const align = anchor === \"centerLeft\" ? \"left\" : anchor === \"centerRight\" ? \"right\" : \"center\"\n const at = (): Vector2 => labelPoint(i, count, radius(), style().fontSize)\n labels.push(\n new Text({\n ...textOps.styleProps(markerText(state.style, align)),\n text: () => categoriesOf(state.data, state.categoryField)[i] ?? \"\",\n fontSize: () => style().fontSize,\n fontWeight: () => style().fontWeight,\n fill: () => style().muted,\n [anchor]: at,\n }) as unknown as Node2D\n )\n }\n parts.push(new Rect({ width: \"fill\", height: \"fill\", children: labels }) as unknown as Node2D)\n }\n\n plot = new Rect({ width: \"fill\", height: \"fill\", children: parts }) as unknown as Node2D\n\n const row: Node2D[] = [plot]\n const position = state.style.legend\n if (position !== \"none\") {\n const side = position === \"right\"\n const config = legendConfigOf(state.style)\n const legend = new ChartLegend({\n series: state.series,\n swatches: () => state.series.map((s, i) => seriesFill(style(), s, i)),\n legend: () => legendConfigOf(style()),\n flow: side ? \"vertical\" : \"horizontal\",\n // Spacing is fixed as built; a style tween re-paints the swatches and captions only.\n gap: side ? Math.round(config.itemGap / 2) : config.itemGap,\n padding: config.padding,\n }) as unknown as Node2D\n if (position === \"top\") row.unshift(legend)\n else row.push(legend)\n }\n\n const frame = new Rect({\n flow: position === \"right\" ? \"horizontal\" : \"vertical\",\n width: \"fill\",\n height: \"fill\",\n gap: 24,\n align: \"center\",\n fill: () => style().background,\n children: row,\n })\n return asParts([frame as unknown as Node2D])\n },\n commands: {\n /** The web grows out, the polygons grow from the centre one series after another, then the labels and legend come up. */\n enter: {\n args: {},\n // Held from arrival, so it never shows finished ahead of its draw.\n entrance: true,\n easing: easeOut(),\n run: (timeline, _state, children) => {\n const parts = partsOf(children)\n if (!parts) return timeline.wait(timeline.duration)\n const duration = timeline.duration\n const web = duration * ENTER_SHARE.axes\n const marks = duration * ENTER_SHARE.marks\n const last = duration * ENTER_SHARE.legend\n const n = Math.max(1, parts.series.length)\n const each = marks / (1 + STAGGER * (n - 1))\n const { legend, labels } = parts\n const at0 = (piece: Beat[\"piece\"]): Beat => ({ at: 0, duration: 0, piece })\n // The first frame arms what every later beat moves: a beat ahead of the playhead writes nothing.\n return beats(timeline, [\n at0(parts.grid.to({ reveal: 0 })),\n ...parts.series.map((s) => at0(s.to({ progress: 0 }))),\n ...(labels ? [at0(labels.to({ opacity: 0 }))] : []),\n ...(legend ? [at0(legend.to({ opacity: 0, y: -LEGEND_SLIDE }))] : []),\n { at: 0, duration: web, piece: parts.grid.to({ reveal: 1 }) },\n ...parts.series.map((s, i) => ({ at: web + i * each * STAGGER, duration: each, piece: s.to({ progress: 1 }) })),\n ...(labels ? [{ at: web + marks * 0.6, duration: last + marks * 0.4, piece: labels.to({ opacity: 1 }) }] : []),\n ...(legend ? [{ at: web + marks, duration: last, piece: legend.to({ opacity: 1, y: 0 }) }] : []),\n ])\n },\n },\n /** Grow series `index`'s polygon back out of the centre, with its legend entry growing in. */\n showSeries: {\n args: { seriesIndex: SERIES_ARG },\n easing: easeOut(),\n run: (timeline, _state, children) => toggling(timeline, children, timeline.args.seriesIndex, true),\n },\n /** Shrink series `index`'s polygon into the centre as its legend entry shrinks away. */\n hideSeries: {\n args: { seriesIndex: SERIES_ARG },\n easing: easeOut(),\n run: (timeline, _state, children) => toggling(timeline, children, timeline.args.seriesIndex, false),\n },\n /** Fade every other series, polygon and legend entry, to focus on `index`. The legend dims in place, so the row does not reflow. */\n spotlightSeries: {\n args: { seriesIndex: SERIES_ARG },\n easing: easeOut(),\n run: (timeline, _state, children) => {\n const parts = partsOf(children)\n if (!parts) return timeline.wait(timeline.duration)\n const index = timeline.args.seriesIndex\n return timeline.together([\n ...parts.series.map((s, i) => s.to({ opacity: i === index ? 1 : SPOTLIGHT_DIM })),\n ...(parts.legend ? [parts.legend.run(\"spotlightSeries\", { index })] : []),\n ])\n },\n },\n },\n})\n\nexport type RadarChart = NodeOf<typeof RadarChart>\n", "import {\n Graphics2D,\n Types,\n clamp,\n component2d,\n strokeOps,\n type NodeOf,\n // Named so this component's emitted type reaches `Node2D` and its props through the sdk, not core.\n type Node2D as _Node2D,\n type Node2DProps as _Node2DProps,\n type Stroke,\n type StrokeResolved,\n type Vector2,\n} from \"@motionscript/sdk\"\n\nimport { loadPaints } from \"../kit/paints\"\nimport { spokeDirection, type GridShape } from \"./shared\"\n\n/**\n * The web of a {@link RadarChart}: `levels` rings and, if asked, a spoke to each\n * of `count` categories, drawn from the node's centre out to `radius`. `reveal`\n * grows the web from nothing.\n */\nexport const RadarGrid = component2d({\n key: \"radarGrid\",\n state: {\n count: 0,\n /** The rim, in px. */\n radius: 0,\n levels: 4,\n shape: Types.custom<GridShape>(\"polygon\"),\n stroke: Types.custom<Stroke, StrokeResolved[]>([], { resolve: strokeOps.resolve, lerp: strokeOps.lerp }),\n /** The line out to each category; empty draws none. */\n spokeStroke: Types.custom<Stroke, StrokeResolved[]>([], { resolve: strokeOps.resolve, lerp: strokeOps.lerp }),\n /** How far the web has grown out, `0`-`1`. Rests at 1 so a paused canvas paints it. */\n reveal: 1,\n },\n defaults: { width: \"fill\", height: \"fill\" },\n load: (loader, state) => loadPaints(loader, { strokes: [state.stroke, state.spokeStroke] }),\n render: (ctx, state) => {\n const grow = clamp(state.reveal, 0, 1)\n const rim = state.radius * grow\n if (rim <= 0 || grow <= 0) return\n const count = Math.max(0, Math.round(state.count))\n const levels = Math.max(1, Math.round(state.levels))\n const round = state.shape === \"circle\" || count < 3\n\n // One draw per ring: rings chained into one surface would stroke only their union's outline.\n for (let level = 1; state.stroke.length > 0 && level <= levels; level++) {\n const r = (rim * level) / levels\n const ring = new Graphics2D()\n if (round) {\n ring.ellipse({ width: r * 2, height: r * 2 })\n } else {\n const points: Vector2[] = []\n for (let i = 0; i < count; i++) {\n const d = spokeDirection(i, count)\n points.push({ x: d.x * r, y: d.y * r })\n }\n ring.line({ points, closed: true })\n }\n ctx.draw(ring.stroke(state.stroke).opacity(grow))\n }\n\n if (state.spokeStroke.length === 0) return\n for (let i = 0; i < count; i++) {\n const d = spokeDirection(i, count)\n ctx.draw(\n new Graphics2D()\n .line({ points: [{ x: 0, y: 0 }, { x: d.x * rim, y: d.y * rim }] })\n .stroke(state.spokeStroke)\n .opacity(grow)\n )\n }\n },\n})\n\nexport type RadarGrid = NodeOf<typeof RadarGrid>\n", "import { Types, type DataRecord, type Size2D, type StrokeResolved, type Stroke as _Stroke, type Vector2 } from \"@motionscript/sdk\"\n\nimport { num, text, type ChartSeries } from \"../kit/shared\"\n\nexport type GridShape = \"polygon\" | \"circle\"\n\n/** The radar chart's own grid group: the web the polygons are drawn over. */\nexport const RADAR_GRID = {\n /** Whether the rings are straight-edged (a polygon through the spokes) or round. */\n gridShape: Types.oneOf([\"polygon\", \"circle\"] as const),\n /** How many rings, outermost at the scale's maximum. */\n gridLevels: Types.number(4, { min: 1, max: 10, step: 1 }),\n /** The rings; empty draws none. */\n gridStroke: Types.stroke({ weight: 2, fill: \"white/15\" }),\n /** The line from the centre out to each category; empty draws none. */\n spokeStroke: Types.stroke({ weight: 2, fill: \"white/15\" }),\n /** Read as the chart is built: whether the category names stand around the rim. */\n spokeLabels: Types.boolean(true, { animatable: false }),\n}\n\nexport const RADAR_MARKS = {\n /** Outline weight of each series' polygon. */\n strokeWidth: Types.number(4, { min: 0, max: 24, step: 1, unit: \"px\" }),\n /** How strongly each polygon is filled in its series colour; 0 leaves an outline. */\n areaOpacity: Types.number(0.25, { min: 0, max: 1, step: 0.05 }),\n /** Whether a dot marks each value on its spoke. */\n dots: Types.boolean(true),\n dotSize: Types.number(10, { min: 2, max: 40, step: 1, unit: \"px\" }),\n}\n\n/** The grid and marks fields the parts read, whichever way the chart's style is spelled. */\nexport interface RadarStyle {\n readonly gridShape: GridShape\n readonly gridLevels: number\n readonly gridStroke: StrokeResolved[]\n readonly spokeStroke: StrokeResolved[]\n readonly spokeLabels: boolean\n readonly strokeWidth: number\n readonly areaOpacity: number\n readonly dots: boolean\n readonly dotSize: number\n readonly fontSize: number\n}\n\n/** Fraction of the label's font size between the rim and the label. */\nconst LABEL_PAD = 0.55\n/** Glyph width as a fraction of the font size, for fitting labels. */\nconst GLYPH = 0.58\n/** Room kept clear around the web when nothing else claims it, in px. */\nconst MARGIN = 10\n/** Below this a spoke counts as vertical, and its label centres over it. */\nconst SIDE = 0.35\n\n/** Spoke `index` of `count`, as a unit direction: 12 o'clock first, clockwise on screen, y up. */\nexport function spokeDirection(index: number, count: number): Vector2 {\n const angle = (index / Math.max(1, count)) * Math.PI * 2\n return { x: Math.sin(angle), y: Math.cos(angle) }\n}\n\n/** One category per data row. */\nexport function categoriesOf(data: readonly DataRecord[], field: string): string[] {\n return data.map((row) => text(row, field))\n}\n\n/** One list of values per series, a value per row. */\nexport function valuesOf(data: readonly DataRecord[], series: readonly ChartSeries[]): number[][] {\n return series.map((s) => data.map((row) => num(row, s.field)))\n}\n\nconst MANTISSAS = [1, 1.2, 1.5, 2, 2.5, 3, 4, 5, 6, 8, 10]\n\n/** `value` rounded up to a tidy 1, 1.5, 2, 2.5, 3, 4, 5, 6, 8 times a power of ten. */\nexport function niceCeil(value: number): number {\n if (!(value > 0)) return 1\n const power = 10 ** Math.floor(Math.log10(value))\n const mantissa = value / power\n const pick = MANTISSAS.find((m) => m >= mantissa - 1e-9) ?? 10\n return pick * power\n}\n\n/**\n * The scale the web is drawn to: `min` (default 0) to `max`, which when unset\n * (or not above `min`) is the largest value rounded up tidily.\n */\nexport function scaleOf(values: readonly (readonly number[])[], min: number, max: number): { min: number; max: number } {\n if (max > min) return { min, max }\n let top = min\n for (const list of values) for (const v of list) top = Math.max(top, v)\n const span = niceCeil(top - min)\n return { min, max: min + span }\n}\n\n/** Where `value` stands between the scale's ends, `0`-`1`. */\nexport function fractionOf(value: number, scale: { min: number; max: number }): number {\n const span = scale.max - scale.min\n if (span <= 0) return 0\n return Math.min(1, Math.max(0, (value - scale.min) / span))\n}\n\nexport type LabelAnchor = \"centerLeft\" | \"centerRight\" | \"bottomCenter\" | \"topCenter\"\n\n/** Which corner of a category's label touches the point beside its spoke's end. */\nexport function labelAnchor(index: number, count: number): LabelAnchor {\n const { x, y } = spokeDirection(index, count)\n if (x > SIDE) return \"centerLeft\"\n if (x < -SIDE) return \"centerRight\"\n return y >= 0 ? \"bottomCenter\" : \"topCenter\"\n}\n\nexport function labelPad(fontSize: number): number {\n return fontSize * LABEL_PAD\n}\n\n/** Rough size of a label, since the web is fitted before any text is measured. */\nexport function labelSize(caption: string, fontSize: number): Size2D {\n return { width: caption.length * fontSize * GLYPH, height: fontSize * 1.25 }\n}\n\n/**\n * The rim's radius for a box: the largest the web can be with every label\n * (when there are labels) still inside it.\n */\nexport function fitRadius(box: Size2D, categories: readonly string[], fontSize: number, labelled: boolean): number {\n let radius = Math.min(box.width, box.height) / 2 - MARGIN\n if (!labelled) return Math.max(0, radius)\n const pad = labelPad(fontSize)\n const count = categories.length\n categories.forEach((caption, i) => {\n const { x, y } = spokeDirection(i, count)\n const size = labelSize(caption, fontSize)\n const side = labelAnchor(i, count)\n // How much of the label hangs past its anchor point on each axis.\n const reachX = side === \"centerLeft\" || side === \"centerRight\" ? size.width : size.width / 2\n const reachY = side === \"bottomCenter\" || side === \"topCenter\" ? size.height : size.height / 2\n if (Math.abs(x) > 1e-6) radius = Math.min(radius, (box.width / 2 - reachX - MARGIN / 2) / Math.abs(x) - pad)\n if (Math.abs(y) > 1e-6) radius = Math.min(radius, (box.height / 2 - reachY - MARGIN / 2) / Math.abs(y) - pad)\n })\n return Math.max(0, radius)\n}\n\n/** Where spoke `index`'s label is pinned: just past the rim, centre-relative, y up. */\nexport function labelPoint(index: number, count: number, radius: number, fontSize: number): Vector2 {\n const { x, y } = spokeDirection(index, count)\n const r = radius + labelPad(fontSize)\n return { x: x * r, y: y * r }\n}\n", "import {\n Graphics2D,\n Types,\n clamp,\n component2d,\n fillOps,\n strokeOps,\n type Fill,\n type FillResolved,\n type NodeOf,\n // Named so this component's emitted type reaches `Node2D` and its props through the sdk, not core.\n type Node2D as _Node2D,\n type Node2DProps as _Node2DProps,\n type Stroke,\n type StrokeResolved,\n type Vector2,\n} from \"@motionscript/sdk\"\n\nimport { fresh } from \"../kit/entries\"\nimport { frameEase } from \"../kit/motion\"\nimport { loadPaints } from \"../kit/paints\"\nimport { spokeDirection } from \"./shared\"\n\n/** The vertices of a series' polygon: spoke `i` at `fractions[i]` of the rim, scaled by `grow` about the centre. */\nexport function seriesVertices(fractions: readonly number[], radius: number, grow = 1): Vector2[] {\n return fractions.map((f, i) => {\n const d = spokeDirection(i, fractions.length)\n const r = radius * f * grow\n return { x: d.x * r, y: d.y * r }\n })\n}\n\n/** One series of a {@link RadarChart}: a closed polygon through its values, washed in its colour, with a dot on each vertex. `progress` grows it out of the centre. */\nexport const RadarSeries = component2d({\n key: \"radarSeries\",\n state: {\n /** Each spoke's value as a fraction of the rim, `0`-`1`, in spoke order. */\n fractions: fresh<number[]>(() => []),\n /** The rim, in px. */\n radius: 0,\n fill: Types.custom<Fill, FillResolved[]>([], { resolve: fillOps.resolve, lerp: fillOps.lerp }),\n stroke: Types.custom<Stroke, StrokeResolved[]>([], { resolve: strokeOps.resolve, lerp: strokeOps.lerp }),\n areaOpacity: 0.25,\n dots: true,\n dotSize: 10,\n /** Growth out of the centre, `0`-`1`. Rests at 1 so a paused canvas paints it; `enter` drives it from 0. */\n progress: 1,\n /** Whether the series is drawn at all, flipped alongside its legend entry. */\n enabled: true,\n },\n defaults: { width: \"fill\", height: \"fill\" },\n load: (loader, state) => loadPaints(loader, { fills: [state.fill], strokes: [state.stroke] }),\n commands: {\n /** Grow the polygon from `from` to `to` (of its full size); `showSeries`/`hideSeries` are this with the ends stated. */\n enter: {\n args: { from: Types.number(0, { min: 0, max: 1 }), to: Types.number(1, { min: 0, max: 1 }) },\n run: (timeline) => {\n const { from, to } = timeline.args\n const ease = frameEase(timeline)\n return timeline.animate((t) => {\n const progress = from + (to - from) * ease(t)\n // Hidden only once fully shrunk, so a hide does not vanish a frame early.\n return { progress, enabled: progress > 0 }\n })\n },\n },\n },\n render: (ctx, state) => {\n if (!state.enabled) return\n const grow = clamp(state.progress, 0, 1)\n if (grow <= 0 || state.radius <= 0 || state.fractions.length === 0) return\n const points = seriesVertices(state.fractions, state.radius, grow)\n\n if (points.length >= 2) {\n const fill = new Graphics2D().line({ points, closed: true })\n if (state.areaOpacity > 0 && state.fill.length > 0) ctx.draw(fill.fill(state.fill).opacity(clamp(state.areaOpacity, 0, 1)))\n if (state.stroke.length > 0) ctx.draw(new Graphics2D().line({ points, closed: true }).stroke(state.stroke))\n }\n\n if (state.dots && state.dotSize > 0 && state.fill.length > 0) {\n const dots = new Graphics2D()\n for (const p of points) dots.ellipse({ x: p.x, y: p.y, width: state.dotSize, height: state.dotSize })\n ctx.draw(dots.fill(state.fill))\n }\n },\n})\n\nexport type RadarSeries = NodeOf<typeof RadarSeries>\n", "import {\n Rect,\n Types,\n clamp,\n component2d,\n easeOut,\n type ChildView,\n type DataRecord,\n type NodeOf,\n // Named so this component's emitted type reaches `Node2D` and its props through the sdk, not core.\n type Node2D,\n type Node2DProps as _Node2DProps,\n type Fill as _Fill,\n type FillResolved as _FillResolved,\n} from \"@motionscript/sdk\"\n\nimport { SERIES_ARG, asParts, fresh } from \"../kit/entries\"\nimport { beats, type AnyTimeline, type Beat } from \"../kit/motion\"\nimport { CHART_STYLE_FAMILY, CHART_STYLE_PRESETS } from \"../kit/style\"\nimport { PieLegend } from \"../kit/pie-legend\"\nimport { PIE_SPOTLIGHT_DIM, selectionFade } from \"../kit/polar\"\nimport { RadialRings } from \"./radial-rings\"\nimport {\n RADIAL_STYLE_GROUPS,\n centerOf,\n legendOf,\n marksOf,\n resolveRadialRows,\n ringLabelOf,\n type RadialRow,\n type RadialStyle,\n} from \"./shared\"\n\nexport interface RadialChartValues {\n readonly data: DataRecord[]\n readonly categoryField: string\n readonly valueField: string\n readonly max: number\n readonly style: RadialStyle\n readonly pops: number[]\n}\n\n/** How `enter` divides its duration: rings sweeping in, then captions and legend together. Sums to 1. */\nconst SWEEP_SHARE = 0.7\nconst LABEL_SHARE = 0.3\n\nfunction rowsOf(s: RadialChartValues): RadialRow[] {\n return resolveRadialRows(s.data, s.categoryField, s.valueField, s.style)\n}\n\nfunction popAt(s: RadialChartValues, index: number): number {\n return clamp(s.pops[index] ?? 0, 0, 1)\n}\n\n/** Per-row opacity for the legend: 1 while nothing is selected and for the selected ring, falling toward the dim for the rest. */\nfunction ringDims(s: RadialChartValues): number[] {\n let focus = 0\n for (let i = 0; i < s.data.length; i++) focus = Math.max(focus, popAt(s, i))\n return s.data.map((_, i) => selectionFade(focus, RING_DIM, popAt(s, i)))\n}\n\nconst RING_DIM = Math.max(PIE_SPOTLIGHT_DIM, 0.25)\n\nfunction popping(timeline: AnyTimeline, s: RadialChartValues, pop: (index: number) => number) {\n const from = s.data.map((_, i) => popAt(s, i))\n const targets = s.data.map((_, i) => clamp(pop(i), 0, 1))\n if (from.every((value, i) => value === targets[i])) return timeline.wait(timeline.duration)\n return timeline.animate((t) => ({ pops: from.map((value, i) => value + (targets[i] - value) * t) }))\n}\n\n/** The rings and legend among the children; the last row is the one the chart built. */\nfunction partsOf(children: readonly ChildView[]) {\n for (let i = children.length - 1; i >= 0; i--) {\n const row = children[i]\n const rings = Rect.is(row) ? row.children.find(RadialRings.is) : undefined\n if (rings) return { rings, legend: row.children.find(PieLegend.is) ?? null }\n }\n return null\n}\n\n/**\n * A radial bar chart: one concentric ring per row, the first row outermost,\n * each an arc from `startAngle` sweeping `value / max` of `sweep` degrees.\n * Rows are the marks and none can be hidden; `selectRing` thickens a ring and\n * dims the rest.\n */\nexport const RadialChart = component2d({\n key: \"radialChart\",\n state: {\n data: fresh<DataRecord[]>(() => [], { kind: \"dataset\" }),\n /** Ring caption, used on the ring labels and the legend. */\n categoryField: \"\",\n /** Ring magnitude: the arc's share of the full sweep. */\n valueField: \"\",\n /** The value a full sweep stands for. 0 lets the largest value fill its ring. */\n max: Types.number(0, { min: 0, step: 1 }),\n style: Types.style(CHART_STYLE_FAMILY, RADIAL_STYLE_GROUPS, { presets: CHART_STYLE_PRESETS }),\n /** Gap between the rings and the legend, in px. */\n gap: 40,\n /** Text set in the centre hole. */\n centerLabel: \"\",\n /** Smaller second line under `centerLabel`. */\n centerCaption: \"\",\n /** How far each ring is emphasised, `0`-`1` per index. Here because the rings and the legend both read it. */\n pops: fresh<number[]>(() => []),\n /** Read as the chart is built: whether the centre summary is drawn at rest. A scene that wants it to land later sets `false` and runs `revealCenter`. */\n showCenter: Types.boolean(true, { animatable: false }),\n },\n defaults: {\n width: \"fill\",\n height: \"fill\",\n pops: (state) => state.data.map(() => 0),\n },\n allowedChildren: [],\n children: (state) => {\n const style = () => state.style\n const rows = () => rowsOf(state)\n const parts: Node2D[] = [\n new RadialRings({\n width: \"fill\",\n height: \"fill\",\n rows,\n max: () => state.max,\n marks: () => marksOf(style()),\n label: () => ringLabelOf(style()),\n centerStyle: () => centerOf(style()),\n trackFill: () => style().track,\n ringLabels: () => style().ringLabels,\n pops: () => state.pops,\n dimOpacity: RING_DIM,\n centerLabel: state.centerLabel,\n centerCaption: state.centerCaption,\n centerReveal: state.showCenter === false ? 0 : 1,\n }) as unknown as Node2D,\n ]\n const position = state.style.legend\n if (position !== \"none\") {\n const side = position === \"right\"\n const config = legendOf(state.style)\n const legend = new PieLegend({\n slices: rows,\n legend: () => legendOf(style()),\n dims: () => ringDims(state),\n flow: side ? \"vertical\" : \"horizontal\",\n align: \"center\",\n gap: side ? config.itemGap / 3 : config.itemGap,\n padding: 0,\n }) as unknown as Node2D\n if (position === \"top\") parts.unshift(legend)\n else parts.push(legend)\n }\n const row = new Rect({\n flow: position === \"right\" || position === \"none\" ? \"horizontal\" : \"vertical\",\n width: \"fill\",\n height: \"fill\",\n gap: state.gap,\n padding: 24,\n align: \"center\",\n fill: () => state.style.background,\n children: parts,\n })\n return asParts([row as unknown as Node2D])\n },\n commands: {\n /** Rings sweep in from `startAngle`, outer ring first, then captions fade up and the legend staggers in. `duration` is the whole entrance; the centre summary keeps its own signal. */\n enter: {\n args: {},\n entrance: true,\n easing: easeOut(),\n run: (timeline, _state, children) => {\n const parts = partsOf(children)\n if (!parts) return timeline.wait(timeline.duration)\n const { rings, legend } = parts\n const sweep = timeline.duration * SWEEP_SHARE\n const labels = timeline.duration * LABEL_SHARE\n const at0 = (piece: Beat[\"piece\"]): Beat => ({ at: 0, duration: 0, piece })\n return beats(timeline, [\n at0(rings.to({ growth: 0, labelReveal: 0 })),\n ...(legend ? [at0(legend.run(\"arm\"))] : []),\n { at: 0, duration: sweep, piece: rings.run(\"sweep\") },\n { at: sweep, duration: labels, piece: rings.run(\"revealLabels\") },\n ...(legend ? [{ at: sweep, duration: labels, piece: legend.run(\"enter\") }] : []),\n ])\n },\n },\n /** Fade the centre summary up. Not part of `enter`: it is usually the conclusion, which a scene lands on its own beat. */\n revealCenter: {\n args: {},\n easing: easeOut(),\n run: (timeline, _state, children) => partsOf(children)?.rings.run(\"revealCenter\") ?? timeline.wait(timeline.duration),\n },\n /** Thicken ring `ringIndex` and dim the rest, leaving any other selected ring where it is. */\n selectRing: {\n args: { ringIndex: SERIES_ARG },\n easing: easeOut(),\n run: (timeline, state) => {\n const index = timeline.args.ringIndex\n return popping(timeline, state, (i) => (i === index ? 1 : popAt(state, i)))\n },\n },\n /** Settle every ring and bring the whole chart back to full. */\n clearSelection: {\n args: {},\n easing: easeOut(),\n run: (timeline, state) => popping(timeline, state, () => 0),\n },\n },\n})\n\nexport type RadialChart = NodeOf<typeof RadialChart>\n", "import {\n Graphics2D,\n PathBuilder,\n Rect,\n Text,\n Types,\n clamp,\n component2d,\n fillOps,\n textOps,\n type NodeOf,\n // Named so this component's emitted type reaches `Node2D` and its props through the sdk, not core.\n type Node2D,\n type Node2DProps as _Node2DProps,\n type Fill as _Fill,\n type FillResolved as _FillResolved,\n type TextStyle,\n type Vector2,\n} from \"@motionscript/sdk\"\n\nimport { asParts, fresh } from \"../kit/entries\"\nimport { frameEase } from \"../kit/motion\"\nimport { loadPaints } from \"../kit/paints\"\nimport { DEG, ringFills, ringPoint, selectionFade, type CenterConfig } from \"../kit/polar\"\nimport { radialFractions, type RadialMarks, type RadialRow } from \"./shared\"\n\n/** Share of the entrance one ring's sweep starts after the last. */\nconst STAGGER = 0.12\n/** A selected ring's thickness grows by this share of itself, on each side. */\nconst GROW = 0.12\nconst ARC_STEP = 4 * DEG\nconst LABEL_PAD = 10\nconst CENTER_FIT = 0.78\nconst GLYPH_RATIO = 0.62\n/** How far the radius is held in from the box, for the sake of a ring's growth. */\nconst EDGE = 4\n\nconst DEFAULT_MARKS: RadialMarks = { innerRadius: 0.3, ringGap: 8, sweep: 360, startAngle: 0, track: true, roundCaps: true }\nconst DEFAULT_LABEL: TextStyle = { fontSize: 28, fontWeight: 500, textAlign: \"center\", fill: \"#a1a1aa\" }\nconst DEFAULT_CENTER: CenterConfig = {\n labelStyle: { fontSize: 50, fontWeight: 800, textAlign: \"center\", fill: \"#f4f4f5\" },\n captionStyle: { fontSize: 22, fontWeight: 500, textAlign: \"center\", fill: \"#a1a1aa\" },\n}\n\ninterface RingsState {\n readonly rows: RadialRow[]\n readonly max: number\n readonly marks: RadialMarks\n readonly label: TextStyle\n readonly centerStyle: CenterConfig\n readonly ringLabels: boolean\n readonly pops: readonly number[]\n readonly dimOpacity: number\n readonly centerLabel: string\n readonly centerCaption: string\n}\n\nfunction sizeOf(style: TextStyle, fallback: number): number {\n return typeof style.fontSize === \"number\" ? style.fontSize : fallback\n}\n\n/** Every radius and angle for one box, derived wherever read so the drawing and the labels cannot disagree. */\nexport class RadialGeometry {\n constructor(\n private readonly s: RingsState,\n private readonly box: { readonly width: number; readonly height: number }\n ) {}\n\n get count(): number {\n return this.s.rows.length\n }\n\n get outerRadius(): number {\n return Math.max(0, Math.min(this.box.width, this.box.height) / 2 - EDGE)\n }\n\n get holeRadius(): number {\n return clamp(this.s.marks.innerRadius, 0, 0.9) * this.outerRadius\n }\n\n /** Radial depth of one ring. */\n get thickness(): number {\n const n = this.count\n if (n === 0) return 0\n return Math.max(0, (this.outerRadius - this.holeRadius - (n - 1) * Math.max(0, this.s.marks.ringGap)) / n)\n }\n\n /** Rim of ring `index`; ring 0 is the outermost. */\n ringOuter(index: number): number {\n return this.outerRadius - index * (this.thickness + Math.max(0, this.s.marks.ringGap))\n }\n\n ringMid(index: number): number {\n return this.ringOuter(index) - this.thickness / 2\n }\n\n get fractions(): number[] {\n return radialFractions(this.s.rows, this.s.max)\n }\n\n get startRad(): number {\n return this.s.marks.startAngle * DEG\n }\n\n get sweepRad(): number {\n return clamp(this.s.marks.sweep, 0, 360) * DEG\n }\n\n popOf(index: number): number {\n return clamp(this.s.pops[index] ?? 0, 0, 1)\n }\n\n get selectionStrength(): number {\n let strongest = 0\n for (let i = 0; i < this.count; i++) strongest = Math.max(strongest, this.popOf(i))\n return strongest\n }\n\n ringOpacity(index: number): number {\n return selectionFade(this.selectionStrength, this.s.dimOpacity, this.popOf(index))\n }\n\n /** How far ring `index`'s sweep has come at entrance progress `growth`: rings start in turn, outer first. */\n progress(index: number, growth: number): number {\n const total = 1 + STAGGER * Math.max(0, this.count - 1)\n return clamp(growth * total - index * STAGGER, 0, 1)\n }\n\n get labelFont(): number {\n return Math.max(1, Math.min(sizeOf(this.s.label, 28), this.thickness * 0.62))\n }\n\n /** Where ring `index`'s caption is pinned: just behind its start, reading away from the sweep. */\n labelAnchor(index: number): { at: Vector2; side: 1 | -1 } {\n const a = this.startRad\n const back = { x: -Math.cos(a), y: Math.sin(a) }\n const p = ringPoint(this.ringMid(index), a)\n const side: 1 | -1 = back.x <= 0 ? -1 : 1\n return { at: { x: p.x + back.x * LABEL_PAD, y: p.y + back.y * LABEL_PAD }, side }\n }\n\n get centerFont(): number {\n const { centerStyle, centerLabel, centerCaption } = this.s\n const wanted = sizeOf(centerStyle.labelStyle, 50)\n const hole = this.holeRadius\n if (hole <= 0) return wanted\n const ratio = sizeOf(centerStyle.captionStyle, 22) / Math.max(1, wanted)\n const glyphs = Math.max(1, centerLabel.length, centerCaption.length * ratio)\n return Math.min(wanted, (hole * 2 * CENTER_FIT) / (glyphs * GLYPH_RATIO))\n }\n}\n\n/**\n * An arc band between `rIn` and `rOut` over `a0`..`a1` (radians clockwise from\n * 12 o'clock), the ends squared or capped with half circles. A band shorter\n * than its caps is two overlapping caps, which fill as a pill.\n */\nexport function bandPath(a0: number, a1: number, rIn: number, rOut: number, round: boolean): PathBuilder {\n const path = new PathBuilder()\n const mid = (rIn + rOut) / 2\n const cap = (rOut - rIn) / 2\n const delta = round && mid > 0 ? Math.min(cap / mid, (a1 - a0) / 2) : 0\n const from = a0 + delta\n const to = a1 - delta\n const steps = Math.max(2, Math.ceil(Math.abs(to - from) / ARC_STEP))\n const arc = (r: number, x: number, y: number, first: boolean) => {\n for (let i = 0; i <= steps; i++) {\n const p = ringPoint(r, x + ((y - x) * i) / steps)\n if (first && i === 0) path.moveTo(p.x, p.y)\n else path.lineTo(p.x, p.y)\n }\n }\n // The end at `angle` rounded through a tip `direction` along the sweep.\n const semicircle = (angle: number, direction: 1 | -1, fromOuter: boolean) => {\n const centre = ringPoint(mid, angle)\n const radial = { x: Math.sin(angle), y: Math.cos(angle) }\n const tangent = { x: Math.cos(angle) * direction, y: -Math.sin(angle) * direction }\n const turns = 12\n for (let i = 1; i < turns; i++) {\n const phi = (Math.PI * i) / turns\n const r = fromOuter ? Math.cos(phi) : -Math.cos(phi)\n path.lineTo(centre.x + cap * (radial.x * r + tangent.x * Math.sin(phi)), centre.y + cap * (radial.y * r + tangent.y * Math.sin(phi)))\n }\n }\n arc(rOut, from, to, true)\n if (round) semicircle(to, 1, true)\n arc(rIn, to, from, false)\n if (round) semicircle(from, -1, false)\n path.close()\n return path\n}\n\nconst NO_BOX = { width: 0, height: 0 }\n\nfunction labelBlocks(s: RingsState & { readonly labelReveal: number; readonly centerReveal: number }) {\n const blocks: Node2D[] = []\n const geometry = () => new RadialGeometry(s, (blocks[0]?.parent as Node2D | null | undefined)?.layoutBounds ?? NO_BOX)\n const side = geometry().labelAnchor(0).side\n\n s.rows.forEach((_, index) => {\n const anchor = () => geometry().labelAnchor(index).at\n blocks.push(\n new Rect({\n flow: \"vertical\",\n width: \"hug\",\n height: \"hug\",\n align: side > 0 ? \"centerLeft\" : \"centerRight\",\n opacity: () => (s.ringLabels ? clamp(s.labelReveal, 0, 1) * geometry().ringOpacity(index) : 0),\n centerLeft: side > 0 ? anchor : undefined,\n centerRight: side > 0 ? undefined : anchor,\n children: [\n new Text({\n ...textOps.styleProps(s.label),\n text: () => s.rows[index]?.category ?? \"\",\n textAlign: side > 0 ? \"left\" : \"right\",\n fontSize: () => geometry().labelFont,\n }),\n ],\n })\n )\n })\n\n if (s.centerLabel !== \"\" || s.centerCaption !== \"\") {\n const children: Node2D[] = []\n if (s.centerLabel !== \"\") {\n children.push(new Text({ ...textOps.styleProps(s.centerStyle.labelStyle), text: s.centerLabel, fontSize: () => geometry().centerFont }))\n }\n if (s.centerCaption !== \"\") {\n children.push(\n new Text({\n ...textOps.styleProps(s.centerStyle.captionStyle),\n text: s.centerCaption,\n fontSize: () => geometry().centerFont * (sizeOf(s.centerStyle.captionStyle, 22) / sizeOf(s.centerStyle.labelStyle, 50)),\n })\n )\n }\n blocks.push(\n new Rect({\n flow: \"vertical\",\n width: \"hug\",\n height: \"hug\",\n gap: 2,\n align: \"center\",\n opacity: () => clamp(s.centerReveal, 0, 1),\n center: { x: 0, y: 0 },\n children,\n })\n )\n }\n return asParts(blocks)\n}\n\n/**\n * The rings: row `i` is the `i`-th ring from the outside, an arc from\n * `startAngle` whose sweep is `value / max` of the full sweep, over an\n * optional full-sweep track. A selected ring thickens and the rest dims.\n */\nexport const RadialRings = component2d({\n key: \"radialRings\",\n state: {\n rows: fresh<RadialRow[]>(() => []),\n max: 0,\n marks: Types.custom<RadialMarks>(DEFAULT_MARKS),\n label: Types.custom<TextStyle>(DEFAULT_LABEL),\n centerStyle: Types.custom<CenterConfig>(DEFAULT_CENTER),\n /** The empty-ring colour drawn under each arc. */\n trackFill: Types.fill(\"white/15\"),\n ringLabels: Types.boolean(false),\n /** Entrance progress `[0, 1]`: rings sweep in turn. */\n growth: 1,\n labelReveal: 1,\n pops: fresh<number[]>(() => []),\n dimOpacity: 0.25,\n centerLabel: \"\",\n centerCaption: \"\",\n centerReveal: 1,\n },\n defaults: { width: \"fill\", height: \"fill\" },\n children: (state) => labelBlocks(state),\n load: (loader, state) => loadPaints(loader, { fills: [...ringFills(state.rows), fillOps.resolve(state.trackFill)] }),\n commands: {\n /** Sweep the rings in, outer first. */\n sweep: (timeline) => {\n const ease = frameEase(timeline)\n return timeline.animate((t) => ({ growth: ease(t) }))\n },\n /** Fade the ring captions up. */\n revealLabels: (timeline) => {\n const ease = frameEase(timeline)\n return timeline.animate((t) => ({ labelReveal: ease(t) }))\n },\n /** Fade the centre summary up. */\n revealCenter: (timeline, state) => {\n const ease = frameEase(timeline)\n const from = clamp(state.centerReveal, 0, 1)\n return timeline.animate((t) => ({ centerReveal: from + (1 - from) * ease(t) }))\n },\n },\n render: (ctx, state) => {\n const g = new RadialGeometry(state, ctx.size)\n const thickness = g.thickness\n if (g.outerRadius > 0 && g.count > 0 && thickness > 0) {\n const half = g.outerRadius + EDGE + 1\n const frame = { centerBounds: [-half, -half, half, half] as [number, number, number, number], width: half * 2, height: half * 2 }\n const fills = ringFills(state.rows)\n const fractions = g.fractions\n const a0 = g.startRad\n const round = state.marks.roundCaps\n // Selected rings last, so a thickened ring is never under its neighbour.\n const order = [...state.rows.keys()].sort((a, b) => g.popOf(a) - g.popOf(b))\n for (const i of order) {\n const grow = thickness * GROW * g.popOf(i)\n const rOut = g.ringOuter(i) + grow\n const rIn = g.ringOuter(i) - thickness - grow\n const opacity = g.ringOpacity(i)\n if (state.marks.track && g.sweepRad > 0) {\n ctx.draw(new Graphics2D().path(bandPath(a0, a0 + g.sweepRad, rIn, rOut, round).toPathState(frame)).fill(state.trackFill).opacity(opacity))\n }\n const span = g.sweepRad * fractions[i] * g.progress(i, state.growth)\n if (span <= 1e-4) continue\n ctx.draw(new Graphics2D().path(bandPath(a0, a0 + span, rIn, rOut, round).toPathState(frame)).fill(fills[i] ?? []).opacity(opacity))\n }\n }\n ctx.children()\n },\n})\n\nexport type RadialRings = NodeOf<typeof RadialRings>\n", "import { Types, clamp, type DataRecord, type TextStyle, type Fill as _Fill, type FillResolved as _FillResolved } from \"@motionscript/sdk\"\n\nimport { CHART_COLORS, CHART_LEGEND, CHART_TEXT, legendConfigOf, type ChartStyleBase, paletteFill } from \"../kit/style\"\nimport type { LegendConfig } from \"../kit/shared\"\nimport { num, text } from \"../kit/shared\"\nimport type { CenterConfig, PieSlice } from \"../kit/polar\"\n\n/** One ring: a row's caption, magnitude and paint. The same shape as a pie's slice, so the legend is shared. */\nexport type RadialRow = PieSlice\n\nexport function resolveRadialRows(data: readonly DataRecord[], category: string, value: string, style: Pick<ChartStyleBase, \"palette\">): RadialRow[] {\n return data.map((row, i) => ({ category: text(row, category), value: num(row, value), fill: paletteFill(style, i) }))\n}\n\n/** A row's plotted value: negatives and non-finite values count as 0. */\nexport function rowValue(row: RadialRow): number {\n return row.value > 0 && Number.isFinite(row.value) ? row.value : 0\n}\n\n/** What a full sweep stands for: `max` when it is positive, else the largest value (1 when every value is 0). */\nexport function radialMax(rows: readonly RadialRow[], max: number): number {\n if (max > 0 && Number.isFinite(max)) return max\n let largest = 0\n for (const row of rows) largest = Math.max(largest, rowValue(row))\n return largest > 0 ? largest : 1\n}\n\n/** The share of a full sweep each row fills, `[0, 1]`. */\nexport function radialFractions(rows: readonly RadialRow[], max: number): number[] {\n const top = radialMax(rows, max)\n return rows.map((row) => clamp(rowValue(row) / top, 0, 1))\n}\n\n/** The ring geometry and look, from `style`. */\nexport interface RadialMarks {\n innerRadius: number\n ringGap: number\n /** Degrees of a full ring. */\n sweep: number\n /** Degrees clockwise from 12 o'clock. */\n startAngle: number\n track: boolean\n roundCaps: boolean\n}\n\nexport interface RadialStyle extends ChartStyleBase {\n readonly innerRadius: number\n readonly ringGap: number\n readonly sweep: number\n readonly startAngle: number\n readonly track: _FillResolved[]\n readonly roundCaps: boolean\n readonly ringLabels: boolean\n}\n\nexport const RADIAL_STYLE_GROUPS = {\n colors: CHART_COLORS,\n text: CHART_TEXT,\n marks: {\n /** Where the innermost ring starts, as a fraction of the outer radius. */\n innerRadius: Types.number(0.3, { min: 0, max: 0.9, step: 0.05 }),\n /** Space between neighbouring rings, px. */\n ringGap: Types.number(8, { min: 0, max: 60, step: 1, unit: \"px\" }),\n /** Degrees a full ring spans: 360 a circle, 270 a gauge-like open ring. */\n sweep: Types.number(360, { min: 30, max: 360, step: 5, unit: \"deg\" }),\n /** Degrees clockwise from 12 o'clock where every ring begins. */\n startAngle: Types.number(0, { min: -360, max: 360, step: 5, unit: \"deg\" }),\n /** The full ring under each arc; empty draws none. */\n track: Types.fill(\"white/10\"),\n /** Round the ends of the arcs and tracks. */\n roundCaps: Types.boolean(true),\n },\n labels: {\n /** The category written at each ring's start, in the muted colour. */\n ringLabels: Types.boolean(false),\n },\n legend: CHART_LEGEND,\n}\n\nexport function marksOf(style: RadialStyle): RadialMarks {\n return {\n innerRadius: style.innerRadius,\n ringGap: style.ringGap,\n sweep: style.sweep,\n startAngle: style.startAngle,\n track: style.track.length > 0,\n roundCaps: style.roundCaps,\n }\n}\n\nexport function legendOf(style: RadialStyle): LegendConfig {\n return legendConfigOf(style)\n}\n\nfunction face(style: RadialStyle): Pick<TextStyle, \"fontFamily\"> {\n return style.fontFamily ? { fontFamily: style.fontFamily } : {}\n}\n\nexport function ringLabelOf(style: RadialStyle): TextStyle {\n return { ...face(style), fontSize: style.fontSize, fontWeight: style.fontWeight, textAlign: \"center\", fill: style.muted }\n}\n\nexport function centerOf(style: RadialStyle): CenterConfig {\n return {\n labelStyle: {\n ...face(style),\n fontSize: Math.round(style.fontSize * 1.8),\n fontWeight: Math.min(900, style.fontWeight + 300),\n textAlign: \"center\",\n fill: style.foreground,\n },\n captionStyle: { ...face(style), fontSize: Math.round(style.fontSize * 0.8), fontWeight: style.fontWeight, textAlign: \"center\", fill: style.muted },\n }\n}\n", "import { LineChart } from \"./line-chart\";\nimport { BarChart } from \"./bar-chart\";\nimport { PieChart } from \"./pie-chart\";\nimport { RadarChart } from \"./radar-chart\";\nimport { RadialChart } from \"./radial-chart\";\n\n// Typed by name, so the declaration names each component rather than spelling out its type through core.\nexport const NODES: (typeof LineChart | typeof BarChart | typeof PieChart | typeof RadarChart | typeof RadialChart)[] = [\n LineChart,\n BarChart,\n PieChart,\n RadarChart,\n RadialChart,\n];\n"],
5
- "mappings": "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",
6
- "names": ["Rect", "Text", "Types", "clamp", "component2d", "easeOut", "formatNumber", "Graphics2D", "Types", "clamp", "component2d", "fillOps", "strokeOps", "Types", "EMPTY_REGION_BOX", "hasRegion", "box", "resolveRegionBox", "region", "plot", "xScale", "yScale", "span", "range", "min", "max", "lo", "hi", "a", "b", "toPx", "v", "left", "right", "xBounded", "bottom", "top", "yBounded", "clipPolylineToBox", "points", "runs", "run", "i", "seg", "clipSegment", "samePoint", "dx", "dy", "t0", "t1", "edges", "p", "q", "r", "seriesPoints", "data", "x", "series", "row", "num", "yExtent", "s", "resolveYScale", "divisions", "niceRange", "stackSeries", "stack", "weights", "order", "_", "weight", "totals", "sum", "running", "base", "k", "value", "stackExtent", "stacks", "y", "SAMPLES", "curvePoints", "curve", "out", "mid", "tangents", "monotoneTangents", "c1", "c2", "t", "u", "n", "slope", "h", "m", "h0", "h1", "s0", "s1", "endTangent", "secant", "inner", "cutAt", "clipPolygonToBox", "polygon", "inside", "input", "cur", "prev", "dc", "dp", "crossing", "da", "db", "LINE_MARKS", "Types", "LINE_LABELS", "traceX", "points", "progress", "first", "last", "traced", "curve", "path", "curvePoints", "cutAt", "curveEntry", "Types", "outlineCommands", "p", "i", "fillOutline", "ctx", "outline", "fill", "opacity", "width", "height", "centerBounds", "Graphics2D", "ChartLine", "component2d", "fresh", "strokeOps", "fillOps", "EMPTY_REGION_BOX", "SPOTLIGHT_DIM", "loader", "state", "loadPaints", "timeline", "from", "to", "ease", "frameEase", "t", "shown", "pts", "clamp", "box", "lit", "hasRegion", "dim", "stroke", "weight", "drawn", "radius", "run", "clipPolylineToBox", "size", "reach", "bright", "dimmed", "brightAny", "dimAny", "pt", "grown", "inside", "ChartArea", "outlineAt", "top", "base", "span", "verticalSpan", "paint", "areaFill", "clipPolygonToBox", "bottom", "colour", "area", "whole", "own", "fade", "r", "g", "b", "a", "middle", "half", "Graphics2D", "Types", "component2d", "fillOps", "strokeOps", "ChartRegion", "component2d", "fresh", "EMPTY_REGION_BOX", "Types", "strokeOps", "fillOps", "loader", "state", "loadPaints", "ctx", "box", "hasRegion", "width", "height", "cx", "cy", "Graphics2D", "half", "x", "rule", "y", "formatNumber", "DAY", "MONTHS", "NOMINAL_YEAR", "monthIndex", "word", "month", "isoWeekStart", "year", "week", "jan4", "weekday", "parseInstant", "raw", "s", "ymd", "day", "n", "named", "y", "dayNamed", "formatInstant", "value", "span", "date", "label", "isNumericColumn", "data", "field", "sawValue", "row", "v", "instantColumn", "parsed", "t", "last", "extentOf", "values", "lo", "hi", "EVERY_SAMPLE", "sampledTicks", "positions", "min", "max", "divisions", "inside", "unique", "a", "b", "markerValues", "evenlySpaced", "nearest", "target", "best", "out", "tick", "sorted", "mean", "i", "labelBySample", "captions", "fallback", "scales", "resolveXScale", "pattern", "byKey", "key", "scale", "xScaleOf", "num", "formatMarker", "text", "instants", "extent", "range", "_", "LINE_STYLE", "Types", "CHART_STYLE_FAMILY", "CHART_COLORS", "CHART_TEXT", "CARTESIAN_GRID", "LINE_MARKS", "LINE_LABELS", "CHART_LEGEND", "CHART_STYLE_PRESETS", "REGION_ARG", "PERCENT", "columnOf", "s", "format", "resolveXScale", "stacksOf", "weighted", "stackSeries", "drawnX", "domain", "column", "range", "DEFAULT_MARKERS", "autoY", "divisions", "lo", "hi", "stackExtent", "zero", "niceRange", "drawnY", "even", "markerValues", "niceTicks", "domainsDrawn", "lineChartDomains", "key", "kept", "value", "domains", "settleAxisDomain", "d", "mapper", "plot", "xMin", "xMax", "yMin", "yMax", "x", "y", "NO_PIXELS", "seriesPixels", "index", "stack", "map", "toPx", "k", "baselineValue", "clamp", "overflows", "ylo", "yhi", "xlo", "xhi", "within", "v", "a", "b", "regionBox", "w", "h", "resolveRegionBox", "hasCallout", "region", "regionArg", "span", "rescale", "ticks", "to", "axesAt", "from", "t", "lerpAxisDomain", "yLabel", "formatNumber", "text", "formatMarker", "markerStep", "weightOf", "partsOf", "children", "views", "chartViews", "VerticalAxis", "HorizontalAxis", "ChartLine", "ChartLegend", "clearing", "timeline", "state", "toggling", "show", "parts", "line", "legend", "_", "i", "start", "target", "weights", "LineChart", "component2d", "fresh", "resolveAxisDomain", "lerpAxisEntry", "style", "plotSize", "laidOutSize", "pixels", "enabled", "built", "yConfig", "axisConfigOf", "xConfig", "yCaptions", "vAxis", "hAxis", "overhang", "ghost", "columnGhost", "axisPads", "spotlight", "dimOpacity", "SPOTLIGHT_DIM", "lines", "seriesFill", "areas", "ChartArea", "labels", "below", "_row", "label", "Text", "boundText", "valueText", "half", "point", "clear", "reach", "traceX", "legendAt", "legendConfigOf", "Rect", "ChartCanvas", "ChartRegion", "fade", "cartesianFrame", "frameGap", "headroom", "easeOut", "duration", "revealing", "body", "axes", "ENTER_SHARE", "traced", "at0", "piece", "away", "legendAway", "beats", "previous", "home", "SERIES_ARG", "_state", "Rect", "Types", "clamp", "component2d", "easeOut", "formatNumber", "Rect", "Text", "Types", "clamp", "component2d", "enterBudget", "SLIDE", "slotCentre", "index", "count", "length", "CategoryAxis", "component2d", "fresh", "Types", "DEFAULT_X_AXIS", "arrivalsEntry", "state", "n", "dim", "i", "clamp", "captionColumn", "height", "pads", "axisPads", "captions", "caption", "slot", "Rect", "Text", "boundText", "arrivalOf", "children", "timeline", "stagger", "slide", "captioned", "from", "keys", "arm", "armed", "step", "per", "enterBudget", "ease", "frameEase", "_", "arrival", "label", "beats", "Graphics2D", "Text", "Types", "clamp", "component2d", "fillOps", "Types", "fillOps", "barSpans", "row", "series", "stack", "weights", "weight", "i", "s", "value", "num", "values", "total", "sum", "v", "scaled", "lastUp", "lastDown", "up", "down", "from", "barCategories", "data", "field", "text", "barValueExtent", "lo", "hi", "span", "resolveBarScale", "range", "divisions", "niceRange", "inkOn", "fill", "layers", "fillOps", "top", "g", "b", "lift", "c", "BAR_MARKS", "Types", "BAR_LABELS", "INSIDE_ROOM", "dimAt", "s", "index", "clamp", "endsAt", "bar", "g", "sizeOf", "style", "captionAlong", "extent", "ends", "direction", "fitsInside", "across", "room", "ChartBars", "component2d", "fresh", "Types", "fillOps", "state", "_", "i", "caption", "Text", "boundText", "inkOn", "box", "along", "loader", "loadPaints", "timeline", "ease", "frameEase", "t", "ctx", "seam", "length", "radius", "forward", "mid", "far", "Graphics2D", "BAR_STYLE", "Types", "CHART_STYLE_FAMILY", "CHART_COLORS", "CHART_TEXT", "CARTESIAN_GRID", "BAR_MARKS", "BAR_LABELS", "CHART_LEGEND", "CHART_STYLE_PRESETS", "drawnValue", "s", "domain", "divisions", "DEFAULT_MARKERS", "range", "resolveBarScale", "even", "markerValues", "niceTicks", "domainsDrawn", "barChartDomain", "key", "kept", "value", "settleAxisDomain", "d", "valueLabel", "pattern", "formatNumber", "text", "formatMarker", "markerStep", "valueToPx", "length", "min", "max", "baselineValue", "lo", "hi", "clamp", "weightAt", "index", "runs", "plot", "slotAt", "row", "across", "centre", "slotCentre", "seriesBars", "series", "along", "n", "inner", "stacked", "total", "i", "unit", "weight", "before", "gap", "values", "rowIndex", "span", "barSpans", "offset", "caption", "num", "categoryDims", "focus", "chosen", "_", "SPOTLIGHT_DIM", "partsOf", "children", "views", "chartViews", "view", "VerticalAxis", "HorizontalAxis", "CategoryAxis", "ChartBars", "ChartLegend", "toggling", "timeline", "state", "target", "parts", "from", "start", "showing", "t", "weights", "shown", "BarChart", "component2d", "fresh", "resolveAxisDomain", "lerpAxisEntry", "lerpAxisDomain", "style", "plotSize", "laidOutSize", "built", "horizontal", "categories", "barCategories", "valueConfig", "axisConfigOf", "categoryConfig", "valueCaptions", "showValue", "showCategory", "valueAxis", "overhang", "categoryAxis", "left", "bottom", "leftConfig", "ghost", "columnGhost", "axisPads", "barSets", "seriesFill", "valueText", "legendAt", "legend", "legendConfigOf", "boundaries", "slots", "Rect", "ChartCanvas", "cartesianFrame", "frameGap", "headroom", "easeOut", "duration", "axes", "ENTER_SHARE", "rise", "at0", "piece", "beats", "legendAway", "SERIES_ARG", "_state", "bars", "lit", "Rect", "Types", "clamp", "component2d", "easeOut", "Graphics2D", "PathBuilder", "Rect", "Text", "Types", "clamp", "component2d", "strokeOps", "textOps", "Types", "resolvePieSlices", "data", "category", "value", "palette", "row", "text", "num", "sliceValue", "slice", "sliceTotal", "slices", "sum", "pieArcs", "startDegrees", "total", "arcs", "cursor", "DEG", "index", "fraction", "a0", "a1", "relaxLabels", "slots", "minGap", "top", "bottom", "a", "b", "ceiling", "slot", "floor", "i", "PIE_STYLE_GROUPS", "CHART_COLORS", "CHART_TEXT", "Types", "CHART_LEGEND", "legendOf", "style", "legendConfigOf", "face", "ringConfigOf", "labelConfigOf", "base", "bold", "centerConfigOf", "DEFAULT_RING", "DEFAULT_LABEL", "DEFAULT_CENTER", "onFill", "fill", "solid", "resolvedFill", "layer", "g", "b", "LABEL_GAP", "LABEL_PAD", "GLYPH_RATIO", "LEADER_LIFTOFF", "LEADER_LENGTH", "LABEL_STUB", "TEXT_INSET", "MIN_ELBOW", "ARC_STEPS", "ELBOW_RADIUS", "BARE_PAD", "INSIDE_CAPTION_RATIO", "PIE_LABEL_RADIUS", "CENTER_LABEL_FIT", "INSIDE_LABEL_FIT", "AXIS_EPSILON", "FALLBACK_SIZE", "sizeOf", "style", "fallback", "size", "wedgePath", "a0", "a1", "rInner", "rOuter", "halfGap", "corner", "cx", "path", "PathBuilder", "span", "steps", "insetAt", "r", "at", "a", "p", "ringPoint", "hasHole", "oa0", "oa1", "ia0", "ia1", "O0", "O1", "half", "apex", "I0", "I1", "band", "rho", "rounded", "toward", "from", "to", "d", "len", "k", "dOuter", "dInner", "arc", "i", "round", "next", "first", "beforeI1", "beforeO0", "RingGeometry", "s", "box", "pieArcs", "outer", "hole", "mid", "sin", "cos", "acrossBand", "alongArc", "mode", "category", "percent", "formatPercent", "caption", "fits", "centerStyle", "centerLabel", "centerCaption", "wanted", "captionRatio", "glyphs", "index", "gutters", "glyph", "room", "key", "sideOf", "left", "right", "configured", "px", "clamp", "rim", "point", "strongest", "selectionFade", "arcs", "radius", "rowHeight", "top", "bottom", "side", "ideal", "relaxLabels", "slot", "start", "onCircle", "elbowX", "endX", "placement", "NO_BOX", "ringLabels", "blocks", "geometry", "label", "opacity", "wantsCategory", "wantsPercent", "inside", "Text", "textOps", "Rect", "children", "PieRing", "component2d", "fresh", "Types", "PIE_SPOTLIGHT_DIM", "state", "loader", "loadPaints", "ringFills", "strokeOps", "timeline", "ease", "frameEase", "t", "ctx", "sweep", "revealEnd", "centerBounds", "fills", "wedge", "Graphics2D", "reveal", "SWEEP_SHARE", "LABEL_SHARE", "SLICE_ARG", "Types", "slicesOf", "s", "resolvePieSlices", "_", "i", "paletteFill", "popAt", "index", "clamp", "isSliceSelected", "sliceDims", "focus", "selectionFade", "PIE_SPOTLIGHT_DIM", "popping", "timeline", "pop", "from", "targets", "value", "t", "partsOf", "children", "row", "ring", "Rect", "PieRing", "PieLegend", "PieChart", "component2d", "fresh", "CHART_STYLE_FAMILY", "PIE_STYLE_GROUPS", "CHART_STYLE_PRESETS", "state", "style", "slices", "parts", "ringConfigOf", "labelConfigOf", "centerConfigOf", "position", "side", "legend", "legendOf", "easeOut", "_state", "sweep", "labels", "at0", "piece", "beats", "Rect", "Text", "Types", "component2d", "easeOut", "textOps", "Graphics2D", "Types", "clamp", "component2d", "strokeOps", "Types", "RADAR_GRID", "Types", "RADAR_MARKS", "LABEL_PAD", "GLYPH", "MARGIN", "SIDE", "spokeDirection", "index", "count", "angle", "categoriesOf", "data", "field", "row", "text", "valuesOf", "series", "s", "num", "MANTISSAS", "niceCeil", "value", "power", "mantissa", "m", "scaleOf", "values", "min", "max", "top", "list", "v", "span", "fractionOf", "scale", "labelAnchor", "x", "y", "labelPad", "fontSize", "labelSize", "caption", "fitRadius", "box", "categories", "labelled", "radius", "pad", "i", "size", "side", "reachX", "reachY", "labelPoint", "r", "RadarGrid", "component2d", "Types", "strokeOps", "loader", "state", "loadPaints", "ctx", "grow", "clamp", "rim", "count", "levels", "round", "level", "r", "ring", "Graphics2D", "points", "i", "d", "spokeDirection", "Graphics2D", "Types", "clamp", "component2d", "fillOps", "strokeOps", "seriesVertices", "fractions", "radius", "grow", "f", "i", "d", "spokeDirection", "r", "RadarSeries", "component2d", "fresh", "Types", "fillOps", "strokeOps", "loader", "state", "loadPaints", "timeline", "from", "to", "ease", "frameEase", "t", "progress", "ctx", "clamp", "points", "fill", "Graphics2D", "dots", "p", "radarScale", "state", "scaleOf", "valuesOf", "radarFractions", "index", "series", "scale", "row", "v", "fractionOf", "partsOf", "children", "i", "Rect", "plot", "part", "RadarGrid", "RadarSeries", "ChartLegend", "toggling", "timeline", "show", "parts", "STAGGER", "RadarChart", "component2d", "fresh", "Types", "CHART_STYLE_FAMILY", "CHART_COLORS", "CHART_TEXT", "RADAR_GRID", "RADAR_MARKS", "CHART_LEGEND", "CHART_STYLE_PRESETS", "style", "plotSize", "laidOutSize", "radius", "fitRadius", "categoriesOf", "count", "enabled", "s", "grid", "seriesFill", "weight", "labels", "anchor", "labelAnchor", "align", "at", "labelPoint", "Text", "textOps", "markerText", "position", "side", "config", "legendConfigOf", "legend", "frame", "easeOut", "_state", "duration", "web", "ENTER_SHARE", "marks", "last", "n", "each", "at0", "piece", "beats", "LEGEND_SLIDE", "SERIES_ARG", "SPOTLIGHT_DIM", "Rect", "Types", "clamp", "component2d", "easeOut", "Graphics2D", "PathBuilder", "Rect", "Text", "Types", "clamp", "component2d", "fillOps", "textOps", "Types", "clamp", "resolveRadialRows", "data", "category", "value", "style", "row", "text", "num", "paletteFill", "rowValue", "radialMax", "rows", "max", "largest", "radialFractions", "top", "clamp", "RADIAL_STYLE_GROUPS", "CHART_COLORS", "CHART_TEXT", "Types", "CHART_LEGEND", "marksOf", "legendOf", "legendConfigOf", "face", "ringLabelOf", "centerOf", "STAGGER", "GROW", "ARC_STEP", "DEG", "LABEL_PAD", "CENTER_FIT", "GLYPH_RATIO", "EDGE", "DEFAULT_MARKS", "DEFAULT_LABEL", "DEFAULT_CENTER", "sizeOf", "style", "fallback", "RadialGeometry", "s", "box", "clamp", "n", "index", "radialFractions", "strongest", "i", "selectionFade", "growth", "total", "a", "back", "p", "ringPoint", "side", "centerStyle", "centerLabel", "centerCaption", "wanted", "hole", "ratio", "glyphs", "bandPath", "a0", "a1", "rIn", "rOut", "round", "path", "PathBuilder", "mid", "cap", "delta", "from", "to", "steps", "arc", "r", "x", "y", "first", "semicircle", "angle", "direction", "fromOuter", "centre", "radial", "tangent", "turns", "phi", "NO_BOX", "labelBlocks", "blocks", "geometry", "_", "anchor", "Rect", "Text", "textOps", "children", "RadialRings", "component2d", "fresh", "Types", "state", "loader", "loadPaints", "ringFills", "fillOps", "timeline", "ease", "frameEase", "t", "ctx", "g", "thickness", "half", "frame", "fills", "fractions", "order", "b", "grow", "opacity", "Graphics2D", "span", "SWEEP_SHARE", "LABEL_SHARE", "rowsOf", "s", "resolveRadialRows", "popAt", "index", "clamp", "ringDims", "focus", "i", "_", "selectionFade", "RING_DIM", "PIE_SPOTLIGHT_DIM", "popping", "timeline", "pop", "from", "targets", "value", "t", "partsOf", "children", "row", "rings", "Rect", "RadialRings", "PieLegend", "RadialChart", "component2d", "fresh", "Types", "CHART_STYLE_FAMILY", "RADIAL_STYLE_GROUPS", "CHART_STYLE_PRESETS", "state", "style", "rows", "parts", "marksOf", "ringLabelOf", "centerOf", "position", "side", "config", "legendOf", "legend", "easeOut", "_state", "sweep", "labels", "at0", "piece", "beats", "SERIES_ARG", "NODES", "LineChart", "BarChart", "PieChart", "RadarChart", "RadialChart"]
4
+ "sourcesContent": ["import {\n Rect,\n Text,\n Types,\n clamp,\n component2d,\n easeOut,\n type ChildView,\n type DataRecord,\n type NodeOf,\n type OutOf,\n // Named so this component's emitted type reaches `Node2D` and its props through the sdk, not core.\n type Node2D,\n type Node2DProps as _Node2DProps,\n type TextStyle as _TextStyle,\n type Fill as _Fill,\n type FillResolved as _FillResolved,\n type Stroke as _Stroke,\n type StrokeResolved as _StrokeResolved,\n type Size2D,\n type StyleInput as _StyleInput,\n type StyleValues as _StyleValues,\n type Vector2,\n} from \"@motionscript/sdk\"\nimport { formatNumber } from \"@motionscript/sdk/component\"\n\nimport { boundText, cartesianFrame, chartViews, columnGhost, fade, frameGap, headroom, laidOutSize, overhang } from \"../kit/cartesian\"\nimport { ChartCanvas } from \"../kit/chart-canvas\"\nimport { ChartLegend } from \"../kit/chart-legend\"\nimport { SERIES_ARG, asParts, fresh } from \"../kit/entries\"\nimport { HorizontalAxis } from \"../kit/horizontal-axis\"\nimport { DEFAULT_MARKERS, ENTER_SHARE, beats, legendAway, type AnyTimeline, type Beat } from \"../kit/motion\"\nimport {\n SPOTLIGHT_DIM,\n formatMarker,\n lerpAxisDomain,\n lerpAxisEntry,\n markerStep,\n markerValues,\n niceRange,\n niceTicks,\n resolveAxisDomain,\n settleAxisDomain,\n type AxisDomainConfig,\n type Range,\n type ResolvedAxisDomain,\n} from \"../kit/shared\"\nimport {\n CARTESIAN_GRID,\n CARTESIAN_TEXT,\n CHART_LEGEND,\n CHART_SERIES,\n CHART_STYLE_FAMILY,\n CHART_STYLE_PRESETS,\n GRID_BACKGROUND,\n axisConfigOf,\n legendConfigOf,\n migrateChartStyle,\n seriesFill,\n sizeOf,\n valueText,\n} from \"../kit/style\"\nimport { VerticalAxis, axisPads } from \"../kit/vertical-axis\"\nimport { ChartArea, ChartLine, traceX } from \"./chart-line\"\nimport { ChartRegion } from \"./chart-region\"\nimport {\n LINE_LABELS,\n LINE_MARKS,\n resolveRegionBox,\n stackExtent,\n stackSeries,\n type LineSeries,\n type LineStack,\n type PlotRegion,\n type RegionBox,\n type StackedSeries,\n} from \"./shared\"\nimport { resolveXScale, type XScale } from \"./x-scale\"\n\nconst LINE_STYLE = Types.style(\n CHART_STYLE_FAMILY,\n { series: CHART_SERIES, background: GRID_BACKGROUND, text: CARTESIAN_TEXT, grid: CARTESIAN_GRID, marks: LINE_MARKS, labels: LINE_LABELS, legend: CHART_LEGEND },\n { presets: CHART_STYLE_PRESETS }\n)\n\n/** A line chart's resolved style. */\nexport type LineChartStyle = OutOf<typeof LINE_STYLE>\n\n/** Both axes' domains with their ranges and ticks resolved. */\nexport interface LineChartDomains {\n readonly x: ResolvedAxisDomain\n readonly y: ResolvedAxisDomain\n}\n\n/** What a line chart plots, as its entries hold it. */\nexport interface LineChartValues {\n readonly data: DataRecord[]\n readonly xField: string\n readonly series: LineSeries[]\n readonly stack: LineStack\n readonly xAxis: AxisDomainConfig\n readonly yAxis: AxisDomainConfig\n /** Each series' share of a stack, `1` when missing. */\n readonly weights?: readonly number[]\n /** An area must reach its baseline, so a chart with areas keeps zero on the scale. */\n readonly style?: { readonly area: string }\n}\n\n/** One argument, two controls: the commands take a `PlotRegion`, so the x and y spans a host draws are declared inside it. */\nconst REGION_ARG = Types.custom<PlotRegion | undefined>(undefined, {\n kind: \"region\",\n properties: {\n x: { kind: \"range\", default: true, defaultMin: 0, defaultMax: 100 },\n y: { kind: \"range\", default: false, defaultMin: 0, defaultMax: 100 },\n },\n})\n\n/** What the chart's own commands read: its entries, and the private state they write. */\ninterface LineState extends LineChartValues {\n readonly style: LineChartStyle\n readonly region: PlotRegion | null\n readonly regionReveal: number\n readonly home: LineChartDomains | null\n readonly weights: number[]\n}\n\n/** The share of the y axis a percent stack reads to. */\nconst PERCENT: Range = [0, 100]\n\n/** What the x column is (a number, an instant, or a place in the file), and so how rows are positioned, ticked and captioned. */\nfunction columnOf(s: LineChartValues, format = s.xAxis.format): XScale {\n return resolveXScale(s.data, s.xField, format)\n}\n\n/** Every series as drawn; `weighted` false reads each at full share, as the scale does so the ticks hold still while a series sinks out. */\nfunction stacksOf(s: LineChartValues, weighted = true): StackedSeries[] {\n return stackSeries(s.data, columnOf(s), s.series, s.stack, weighted ? s.weights : undefined)\n}\n\n/** The explicit range and ticks, else the column's extent and ticks: only a numeric column has round numbers between its samples. */\nfunction drawnX(s: LineChartValues, domain: AxisDomainConfig): AxisDomainConfig {\n const column = columnOf(s, domain.format)\n const range = domain.range ?? column.extent\n return { ...domain, range, ticks: domain.ticks ?? column.ticks(range, DEFAULT_MARKERS - 1) }\n}\n\n/** The y range the data asks for: a percent stack reads to 100; areas and stacks keep zero on the scale. */\nfunction autoY(s: LineChartValues, divisions: number): Range {\n const [lo, hi] = stackExtent(stacksOf(s, false))\n if (s.stack === \"percent\" && lo >= 0) return PERCENT\n const zero = s.stack !== \"none\" || (s.style?.area ?? \"none\") !== \"none\"\n return niceRange(zero ? [Math.min(0, lo), Math.max(0, hi)] : [lo, hi], divisions)\n}\n\n/** Auto-ranging steps into one fewer segment than the marker count, so the tidy bounds frame the ticks drawn. */\nfunction drawnY(s: LineChartValues, domain: AxisDomainConfig): AxisDomainConfig {\n const divisions = (domain.ticks?.length ?? DEFAULT_MARKERS) - 1\n const range = domain.range ?? autoY(s, divisions)\n const even = domain.range !== undefined || (s.stack === \"percent\" && range === PERCENT)\n return { ...domain, range, ticks: domain.ticks ?? (even ? markerValues(range, DEFAULT_MARKERS - 1) : niceTicks(range, DEFAULT_MARKERS - 1)) }\n}\n\n/** The last domains worked out from each data array, and what else they were read from. */\nconst domainsDrawn = new WeakMap<DataRecord[], { readonly key: readonly unknown[]; readonly domains: LineChartDomains }>()\n\n/** Both axes as drawn now. */\nexport function lineChartDomains(s: LineChartValues): LineChartDomains {\n const key = [s.xField, s.xAxis, s.yAxis, s.series, s.stack, s.style?.area]\n const kept = domainsDrawn.get(s.data)\n if (kept && kept.key.every((value, i) => value === key[i])) return kept.domains\n const domains = {\n x: settleAxisDomain(s.xAxis, (d) => drawnX(s, d)) as LineChartDomains[\"x\"],\n y: settleAxisDomain(s.yAxis, (d) => drawnY(s, d)) as LineChartDomains[\"y\"],\n }\n domainsDrawn.set(s.data, { key, domains })\n return domains\n}\n\n/** Data to the plot's centred pixel space (origin at its centre, y-up). */\nfunction mapper(domains: LineChartDomains, plot: Size2D) {\n const [xMin, xMax] = domains.x.range\n const [yMin, yMax] = domains.y.range\n return {\n x: (x: number) => (xMax <= xMin ? 0 : ((x - xMin) / (xMax - xMin) - 0.5) * plot.width),\n y: (y: number) => (yMax === yMin ? 0 : ((y - yMin) / (yMax - yMin) - 0.5) * plot.height),\n }\n}\n\ninterface SeriesPixels {\n readonly points: Vector2[]\n /** The line under the series in a stack; empty when it fills to the baseline. */\n readonly base: Vector2[]\n /** What each point reads: its own value, or its share in a percent stack. */\n readonly values: number[]\n}\n\nconst NO_PIXELS: SeriesPixels = { points: [], base: [], values: [] }\n\n/** Series `index` in the plot's centred pixel space. */\nfunction seriesPixels(s: LineChartValues, domains: LineChartDomains, index: number, plot: Size2D): SeriesPixels {\n const stack = stacksOf(s)[index]\n if (!stack) return NO_PIXELS\n const map = mapper(domains, plot)\n const toPx = ([x, y]: [number, number]): Vector2 => ({ x: map.x(x), y: map.y(y) })\n return {\n points: stack.points.map(toPx),\n base: stack.base ? stack.base.map(toPx) : [],\n values: stack.points.map(([, y], k) => y - (stack.base?.[k]?.[1] ?? 0)),\n }\n}\n\n/** Where the areas fill down to: zero, held inside the scale. */\nfunction baselineValue(domains: LineChartDomains): number {\n const [lo, hi] = domains.y.range\n return clamp(0, Math.min(lo, hi), Math.max(lo, hi))\n}\n\n/** Whether anything plotted runs past the scale, so the plot clips it: a zoom, or an author's range narrower than the data. */\nfunction overflows(s: LineChartValues, domains: LineChartDomains): boolean {\n const [ylo, yhi] = stackExtent(stacksOf(s, false))\n const [xlo, xhi] = columnOf(s).extent\n const within = (v: number, [a, b]: Range) => v >= Math.min(a, b) - 1e-9 && v <= Math.max(a, b) + 1e-9\n return !(within(ylo, domains.y.range) && within(yhi, domains.y.range) && within(xlo, domains.x.range) && within(xhi, domains.x.range))\n}\n\n/** `region` in centred pixel space against the live scales, so it travels with a zoom. */\nfunction regionBox(s: LineChartValues & { readonly region: PlotRegion | null }, domains: LineChartDomains, plot: Size2D): RegionBox {\n const { width: w, height: h } = plot\n return resolveRegionBox(s.region, { left: -w / 2, right: w / 2, bottom: -h / 2, top: h / 2 }, domains.x.range, domains.y.range)\n}\n\n/** Whether a call-out is authored, not whether it resolves to pixels: a command is built before the first layout. A region bounding neither axis is none. */\nfunction hasCallout(s: { readonly region: PlotRegion | null }): boolean {\n const region = s.region\n return region != null && (region.x !== undefined || region.y !== undefined)\n}\n\n/** The `region` argument, or `{}`: a command is added before its arguments are filled in. */\nfunction regionArg(region: PlotRegion | null | undefined): PlotRegion {\n return region != null && typeof region === \"object\" ? region : {}\n}\n\n/** A range ordered low to high. */\nfunction span([a, b]: Range): Range {\n return a <= b ? [a, b] : [b, a]\n}\n\n/** Rescale to `range` keeping the tick count, so each marker slides rather than the row popping. */\nfunction rescale(range: Range, ticks: readonly number[]): AxisDomainConfig {\n const to = span(range)\n return { range: to, ticks: markerValues(to, Math.max(2, ticks.length) - 1) }\n}\n\nfunction axesAt(from: LineChartDomains, to: Partial<Record<\"x\" | \"y\", AxisDomainConfig>>, t: number) {\n return {\n ...(to.x && { xAxis: lerpAxisDomain(from.x, to.x, t) }),\n ...(to.y && { yAxis: lerpAxisDomain(from.y, to.y, t) }),\n }\n}\n\n/** A value as the y axis writes it: the author's pattern, a share in a percent stack, else the bare reading at the ticks' precision. */\nfunction yLabel(s: LineChartValues, value: number, ticks: readonly number[]): string {\n const format = s.yAxis.format\n if (format !== undefined) return formatNumber(value, format)\n const text = formatMarker(value, markerStep(ticks))\n return s.stack === \"percent\" ? `${text}%` : text\n}\n\nfunction weightOf(s: { readonly weights: readonly number[] }, index: number): number {\n return Math.max(0, s.weights[index] ?? 1)\n}\n\n/** The parts a line chart's commands drive, found through its children. */\nfunction partsOf(children: readonly ChildView[]) {\n const views = chartViews(children)\n return {\n vAxis: views.find(VerticalAxis.is) ?? null,\n hAxis: views.find(HorizontalAxis.is) ?? null,\n lines: views.filter(ChartLine.is),\n legend: views.find(ChartLegend.is) ?? null,\n }\n}\n\nfunction clearing(timeline: AnyTimeline, state: LineState) {\n const from = state.regionReveal\n const region = state.region\n // Nothing to retract, but the call still takes its slot.\n if (from === 0) return timeline.animate(() => ({ region: null, regionReveal: 0 }), { eased: false })\n // `region` is held until the retraction lands, or there would be nothing left to retract.\n return timeline.animate((t) => (t >= 1 ? { region: null, regionReveal: 0 } : { region, regionReveal: from * (1 - t) }))\n}\n\n/**\n * Show or hide series `index` with its legend entry. Apart, the line retraces;\n * in a stack it sinks into the series below as its share falls to nothing, so\n * the ones above settle rather than leaving a gap.\n */\nfunction toggling(timeline: AnyTimeline, state: LineState, children: readonly ChildView[], index: number, show: boolean) {\n const parts = partsOf(children)\n const line = parts.lines[index]\n if (!line) return timeline.wait(timeline.duration)\n const legend = parts.legend ? [parts.legend.run(show ? \"showSeries\" : \"hideSeries\", { index })] : []\n if (state.stack === \"none\") {\n return timeline.together([line.run(\"enter\", show ? { from: 0, to: 1 } : { from: 1, to: 0 }), ...legend])\n }\n const from = state.series.map((_, i) => weightOf(state, i))\n const start = from[index] ?? 1\n const target = show ? 1 : 0\n return timeline.together([\n timeline.animate((t) => {\n const weights = [...from]\n weights[index] = start + (target - start) * timeline.ease(t)\n return { weights }\n }, { eased: false }),\n line.run(\"hold\", { shown: show }),\n ...legend,\n ])\n}\n\n/**\n * A multi-series line or area chart composed of {@link ChartCanvas}, the value\n * and x axes, {@link ChartRegion}, a {@link ChartArea} and a {@link ChartLine}\n * per series, and {@link ChartLegend}. Every part reads the chart's entries\n * through bindings and maps against the plot panel's own laid-out box.\n *\n * Resting state is the finished chart; `enter` arms every part on its first\n * frame. A `to` of an axis `range` or `ticks` tweens from the domain as drawn\n * (see {@link lerpAxisEntry}), so an auto axis rescales continuously.\n */\nexport const LineChart = component2d({\n key: \"lineChart\",\n state: {\n data: fresh<DataRecord[]>(() => [], { kind: \"dataset\" }),\n // Not `x`: every node already has an `x`, its position.\n xField: \"\",\n series: fresh<LineSeries[]>(() => [], { kind: \"series\" }),\n /** `stacked`: each series sits on the sum of those before it; `percent`: every row reads as shares of 100. */\n stack: Types.oneOf([\"none\", \"stacked\", \"percent\"] as const),\n xAxis: Types.custom<AxisDomainConfig>({}, { resolve: resolveAxisDomain, lerp: lerpAxisEntry }),\n yAxis: Types.custom<AxisDomainConfig>({}, { resolve: resolveAxisDomain, lerp: lerpAxisEntry }),\n style: LINE_STYLE,\n /** The spotlit slice in data units, or `null`. The box snaps; {@link regionReveal} animates it. */\n region: Types.custom<PlotRegion | null>(null),\n /** How far the `region` call-out is drawn in, `[0, 1]`: rules grow, wash fades up, out-of-region stretches fade. */\n regionReveal: 0,\n /** The domain `zoomTo` first left, so `resetZoom` restores it, auto-derived ticks included. */\n home: Types.custom<LineChartDomains | null>(null, { private: true }),\n /** Each series' share of a stack, seeded from `enabled`: a weight rather than a switch, so a hidden series sinks out. */\n weights: Types.custom<number[]>([], { private: true }),\n /** Whether the plot clips its marks, from a zoom's first frame until a reset lands. */\n clipped: Types.boolean(false, { private: true }),\n },\n // A node made of parts that fill would otherwise hug them.\n defaults: {\n width: \"fill\",\n height: \"fill\",\n weights: (state) => state.series.map((s) => ((s.enabled ?? true) ? 1 : 0)),\n },\n migrate: { style: migrateChartStyle(\"cartesian\") },\n allowedChildren: [],\n children: (state) => {\n const style = () => state.style\n const domains = () => lineChartDomains(state)\n let plot: Node2D | undefined\n const plotSize = () => laidOutSize(plot)\n const pixels = (i: number) => seriesPixels(state, domains(), i, plotSize())\n const enabled = state.series.map((s) => s.enabled ?? true)\n const built = state.style\n const yConfig = () => axisConfigOf(style(), \"y\")\n const xConfig = () => axisConfigOf(style(), \"x\")\n const yCaptions = () => {\n const ticks = domains().y.ticks\n return ticks.map((value) => yLabel(state, value, ticks))\n }\n\n // Bound, not snapshotted, so a rescale re-labels and re-places the row as it\n // tweens. The marker *count* is read once, which is why `zoomTo` keeps it.\n const vAxis = built.showYAxis\n ? (new VerticalAxis({\n range: () => domains().y.range,\n markers: () => domains().y.ticks,\n captions: yCaptions,\n axis: yConfig,\n label: state.yAxis.label ?? \"\",\n width: \"hug\",\n height: \"fill\",\n }) as unknown as Node2D)\n : undefined\n\n const hAxis = built.showXAxis\n ? (new HorizontalAxis({\n range: () => domains().x.range,\n markers: () => domains().x.ticks,\n // A month or category tick is captioned with its cell (`Jan`), not the instant it parsed to.\n captions: () => {\n const column = columnOf(state)\n return domains().x.ticks.map((value) => column.label(value))\n },\n axis: xConfig,\n label: state.xAxis.label ?? \"\",\n overhang: () => ({ left: overhang(style()), right: overhang(style()) }),\n width: \"fill\",\n height: \"hug\",\n }) as unknown as Node2D)\n : undefined\n\n const ghost = vAxis && hAxis\n ? columnGhost({\n captions: yCaptions,\n count: lineChartDomains(state).y.ticks.length,\n text: () => yConfig().labelStyle,\n title: state.yAxis.label ?? \"\",\n titleText: () => yConfig().titleStyle,\n tickPad: () => axisPads(yConfig(), \"right\").tick,\n titlePad: () => axisPads(yConfig(), \"right\").title,\n })\n : undefined\n\n const spotlight = () => regionBox(state, domains(), plotSize())\n const dimOpacity = () => 1 - (1 - SPOTLIGHT_DIM) * state.regionReveal\n const lines = state.series.map((s, i) =>\n new ChartLine({\n points: () => pixels(i).points,\n curve: () => style().curve,\n stroke: () => ({ weight: style().strokeWidth, fill: seriesFill(style(), s, i), align: \"center\", cap: \"round\", join: \"round\" }),\n dotSize: () => (style().dots ? style().dotSize : 0),\n dotFill: () => seriesFill(style(), s, i),\n enabled: enabled[i],\n spotlight,\n dimOpacity,\n })\n )\n const areas = state.series.map((s, i) =>\n new ChartArea({\n points: () => pixels(i).points,\n base: () => pixels(i).base,\n baseline: () => mapper(domains(), plotSize()).y(baselineValue(domains())),\n curve: () => style().curve,\n area: () => style().area,\n fill: () => seriesFill(style(), s, i),\n areaOpacity: () => style().areaOpacity,\n // The line's own trace, switch and fade, so the two arrive, leave and dim as one.\n progress: () => lines[i].progress,\n enabled: () => lines[i].enabled,\n opacity: () => lines[i].opacity,\n spotlight,\n dimOpacity,\n })\n )\n\n const labels: Node2D[] = []\n if (built.values !== \"none\") {\n const below = built.values === \"below\"\n state.series.forEach((_, i) => {\n state.data.forEach((_row, k) => {\n const line = lines[i]\n const label: Node2D = new Text({\n ...boundText(() => valueText(style())),\n text: () => {\n const value = pixels(i).values[k]\n return value === undefined ? \"\" : yLabel(state, value, domains().y.ticks)\n },\n // Held inside the plot, so a figure on an end point does not run into the axis beside it.\n x: () => {\n const half = (plotSize().width - label.layoutBounds.width) / 2\n return clamp(pixels(i).points[k]?.x ?? 0, -Math.max(0, half), Math.max(0, half))\n },\n y: () => {\n const point = pixels(i).points[k]\n const clear = label.layoutBounds.height / 2 + (style().dots ? style().dotSize / 2 : style().strokeWidth / 2) + Math.round(sizeOf(style().valueText) * 0.25)\n return (point?.y ?? 0) + (below ? -clear : clear)\n },\n // In once the trace has passed its point.\n opacity: () => {\n const point = pixels(i).points[k]\n if (!line.enabled || !point) return 0\n const reach = traceX(pixels(i).points, line.progress)\n return line.opacity * (reach === Infinity ? 1 : clamp((reach - point.x) / 24, 0, 1))\n },\n }) as unknown as Node2D\n labels.push(label)\n })\n })\n }\n\n const legendAt = built.legend\n const legend = legendAt !== \"none\"\n ? (new ChartLegend({\n series: state.series,\n swatches: () => state.series.map((s, i) => seriesFill(style(), s, i)),\n legend: () => legendConfigOf(style()),\n flow: legendAt === \"right\" ? \"vertical\" : \"horizontal\",\n }) as unknown as Node2D)\n : undefined\n\n plot = new Rect({\n clip: () => state.clipped || overflows(state, domains()),\n children: [\n new ChartCanvas({\n fill: () => style().gridBackground,\n xGridStroke: () => style().verticalGrid,\n yGridStroke: () => style().horizontalGrid,\n xMarkers: () => domains().x.ticks,\n yMarkers: () => domains().y.ticks,\n xExtent: () => domains().x.range,\n yExtent: () => domains().y.range,\n axisStroke: () => style().axisStroke,\n xAxisAt: () => baselineValue(domains()),\n yAxisAt: () => domains().x.range[0],\n }),\n // Under the marks, so the highlight does not tint the stretch it picks out.\n new ChartRegion({\n box: spotlight,\n stroke: () => ({ weight: 2, fill: fade(style().valueText.fill ?? \"white\", 0.7), dash: [14, 12], cap: \"butt\", align: \"center\" }),\n fill: () => fade(style().valueText.fill ?? \"white\", 0.06),\n reveal: () => state.regionReveal,\n }),\n ...areas,\n ...lines,\n ...labels,\n ],\n }) as unknown as Node2D\n\n return asParts([\n cartesianFrame({\n background: () => style().background,\n left: vAxis,\n ghost,\n plot,\n bottom: hAxis,\n legend,\n legendAt,\n gap: () => frameGap(style()),\n padding: () => ({\n top: headroom(style()),\n right: hAxis ? overhang(style()) : 0,\n left: hAxis && !vAxis ? overhang(style()) : 0,\n bottom: 0,\n }),\n }),\n ])\n },\n commands: {\n /**\n * Axes stagger in, lines (and their areas) trace left to right, the legend\n * fades up last. `duration` is the whole entrance; a chart with a `region`\n * lands its call-out in the final quarter.\n */\n enter: {\n args: {},\n // Held from arrival, so it never shows finished ahead of its draw.\n entrance: true,\n easing: easeOut(),\n run: (timeline, state, children) => {\n const parts = partsOf(children)\n const duration = timeline.duration\n const revealing = hasCallout(state) && state.regionReveal === 0\n const body = revealing ? duration * 0.75 : duration\n const axes = body * ENTER_SHARE.axes\n const traced = body * ENTER_SHARE.marks\n const { legend } = parts\n const at0 = (piece: Beat[\"piece\"]): Beat => ({ at: 0, duration: 0, piece })\n const away = legendAway(state.style.legend)\n // The first frame arms what every later beat moves: a beat ahead of the\n // playhead writes nothing. A beat with nothing to do still takes its share.\n return beats(timeline, [\n ...(revealing ? [at0(timeline.animate(() => ({ regionReveal: 0 })))] : []),\n ...parts.lines.map((line) => at0(line.to({ progress: 0 }))),\n ...(legend ? [at0(legend.to({ opacity: 0, ...away }))] : []),\n ...(parts.vAxis ? [{ at: 0, duration: axes, piece: parts.vAxis.run(\"enter\", { slide: 24 }) }] : []),\n ...(parts.hAxis ? [{ at: 0, duration: axes, piece: parts.hAxis.run(\"enter\", { slide: 24 }) }] : []),\n ...parts.lines.map((line) => ({ at: axes, duration: traced, piece: line.run(\"enter\") })),\n ...(legend ? [{ at: axes + traced, duration: body * ENTER_SHARE.legend, piece: legend.to({ opacity: 1, x: 0, y: 0 }) }] : []),\n ...(revealing ? [{ at: body, duration: duration * 0.25, piece: timeline.animate((t) => ({ regionReveal: t })) }] : []),\n // Takes the whole slot even with no parts to move.\n { at: 0, duration, piece: timeline.wait(duration) },\n ])\n },\n },\n /**\n * Spotlight a slice of the plot in data units; either axis alone is a band.\n * Over a region already up, the old one retracts in the first half and the\n * new one draws in over the second, each half eased on its own.\n */\n spotlightRegion: {\n args: { region: REGION_ARG },\n easing: easeOut(),\n run: (timeline, state) => {\n const region = regionArg(timeline.args.region)\n const from = state.regionReveal\n const previous = state.region\n // A region bounding neither axis is no call-out: spotlighting it is a clear.\n if (region.x === undefined && region.y === undefined) return clearing(timeline, state)\n // Nothing up yet: the region is set from the first frame and just draws on.\n if (from <= 0 || !hasCallout(state)) return timeline.animate((t) => ({ region, regionReveal: from + (1 - from) * t }))\n return timeline.animate(\n (t) => (t < 0.5\n ? { region: previous, regionReveal: from * (1 - timeline.ease(t * 2)) }\n : { region, regionReveal: timeline.ease(t * 2 - 1) }),\n { eased: false }\n )\n },\n },\n /** Drop the call-out. A no-op when nothing is spotlit, which still takes its slot. */\n clearRegion: {\n args: {},\n easing: easeOut(),\n run: (timeline, state) => clearing(timeline, state),\n },\n /** Rescale the named axes so a slice (data units) fills the plot; an omitted axis is left. The first zoom remembers the domain for `resetZoom`. */\n zoomTo: {\n args: { region: REGION_ARG },\n easing: easeOut(),\n run: (timeline, state) => {\n const region = regionArg(timeline.args.region)\n if (!region.x && !region.y) return timeline.wait(timeline.duration)\n const from = lineChartDomains(state)\n const home = state.home ?? from\n const to = {\n ...(region.x && { x: { ...from.x, ...rescale(region.x, from.x.ticks) } }),\n ...(region.y && { y: { ...from.y, ...rescale(region.y, from.y.ticks) } }),\n }\n return timeline.animate((t) => ({ home, clipped: true, ...axesAt(from, to, t) }))\n },\n },\n /** Back to the domain the first zoom left; a hold if it never zoomed. */\n resetZoom: {\n args: {},\n easing: easeOut(),\n run: (timeline, state) => {\n const home = state.home\n if (!home) return timeline.wait(timeline.duration)\n const from = lineChartDomains(state)\n return timeline.animate((t) => ({ home: null, clipped: t < 1, ...axesAt(from, home, t) }))\n },\n },\n /** Bring series `index` in, with its legend entry growing in: traced, or in a stack risen out of the series below. */\n showSeries: {\n args: { seriesIndex: SERIES_ARG },\n easing: easeOut(),\n run: (timeline, state, children) => toggling(timeline, state, children, timeline.args.seriesIndex, true),\n },\n /** The mirror of `showSeries`. */\n hideSeries: {\n args: { seriesIndex: SERIES_ARG },\n easing: easeOut(),\n run: (timeline, state, children) => toggling(timeline, state, children, timeline.args.seriesIndex, false),\n },\n /** Fade every other series, line, area and legend entry, to focus on `index`. The legend dims in place, so the row does not reflow. */\n spotlightSeries: {\n args: { seriesIndex: SERIES_ARG },\n easing: easeOut(),\n run: (timeline, _state, children) => {\n const parts = partsOf(children)\n const index = timeline.args.seriesIndex\n return timeline.together([\n ...parts.lines.map((line, i) => line.to({ opacity: i === index ? 1 : SPOTLIGHT_DIM })),\n ...(parts.legend ? [parts.legend.run(\"spotlightSeries\", { index })] : []),\n timeline.wait(timeline.duration),\n ])\n },\n },\n },\n})\n\nexport type LineChart = NodeOf<typeof LineChart>\n", "import {\n Graphics2D,\n Types,\n clamp,\n component2d,\n fillOps,\n strokeOps,\n type Fill,\n type FillResolved,\n type NodeOf,\n // Named so this component's emitted type reaches `Node2D` and its props through the sdk, not core.\n type Node2D as _Node2D,\n type Node2DProps as _Node2DProps,\n type PathCommand,\n type RenderContext,\n type Stroke,\n type StrokeResolved,\n type Vector2,\n} from \"@motionscript/sdk\"\n\nimport { fade } from \"../kit/cartesian\"\nimport { fresh } from \"../kit/entries\"\nimport { frameEase } from \"../kit/motion\"\nimport { loadPaints } from \"../kit/paints\"\nimport { SPOTLIGHT_DIM } from \"../kit/shared\"\nimport {\n EMPTY_REGION_BOX,\n clipPolygonToBox,\n clipPolylineToBox,\n cutAt,\n curvePoints,\n hasRegion,\n type LineCurve,\n type RegionBox,\n} from \"./shared\"\n\n/** The x a trace at `progress` has reached, across `points` ordered along x. */\nexport function traceX(points: readonly Vector2[], progress: number): number {\n if (points.length === 0) return 0\n const first = points[0].x\n const last = points[points.length - 1].x\n return progress >= 1 ? Infinity : first + (last - first) * progress\n}\n\n/** The drawn path at `progress`: the whole curve once traced, else the part left of the trace. */\nfunction traced(points: readonly Vector2[], curve: LineCurve, progress: number): Vector2[] {\n const path = curvePoints(points, curve)\n return progress >= 1 ? path : cutAt(path, traceX(points, progress))\n}\n\nconst curveEntry = () => Types.custom<LineCurve>(\"smooth\")\n\n/** A closed outline as path commands. */\nfunction outlineCommands(points: readonly Vector2[]): PathCommand[] {\n return [...points.map((p, i): PathCommand => ({ type: i === 0 ? \"M\" : \"L\", x: p.x, y: p.y })), { type: \"Z\" }]\n}\n\nfunction fillOutline(ctx: RenderContext, outline: readonly Vector2[], fill: FillResolved[], opacity: number): void {\n if (outline.length < 3 || opacity <= 0) return\n const { width, height } = ctx.size\n // A frame symmetric about the origin, so the outline draws where its points say rather than re-centred on itself.\n const centerBounds: [number, number, number, number] = [-width / 2, -height / 2, width / 2, height / 2]\n ctx.draw(new Graphics2D().path({ data: outlineCommands(outline), centerBounds }).fill(fill).opacity(opacity))\n}\n\n/**\n * One series of a {@link LineChart}: its line through pre-mapped pixel `points`,\n * shaped by `curve`, and a dot on each point. `progress` traces it in from the\n * left; `enabled` shows or hides it wholesale.\n */\nexport const ChartLine = component2d({\n key: \"chartLine\",\n state: {\n /** In this node's pixel space (origin at centre, y-up), mapped by the parent and ordered along x. */\n points: fresh<Vector2[]>(() => []),\n curve: curveEntry(),\n stroke: Types.custom<Stroke, StrokeResolved[]>([], { resolve: strokeOps.resolve, lerp: strokeOps.lerp }),\n /** A dot of `dotSize` on each point, in `dotFill`; none at size 0. */\n dotSize: 0,\n dotFill: Types.custom<Fill, FillResolved[]>([], { resolve: fillOps.resolve, lerp: fillOps.lerp }),\n /** Trace from the left end, `[0, 1]`. Rests at 1 so a paused editor canvas paints the line; `enter` drives it from 0. */\n progress: 1,\n /** Whether the line is drawn at all, flipped alongside its legend entry. */\n enabled: true,\n /** In this node's pixel space; outside it the line drops to `dimOpacity`. */\n spotlight: fresh<RegionBox>(() => EMPTY_REGION_BOX),\n dimOpacity: SPOTLIGHT_DIM,\n },\n load: (loader, state) => loadPaints(loader, { fills: [state.dotFill], strokes: [state.stroke] }),\n commands: {\n /**\n * Trace the line from `from` to `to`; `showSeries`/`hideSeries` are this with\n * the ends stated. `enabled` rides along in the same value, so the line is\n * drawable for every `t` the trace covers and arriving backwards matches\n * arriving forwards.\n */\n enter: {\n args: { from: Types.number(0, { min: 0, max: 1 }), to: Types.number(1, { min: 0, max: 1 }) },\n run: (timeline) => {\n const { from, to } = timeline.args\n const ease = frameEase(timeline)\n return timeline.animate((t) => {\n const progress = from + (to - from) * ease(t)\n // Hidden only once fully retraced, so a hide does not vanish a frame early.\n return { progress, enabled: progress > 0 }\n })\n },\n },\n /** Hold the line fully traced while its chart moves it, switched on throughout a show and off once a hide lands. */\n hold: {\n args: { shown: Types.boolean(true) },\n run: (timeline) => {\n const { shown } = timeline.args\n return timeline.animate((t) => ({ progress: 1, enabled: shown || t < 1 }), { eased: false })\n },\n },\n },\n render: (ctx, state) => {\n if (!state.enabled) return\n const pts = state.points\n const p = clamp(state.progress, 0, 1)\n if (pts.length === 0 || p <= 0) return\n\n const box = state.spotlight\n const lit = hasRegion(box)\n const dim = clamp(state.dimOpacity, 0, 1)\n const stroke = state.stroke\n const weight = stroke[0]?.weight ?? 0\n const drawn = traced(pts, state.curve, p)\n\n if (drawn.length >= 2 && weight > 0) {\n // Rounded corners only where the line has corners to round.\n const radius = state.curve === \"linear\" ? weight * 2 : 0\n ctx.draw(new Graphics2D().line({ points: drawn, radius }).stroke(stroke).opacity(lit ? dim : 1))\n // One `draw` per run: shapes chained before `stroke()` combine into one surface, and stroking a union of disjoint open paths paints nothing.\n if (lit) for (const run of clipPolylineToBox(drawn, box)) ctx.draw(new Graphics2D().line({ points: run, radius }).stroke(stroke))\n }\n\n const size = state.dotSize\n if (size <= 0) return\n const reach = traceX(pts, p)\n const bright = new Graphics2D()\n const dimmed = new Graphics2D()\n let brightAny = false\n let dimAny = false\n for (const pt of pts) {\n // A dot grows in as the trace passes it.\n const grown = reach === Infinity ? 1 : clamp((reach - pt.x) / (size * 2), 0, 1)\n if (grown <= 0) continue\n const inside = !lit || (pt.x >= box.left && pt.x <= box.right && pt.y >= box.bottom && pt.y <= box.top)\n ;(inside ? bright : dimmed).ellipse({ x: pt.x, y: pt.y, width: size * grown, height: size * grown })\n if (inside) brightAny = true\n else dimAny = true\n }\n if (dimAny) ctx.draw(dimmed.fill(state.dotFill).opacity(dim))\n if (brightAny) ctx.draw(bright.fill(state.dotFill))\n },\n})\n\nexport type ChartLine = NodeOf<typeof ChartLine>\n\n/**\n * The fill under one series of a {@link LineChart}: down to `base` (the series\n * below it in a stack) or, without one, to the `baseline`. Drawn by its own node\n * so every area sits under every line; the chart binds its trace, switch and\n * opacity to its line's, so the two move as one.\n */\nexport const ChartArea = component2d({\n key: \"chartArea\",\n state: {\n /** The series' points, as its line has them. */\n points: fresh<Vector2[]>(() => []),\n /** The line the area fills down to, at the same x positions; empty for the baseline. */\n base: fresh<Vector2[]>(() => []),\n /** Pixel y of the baseline. */\n baseline: 0,\n curve: curveEntry(),\n area: Types.custom<\"none\" | \"solid\" | \"gradient\">(\"solid\"),\n /** The series colour; the area paints it at `areaOpacity`, a gradient fading it out towards the bottom. */\n fill: Types.custom<Fill, FillResolved[]>([], { resolve: fillOps.resolve, lerp: fillOps.lerp }),\n areaOpacity: 0.4,\n progress: 1,\n enabled: true,\n spotlight: fresh<RegionBox>(() => EMPTY_REGION_BOX),\n dimOpacity: SPOTLIGHT_DIM,\n },\n load: (loader, state) => loadPaints(loader, { fills: [state.fill] }),\n render: (ctx, state) => {\n const pts = state.points\n const p = clamp(state.progress, 0, 1)\n if (!state.enabled || state.area === \"none\" || pts.length < 2 || p <= 0 || state.fill.length === 0) return\n const outlineAt = (progress: number) => {\n const top = traced(pts, state.curve, progress)\n if (top.length < 2) return []\n const base = state.base.length === pts.length\n ? traced(state.base, state.curve, progress)\n : [{ x: top[0].x, y: state.baseline }, { x: top[top.length - 1].x, y: state.baseline }]\n return [...top, ...[...base].reverse()]\n }\n // The gradient spans the whole area's height, so it holds still while the area traces in and across a spotlight's cut.\n const span = verticalSpan(outlineAt(1))\n const paint = (outline: readonly Vector2[], opacity: number) =>\n fillOutline(ctx, outline, areaFill(state.fill, state.area, state.areaOpacity, span, verticalSpan(outline)), opacity)\n const outline = outlineAt(p)\n const box = state.spotlight\n if (!hasRegion(box)) {\n paint(outline, 1)\n return\n }\n paint(outline, clamp(state.dimOpacity, 0, 1))\n paint(clipPolygonToBox(outline, box), 1)\n },\n})\n\ninterface Span {\n readonly top: number\n readonly bottom: number\n}\n\nfunction verticalSpan(points: readonly Vector2[]): Span {\n let top = -Infinity\n let bottom = Infinity\n for (const p of points) {\n if (p.y > top) top = p.y\n if (p.y < bottom) bottom = p.y\n }\n return { top, bottom }\n}\n\n/**\n * The area's paint for an outline spanning `own`: the series colour at\n * `opacity`, or for a gradient that colour fading to nearly nothing across\n * `whole`. A gradient maps onto the bounds of the shape it fills, so its ends\n * are placed in `own`'s unit box (y-up) at `whole`'s top and bottom.\n */\nexport function areaFill(colour: FillResolved[], area: \"none\" | \"solid\" | \"gradient\", opacity: number, whole: Span, own: Span): FillResolved[] {\n const top = colour[colour.length - 1]\n if (area !== \"gradient\" || top?.type !== \"solid\" || !(own.top > own.bottom)) return fade(colour, opacity) as FillResolved[]\n const [r, g, b, a] = top.color\n const middle = (own.top + own.bottom) / 2\n const half = (own.top - own.bottom) / 2\n return fillOps.resolve({\n type: \"linear-gradient\",\n colors: [[r, g, b, a * opacity], [r, g, b, a * opacity * 0.04]],\n start: { x: 0, y: (whole.top - middle) / half },\n end: { x: 0, y: (whole.bottom - middle) / half },\n })\n}\n\nexport type ChartArea = NodeOf<typeof ChartArea>\n", "import { Types, type DataRecord, type Vector2 } from \"@motionscript/sdk\"\n\nimport { niceRange, num, type ChartSeries, type Range } from \"../kit/shared\"\nimport type { XScale } from \"./x-scale\"\n\n/** One polyline of a {@link LineChart}: {@link ChartSeries} under the name for what it draws here. */\nexport type LineSeries = ChartSeries\n\n/**\n * A rectangular slice of the plot in data units, the input to `spotlightRegion`\n * and `zoomTo`. Either axis may be omitted: `{ x: [60, 100] }` is a full-height\n * band. A reversed range reads the same as a forward one.\n */\nexport interface PlotRegion {\n /** Omit to span the full plot width. */\n x?: Range\n /** Omit to span the full plot height. */\n y?: Range\n}\n\n/**\n * A {@link PlotRegion} in the plot's centred pixel space (origin at the centre,\n * y-up), the frame the series points live in. An axis the author left unbounded\n * has its edges pinned to the plot's own and draws no rule.\n */\nexport interface RegionBox {\n left: number\n right: number\n bottom: number\n top: number\n xBounded: boolean\n yBounded: boolean\n}\n\n/** The \"no region\" resting value. */\nexport const EMPTY_REGION_BOX: RegionBox = {\n left: 0,\n right: 0,\n bottom: 0,\n top: 0,\n xBounded: false,\n yBounded: false,\n}\n\n/** Whether `box` is non-degenerate, so there is something to spotlight. */\nexport function hasRegion(box: RegionBox): boolean {\n return box.right > box.left && box.top > box.bottom\n}\n\n/**\n * Resolve a {@link PlotRegion} against the plot rectangle (centred pixel space)\n * and the data ranges its edges span. An omitted axis takes the plot's own\n * edges; a given one is clamped to the plot.\n */\nexport function resolveRegionBox(\n region: PlotRegion | null | undefined,\n plot: { left: number; right: number; bottom: number; top: number },\n xScale: Range,\n yScale: Range\n): RegionBox {\n if (!region || (region.x === undefined && region.y === undefined)) {\n return EMPTY_REGION_BOX\n }\n\n const span = (\n range: Range | undefined,\n [min, max]: Range,\n lo: number,\n hi: number\n ): [number, number, boolean] => {\n if (range === undefined || max <= min) return [lo, hi, false]\n const a = Math.min(range[0], range[1])\n const b = Math.max(range[0], range[1])\n const toPx = (v: number) => lo + ((v - min) / (max - min)) * (hi - lo)\n return [\n Math.max(lo, Math.min(hi, toPx(a))),\n Math.max(lo, Math.min(hi, toPx(b))),\n true,\n ]\n }\n\n const [left, right, xBounded] = span(region.x, xScale, plot.left, plot.right)\n const [bottom, top, yBounded] = span(region.y, yScale, plot.bottom, plot.top)\n return { left, right, bottom, top, xBounded, yBounded }\n}\n\n/**\n * The parts of `points` inside `box`, as contiguous sub-polylines: a series is\n * drawn dimmed in full, then these runs are re-drawn at full strength. Segments\n * are clipped, not filtered by endpoint, so a line entering mid-segment is cut\n * exactly on the boundary.\n */\nexport function clipPolylineToBox(\n points: Vector2[],\n box: RegionBox\n): Vector2[][] {\n if (points.length < 2 || !hasRegion(box)) return []\n\n const runs: Vector2[][] = []\n let run: Vector2[] = []\n\n for (let i = 1; i < points.length; i++) {\n const seg = clipSegment(points[i - 1], points[i], box)\n if (!seg) {\n // Misses the box: close the open run.\n if (run.length >= 2) runs.push(run)\n run = []\n continue\n }\n const [a, b] = seg\n // Continues the open run if it starts where the last ended; otherwise the line left and came back.\n if (run.length > 0 && samePoint(run[run.length - 1], a)) run.push(b)\n else {\n if (run.length >= 2) runs.push(run)\n run = [a, b]\n }\n }\n if (run.length >= 2) runs.push(run)\n return runs\n}\n\n/** Points within half a pixel are the same point, for run-joining purposes. */\nfunction samePoint(a: Vector2, b: Vector2): boolean {\n return Math.abs(a.x - b.x) < 0.5 && Math.abs(a.y - b.y) < 0.5\n}\n\n/** Liang-Barsky clip of one segment against `box`: the surviving `[start, end]`, or `null` when wholly outside. */\nfunction clipSegment(\n a: Vector2,\n b: Vector2,\n box: RegionBox\n): [Vector2, Vector2] | null {\n const dx = b.x - a.x\n const dy = b.y - a.y\n let t0 = 0\n let t1 = 1\n\n // Each edge as (p, q): the segment survives where p*t <= q.\n const edges: [number, number][] = [\n [-dx, a.x - box.left],\n [dx, box.right - a.x],\n [-dy, a.y - box.bottom],\n [dy, box.top - a.y],\n ]\n for (const [p, q] of edges) {\n if (p === 0) {\n // Parallel to this edge: outside it, the whole segment is out.\n if (q < 0) return null\n continue\n }\n const r = q / p\n if (p < 0) {\n if (r > t1) return null\n if (r > t0) t0 = r\n } else {\n if (r < t0) return null\n if (r < t1) t1 = r\n }\n }\n return [\n { x: a.x + t0 * dx, y: a.y + t0 * dy },\n { x: a.x + t1 * dx, y: a.y + t1 * dy },\n ]\n}\n\n/**\n * One series' `[x, y]` points, sorted along x so the polyline traces left to\n * right. A row missing its y contributes 0 rather than a gap, since dropping it\n * would silently bridge the hole.\n */\nexport function seriesPoints(\n data: DataRecord[],\n x: XScale,\n series: LineSeries\n): [x: number, y: number][] {\n return data\n .map((row, i): [number, number] => [x.at(i), num(row, series.field)])\n .sort((a, b) => a[0] - b[0])\n}\n\nexport function yExtent(data: DataRecord[], series: LineSeries[]): Range {\n let lo = Infinity\n let hi = -Infinity\n for (const row of data)\n for (const s of series) {\n const v = num(row, s.field)\n if (v < lo) lo = v\n if (v > hi) hi = v\n }\n return lo <= hi ? [lo, hi] : [0, 1]\n}\n\n/**\n * The explicit `range`, else the data's y extent nudged out to tidy step bounds.\n * `divisions` (one fewer than the marker count) only shapes the step when\n * `range` is omitted.\n */\nexport function resolveYScale(\n data: DataRecord[],\n series: LineSeries[],\n range: Range | undefined,\n divisions: number\n): Range {\n return range ?? niceRange(yExtent(data, series), divisions)\n}\n\n/** How the series sit on one another: apart, each on the sum of those before it, or as shares of the row's total. */\nexport type LineStack = \"none\" | \"stacked\" | \"percent\"\n\n/** One series as drawn: its `[x, y]` points along x, and the line its area fills down to (`null`: the baseline). */\nexport interface StackedSeries {\n readonly points: [x: number, y: number][]\n readonly base: [x: number, y: number][] | null\n}\n\n/**\n * Every series' points under `stack`, rows in x order. A series contributes its\n * values times its weight (`1` when missing), so a series sinking out of a stack\n * lowers the ones above it. `percent` reads each row as shares of its total\n * magnitude, so the top of a full stack is 100.\n */\nexport function stackSeries(\n data: DataRecord[],\n x: XScale,\n series: readonly LineSeries[],\n stack: LineStack,\n weights: readonly number[] = []\n): StackedSeries[] {\n const order = data.map((_, i) => i).sort((a, b) => x.at(a) - x.at(b))\n if (stack !== \"stacked\" && stack !== \"percent\") {\n return series.map((s) => ({ points: order.map((r): [number, number] => [x.at(r), num(data[r], s.field)]), base: null }))\n }\n const weight = (i: number) => Math.max(0, weights[i] ?? 1)\n const totals = order.map((r) => series.reduce((sum, s, i) => sum + Math.abs(num(data[r], s.field) * weight(i)), 0))\n const running = order.map(() => 0)\n return series.map((s, i) => {\n const base = order.map((r, k): [number, number] => [x.at(r), running[k]])\n const points = order.map((r, k): [number, number] => {\n const value = num(data[r], s.field) * weight(i)\n running[k] += stack === \"percent\" ? (totals[k] > 0 ? (value / totals[k]) * 100 : 0) : value\n return [x.at(r), running[k]]\n })\n return { points, base }\n })\n}\n\n/** The lowest and highest y anything in `stacks` reaches, its bases included. */\nexport function stackExtent(stacks: readonly StackedSeries[]): Range {\n let lo = Infinity\n let hi = -Infinity\n for (const { points, base } of stacks)\n for (const [, y] of [...points, ...(base ?? [])]) {\n if (y < lo) lo = y\n if (y > hi) hi = y\n }\n return lo <= hi ? [lo, hi] : [0, 1]\n}\n\n/** How a series' line runs between its points. */\nexport type LineCurve = \"smooth\" | \"linear\" | \"step\"\n\n/** Points along a cubic Bezier segment, its start left out. */\nconst SAMPLES = 16\n\n/**\n * The drawn path through `points` (ordered along x) as a polyline: the points\n * themselves for `linear`; for `step`, level runs that change at the midpoint\n * between neighbours; for `smooth`, a monotone cubic (Fritsch-Carlson, as d3's\n * `curveMonotoneX`), which never overshoots the data between two points.\n */\nexport function curvePoints(points: readonly Vector2[], curve: LineCurve): Vector2[] {\n if (curve === \"step\") {\n const out: Vector2[] = points.length > 0 ? [points[0]] : []\n for (let i = 1; i < points.length; i++) {\n const mid = (points[i - 1].x + points[i].x) / 2\n out.push({ x: mid, y: points[i - 1].y }, { x: mid, y: points[i].y }, points[i])\n }\n return out\n }\n if (curve !== \"smooth\" || points.length < 3) return [...points]\n const tangents = monotoneTangents(points)\n const out: Vector2[] = [points[0]]\n for (let i = 1; i < points.length; i++) {\n const a = points[i - 1]\n const b = points[i]\n const dx = (b.x - a.x) / 3\n const c1 = { x: a.x + dx, y: a.y + dx * tangents[i - 1] }\n const c2 = { x: b.x - dx, y: b.y - dx * tangents[i] }\n for (let k = 1; k <= SAMPLES; k++) {\n const t = k / SAMPLES\n const u = 1 - t\n out.push({\n x: u * u * u * a.x + 3 * u * u * t * c1.x + 3 * u * t * t * c2.x + t * t * t * b.x,\n y: u * u * u * a.y + 3 * u * u * t * c1.y + 3 * u * t * t * c2.y + t * t * t * b.y,\n })\n }\n }\n return out\n}\n\nfunction monotoneTangents(points: readonly Vector2[]): number[] {\n const n = points.length\n const slope = (i: number) => {\n const h = points[i + 1].x - points[i].x\n return h === 0 ? 0 : (points[i + 1].y - points[i].y) / h\n }\n const m = new Array<number>(n).fill(0)\n for (let i = 1; i < n - 1; i++) {\n const h0 = points[i].x - points[i - 1].x\n const h1 = points[i + 1].x - points[i].x\n const s0 = slope(i - 1)\n const s1 = slope(i)\n const p = h0 + h1 === 0 ? 0 : (s0 * h1 + s1 * h0) / (h0 + h1)\n m[i] = (Math.sign(s0) + Math.sign(s1)) * Math.min(Math.abs(s0), Math.abs(s1), 0.5 * Math.abs(p)) || 0\n }\n m[0] = endTangent(slope(0), m[1])\n m[n - 1] = endTangent(slope(n - 2), m[n - 2])\n return m\n}\n\n/** d3's one-sided end tangent, held to the end segment's own direction and to three times its slope, past which it would overshoot. */\nfunction endTangent(secant: number, inner: number): number {\n const t = (3 * secant - inner) / 2\n if (secant === 0 || Math.sign(t) !== Math.sign(secant)) return 0\n return Math.abs(t) > 3 * Math.abs(secant) ? 3 * secant : t\n}\n\n/** The part of `points` (ordered along x) left of `x`, ending on the point where it crosses `x`. */\nexport function cutAt(points: readonly Vector2[], x: number): Vector2[] {\n if (points.length === 0 || x < points[0].x) return []\n const out: Vector2[] = []\n for (let i = 0; i < points.length; i++) {\n const p = points[i]\n if (p.x <= x) {\n out.push(p)\n continue\n }\n const a = points[i - 1]\n if (a && p.x > a.x) out.push({ x, y: a.y + ((p.y - a.y) * (x - a.x)) / (p.x - a.x) })\n break\n }\n return out\n}\n\n/**\n * `polygon` clipped to `box` (Sutherland-Hodgman against each edge in turn).\n * The box is convex, so the result is the part inside, possibly with seams of\n * no width where a concave outline leaves and re-enters, which fill as nothing.\n */\nexport function clipPolygonToBox(polygon: readonly Vector2[], box: RegionBox): Vector2[] {\n if (polygon.length < 3 || !hasRegion(box)) return []\n const edges: ((p: Vector2) => number)[] = [\n (p) => p.x - box.left,\n (p) => box.right - p.x,\n (p) => p.y - box.bottom,\n (p) => box.top - p.y,\n ]\n let out: Vector2[] = [...polygon]\n for (const inside of edges) {\n const input = out\n out = []\n for (let i = 0; i < input.length; i++) {\n const cur = input[i]\n const prev = input[(i + input.length - 1) % input.length]\n const dc = inside(cur)\n const dp = inside(prev)\n if (dc >= 0) {\n if (dp < 0) out.push(crossing(prev, cur, dp, dc))\n out.push(cur)\n } else if (dp >= 0) out.push(crossing(prev, cur, dp, dc))\n }\n if (out.length === 0) return []\n }\n return out\n}\n\nfunction crossing(a: Vector2, b: Vector2, da: number, db: number): Vector2 {\n const t = da / (da - db)\n return { x: a.x + (b.x - a.x) * t, y: a.y + (b.y - a.y) * t }\n}\n\n/** A line chart's own look: how each series is stroked, dotted and filled. */\nexport const LINE_MARKS = {\n strokeWidth: Types.number(4, { min: 0, max: 24, step: 0.5, unit: \"px\" }),\n curve: Types.oneOf([\"smooth\", \"linear\", \"step\"] as const),\n dots: Types.boolean(false),\n /** Each dot's diameter. */\n dotSize: Types.number(12, { min: 0, max: 48, step: 1, unit: \"px\" }),\n /** Fill under each line: none, the series colour, or the colour fading to nothing at the baseline. */\n area: Types.oneOf([\"none\", \"solid\", \"gradient\"] as const),\n /** The fill's opacity at the line. */\n areaOpacity: Types.number(0.4, { min: 0, max: 1, step: 0.05 }),\n}\n\nexport const LINE_LABELS = {\n /** Read as the chart is built: each point's value printed above or below it, or none. */\n values: Types.oneOf([\"none\", \"above\", \"below\"] as const, { animatable: false }),\n}\n", "import {\n Graphics2D,\n Types,\n component2d,\n fillOps,\n strokeOps,\n type Fill,\n type FillResolved,\n type NodeOf,\n // Named so this component's emitted type reaches `Node2D` and its props through the sdk, not core.\n type Node2D as _Node2D,\n type Node2DProps as _Node2DProps,\n type Stroke,\n type StrokeResolved,\n} from \"@motionscript/sdk\"\n\nimport { rule } from \"../kit/chart-canvas\"\nimport { fresh } from \"../kit/entries\"\nimport { loadPaints } from \"../kit/paints\"\nimport {\n EMPTY_REGION_BOX,\n hasRegion,\n type RegionBox,\n} from \"./shared\"\n\n/**\n * The call-out of a {@link LineChart}: a washed rectangle with a dashed rule on\n * each bounded edge, drawn from the pre-mapped `box`. Dimming the series outside\n * is the line's and area's job, clipped against the same box so they agree on\n * the boundary. An unbounded edge is the plot's own border, and a rule there\n * would assert a limit the author did not set.\n */\nexport const ChartRegion = component2d({\n key: \"chartRegion\",\n state: {\n /** In this node's pixel space (origin at centre, y-up), mapped by the parent. A degenerate box draws nothing. */\n box: fresh<RegionBox>(() => EMPTY_REGION_BOX),\n stroke: Types.custom<Stroke, StrokeResolved[]>({ weight: 2, fill: \"white/70\", dash: [14, 12], cap: \"butt\", align: \"center\" }, { resolve: strokeOps.resolve, lerp: strokeOps.lerp }),\n fill: Types.custom<Fill, FillResolved[]>(\"white/6\", { resolve: fillOps.resolve, lerp: fillOps.lerp }),\n /** Driven by the chart's `regionReveal`, so the rules and the series' dimming move as one. */\n reveal: 0,\n },\n load: (loader, state) => loadPaints(loader, { fills: [state.fill], strokes: [state.stroke] }),\n render: (ctx, state) => {\n const box = state.box\n if (!hasRegion(box)) return\n\n const r = Math.max(0, Math.min(1, state.reveal))\n if (r <= 0) return\n\n const width = box.right - box.left\n const height = box.top - box.bottom\n const cx = (box.left + box.right) / 2\n const cy = (box.bottom + box.top) / 2\n\n if (state.fill.length > 0) {\n ctx.draw(new Graphics2D().rect({ x: cx, y: cy, width, height }).fill(state.fill).opacity(r))\n }\n\n if (state.stroke.length === 0) return\n\n if (box.xBounded) {\n const half = (height / 2) * r\n for (const x of [box.left, box.right]) rule(ctx, { x, y: cy - half }, { x, y: cy + half }, state.stroke, r)\n }\n if (box.yBounded) {\n const half = (width / 2) * r\n for (const y of [box.bottom, box.top]) rule(ctx, { x: cx - half, y }, { x: cx + half, y }, state.stroke, r)\n }\n },\n})\n\nexport type ChartRegion = NodeOf<typeof ChartRegion>\n", "/**\n * What a line chart's x column means: a number (plotted as is), an instant\n * (`Jan`, `2026-W12`; plotted by time, so a gap in the data reads as a gap), or\n * anything else (the row's position, evenly spaced).\n *\n * A tick on a time or ordinal scale is a sample, so its caption is the cell the\n * author wrote; only a tick that is not (an author-set range, a `zoomTo`\n * mid-flight) is formatted, by {@link formatInstant}.\n */\n\nimport type { DataRecord } from \"@motionscript/sdk\"\n\nimport {\n formatMarker,\n markerValues,\n num,\n text,\n type Range,\n} from \"../kit/shared\"\nimport { formatNumber } from \"@motionscript/sdk/component\"\n\n/** How an x column's cells become positions along the axis. */\nexport type XScaleKind = \"numeric\" | \"time\" | \"ordinal\"\n\n/** An x column resolved into positions, captions and ticks: three closures built once per (data, column), not a tag callers switch on. */\nexport interface XScale {\n kind: XScaleKind\n /** Position of row `index` along the axis, in this scale's own units. */\n at(index: number): number\n /** `[min, max]` across the rows: the scale when no range is set. */\n extent: Range\n label(value: number): string\n /** `divisions + 1` tick values spanning `range`, ends included. */\n ticks(range: Range, divisions: number): number[]\n}\n\nconst DAY = 86_400_000\n\nconst MONTHS = [\n \"january\",\n \"february\",\n \"march\",\n \"april\",\n \"may\",\n \"june\",\n \"july\",\n \"august\",\n \"september\",\n \"october\",\n \"november\",\n \"december\",\n]\n\n/** The year a cell naming none is dated into; a leap year, so February spaces the same as in a column that carries years. */\nconst NOMINAL_YEAR = 2024\n\n/** Month index for `jan`, `sept` or `january`, else -1: three letters minimum, then a prefix match, so `sept` passes and `janitor` does not. */\nfunction monthIndex(word: string): number {\n if (word.length < 3) return -1\n return MONTHS.findIndex((month) => month.startsWith(word))\n}\n\nfunction isoWeekStart(year: number, week: number): number {\n // ISO week 1 is the week containing 4 January, and weeks start on Monday.\n const jan4 = Date.UTC(year, 0, 4)\n const weekday = (new Date(jan4).getUTCDay() + 6) % 7 // Monday = 0\n return jan4 - weekday * DAY + (week - 1) * 7 * DAY\n}\n\n/**\n * One cell read as an instant, or `null`. Not `Date.parse`, which accepts `\"5\"`\n * and `\"Q3\"`, differs between engines off ISO, and reads `2026-03-14` as UTC but\n * `2026/03/14` as local. Every form is matched explicitly, and an ambiguous\n * all-numeric date (`03/04/2026`) is not one of them.\n */\nexport function parseInstant(raw: unknown): number | null {\n if (typeof raw !== \"string\") return null\n const s = raw.trim().toLowerCase()\n if (s === \"\") return null\n\n // 2026-03-14 · 2026/03/14 · 2026-03 · 2026/03\n const ymd = /^(\\d{4})[-/](\\d{1,2})(?:[-/](\\d{1,2}))?$/.exec(s)\n if (ymd) {\n const month = Number(ymd[2])\n const day = ymd[3] === undefined ? 1 : Number(ymd[3])\n if (month < 1 || month > 12 || day < 1 || day > 31) return null\n return Date.UTC(Number(ymd[1]), month - 1, day)\n }\n\n // 2026-W12 · 2026W12 · w12 · week 12\n const week = /^(?:(\\d{4})[-\\s]?)?w(?:ee)?k?[-\\s]?(\\d{1,2})$/.exec(s)\n if (week) {\n const n = Number(week[2])\n if (n < 1 || n > 53) return null\n return isoWeekStart(\n week[1] === undefined ? NOMINAL_YEAR : Number(week[1]),\n n\n )\n }\n\n // jan · january · jan 2026 · january-2026 · 2026 jan\n const named = /^(?:(\\d{4})[-\\s]+)?([a-z]+)(?:[-\\s]+(\\d{4}))?$/.exec(s)\n if (named) {\n const month = monthIndex(named[2])\n if (month >= 0) {\n const year = named[1] ?? named[3]\n const y = year === undefined ? NOMINAL_YEAR : Number(year)\n return Date.UTC(y, month, 1)\n }\n }\n\n // 14 mar 2026 · mar 14 2026 · mar 14, 2026\n const dayNamed =\n /^(?:(\\d{1,2})[-\\s]+([a-z]+)|([a-z]+)[-\\s]+(\\d{1,2}),?)[-\\s]+(\\d{4})$/.exec(\n s\n )\n if (dayNamed) {\n const month = monthIndex(dayNamed[2] ?? dayNamed[3])\n const day = Number(dayNamed[1] ?? dayNamed[4])\n if (month >= 0 && day >= 1 && day <= 31) {\n return Date.UTC(Number(dayNamed[5]), month, day)\n }\n }\n\n return null\n}\n\n/** An instant captioned at the coarsest granularity the span tells apart: a decade reads as years, a year as months. */\nexport function formatInstant(value: number, span: number): string {\n const date = new Date(value)\n const year = date.getUTCFullYear()\n const month = MONTHS[date.getUTCMonth()].slice(0, 3)\n const label = month.charAt(0).toUpperCase() + month.slice(1)\n if (span > 4 * 365 * DAY) return String(year)\n if (span > 60 * DAY) return `${label} ${year}`\n return `${label} ${date.getUTCDate()}`\n}\n\n/** `numericFields`' rule for one column: a single text cell takes it off the numeric scale rather than plot that row at 0. */\nfunction isNumericColumn(data: DataRecord[], field: string): boolean {\n let sawValue = false\n for (const row of data) {\n const v = row[field]\n if (v === undefined || v === null || v === \"\") continue\n if (typeof v !== \"number\") return false\n sawValue = true\n }\n return sawValue\n}\n\n/**\n * Every non-empty cell as an instant, or `null` if any is not one. A blank cell\n * keeps its slot and takes the nearest known instant: stacking it on the epoch\n * would drag the whole scale back fifty years.\n */\nfunction instantColumn(data: DataRecord[], field: string): number[] | null {\n const parsed: (number | null)[] = []\n let sawValue = false\n for (const row of data) {\n const raw = row[field]\n if (raw === undefined || raw === null || raw === \"\") {\n parsed.push(null)\n continue\n }\n const t = parseInstant(raw)\n if (t === null) return null\n parsed.push(t)\n sawValue = true\n }\n if (!sawValue) return null\n\n const first = parsed.find((t): t is number => t !== null) as number\n let last = first\n return parsed.map((t) => (t === null ? last : (last = t)))\n}\n\n/** `[min, max]` of `values`, or `[0, 1]` when there is nothing to span. */\nfunction extentOf(values: number[]): Range {\n let lo = Infinity\n let hi = -Infinity\n for (const v of values) {\n if (v < lo) lo = v\n if (v > hi) hi = v\n }\n return lo <= hi ? [lo, hi] : [0, 1]\n}\n\n/** Up to this many samples in view, every one is a tick. */\nexport const EVERY_SAMPLE = 12\n\n/**\n * Ticks spanning `range`, each a sample, nearest to where an evenly spaced tick\n * would go. They must be samples (a caption between two has nothing to say) and\n * spread (every nth sample would print five dates on top of each other across a\n * burst of rows), so this walks the evenly spaced targets, not the samples.\n * Targets that pick the same sample collapse to one tick, so a gappy column\n * draws fewer honest ticks rather than overlapping ones.\n */\nfunction sampledTicks(\n positions: number[],\n [min, max]: Range,\n divisions: number\n): number[] {\n const inside = positions.filter((v) => v >= min && v <= max)\n const unique = [...new Set(inside)].sort((a, b) => a - b)\n if (unique.length === 0) return markerValues([min, max], divisions)\n // Few and even enough to caption every one: a month left out reads as missing data.\n if (unique.length <= EVERY_SAMPLE && evenlySpaced(unique)) return unique\n\n const nearest = (target: number) =>\n unique.reduce((best, v) =>\n Math.abs(v - target) < Math.abs(best - target) ? v : best\n )\n\n const out: number[] = []\n for (const target of markerValues([min, max], divisions)) {\n const tick = nearest(target)\n if (out[out.length - 1] !== tick) out.push(tick)\n }\n return out\n}\n\n/** Whether no two neighbouring samples sit much closer than the average gap: months do, a burst of days between weeks of nothing does not. */\nfunction evenlySpaced(sorted: readonly number[]): boolean {\n if (sorted.length < 3) return true\n const mean = (sorted[sorted.length - 1] - sorted[0]) / (sorted.length - 1)\n for (let i = 1; i < sorted.length; i++) if (sorted[i] - sorted[i - 1] < mean * 0.75) return false\n return true\n}\n\n/** The cell of the row a tick came from, or `fallback` when it is not a sample. */\nfunction labelBySample(\n positions: number[],\n captions: string[],\n value: number,\n fallback: (value: number) => string\n): string {\n const i = positions.indexOf(value)\n return i >= 0 ? captions[i] : fallback(value)\n}\n\n/** Resolved scales by data array, then by field and pattern. */\nconst scales = new WeakMap<DataRecord[], Map<string, XScale>>()\n\n/** Kept per `data` array: bound props ask a dozen times a frame, and parsing every row's instant each time was most of a frame. */\nexport function resolveXScale(\n data: DataRecord[],\n field: string,\n pattern?: string\n): XScale {\n let byKey = scales.get(data)\n if (!byKey) scales.set(data, (byKey = new Map()))\n const key = JSON.stringify([field, pattern ?? null])\n let scale = byKey.get(key)\n if (!scale) byKey.set(key, (scale = xScaleOf(data, field, pattern)))\n return scale\n}\n\nfunction xScaleOf(\n data: DataRecord[],\n field: string,\n /** Number-format pattern for a numeric column only; ticks on the other kinds are the author's cells. */\n pattern?: string\n): XScale {\n if (field !== \"\" && isNumericColumn(data, field)) {\n const positions = data.map((row) => num(row, field))\n return {\n kind: \"numeric\",\n at: (i) => positions[i] ?? 0,\n extent: extentOf(positions),\n label: (value) =>\n pattern === undefined ? formatMarker(value) : formatNumber(value, pattern),\n // A continuous axis is read by its scale, not by which samples are on it.\n ticks: markerValues,\n }\n }\n\n const captions = data.map((row) => text(row, field))\n const instants = field === \"\" ? null : instantColumn(data, field)\n\n if (instants) {\n const extent = extentOf(instants)\n const span = extent[1] - extent[0]\n return {\n kind: \"time\",\n at: (i) => instants[i] ?? 0,\n extent,\n label: (value) =>\n labelBySample(instants, captions, value, (v) =>\n formatInstant(v, span)\n ),\n ticks: (range, divisions) => sampledTicks(instants, range, divisions),\n }\n }\n\n const positions = data.map((_, i) => i)\n return {\n kind: \"ordinal\",\n at: (i) => i,\n // `[0, n-1]`, not `[0, n]`: the first and last rows sit on the plot's edges.\n extent: positions.length > 0 ? [0, positions.length - 1] : [0, 1],\n label: (value) => captions[Math.round(value)] ?? \"\",\n ticks: (range, divisions) => sampledTicks(positions, range, divisions),\n }\n}\n", "import {\n Rect,\n Types,\n clamp,\n component2d,\n easeOut,\n type ChildView,\n type DataRecord,\n type NodeOf,\n type OutOf,\n // Named so this component's emitted type reaches `Node2D` and its props through the sdk, not core.\n type Node2D,\n type Node2DProps as _Node2DProps,\n type TextStyle as _TextStyle,\n type CornerRadiusResolved as _CornerRadiusResolved,\n type CornerStyleResolved as _CornerStyleResolved,\n type RectCornerRadius as _RectCornerRadius,\n type RectCornerStyle as _RectCornerStyle,\n type Fill as _Fill,\n type FillResolved as _FillResolved,\n type Stroke as _Stroke,\n type StrokeResolved as _StrokeResolved,\n type Size2D,\n type StyleInput as _StyleInput,\n type StyleValues as _StyleValues,\n} from \"@motionscript/sdk\"\nimport { formatNumber } from \"@motionscript/sdk/component\"\n\nimport { cartesianFrame, chartViews, columnGhost, frameGap, headroom, laidOutSize, overhang } from \"../kit/cartesian\"\nimport { ChartCanvas } from \"../kit/chart-canvas\"\nimport { ChartLegend } from \"../kit/chart-legend\"\nimport { SERIES_ARG, asParts, fresh } from \"../kit/entries\"\nimport { HorizontalAxis } from \"../kit/horizontal-axis\"\nimport { DEFAULT_MARKERS, ENTER_SHARE, beats, legendAway, type AnyTimeline, type Beat } from \"../kit/motion\"\nimport {\n SPOTLIGHT_DIM,\n formatMarker,\n lerpAxisDomain,\n lerpAxisEntry,\n markerStep,\n markerValues,\n niceTicks,\n num,\n resolveAxisDomain,\n settleAxisDomain,\n type AxisDomainConfig,\n type Range,\n type ResolvedAxisDomain,\n} from \"../kit/shared\"\nimport {\n CARTESIAN_GRID,\n CARTESIAN_TEXT,\n CHART_LEGEND,\n CHART_SERIES,\n CHART_STYLE_FAMILY,\n CHART_STYLE_PRESETS,\n GRID_BACKGROUND,\n axisConfigOf,\n migrateChartStyle,\n legendConfigOf,\n seriesFill,\n valueText,\n} from \"../kit/style\"\nimport { VerticalAxis, axisPads } from \"../kit/vertical-axis\"\nimport { CategoryAxis, slotCentre } from \"./category-axis\"\nimport { ChartBars, type BarGeometry } from \"./chart-bars\"\nimport {\n BAR_LABELS,\n BAR_MARKS,\n barCategories,\n barSpans,\n resolveBarScale,\n type BarOrientation,\n type BarSeries,\n type BarStack,\n} from \"./shared\"\n\nconst BAR_STYLE = Types.style(\n CHART_STYLE_FAMILY,\n { series: CHART_SERIES, background: GRID_BACKGROUND, text: CARTESIAN_TEXT, grid: CARTESIAN_GRID, marks: BAR_MARKS, labels: BAR_LABELS, legend: CHART_LEGEND },\n { presets: CHART_STYLE_PRESETS }\n)\n\n/** A bar chart's resolved style. */\nexport type BarChartStyle = OutOf<typeof BAR_STYLE>\n\n/** What a bar chart plots, as its entries hold it. */\nexport interface BarChartValues {\n readonly data: DataRecord[]\n readonly series: BarSeries[]\n readonly stack: BarStack\n readonly valueAxis: AxisDomainConfig\n}\n\n/** The value axis's domain with its range and ticks resolved. */\nexport type BarChartDomain = ResolvedAxisDomain\n\ninterface BarState extends BarChartValues {\n readonly categoryField: string\n readonly orientation: BarOrientation\n readonly style: BarChartStyle\n readonly weights: number[]\n readonly showing: boolean[]\n readonly spotlight: number | null\n readonly spotlightReveal: number\n}\n\nfunction drawnValue(s: BarChartValues, domain: AxisDomainConfig): AxisDomainConfig {\n const divisions = (domain.ticks?.length ?? DEFAULT_MARKERS) - 1\n const range = resolveBarScale(s.data, s.series, s.stack, domain.range, divisions)\n const even = domain.range !== undefined || s.stack === \"percent\"\n return { ...domain, range, ticks: domain.ticks ?? (even ? markerValues(range, DEFAULT_MARKERS - 1) : niceTicks(range, DEFAULT_MARKERS - 1)) }\n}\n\n/** The last domain worked out from each data array, and what it was read from. */\nconst domainsDrawn = new WeakMap<DataRecord[], { readonly key: readonly unknown[]; readonly domain: BarChartDomain }>()\n\n/** The value axis as drawn now. A series being hidden keeps its room, so the ticks hold still while it goes. */\nexport function barChartDomain(s: BarChartValues): BarChartDomain {\n const key = [s.series, s.stack, s.valueAxis]\n const kept = domainsDrawn.get(s.data)\n if (kept && kept.key.every((value, i) => value === key[i])) return kept.domain\n const domain = settleAxisDomain(s.valueAxis, (d) => drawnValue(s, d)) as BarChartDomain\n domainsDrawn.set(s.data, { key, domain })\n return domain\n}\n\n/** Ticks and the figures printed by bars both read through here, so they cannot disagree about how a number looks. */\nfunction valueLabel(s: BarChartValues, domain: BarChartDomain, value: number): string {\n const pattern = s.valueAxis.format\n if (pattern !== undefined) return formatNumber(value, pattern)\n const text = formatMarker(value, markerStep(domain.ticks))\n return s.stack === \"percent\" ? `${text}%` : text\n}\n\n/** A value along the value axis, a run of `length` px centred on 0. */\nfunction valueToPx(domain: BarChartDomain, length: number, value: number): number {\n const [min, max] = domain.range\n if (max === min) return -length / 2\n return ((value - min) / (max - min) - 0.5) * length\n}\n\n/** Where bars grow from: zero held on the scale, so a cropped axis grows them from the plot's edge. */\nfunction baselineValue(domain: BarChartDomain): number {\n const [lo, hi] = domain.range\n return clamp(0, Math.min(lo, hi), Math.max(lo, hi))\n}\n\nfunction weightAt(s: { readonly weights: readonly number[] }, index: number): number {\n return Math.max(0, s.weights[index] ?? 1)\n}\n\n/** The plot's run along the value axis and across the categories. */\nfunction runs(s: BarState, plot: Size2D): { along: number; across: number } {\n return s.orientation === \"horizontal\" ? { along: plot.width, across: plot.height } : { along: plot.height, across: plot.width }\n}\n\n/** Category `row`'s slot centre across the plot: left to right, or top to bottom. */\nfunction slotAt(s: BarState, row: number, across: number): number {\n const centre = slotCentre(row, s.data.length, across)\n return s.orientation === \"horizontal\" ? -centre : centre\n}\n\n/**\n * Series `index`'s bars in centred pixel space. Side by side, a series divides\n * the slot with its siblings by live weight; stacked, it takes the whole slot\n * and its weight scales its length, so hiding a series reflows rather than\n * punching a hole.\n */\nfunction seriesBars(s: BarState, index: number, plot: Size2D): BarGeometry[] {\n const series = s.series[index]\n if (!series) return []\n const domain = barChartDomain(s)\n const { along, across } = runs(s, plot)\n const n = s.data.length\n const slot = n > 0 ? across / n : 0\n const inner = slot * clamp(s.style.barWidth, 0, 1)\n const stacked = s.stack !== \"none\"\n let total = 0\n for (let i = 0; i < s.series.length; i++) total += weightAt(s, i)\n const unit = inner / (total > 0 ? total : 1)\n const weight = weightAt(s, index)\n let before = 0\n for (let i = 0; i < index; i++) before += weightAt(s, i)\n const gap = s.series.length > 1 ? s.style.barGap : 0\n const values = s.style.values\n\n return s.data.map((row, rowIndex) => {\n // Built from live contributions, so a fading series lowers the segments beyond it.\n const spans = barSpans(row, s.series, s.stack, s.weights)\n const span = spans[index] ?? { from: 0, to: 0, value: 0, outer: false }\n const centre = slotAt(s, rowIndex, across)\n const offset = -inner / 2 + unit * before + (unit * weight) / 2\n let caption = \"\"\n if (values !== \"none\" && span.value !== 0) {\n if (!stacked || values === \"inside\" || s.stack === \"percent\") caption = valueLabel(s, domain, stacked ? span.value : num(row, series.field))\n else if (span.outer) caption = valueLabel(s, domain, span.to)\n }\n return {\n center: stacked ? centre : centre + (s.orientation === \"horizontal\" ? -offset : offset),\n thickness: stacked ? inner : Math.max(0, unit * weight - gap),\n from: valueToPx(domain, along, span.from),\n to: valueToPx(domain, along, span.to),\n round: span.outer,\n grounded: !stacked || span.from === 0,\n caption,\n }\n })\n}\n\n/** Per-row opacity: 1 while nothing is spotlit, falling to {@link SPOTLIGHT_DIM} for all but the chosen category. */\nfunction categoryDims(s: BarState): number[] {\n const focus = clamp(s.spotlightReveal, 0, 1)\n const chosen = s.spotlight\n return s.data.map((_, i) => (focus <= 0 || chosen === i ? 1 : 1 - (1 - SPOTLIGHT_DIM) * focus))\n}\n\n/** The parts a bar chart's commands drive, found through its children. */\nfunction partsOf(children: readonly ChildView[]) {\n const views = chartViews(children)\n return {\n valueAxis: views.find((view) => VerticalAxis.is(view) || HorizontalAxis.is(view)) ?? null,\n categoryAxis: views.find(CategoryAxis.is) ?? null,\n bars: views.filter(ChartBars.is),\n legend: views.find(ChartLegend.is) ?? null,\n }\n}\n\n/**\n * Move series `index`'s share to `target` with its legend entry. Its bars stay\n * drawn for every frame the move covers and switch off only once a hide has\n * landed, so arriving at a time backwards matches arriving forwards.\n */\nfunction toggling(timeline: AnyTimeline, state: BarState, children: readonly ChildView[], index: number, target: number) {\n const parts = partsOf(children)\n if (!parts.bars[index]) return timeline.wait(timeline.duration)\n const from = state.series.map((_, i) => weightAt(state, i))\n const start = from[index] ?? 1\n const showing = state.series.map((s, i) => state.showing[i] ?? (s.enabled ?? true))\n return timeline.together([\n timeline.animate((t) => {\n const weights = [...from]\n weights[index] = start + (target - start) * timeline.ease(t)\n const shown = [...showing]\n shown[index] = target > 0 || t < 1\n return { weights, showing: shown }\n }, { eased: false }),\n ...(parts.legend ? [parts.legend.run(target > 0 ? \"showSeries\" : \"hideSeries\", { index })] : []),\n ])\n}\n\n/**\n * A bar chart, vertical or horizontal, its series side by side, stacked, or\n * stacked as shares of 100. Built like the line chart from `ChartCanvas`, a\n * value axis, a {@link CategoryAxis}, one {@link ChartBars} per series and\n * `ChartLegend`. Zero is always on the scale and bars grow about it, so a\n * negative value draws the other way from the same `growth` signal.\n *\n * Resting state is the finished chart; `enter` arms every part on its first\n * frame. A `to` of the value axis's `range` or `ticks` tweens from the domain as\n * drawn, so an auto axis rescales the bars continuously.\n */\nexport const BarChart = component2d({\n key: \"barChart\",\n state: {\n data: fresh<DataRecord[]>(() => [], { kind: \"dataset\" }),\n // Names a column, not a value, like the line chart's `xField`.\n categoryField: \"\",\n series: fresh<BarSeries[]>(() => [], { kind: \"series\" }),\n /** `vertical`: columns rise from a row of categories; `horizontal`: bars grow right from a column of them. */\n orientation: Types.oneOf([\"vertical\", \"horizontal\"] as const, { animatable: false }),\n /** `stacked`: each series sits on the sum of those before it; `percent`: every category reads as shares of 100. */\n stack: Types.oneOf([\"none\", \"stacked\", \"percent\"] as const),\n valueAxis: Types.custom<AxisDomainConfig>({}, { resolve: resolveAxisDomain, lerp: lerpAxisEntry }),\n categoryAxis: Types.custom<AxisDomainConfig>({}, { resolve: resolveAxisDomain, lerp: lerpAxisDomain }),\n style: BAR_STYLE,\n /** Rise of every bar about the baseline, `[0, 1]`: 0 collapses them onto it. */\n growth: 1,\n /** The category spotlit, or `null`. The choice snaps; `spotlightReveal` animates it. */\n spotlight: Types.custom<number | null>(null),\n spotlightReveal: 0,\n /** Each series' share of the slot, seeded from `enabled`: a weight rather than a switch, so hiding one widens the others. */\n weights: Types.custom<number[]>([], { private: true }),\n /** Whether each series' bars are drawn: on for every frame a show or hide covers, off once a hide lands. */\n showing: Types.custom<boolean[]>([], { private: true }),\n },\n defaults: {\n // A node made of parts that fill would otherwise hug them.\n width: \"fill\",\n height: \"fill\",\n weights: (state) => state.series.map((s) => ((s.enabled ?? true) ? 1 : 0)),\n showing: (state) => state.series.map((s) => s.enabled ?? true),\n },\n migrate: { style: migrateChartStyle(\"cartesian\") },\n allowedChildren: [],\n children: (state) => {\n const style = () => state.style\n const domain = () => barChartDomain(state)\n let plot: Node2D | undefined\n const plotSize = () => laidOutSize(plot)\n const built = state.style\n const horizontal = state.orientation === \"horizontal\"\n const categories = barCategories(state.data, state.categoryField)\n const valueConfig = () => axisConfigOf(style(), horizontal ? \"x\" : \"y\")\n const categoryConfig = () => axisConfigOf(style(), horizontal ? \"y\" : \"x\")\n const valueCaptions = () => {\n const d = domain()\n return d.ticks.map((value) => valueLabel(state, d, value))\n }\n const showValue = horizontal ? built.showXAxis : built.showYAxis\n const showCategory = horizontal ? built.showYAxis : built.showXAxis\n\n const valueAxis = showValue\n ? (horizontal\n ? new HorizontalAxis({\n range: () => domain().range,\n markers: () => domain().ticks,\n captions: valueCaptions,\n axis: valueConfig,\n label: state.valueAxis.label ?? \"\",\n overhang: () => ({ left: overhang(style()), right: overhang(style()) }),\n width: \"fill\",\n height: \"hug\",\n })\n : new VerticalAxis({\n range: () => domain().range,\n markers: () => domain().ticks,\n captions: valueCaptions,\n axis: valueConfig,\n label: state.valueAxis.label ?? \"\",\n width: \"hug\",\n height: \"fill\",\n })) as unknown as Node2D\n : undefined\n\n const categoryAxis = showCategory\n ? (new CategoryAxis({\n categories,\n axis: categoryConfig,\n label: state.categoryAxis.label ?? \"\",\n orientation: horizontal ? \"vertical\" : \"horizontal\",\n dims: () => categoryDims(state),\n width: horizontal ? \"hug\" : \"fill\",\n height: horizontal ? \"fill\" : \"hug\",\n }) as unknown as Node2D)\n : undefined\n\n const left = horizontal ? categoryAxis : valueAxis\n const bottom = horizontal ? valueAxis : categoryAxis\n const leftConfig = horizontal ? categoryConfig : valueConfig\n const ghost = left && bottom\n ? columnGhost({\n captions: horizontal ? () => categories : valueCaptions,\n count: horizontal ? categories.length : barChartDomain(state).ticks.length,\n text: () => leftConfig().labelStyle,\n title: (horizontal ? state.categoryAxis.label : state.valueAxis.label) ?? \"\",\n titleText: () => leftConfig().titleStyle,\n tickPad: () => axisPads(leftConfig(), \"right\").tick,\n titlePad: () => axisPads(leftConfig(), \"right\").title,\n })\n : undefined\n\n const barSets = state.series.map(\n (s, i) =>\n new ChartBars({\n bars: () => seriesBars(state, i, plotSize()),\n baseline: () => valueToPx(domain(), runs(state, plotSize()).along, baselineValue(domain())),\n horizontal,\n fill: () => seriesFill(style(), s, i),\n cornerRadius: () => style().barCornerRadius,\n cornerStyle: () => style().barCornerStyle,\n growth: () => state.growth,\n dims: () => categoryDims(state),\n // A figure past a stack's end prints the stack's total; a percent stack has none worth printing, so prints its shares inside.\n values: () => (built.values === \"end\" && state.stack === \"percent\" ? \"inside\" : built.values),\n valueStyle: () => valueText(style()),\n enabled: () => state.showing[i] ?? (s.enabled ?? true),\n }) as unknown as Node2D\n )\n\n const legendAt = built.legend\n const legend = legendAt !== \"none\"\n ? (new ChartLegend({\n series: state.series,\n swatches: () => state.series.map((s, i) => seriesFill(style(), s, i)),\n legend: () => legendConfigOf(style()),\n flow: legendAt === \"right\" ? \"vertical\" : \"horizontal\",\n }) as unknown as Node2D)\n : undefined\n\n const n = state.data.length\n // Category lines fall between the slots, never through a bar.\n const boundaries = () => Array.from({ length: Math.max(0, n - 1) }, (_, i) => i + 1)\n const slots = (): Range => [0, Math.max(1, n)]\n plot = new Rect({\n children: [\n new ChartCanvas({\n fill: () => style().gridBackground,\n xGridStroke: () => style().verticalGrid,\n yGridStroke: () => style().horizontalGrid,\n xMarkers: horizontal ? () => domain().ticks : boundaries,\n yMarkers: horizontal ? boundaries : () => domain().ticks,\n xExtent: horizontal ? () => domain().range : slots,\n yExtent: horizontal ? slots : () => domain().range,\n axisStroke: () => style().axisStroke,\n xAxisAt: () => (horizontal ? 0 : baselineValue(domain())),\n yAxisAt: () => (horizontal ? baselineValue(domain()) : 0),\n }),\n ...barSets,\n ],\n }) as unknown as Node2D\n\n return asParts([\n cartesianFrame({\n background: () => style().background,\n left,\n ghost,\n plot,\n bottom,\n legend,\n legendAt,\n gap: () => frameGap(style()),\n padding: () => ({\n top: headroom(style()),\n right: horizontal && bottom ? overhang(style()) : 0,\n left: horizontal && bottom && !left ? overhang(style()) : 0,\n bottom: 0,\n }),\n }),\n ])\n },\n commands: {\n /** Axes stagger in, bars rise from the baseline, the legend fades up last. `duration` is the whole entrance. */\n enter: {\n args: {},\n // Held from arrival, so it never shows finished ahead of its draw.\n entrance: true,\n easing: easeOut(),\n run: (timeline, state, children) => {\n const parts = partsOf(children)\n const duration = timeline.duration\n const axes = duration * ENTER_SHARE.axes\n const rise = duration * ENTER_SHARE.marks\n const { legend } = parts\n const at0 = (piece: Beat[\"piece\"]): Beat => ({ at: 0, duration: 0, piece })\n return beats(timeline, [\n at0(timeline.animate(() => ({ growth: 0 }))),\n ...(legend ? [at0(legend.to({ opacity: 0, ...legendAway(state.style.legend) }))] : []),\n ...(parts.valueAxis ? [{ at: 0, duration: axes, piece: parts.valueAxis.run(\"enter\", { slide: 24 }) }] : []),\n ...(parts.categoryAxis ? [{ at: 0, duration: axes, piece: parts.categoryAxis.run(\"enter\", { slide: 24 }) }] : []),\n // No priming to 0 first: the value at `t` is a function of `t`.\n { at: axes, duration: rise, piece: timeline.animate((t) => ({ growth: t })) },\n ...(legend ? [{ at: axes + rise, duration: duration * ENTER_SHARE.legend, piece: legend.to({ opacity: 1, x: 0, y: 0 }) }] : []),\n ])\n },\n },\n /** Bring series `index` back, the group reflowing to make room, with its legend entry. */\n showSeries: {\n args: { seriesIndex: SERIES_ARG },\n easing: easeOut(),\n run: (timeline, state, children) => toggling(timeline, state, children, timeline.args.seriesIndex, 1),\n },\n /** The mirror of `showSeries`: bars narrow away (stacked, sink out) while the rest widen into the space. */\n hideSeries: {\n args: { seriesIndex: SERIES_ARG },\n easing: easeOut(),\n run: (timeline, state, children) => toggling(timeline, state, children, timeline.args.seriesIndex, 0),\n },\n /** Fade every other series, bars and legend entry, to focus on `index`. Nothing moves, so the group does not reflow. */\n spotlightSeries: {\n args: { seriesIndex: SERIES_ARG },\n easing: easeOut(),\n run: (timeline, _state, children) => {\n const parts = partsOf(children)\n const index = timeline.args.seriesIndex\n return timeline.together([\n ...parts.bars.map((bars, i) => bars.to({ opacity: i === index ? 1 : SPOTLIGHT_DIM })),\n ...(parts.legend ? [parts.legend.run(\"spotlightSeries\", { index })] : []),\n timeline.wait(timeline.duration),\n ])\n },\n },\n /**\n * Fade every other category's bars and caption to {@link SPOTLIGHT_DIM}. While\n * another is lit the focus moves directly. A missing category takes its slot\n * and changes nothing.\n */\n spotlightCategory: {\n args: { categoryIndex: Types.number(0, { min: 0, step: 1 }) },\n easing: easeOut(),\n run: (timeline, state) => {\n const index = timeline.args.categoryIndex\n if (index < 0 || index >= state.data.length) return timeline.wait(timeline.duration)\n const from = state.spotlightReveal\n return timeline.animate((t) => ({ spotlight: index, spotlightReveal: from + (1 - from) * t }))\n },\n },\n /** Every category back to full; the lit one is held until the fade lands. A no-op when nothing is lit, which still takes its slot. */\n clearCategory: {\n args: {},\n easing: easeOut(),\n run: (timeline, state) => {\n const from = state.spotlightReveal\n if (from === 0) return timeline.wait(timeline.duration)\n const lit = state.spotlight\n return timeline.animate((t) => (t >= 1 ? { spotlight: null, spotlightReveal: 0 } : { spotlight: lit, spotlightReveal: from * (1 - t) }))\n },\n },\n },\n})\n\nexport type BarChart = NodeOf<typeof BarChart>\n", "import {\n Rect,\n Text,\n Types,\n clamp,\n component2d,\n type NodeOf,\n // Named so this component's emitted type reaches `Node2D` and its props through the sdk, not core.\n type Node2D,\n type Node2DProps as _Node2DProps,\n} from \"@motionscript/sdk\"\nimport { enterBudget } from \"@motionscript/sdk/component\"\n\nimport { boundText } from \"../kit/cartesian\"\nimport { asParts, fresh } from \"../kit/entries\"\nimport { armed, arrival, arrivalOf, arrivalsEntry, beats, frameEase, type Arrival } from \"../kit/motion\"\nimport { DEFAULT_X_AXIS, type AxisConfig } from \"../kit/shared\"\nimport { axisPads, captionColumn } from \"../kit/vertical-axis\"\n\nconst SLIDE = 24\n\n/** Slot `index`'s centre along a run of `length` px divided into `count` equal slots, first slot at `-length / 2`. */\nexport function slotCentre(index: number, count: number, length: number): number {\n return count <= 0 ? 0 : -length / 2 + (length / count) * (index + 0.5)\n}\n\n/**\n * The categorical axis of a {@link BarChart}: one {@link Text} caption per row,\n * centred on its slot. `horizontal` is a row under the plot, first category on\n * the left; `vertical` a right-aligned column beside it, first category at the\n * top. It is laid out to exactly the plot's length, so each caption lands by its\n * bars with neither side told about the other. The resting state is landed.\n */\nexport const CategoryAxis = component2d({\n key: \"categoryAxis\",\n state: {\n categories: fresh<string[]>(() => []),\n axis: Types.custom<AxisConfig>(DEFAULT_X_AXIS),\n label: \"\",\n orientation: Types.oneOf([\"horizontal\", \"vertical\"] as const),\n /** Per-category opacity multiplier, so the caption by a dimmed bar dims with it. Missing reads as 1. */\n dims: fresh<number[]>(() => []),\n arrivals: arrivalsEntry(),\n },\n // A node made of captions would otherwise hug them.\n defaults: { width: \"fill\", height: \"fill\" },\n children: (state) => {\n const n = state.categories.length\n const dim = (i: number) => clamp(state.dims[i] ?? 1, 0, 1)\n if (state.orientation === \"vertical\") {\n return asParts([\n captionColumn({\n count: n,\n axis: () => state.axis,\n text: (i) => state.categories[i] ?? \"\",\n // y-up: the first category takes the top slot.\n place: (i, height) => -slotCentre(i, state.categories.length, height),\n arrivals: () => state.arrivals,\n opacity: dim,\n label: state.label,\n }),\n ])\n }\n\n const pads = () => axisPads(state.axis, \"top\")\n // The spotlight dim sits on a hug box around each caption, so the entrance animates the text's own opacity without the two fighting over one value.\n const captions = state.categories.map((caption, i) => {\n const slot: Node2D = new Rect({\n width: \"hug\",\n height: \"hug\",\n flow: \"freeform\",\n opacity: () => dim(i),\n x: () => slotCentre(i, state.categories.length, (slot.parent as Node2D | null)?.layoutBounds.width ?? 0),\n children: [\n new Text({\n ...boundText(() => state.axis.labelStyle),\n text: caption,\n opacity: () => arrivalOf(state.arrivals, i).opacity,\n y: () => arrivalOf(state.arrivals, i).shift,\n }),\n ],\n }) as unknown as Node2D\n return slot\n })\n const children: Node2D[] = [new Rect({ width: \"fill\", height: \"hug\", padding: () => ({ top: pads().tick }), children: captions }) as unknown as Node2D]\n if (state.label !== \"\") {\n children.push(\n new Text({\n ...boundText(() => state.axis.titleStyle),\n text: state.label,\n opacity: () => arrivalOf(state.arrivals, \"label\").opacity,\n y: () => arrivalOf(state.arrivals, \"label\").shift,\n }) as unknown as Node2D\n )\n }\n return asParts([new Rect({ flow: \"vertical\", gap: () => pads().title, height: \"hug\", width: \"fill\", children }) as unknown as Node2D])\n },\n commands: {\n /**\n * Slide and fade captions in, first category first, then the title. The\n * duration is the whole entrance ({@link enterBudget}). `stagger` is seconds\n * between captions (derived when omitted); `slide` is the starting offset in px.\n */\n enter: {\n args: {\n stagger: Types.custom<number | undefined>(undefined),\n slide: Types.number(SLIDE),\n },\n run: (timeline, state) => {\n const { stagger, slide } = timeline.args\n const count = state.categories.length\n const captioned = state.label !== \"\"\n const from: Arrival = { opacity: 0, shift: slide }\n const keys = [...state.categories.keys(), ...(captioned ? [\"label\"] : [])]\n const arm = timeline.animate(() => ({ arrivals: armed(keys, from) }))\n if (count === 0) return arm\n const { step, per, caption } = enterBudget(timeline.duration, count, captioned, stagger)\n const ease = frameEase(timeline)\n const captions = state.categories.map((_, i) => ({ at: i * step, duration: per, piece: arrival(timeline, i, from, ease) }))\n const label = captioned ? [{ at: (count - 1) * step + per, duration: caption, piece: arrival(timeline, \"label\", from, ease) }] : []\n return timeline.together([arm, beats(timeline, [...captions, ...label])])\n },\n },\n },\n})\n\nexport type CategoryAxis = NodeOf<typeof CategoryAxis>\n", "import {\n Graphics2D,\n Text,\n Types,\n clamp,\n component2d,\n fillOps,\n type Fill,\n type FillResolved,\n type NodeOf,\n // Named so this component's emitted type reaches `Node2D` and its props through the sdk, not core.\n type Node2D,\n type Node2DProps as _Node2DProps,\n type RectCornerRadius as _RectCornerRadius,\n type RectCornerStyle as _RectCornerStyle,\n type TextStyle,\n type CornerRadiusResolved,\n type CornerStyleResolved,\n} from \"@motionscript/sdk\"\n\nimport { boundText } from \"../kit/cartesian\"\nimport { asParts, fresh } from \"../kit/entries\"\nimport { frameEase } from \"../kit/motion\"\nimport { loadPaints } from \"../kit/paints\"\nimport { formatMarker } from \"../kit/shared\"\nimport { inkOn } from \"./shared\"\n\n/**\n * One drawn bar in the plot's centred pixel space (origin at the centre, y-up),\n * mapped by the parent {@link BarChart}: `center` and `thickness` across the\n * category slot, `from` and `to` along the value axis (y for a column, x for a\n * horizontal bar). Two ends rather than a base and a length, like `BarSpan`:\n * one shape fits grouped, stacked and negative.\n */\nexport interface BarGeometry {\n center: number\n thickness: number\n /** The base: the baseline when grouped, the running stack end when stacked. */\n from: number\n /** The far end at full growth. */\n to: number\n /** Whether the far end takes the far corners (the stack's last segment on its side). */\n round: boolean\n /** Whether the base takes the base corners (it stands on the baseline: every grouped bar, a stack's first segment). */\n grounded?: boolean\n /** The figure printed by the bar; empty for none. */\n caption: string\n}\n\n/** A figure inside a bar needs this much room around it, in multiples of the type size. */\nconst INSIDE_ROOM = 0.6\n\ninterface Bars {\n readonly bars: readonly BarGeometry[]\n readonly baseline: number\n readonly horizontal: boolean\n readonly growth: number\n readonly dims: readonly number[]\n readonly enabled: boolean\n readonly values: \"none\" | \"end\" | \"inside\"\n readonly valueStyle: TextStyle\n}\n\n/** Bar `i`'s dimming: the category spotlight, then the series switch. */\nfunction dimAt(s: Bars, index: number): number {\n if (!s.enabled) return 0\n return clamp(s.dims[index] ?? 1, 0, 1)\n}\n\n/** Bar `i`'s two ends as grown so far, along the value axis. */\nfunction endsAt(s: Bars, index: number): { base: number; end: number } | null {\n const bar = s.bars[index]\n if (!bar) return null\n const g = clamp(s.growth, 0, 1)\n return { base: s.baseline + (bar.from - s.baseline) * g, end: s.baseline + (bar.to - s.baseline) * g }\n}\n\nfunction sizeOf(style: TextStyle): number {\n return typeof style.fontSize === \"number\" ? style.fontSize : 24\n}\n\n/** Where bar `i`'s figure sits along the value axis: past its end, or in its middle. */\nfunction captionAlong(s: Bars, index: number, extent: number): number {\n const ends = endsAt(s, index)\n if (!ends) return 0\n if (s.values === \"inside\") return (ends.base + ends.end) / 2\n const direction = ends.end >= ends.base ? 1 : -1\n return ends.end + direction * (sizeOf(s.valueStyle) * 0.4 + extent / 2)\n}\n\n/** Whether bar `i` has room for a figure `extent` long inside it. */\nfunction fitsInside(s: Bars, index: number, extent: number, across: number): boolean {\n const bar = s.bars[index]\n const ends = endsAt(s, index)\n if (!bar || !ends) return false\n const room = sizeOf(s.valueStyle) * INSIDE_ROOM\n return Math.abs(ends.end - ends.base) >= extent + room && bar.thickness >= across\n}\n\n/**\n * One series of a {@link BarChart}: its bar in every category plus the printed\n * figures. A node per series, like `ChartLine`, so `showSeries` and\n * `spotlightSeries` mean the same on both: enable the node or tween its opacity.\n * Positions come from the parent, which owns the slot arithmetic.\n */\nexport const ChartBars = component2d({\n key: \"chartBars\",\n state: {\n bars: fresh<BarGeometry[]>(() => []),\n /** Pixel position of value 0 along the value axis, where every bar grows from. */\n baseline: 0,\n /** Bars grow along x from a category column rather than along y from a row. */\n horizontal: false,\n fill: Types.custom<Fill, FillResolved[]>([], { resolve: fillOps.resolve, lerp: fillOps.lerp }),\n /** As for a bar standing up from the baseline: `topLeft`/`topRight` round its far end, the bottom pair its base. */\n cornerRadius: Types.cornerRadius(8),\n cornerStyle: Types.cornerStyle(\"rounded\"),\n /**\n * Rise of every bar in `[0, 1]` about the baseline, not each bar's own base:\n * every segment travels by the same factor, so a stack stays flush\n * mid-animation and a negative bar grows the other way.\n */\n growth: 1,\n /** Per-bar opacity by row index, how the category spotlight reaches one bar. Missing reads as 1. */\n dims: fresh<number[]>(() => []),\n /** Read as built: whether each bar prints its figure, and where. */\n values: Types.custom<\"none\" | \"end\" | \"inside\">(\"none\"),\n valueStyle: Types.custom<TextStyle>({ fontSize: 24, fill: \"white\" }),\n /** The wholesale switch behind `showSeries`/`hideSeries`; off skips the bars and their figures. */\n enabled: true,\n },\n // A node made of its figures would otherwise hug them.\n defaults: { width: \"fill\", height: \"fill\" },\n // One figure per bar, built once (the row count is fixed at construction)\n // and bound to the live geometry so it travels with its bar.\n children: (state) => {\n if (state.values === \"none\") return []\n return asParts(state.bars.map((_, i) => {\n const caption: Node2D = new Text({\n ...boundText(() => ({ ...state.valueStyle, ...(state.values === \"inside\" && { fill: inkOn(state.fill) }) })),\n text: () => state.bars[i]?.caption ?? \"\",\n x: () => (state.horizontal ? captionAlong(state, i, caption.layoutBounds.width) : (state.bars[i]?.center ?? 0)),\n y: () => (state.horizontal ? (state.bars[i]?.center ?? 0) : captionAlong(state, i, caption.layoutBounds.height)),\n opacity: () => {\n const box = caption.layoutBounds\n const along = state.horizontal ? box.width : box.height\n const across = state.horizontal ? box.height : box.width\n if (state.values === \"inside\" && !fitsInside(state, i, along, across)) return 0\n // A figure past the end rises in with its bar's last stretch.\n return dimAt(state, i) * clamp((state.growth - 0.6) / 0.4, 0, 1)\n },\n }) as unknown as Node2D\n return caption\n }))\n },\n load: (loader, state) => loadPaints(loader, { fills: [state.fill] }),\n commands: {\n /** Raise every bar from the baseline (`growth` 0 to 1). The resting state is the finished one; the chart arms it back to 0. */\n enter: (timeline) => {\n const ease = frameEase(timeline)\n return timeline.animate((t) => ({ growth: ease(t) }))\n },\n },\n render: (ctx, state) => {\n if (state.enabled) {\n for (let i = 0; i < state.bars.length; i++) {\n const bar = state.bars[i]\n const ends = endsAt(state, i)\n if (!ends || bar.thickness <= 0) continue\n // A segment inside a stack reaches a pixel under the next, so no seam of background shows between them.\n const seam = bar.round ? 0 : 1\n const length = Math.abs(ends.end - ends.base) + seam\n if (length <= seam) continue\n const forward = ends.end >= ends.base\n const mid = (ends.base + ends.end) / 2 + (forward ? seam : -seam) / 2\n const corners = barCorners(state, bar, forward, length)\n // One `Graphics2D` per bar: opacity belongs to the command list, and the spotlight dims single bars.\n const g = new Graphics2D().rect(state.horizontal\n ? { x: mid, y: bar.center, width: length, height: bar.thickness, ...corners }\n : { x: bar.center, y: mid, width: bar.thickness, height: length, ...corners })\n g.fill(state.fill)\n ctx.draw(g.opacity(dimAt(state, i)))\n }\n }\n ctx.children()\n },\n})\n\nexport type ChartBars = NodeOf<typeof ChartBars>\n\ntype Corners<T> = { topLeft: T; topRight: T; bottomRight: T; bottomLeft: T }\n\n/**\n * Turns corners written for a bar standing up into the drawn bar's visual\n * (y-up) corners: mirrored for a bar below zero, turned a quarter clockwise\n * for one growing right, and both for one growing left.\n */\nfunction orient<T>(c: Corners<T>, horizontal: boolean, forward: boolean): Corners<T> {\n if (!horizontal) return forward ? c : { topLeft: c.bottomLeft, topRight: c.bottomRight, bottomRight: c.topRight, bottomLeft: c.topLeft }\n return forward\n ? { topLeft: c.bottomLeft, topRight: c.topLeft, bottomRight: c.topRight, bottomLeft: c.bottomRight }\n : { topLeft: c.topLeft, topRight: c.bottomLeft, bottomRight: c.bottomRight, bottomLeft: c.topRight }\n}\n\n/** Bar `bar`'s rect corners: the far pair only where its stack ends, the base pair only on the baseline, each held inside the bar. */\nexport function barCorners(\n state: { readonly cornerRadius: CornerRadiusResolved; readonly cornerStyle: CornerStyleResolved; readonly horizontal: boolean },\n bar: BarGeometry,\n forward: boolean,\n length: number\n): { cornerRadius: Corners<number>; cornerStyle: CornerStyleResolved } {\n const grounded = bar.grounded ?? true\n const r = state.cornerRadius\n const ends = (bar.round ? 1 : 0) + (grounded ? 1 : 0)\n const cap = Math.max(0, Math.min(bar.thickness / 2, ends > 1 ? length / 2 : length))\n const fit = (v: number, on: boolean) => (on ? Math.max(0, Math.min(v, cap)) : 0)\n const upright: Corners<number> = {\n topLeft: fit(r.topLeft, bar.round),\n topRight: fit(r.topRight, bar.round),\n bottomRight: fit(r.bottomRight, grounded),\n bottomLeft: fit(r.bottomLeft, grounded),\n }\n return { cornerRadius: orient(upright, state.horizontal, forward), cornerStyle: orient(state.cornerStyle, state.horizontal, forward) }\n}\n\n/** A figure as the bar prints it when the chart gives no caption. */\nexport function barCaption(value: number): string {\n return value === 0 ? \"\" : formatMarker(value)\n}\n", "import {\n Types,\n fillOps,\n type DataRecord,\n type Fill,\n // Named so the emitted marks types reach these through the sdk, not core.\n type CornerRadiusResolved as _CornerRadiusResolved,\n type CornerStyleResolved as _CornerStyleResolved,\n type RectCornerRadius as _RectCornerRadius,\n type RectCornerStyle as _RectCornerStyle,\n} from \"@motionscript/sdk\"\n\nimport { niceRange, num, text, type ChartSeries, type Range } from \"../kit/shared\"\n\n/** One bar per row, beside its siblings in the category slot or stacked on them: {@link ChartSeries} under the name for what it draws here. */\nexport type BarSeries = ChartSeries\n\n/** How the series share a category: side by side, stacked, or stacked as shares of 100. */\nexport type BarStack = \"none\" | \"stacked\" | \"percent\"\n\n/** Which way the bars grow: up from a category row, or right from a category column. */\nexport type BarOrientation = \"vertical\" | \"horizontal\"\n\n/**\n * One bar's span in data units. A span rather than a height because every mode\n * fits it, and a negative value just runs the other way with no special case.\n */\nexport interface BarSpan {\n /** Where the base sits: 0 apart, the running total below (or above, for a negative) when stacked. */\n from: number\n to: number\n /** `to - from`. */\n value: number\n /** Whether it ends its stack on its side of zero, so its far end is rounded. */\n outer: boolean\n}\n\n/**\n * One row's spans, in series order. Stacking keeps a running sum on each side\n * of zero, so a negative value stacks downward from the baseline rather than\n * eating into the positives. In `percent` each value is its share of the row's\n * total magnitude. A zero value still yields a degenerate span, keeping the list\n * index-aligned with the series. `weights` scale each series' contribution.\n */\nexport function barSpans(row: DataRecord, series: readonly BarSeries[], stack: BarStack, weights: readonly number[] = []): BarSpan[] {\n const weight = (i: number) => Math.max(0, weights[i] ?? 1)\n if (stack !== \"stacked\" && stack !== \"percent\") {\n return series.map((s) => {\n const value = num(row, s.field)\n return { from: 0, to: value, value, outer: true }\n })\n }\n const values = series.map((s, i) => num(row, s.field) * weight(i))\n const total = values.reduce((sum, v) => sum + Math.abs(v), 0)\n const scaled = stack === \"percent\" ? values.map((v) => (total > 0 ? (v / total) * 100 : 0)) : values\n let lastUp = -1\n let lastDown = -1\n scaled.forEach((v, i) => {\n if (v > 0) lastUp = i\n else if (v < 0) lastDown = i\n })\n let up = 0\n let down = 0\n return scaled.map((value, i) => {\n if (value < 0) {\n const from = down\n down += value\n return { from, to: down, value, outer: i === lastDown }\n }\n const from = up\n up += value\n return { from, to: up, value, outer: i === lastUp }\n })\n}\n\nexport function barCategories(data: DataRecord[], field: string): string[] {\n return data.map((row) => text(row, field))\n}\n\n/**\n * The `[min, max]` of everything drawn, zero always included: a scale starting\n * at 40 draws a bar three times its neighbour for a 10% difference. A cropped\n * axis takes an explicit range.\n */\nexport function barValueExtent(data: DataRecord[], series: readonly BarSeries[], stack: BarStack, weights?: readonly number[]): Range {\n let lo = 0\n let hi = 0\n for (const row of data) {\n for (const span of barSpans(row, series, stack, weights)) {\n lo = Math.min(lo, span.from, span.to)\n hi = Math.max(hi, span.from, span.to)\n }\n }\n return lo < hi ? [lo, hi] : [0, 1]\n}\n\n/** The explicit `range`, else the data's extent nudged to tidy bounds (a percent stack reads to 100); `divisions` (one fewer than the marker count) makes the drawn ticks land on them. */\nexport function resolveBarScale(\n data: DataRecord[],\n series: readonly BarSeries[],\n stack: BarStack,\n range: Range | undefined,\n divisions: number,\n weights?: readonly number[]\n): Range {\n if (range) return range\n const [lo, hi] = barValueExtent(data, series, stack, weights)\n if (stack === \"percent\") return [lo < 0 ? -100 : 0, hi > 0 ? 100 : 0]\n return niceRange([lo, hi], divisions)\n}\n\n/** Black or white, whichever reads on `fill`: a figure printed inside a bar. */\nexport function inkOn(fill: Fill): string {\n const layers = fillOps.resolve(fill)\n const top = layers[layers.length - 1]\n if (top?.type !== \"solid\") return \"white\"\n const [r, g, b] = top.color\n const lift = (c: number) => (c <= 0.03928 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4)\n const luminance = 0.2126 * lift(r) + 0.7152 * lift(g) + 0.0722 * lift(b)\n return luminance > 0.4 ? \"#0a0a0a\" : \"white\"\n}\n\n/** A bar chart's own look: its corners, and how wide the bars are. */\nexport const BAR_MARKS = {\n /**\n * Each corner as for a bar standing up from the baseline: the top pair round\n * its far end, the bottom pair its base. Inside a stack, a segment's far end\n * stays square unless it ends the stack, and its base unless it starts it.\n */\n barCornerRadius: Types.cornerRadius({ topLeft: 10, topRight: 10, bottomRight: 0, bottomLeft: 0 }),\n barCornerStyle: Types.cornerStyle(\"rounded\"),\n /** How much of its category slot a bar group fills, the rest spacing the groups. */\n barWidth: Types.number(0.7, { min: 0.05, max: 1, step: 0.05, unit: \"%\", scale: 100 }),\n /** Space between the bars of one group, side by side. */\n barGap: Types.number(6, { min: 0, max: 40, step: 1, unit: \"px\" }),\n}\n\nexport const BAR_LABELS = {\n /** Read as the chart is built: each bar's value past its end, inside it, or none. */\n values: Types.oneOf([\"none\", \"end\", \"inside\"] as const, { animatable: false }),\n}\n", "import {\n Rect,\n Types,\n clamp,\n component2d,\n easeOut,\n type ChildView,\n type DataRecord,\n type NodeOf,\n // Named so this component's emitted type reaches `Node2D` and its props through the sdk, not core.\n type Node2D,\n type Node2DProps as _Node2DProps,\n type TextStyle as _TextStyle,\n type Fill as _Fill,\n type FillResolved as _FillResolved,\n} from \"@motionscript/sdk\"\n\nimport { asParts, fresh } from \"../kit/entries\"\nimport { beats, type AnyTimeline, type Beat } from \"../kit/motion\"\nimport { PieLegend } from \"../kit/pie-legend\"\nimport { PieRing } from \"./pie-ring\"\nimport { CHART_STYLE_FAMILY, CHART_STYLE_PRESETS, migrateChartStyle, paletteFill } from \"../kit/style\"\nimport {\n PIE_SPOTLIGHT_DIM,\n PIE_STYLE_GROUPS,\n centerConfigOf,\n labelConfigOf,\n legendOf,\n resolvePieSlices,\n ringConfigOf,\n selectionFade,\n type PieLabelMode,\n type PieSlice,\n type PieStyle,\n} from \"./shared\"\n\nexport interface PieChartValues {\n readonly data: DataRecord[]\n readonly categoryField: string\n readonly valueField: string\n readonly style: PieStyle\n readonly pops: number[]\n}\n\n/** How `enter` divides its duration: wedges sweeping in, then labels and legend together. Sums to 1. */\nconst SWEEP_SHARE = 0.65\nconst LABEL_SHARE = 0.35\n\nconst SLICE_ARG = Types.number(0, { min: 0, step: 1 })\n\nfunction slicesOf(s: PieChartValues): PieSlice[] {\n return resolvePieSlices(\n s.data,\n s.categoryField,\n s.valueField,\n s.data.map((_, i) => paletteFill(s.style, i))\n )\n}\n\nfunction popAt(s: PieChartValues, index: number): number {\n return clamp(s.pops[index] ?? 0, 0, 1)\n}\n\n/** Whether slice `index` is past half way out, so a slice mid-swell is not yet counted. */\nexport function isSliceSelected(s: PieChartValues, index: number): boolean {\n return popAt(s, index) > 0.5\n}\n\n/** Per-slice opacity: 1 while nothing is out and for the selected slice, falling toward `dimOpacity` for the rest as the selection grows. */\nfunction sliceDims(s: PieChartValues): number[] {\n let focus = 0\n for (let i = 0; i < s.data.length; i++) focus = Math.max(focus, popAt(s, i))\n return s.data.map((_, i) => selectionFade(focus, PIE_SPOTLIGHT_DIM, popAt(s, i)))\n}\n\n/** Every slice's pop eased to what `pop` asks for. A move that changes nothing still takes its slot. */\nfunction popping(timeline: AnyTimeline, s: PieChartValues, pop: (index: number) => number) {\n const from = s.data.map((_, i) => popAt(s, i))\n const targets = s.data.map((_, i) => clamp(pop(i), 0, 1))\n if (from.every((value, i) => value === targets[i])) return timeline.wait(timeline.duration)\n return timeline.animate((t) => ({ pops: from.map((value, i) => value + (targets[i] - value) * t) }))\n}\n\n/** The ring and legend among the children; the last row is the one the chart built. */\nfunction partsOf(children: readonly ChildView[]) {\n for (let i = children.length - 1; i >= 0; i--) {\n const row = children[i]\n const ring = Rect.is(row) ? row.children.find(PieRing.is) : undefined\n if (ring) return { ring, legend: row.children.find(PieLegend.is) ?? null }\n }\n return null\n}\n\n/**\n * A pie or donut chart: a {@link PieRing} filling what the hugging {@link PieLegend}\n * leaves. One mark per row, not per column, and nothing to hide, since dropping\n * a slice would re-cut every other wedge; `selectSlice` and its siblings swell\n * a slice and dim the rest instead.\n *\n * Resting state is the finished chart, except the hole's summary, which\n * `showCenter: false` holds back for `revealCenter`.\n */\nexport const PieChart = component2d({\n key: \"pieChart\",\n state: {\n data: fresh<DataRecord[]>(() => [], { kind: \"dataset\" }),\n /** Slice caption, used on the labels and the legend. */\n categoryField: \"\",\n /** Slice magnitude: the wedge's share of the ring. */\n valueField: \"\",\n style: Types.style(CHART_STYLE_FAMILY, PIE_STYLE_GROUPS, { presets: CHART_STYLE_PRESETS }),\n /** What the ring's labels say. */\n labelMode: Types.custom<PieLabelMode>(\"percent\"),\n /** Gap between the ring and the legend, in px. */\n gap: 40,\n /** Text set in the ring's hole. */\n centerLabel: \"\",\n /** Smaller second line under `centerLabel`. */\n centerCaption: \"\",\n /** How far each slice is pushed out, `0`-`1` per index. Here, not on the ring, because the wedges and the legend both read it. */\n pops: fresh<number[]>(() => []),\n /** Read as the chart is built: whether the hole's summary is drawn at rest. A scene that wants it to land later sets `false` and runs `revealCenter`. */\n showCenter: Types.boolean(true, { animatable: false }),\n },\n defaults: {\n // A node made of parts that fill would otherwise hug them.\n width: \"fill\",\n height: \"fill\",\n pops: (state) => slicesOf(state).map(() => 0),\n },\n migrate: { style: migrateChartStyle(\"pie\") },\n allowedChildren: [],\n // The structure (a label and legend row per row) is read once; slices, paint and selection are bound, so a theme tween re-paints and a `set` of `data` re-cuts.\n children: (state) => {\n const style = () => state.style\n const slices = () => slicesOf(state)\n const parts: Node2D[] = [\n new PieRing({\n width: \"fill\",\n height: \"fill\",\n slices,\n ring: () => ringConfigOf(style()),\n label: () => labelConfigOf(style()),\n centerStyle: () => centerConfigOf(style()),\n labelMode: state.labelMode,\n labelPlacement: state.style.labelPlacement,\n pops: () => state.pops,\n dimOpacity: PIE_SPOTLIGHT_DIM,\n centerLabel: state.centerLabel,\n centerCaption: state.centerCaption,\n centerReveal: state.showCenter === false ? 0 : 1,\n }) as unknown as Node2D,\n ]\n const position = state.style.legend\n if (position !== \"none\") {\n const side = position === \"right\"\n const legend = new PieLegend({\n slices,\n legend: () => legendOf(style()),\n dims: () => sliceDims(state),\n flow: side ? \"vertical\" : \"horizontal\",\n align: \"center\",\n // Spacing is fixed as built.\n gap: side ? legendOf(state.style).itemGap / 3 : legendOf(state.style).itemGap,\n padding: 0,\n }) as unknown as Node2D\n if (position === \"top\") parts.unshift(legend)\n else parts.push(legend)\n }\n const row = new Rect({\n flow: position === \"right\" || position === \"none\" ? \"horizontal\" : \"vertical\",\n width: \"fill\",\n height: \"fill\",\n gap: state.gap,\n padding: 24,\n align: \"center\",\n fill: () => state.style.background,\n children: parts,\n })\n return asParts([row as unknown as Node2D])\n },\n commands: {\n /** Wedges sweep in clockwise from `startAngle`, then labels fade up and the legend staggers in. `duration` is the whole entrance; the hole's summary keeps its own signal. */\n enter: {\n args: {},\n // Held from arrival, so it never shows finished ahead of its draw.\n entrance: true,\n easing: easeOut(),\n run: (timeline, _state, children) => {\n const parts = partsOf(children)\n if (!parts) return timeline.wait(timeline.duration)\n const { ring, legend } = parts\n const sweep = timeline.duration * SWEEP_SHARE\n const labels = timeline.duration * LABEL_SHARE\n const at0 = (piece: Beat[\"piece\"]): Beat => ({ at: 0, duration: 0, piece })\n return beats(timeline, [\n at0(ring.to({ growth: 0, labelReveal: 0 })),\n ...(legend ? [at0(legend.run(\"arm\"))] : []),\n { at: 0, duration: sweep, piece: ring.run(\"sweep\") },\n { at: sweep, duration: labels, piece: ring.run(\"revealLabels\") },\n ...(legend ? [{ at: sweep, duration: labels, piece: legend.run(\"enter\") }] : []),\n ])\n },\n },\n /** Fade the hole's summary up. Not part of `enter`: it is usually the conclusion, which a scene lands on its own beat. */\n revealCenter: {\n args: {},\n easing: easeOut(),\n run: (timeline, _state, children) => partsOf(children)?.ring.run(\"revealCenter\") ?? timeline.wait(timeline.duration),\n },\n /** Grow slice `index` out past the ring's rim and dim the rest, leaving any other selected slice where it is. */\n selectSlice: {\n args: { sliceIndex: SLICE_ARG },\n easing: easeOut(),\n run: (timeline, state) => {\n const index = timeline.args.sliceIndex\n return popping(timeline, state, (i) => (i === index ? 1 : popAt(state, i)))\n },\n },\n /** Settle slice `index` back flush with the ring. */\n deselectSlice: {\n args: { sliceIndex: SLICE_ARG },\n easing: easeOut(),\n run: (timeline, state) => {\n const index = timeline.args.sliceIndex\n return popping(timeline, state, (i) => (i === index ? 0 : popAt(state, i)))\n },\n },\n /** Move the focus to slice `index` alone, settling whatever else was out. */\n selectOnlySlice: {\n args: { sliceIndex: SLICE_ARG },\n easing: easeOut(),\n run: (timeline, state) => {\n const index = timeline.args.sliceIndex\n return popping(timeline, state, (i) => (i === index ? 1 : 0))\n },\n },\n /** Settle every slice flush and bring the whole chart back to full. */\n clearSelection: {\n args: {},\n easing: easeOut(),\n run: (timeline, state) => popping(timeline, state, () => 0),\n },\n },\n})\n\nexport type PieChart = NodeOf<typeof PieChart>\n", "import {\n Graphics2D,\n PathBuilder,\n Rect,\n Text,\n Types,\n clamp,\n component2d,\n strokeOps,\n textOps,\n type Fill,\n type NodeOf,\n // Named so this component's emitted type reaches `Node2D` and its props through the sdk, not core.\n type Node2D,\n type Node2DProps as _Node2DProps,\n type TextStyle,\n type Vector2,\n} from \"@motionscript/sdk\"\n\nimport { asParts, fresh } from \"../kit/entries\"\nimport { frameEase } from \"../kit/motion\"\nimport { loadPaints } from \"../kit/paints\"\nimport { resolvedFill, ringFills } from \"../kit/polar\"\nimport { formatPercent } from \"../kit/shared\"\n\nimport {\n PIE_SPOTLIGHT_DIM,\n pieArcs,\n relaxLabels,\n ringPoint,\n selectionFade,\n type CenterConfig,\n type LabelConfig,\n type PieArc,\n type PieLabelMode,\n type PieLabelPlacement,\n type PieSlice,\n type RingConfig,\n} from \"./shared\"\n\nconst DEFAULT_RING: RingConfig = { gap: 3, holeRadius: 0, startAngle: 0, selectedGrow: 1.08, cornerRadius: 4 }\nconst DEFAULT_LABEL: LabelConfig = {\n textStyle: { fontSize: 28, fontWeight: 500, textAlign: \"center\", fill: \"#a1a1aa\" },\n percentStyle: { fontSize: 28, fontWeight: 700, textAlign: \"center\", fill: \"#f4f4f5\" },\n insideStyle: { fontSize: 52, fontWeight: 700, textAlign: \"center\", fill: \"#111113\" },\n leaderStroke: { weight: 2, fill: \"#a1a1aa\" },\n}\nconst DEFAULT_CENTER: CenterConfig = {\n labelStyle: { fontSize: 50, fontWeight: 800, textAlign: \"center\", fill: \"#f4f4f5\" },\n captionStyle: { fontSize: 22, fontWeight: 500, textAlign: \"center\", fill: \"#a1a1aa\" },\n}\n\n/** Black or white, whichever reads better on a solid `fill`; black for any other paint. */\nexport function onFill(fill: Fill): string {\n const layers = resolvedFill(fill)\n const solid = layers.find((layer) => layer.type === \"solid\") as { color: [number, number, number, number] } | undefined\n if (!solid) return \"#111113\"\n const [r, g, b] = solid.color\n return 0.2126 * r + 0.7152 * g + 0.0722 * b > 0.45 ? \"#111113\" : \"#ffffff\"\n}\n\nconst LABEL_GAP = 12\nconst LABEL_PAD = 14\n/** Rough glyph width as a fraction of the font size, for gutter sizing. */\nconst GLYPH_RATIO = 0.62\nconst LEADER_LIFTOFF = 6\nconst LEADER_LENGTH = 34\nconst LABEL_STUB = 26\nconst TEXT_INSET = 8\n/** Floor on the elbow's distance from the ring's axis, as a fraction of the leader radius, so a label pushed above or below the ring still elbows out sideways. */\nconst MIN_ELBOW = 0.18\nconst ARC_STEPS = 240\nconst ELBOW_RADIUS = 8\nconst BARE_PAD = 2\nconst INSIDE_CAPTION_RATIO = 0.44\n/** Where an inside label sits on a solid pie, as a fraction of the radius: far enough out to clear the point every wedge converges on. */\nconst PIE_LABEL_RADIUS = 0.62\nconst CENTER_LABEL_FIT = 0.78\nconst INSIDE_LABEL_FIT = 0.9\n/** Below this a wedge's bisector counts as axis-aligned and that bound stops binding. */\nconst AXIS_EPSILON = 1e-3\n/** Type size when a theme style leaves it unset or on autofit. */\nconst FALLBACK_SIZE = 26\n\nfunction sizeOf(style: TextStyle, fallback = FALLBACK_SIZE): number {\n const size = style.fontSize\n return typeof size === \"number\" ? size : fallback\n}\n\ninterface LabelPlacement {\n index: number\n /** +1 right, -1 left. */\n side: 1 | -1\n /** Wedge edge, elbow, label. */\n leader: Vector2[]\n /** Where the label's inner edge is pinned. */\n text: Vector2\n}\n\n/**\n * A wedge over `a0`..`a1` (radians clockwise from 12 o'clock) from `rInner` to\n * `rOuter`, centred on `cx`; with `rInner <= 0` it closes at an apex pulled\n * off the centre by the gap. `halfGap` is half the px gap to the neighbour,\n * converted to an angle per radius so the channel keeps one width across the\n * band; the inset is capped at the wedge's half-span so a sliver narrows to\n * nothing rather than turning inside out. Corners are rounded by `corner` px\n * (clamped to what the wedge can hold), except a pie's apex.\n */\nexport function wedgePath(a0: number, a1: number, rInner: number, rOuter: number, halfGap: number, corner: number, cx: number): PathBuilder {\n const path = new PathBuilder()\n const span = a1 - a0\n const steps = Math.max(2, Math.ceil((Math.abs(span) / (Math.PI * 2)) * ARC_STEPS))\n const insetAt = (r: number): number => (r <= 0 ? 0 : Math.min(halfGap / r, span / 2.2))\n const at = (r: number, a: number): Vector2 => {\n const p = ringPoint(r, a)\n return { x: p.x + cx, y: p.y }\n }\n const hasHole = rInner > 0\n const oa0 = a0 + insetAt(rOuter)\n const oa1 = a1 - insetAt(rOuter)\n const ia0 = a0 + insetAt(rInner)\n const ia1 = a1 - insetAt(rInner)\n const O0 = at(rOuter, oa0)\n const O1 = at(rOuter, oa1)\n const half = Math.max(1e-3, Math.min(span / 2, Math.PI / 2))\n const apex = at(halfGap > 0 ? Math.min(halfGap / Math.sin(half), rOuter * 0.8) : 0, (a0 + a1) / 2)\n const I0 = hasHole ? at(rInner, ia0) : apex\n const I1 = hasHole ? at(rInner, ia1) : apex\n\n const band = hasHole ? rOuter - rInner : rOuter\n const rho = Math.max(0, Math.min(corner, band / 2.2, ((oa1 - oa0) * rOuter) / 2.2, hasHole ? ((ia1 - ia0) * rInner) / 2.2 : Infinity))\n const rounded = rho >= 0.5\n const toward = (from: Vector2, to: Vector2, d: number): Vector2 => {\n const len = Math.hypot(to.x - from.x, to.y - from.y) || 1\n const k = Math.min(0.5, d / len)\n return { x: from.x + (to.x - from.x) * k, y: from.y + (to.y - from.y) * k }\n }\n const dOuter = rounded ? rho / Math.max(1, rOuter) : 0\n const dInner = rounded && hasHole ? rho / rInner : 0\n\n const arc = (r: number, from: number, to: number) => {\n for (let i = 0; i <= steps; i++) {\n const p = at(r, from + ((to - from) * i) / steps)\n path.lineTo(p.x, p.y)\n }\n }\n const round = (corner: Vector2, next: Vector2) => {\n if (rounded) path.quadraticCurveTo(corner.x, corner.y, next.x, next.y)\n else path.lineTo(corner.x, corner.y)\n }\n\n const first = at(rOuter, oa0 + dOuter)\n path.moveTo(first.x, first.y)\n arc(rOuter, oa0 + dOuter, oa1 - dOuter)\n round(O1, toward(O1, I1, rho))\n if (hasHole) {\n const beforeI1 = toward(I1, O1, rho)\n path.lineTo(beforeI1.x, beforeI1.y)\n round(I1, at(rInner, ia1 - dInner))\n arc(rInner, ia1 - dInner, ia0 + dInner)\n round(I0, toward(I0, O0, rho))\n } else {\n path.lineTo(apex.x, apex.y)\n }\n const beforeO0 = toward(O0, I0, rounded ? rho : 0)\n path.lineTo(beforeO0.x, beforeO0.y)\n round(O0, first)\n path.close()\n return path\n}\n\ninterface RingState {\n readonly slices: PieSlice[]\n readonly ring: RingConfig\n readonly label: LabelConfig\n readonly centerStyle: CenterConfig\n readonly labelMode: PieLabelMode\n readonly labelPlacement: PieLabelPlacement\n readonly pops: readonly number[]\n readonly dimOpacity: number\n readonly centerLabel: string\n readonly centerCaption: string\n}\n\n/** Every radius, gutter and label position for one box, derived afresh wherever read so the drawing and the labels' bound positions cannot disagree. */\nexport class RingGeometry {\n constructor(\n private readonly s: RingState,\n private readonly box: { readonly width: number; readonly height: number }\n ) { }\n\n /** Re-read every frame so a value tween re-cuts them. */\n get arcs(): PieArc[] {\n return pieArcs(this.s.slices, this.s.ring.startAngle)\n }\n\n /** Leader labels are the only thing that costs a gutter. */\n get hasLeaderLabels(): boolean {\n return this.s.labelPlacement === \"outside\" && this.s.labelMode !== \"none\" && this.arcs.length > 0\n }\n\n /**\n * Px a horizontal label centred in `arc`'s band can run before leaving the\n * wedge: bound by the band's thickness near 3 o'clock, by its arc near 12.\n * Measured off the unpopped radius, so a slice growing out of the ring does not\n * resize its own text mid-animation.\n */\n insideRoom(arc: PieArc): number {\n const outer = this.outerRadius\n const hole = this.holeRadius\n const band = hole > 0 ? outer - hole : outer * (1 - PIE_LABEL_RADIUS) * 2\n const mid = hole > 0 ? (hole + outer) / 2 : outer * PIE_LABEL_RADIUS\n const sin = Math.abs(Math.sin(arc.mid))\n const cos = Math.abs(Math.cos(arc.mid))\n const acrossBand = sin > AXIS_EPSILON ? band / sin : Infinity\n const alongArc = cos > AXIS_EPSILON ? ((arc.a1 - arc.a0) * mid) / cos : Infinity\n return Math.max(0, Math.min(acrossBand, alongArc))\n }\n\n /** Widest line, in glyphs at the leading line's size, an inside label runs to. */\n insideGlyphs(arc: PieArc): number {\n const mode = this.s.labelMode\n const category = this.s.slices[arc.index]?.category.length ?? 0\n const percent = mode === \"both\" || mode === \"percent\" ? formatPercent(arc.fraction).length : 0\n // The caption is a fraction of the leading line, unless it is the leading line.\n const caption = mode === \"category\" ? category : mode === \"both\" ? category * INSIDE_CAPTION_RATIO : 0\n return Math.max(1, percent, caption)\n }\n\n /** The theme's `insideStyle.fontSize` shrunk to fit, an upper bound. One size across every inside label (the smallest any needs): mismatched sizes read as a mistake. */\n get insideFont(): number {\n let size = sizeOf(this.s.label.insideStyle, FALLBACK_SIZE * 1.9)\n for (const arc of this.arcs) {\n const fits = (this.insideRoom(arc) * INSIDE_LABEL_FIT) / (this.insideGlyphs(arc) * GLYPH_RATIO)\n size = Math.min(size, fits)\n }\n return Math.max(1, size)\n }\n\n /** The configured size capped to fit across the hole, which derives from the box: a smaller reflow would otherwise push the summary through the ring. */\n get centerFont(): number {\n const { centerStyle, centerLabel, centerCaption } = this.s\n const wanted = sizeOf(centerStyle.labelStyle, 46)\n const hole = this.holeRadius\n if (hole <= 0) return wanted\n const captionRatio = sizeOf(centerStyle.captionStyle, 22) / Math.max(1, wanted)\n // Both lines must clear the hole; the caption is a fraction of this size, so the wider once drawn binds, not the longer.\n const glyphs = Math.max(1, centerLabel.length, centerCaption.length * captionRatio)\n return Math.min(wanted, (hole * 2 * CENTER_LABEL_FIT) / (glyphs * GLYPH_RATIO))\n }\n\n /** Rim radius of a fully selected slice as a multiple of the ring's. */\n get growFactor(): number {\n return Math.max(1, Math.min(1.6, this.s.ring.selectedGrow))\n }\n\n get maxPop(): number {\n return this.outerRadius * (this.growFactor - 1)\n }\n\n /** Height of one leader label block, the unit the columns are spaced by. Inside labels cost no vertical reserve. */\n get labelRowHeight(): number {\n if (!this.hasLeaderLabels) return 0\n const caption = sizeOf(this.s.label.textStyle) * 1.25\n const percent = sizeOf(this.s.label.percentStyle) * 1.25\n if (this.s.labelMode === \"both\") return caption + percent + 2\n return this.s.labelMode === \"category\" ? caption : percent\n }\n\n /** Widest line in glyphs a leader label for slice `index` runs to. */\n captionGlyphs(index: number): number {\n const mode = this.s.labelMode\n // \"100%\" is the widest a percentage gets; captions are their own length.\n const percent = mode === \"percent\" || mode === \"both\" ? 4 : 0\n const category = mode === \"category\" || mode === \"both\" ? (this.s.slices[index]?.category.length ?? 0) : 0\n return Math.max(percent, category)\n }\n\n /** Room reserved per side for leaders and labels, from the slices that leader out that way. Excludes selection growth, which scales with the radius and is divided out in {@link outerRadius}. */\n get labelGutters(): { left: number; right: number } {\n const gutters = { left: BARE_PAD, right: BARE_PAD }\n if (!this.hasLeaderLabels) return gutters\n const glyph = sizeOf(this.s.label.textStyle) * GLYPH_RATIO\n for (const arc of this.arcs) {\n const room = LEADER_LENGTH + LABEL_STUB + TEXT_INSET + this.captionGlyphs(arc.index) * glyph + LABEL_PAD\n const key = sideOf(arc.mid) > 0 ? \"right\" : \"left\"\n gutters[key] = Math.max(gutters[key], room)\n }\n return gutters\n }\n\n /** Slides the ring into the empty half when labels all fall one way, keeping the ring-plus-labels group centred. */\n get centerX(): number {\n const { left, right } = this.labelGutters\n return (left - right) / 2\n }\n\n /** Fitted to what the gutters leave. The divisor keeps a fully selected slice (`radius * growFactor`) inside the box, and the ring one size whether or not anything is selected. */\n get outerRadius(): number {\n const { left, right } = this.labelGutters\n const room = Math.min((this.box.width - left - right) / 2, this.box.height / 2 - this.labelRowHeight - 4)\n return Math.max(0, room / this.growFactor)\n }\n\n get holeRadius(): number {\n const configured = this.s.ring.holeRadius\n if (configured <= 0) return 0\n const px = configured < 1 ? configured * this.outerRadius : configured\n return Math.min(px, this.outerRadius * 0.95)\n }\n\n /** The circle every leader elbows on, clear of even a popped-out slice. */\n get elbowRadius(): number {\n return this.outerRadius + this.maxPop + LEADER_LENGTH\n }\n\n popOf(index: number): number {\n return clamp(this.s.pops[index] ?? 0, 0, 1)\n }\n\n anchorRadius(index: number): number {\n return this.outerRadius + this.maxPop * this.popOf(index)\n }\n\n /** Halfway across the band on a donut, further out on a solid pie, where halfway would crowd the point the wedges converge on. Rides the slice's pop. */\n bandMidRadius(index: number): number {\n const rim = this.anchorRadius(index)\n const hole = this.holeRadius\n return hole > 0 ? (hole + rim) / 2 : rim * PIE_LABEL_RADIUS\n }\n\n insideAnchor(index: number): Vector2 {\n const arc = this.arcs.find((a) => a.index === index)\n if (arc === undefined) return { x: this.centerX, y: 0 }\n const point = ringPoint(this.bandMidRadius(index), arc.mid)\n return { x: point.x + this.centerX, y: point.y }\n }\n\n /** The most-grown slice, so the dim in {@link sliceOpacity} rides the pops' tween. */\n get selectionStrength(): number {\n let strongest = 0\n for (let i = 0; i < this.s.slices.length; i++) strongest = Math.max(strongest, this.popOf(i))\n return strongest\n }\n\n /** Opacity of slice `index` with its leader and label. */\n sliceOpacity(index: number): number {\n return selectionFade(this.selectionStrength, this.s.dimOpacity, this.popOf(index))\n }\n\n percentText(index: number): string {\n const arc = this.arcs.find((a) => a.index === index)\n return formatPercent(arc?.fraction ?? 0)\n }\n\n /** Labels split into left and right columns by their slice's bisector, each spread so nothing overlaps or leaves the box, then a leader built to each. */\n placements(): LabelPlacement[] {\n if (!this.hasLeaderLabels) return []\n const arcs = this.arcs\n if (arcs.length === 0 || this.outerRadius <= 0) return []\n\n const radius = this.elbowRadius\n const rowHeight = this.labelRowHeight\n const top = this.box.height / 2 - rowHeight / 2\n const bottom = -top\n const cx = this.centerX\n\n interface Slot {\n index: number\n side: 1 | -1\n mid: number\n ideal: number\n y: number\n }\n const right: Slot[] = []\n const left: Slot[] = []\n for (const arc of arcs) {\n const side = sideOf(arc.mid)\n const ideal = ringPoint(radius, arc.mid).y\n ;(side > 0 ? right : left).push({ index: arc.index, side, mid: arc.mid, ideal, y: ideal })\n }\n relaxLabels(right, rowHeight + LABEL_GAP, top, bottom)\n relaxLabels(left, rowHeight + LABEL_GAP, top, bottom)\n\n return [...right, ...left].map((slot) => {\n const start = ringPoint(this.anchorRadius(slot.index) + LEADER_LIFTOFF, slot.mid)\n // The elbow sits where the label's y crosses the leader circle. Solving\n // x^2 + y^2 = radius^2 for x keeps it on that circle (never inside the\n // ring); a label pushed past the circle's top or bottom falls back to the\n // sideways floor so its leader still reads as pointing outward.\n const onCircle = Math.sqrt(Math.max(0, radius * radius - slot.y * slot.y))\n const elbowX = cx + slot.side * Math.max(onCircle, radius * MIN_ELBOW)\n const endX = cx + slot.side * (radius + LABEL_STUB)\n\n return {\n index: slot.index,\n side: slot.side,\n leader: [\n { x: start.x + cx, y: start.y },\n { x: elbowX, y: slot.y },\n { x: endX, y: slot.y },\n ],\n text: { x: endX + slot.side * TEXT_INSET, y: slot.y },\n }\n })\n }\n\n placementFor(index: number): LabelPlacement | undefined {\n return this.placements().find((placement) => placement.index === index)\n }\n}\n\nfunction sideOf(mid: number): 1 | -1 {\n return Math.sin(mid) >= 0 ? 1 : -1\n}\n\nconst NO_BOX = { width: 0, height: 0 }\n\n/** Fills resolved once per paint, not per frame: a theme tween hands over new paint, but a frame that moves nothing must not re-resolve. Keyed by the paint, so it needs no node. */\n/** One label per drawn slice (a zero-valued slice has no wedge), then the hole's summary. Only the choice of form is settled here; the pinned points stay reactive. */\nfunction ringLabels(s: RingState & { readonly labelReveal: number; readonly centerReveal: number }) {\n const blocks: Node2D[] = []\n // A label block's parent is the ring, whose box it was laid out at.\n const geometry = () => new RingGeometry(s, (blocks[0]?.parent as Node2D | null | undefined)?.layoutBounds ?? NO_BOX)\n\n const label = (arc: PieArc): Node2D => {\n const opacity = () => clamp(s.labelReveal, 0, 1) * geometry().sliceOpacity(arc.index)\n const wantsCategory = s.labelMode === \"both\" || s.labelMode === \"category\"\n const wantsPercent = s.labelMode === \"both\" || s.labelMode === \"percent\"\n\n if (s.labelPlacement === \"inside\") {\n // The number leads: inside a wedge the reader knows which slice it is. Sizes are bound because the fitted size derives from a radius unknown until layout.\n const inside: Node2D[] = []\n if (wantsPercent) {\n inside.push(new Text({\n ...textOps.styleProps(s.label.insideStyle),\n text: () => geometry().percentText(arc.index),\n fill: () => onFill(s.slices[arc.index]?.fill ?? \"white\"),\n fontSize: () => geometry().insideFont,\n }))\n }\n if (wantsCategory) {\n inside.push(new Text({\n ...textOps.styleProps(s.label.insideStyle),\n text: () => s.slices[arc.index]?.category ?? \"\",\n fill: () => onFill(s.slices[arc.index]?.fill ?? \"white\"),\n fontSize: () => (s.labelMode === \"category\" ? geometry().insideFont : geometry().insideFont * INSIDE_CAPTION_RATIO),\n }))\n }\n return new Rect({\n flow: \"vertical\",\n width: \"hug\",\n height: \"hug\",\n gap: 0,\n align: \"center\",\n opacity,\n center: () => geometry().insideAnchor(arc.index),\n children: inside,\n })\n }\n\n const side = sideOf(arc.mid)\n const at = () => geometry().placementFor(arc.index)?.text ?? { x: 0, y: 0 }\n const children: Node2D[] = []\n if (wantsCategory) {\n children.push(new Text({\n ...textOps.styleProps(s.label.textStyle),\n text: () => s.slices[arc.index]?.category ?? \"\",\n textAlign: side > 0 ? \"left\" : \"right\",\n }))\n }\n if (wantsPercent) {\n children.push(new Text({\n ...textOps.styleProps(s.label.percentStyle),\n text: () => geometry().percentText(arc.index),\n textAlign: side > 0 ? \"left\" : \"right\",\n }))\n }\n return new Rect({\n flow: \"vertical\",\n width: \"hug\",\n height: \"hug\",\n gap: 2,\n align: side > 0 ? \"centerLeft\" : \"centerRight\",\n opacity,\n centerLeft: side > 0 ? at : undefined,\n centerRight: side > 0 ? undefined : at,\n children,\n })\n }\n\n if (s.labelPlacement !== \"none\" && s.labelMode !== \"none\") {\n for (const arc of pieArcs(s.slices, s.ring.startAngle)) blocks.push(label(arc))\n }\n\n // Pinned to the ring's centre, so it tracks the sideways shift a one-sided label column causes.\n if (s.centerLabel !== \"\" || s.centerCaption !== \"\") {\n const children: Node2D[] = []\n if (s.centerLabel !== \"\") {\n children.push(new Text({\n ...textOps.styleProps(s.centerStyle.labelStyle),\n text: s.centerLabel,\n fontSize: () => geometry().centerFont,\n }))\n }\n if (s.centerCaption !== \"\") {\n children.push(new Text({\n ...textOps.styleProps(s.centerStyle.captionStyle),\n text: s.centerCaption,\n fontSize: () =>\n geometry().centerFont * (sizeOf(s.centerStyle.captionStyle, 22) / sizeOf(s.centerStyle.labelStyle, 46)),\n }))\n }\n blocks.push(new Rect({\n flow: \"vertical\",\n width: \"hug\",\n height: \"hug\",\n gap: 2,\n align: \"center\",\n opacity: () => clamp(s.centerReveal, 0, 1) * clamp(geometry().holeRadius / 20, 0, 1),\n center: () => ({ x: geometry().centerX, y: 0 }),\n children,\n }))\n }\n return asParts(blocks)\n}\n\n/**\n * The ring: one wedge per {@link PieSlice} swept clockwise from `startAngle`,\n * with a constant-width `gap` (see {@link wedgePath}). A selected slice swells\n * out while its hole edge stays put, and the rest dims, leaders and labels\n * included. The only path-drawing part of the chart family; labels are real\n * {@link Text} nodes, so no glyph-width guesswork places a caption. Only the\n * sides that carry a leader reserve a gutter, and the ring slides into the rest.\n */\nexport const PieRing = component2d({\n key: \"pieRing\",\n state: {\n slices: fresh<PieSlice[]>(() => []),\n ring: Types.custom<RingConfig>(DEFAULT_RING),\n label: Types.custom<LabelConfig>(DEFAULT_LABEL),\n // Not `center`: every node already has one, the anchor its position is measured from.\n centerStyle: Types.custom<CenterConfig>(DEFAULT_CENTER),\n labelMode: Types.custom<PieLabelMode>(\"percent\"),\n labelPlacement: Types.custom<PieLabelPlacement>(\"outside\"),\n /** Sweep `[0, 1]`: the wedges grow clockwise from `startAngle` as it rises. */\n growth: 1,\n /** Fade of leaders and labels, separate from `growth` so they arrive after the sweep. */\n labelReveal: 1,\n /** Per-slice pop `[0, 1]`, owned by the chart so the ring and legend read one signal. */\n pops: fresh<number[]>(() => []),\n /** Opacity everything unselected falls back to while any slice is selected. */\n dimOpacity: PIE_SPOTLIGHT_DIM,\n /** Empty leaves the hole clear; ignored when there is no hole. */\n centerLabel: \"\",\n centerCaption: \"\",\n /** The hole's summary fade, untouched by the entrance: a scene that wants the conclusion on a later beat sets 0 and calls `revealCenter`. */\n centerReveal: 1,\n },\n // A plain node filled its parent; one made of its labels would hug them.\n defaults: { width: \"fill\", height: \"fill\" },\n children: (state) => ringLabels(state),\n // The paints sit past the paint entries: a fill per slice, the wedge outline and shadow, and the leader stroke.\n load: (loader, state) =>\n loadPaints(loader, {\n fills: ringFills(state.slices),\n strokes: [strokeOps.resolve(state.label.leaderStroke)],\n }),\n commands: {\n /** Wipe the wedges in around the ring (`growth` 0 to 1). */\n sweep: (timeline) => {\n const ease = frameEase(timeline)\n return timeline.animate((t) => ({ growth: ease(t) }))\n },\n /** Fade the leaders and captions up. */\n revealLabels: (timeline) => {\n const ease = frameEase(timeline)\n return timeline.animate((t) => ({ labelReveal: ease(t) }))\n },\n /** Fade the hole's summary up; not part of the entrance, since it is usually the conclusion. */\n revealCenter: (timeline, state) => {\n const ease = frameEase(timeline)\n const from = clamp(state.centerReveal, 0, 1)\n return timeline.animate((t) => ({ centerReveal: from + (1 - from) * ease(t) }))\n },\n },\n render: (ctx, state) => {\n const g = new RingGeometry(state, ctx.size)\n const rOuter = g.outerRadius\n const arcs = rOuter > 0 ? g.arcs : []\n if (arcs.length > 0) {\n const sweep = clamp(state.growth, 0, 1)\n const revealEnd = state.ring.startAngle * (Math.PI / 180) + Math.PI * 2 * sweep\n const hole = g.holeRadius\n const halfGap = Math.max(0, state.ring.gap) / 2\n\n // One shared frame (the whole ring square, grown slices included) pinned onto\n // every wedge path, so `Graphics2D.path()` doesn't re-centre each wedge on its\n // own bbox and collapse them all onto the origin. It stays symmetric about the\n // node's origin, so path coordinates land exactly in node space, and is grown\n // by the ring's sideways offset rather than moved with it, which would undo\n // the very shift it has to contain.\n const cx = g.centerX\n const half = rOuter + g.maxPop + 1 + Math.abs(cx)\n const centerBounds: [number, number, number, number] = [-half, -half, half, half]\n // Explicit width/height alongside centerBounds: a wedge path's command list\n // carries no implied extent, so a slice filled with an image or a video needs\n // this to size its decode.\n const span = half * 2\n\n const fills = ringFills(state.slices)\n for (const arc of arcs) {\n // Clipped to the revealed arc, so the ring draws in as one clockwise wipe.\n const a1 = Math.min(arc.a1, revealEnd)\n if (a1 <= arc.a0) continue\n\n const path = wedgePath(arc.a0, a1, hole, g.anchorRadius(arc.index), halfGap, Math.max(0, state.ring.cornerRadius), cx)\n const wedge = new Graphics2D().path(path.toPathState({ centerBounds, width: span, height: span }))\n wedge.fill(fills[arc.index] ?? [])\n ctx.draw(wedge.opacity(g.sliceOpacity(arc.index)))\n }\n\n // One `Graphics2D` per leader: open polylines chained into one command list\n // are combined into a single surface before the stroke, which closes each\n // contour and paints the leaders as thin triangles.\n const reveal = clamp(state.labelReveal, 0, 1)\n if (reveal > 0.001) {\n for (const placement of g.placements()) {\n ctx.draw(\n new Graphics2D()\n .line({ points: placement.leader, radius: ELBOW_RADIUS })\n .stroke(state.label.leaderStroke)\n .opacity(reveal * g.sliceOpacity(placement.index))\n )\n }\n }\n }\n ctx.children()\n },\n})\n\nexport type PieRing = NodeOf<typeof PieRing>\n", "import { Types, type Fill, type TextStyle, type Stroke, type FillResolved as _FillResolved } from \"@motionscript/sdk\"\n\nimport {\n CHART_BACKGROUND,\n CHART_FOREGROUND,\n CHART_LEGEND,\n CHART_MUTED,\n CHART_SERIES,\n LEGEND_TEXT,\n legendConfigOf,\n placedText,\n sizeOf,\n type ChartStyleBase,\n} from \"../kit/style\"\nimport { num, text, type LegendConfig } from \"../kit/shared\"\nimport { DEG, PIE_SPOTLIGHT_DIM, ringPoint, selectionFade, type CenterConfig, type PieSlice } from \"../kit/polar\"\n\nexport { DEG, PIE_SPOTLIGHT_DIM, ringPoint, selectionFade, type CenterConfig, type PieSlice }\n\n/**\n * One slice per row, painted from `seriesFills` by row order (cycling). Paint comes\n * from the palette, not the rows, because a pie's mark is a row where a line's\n * colour belongs to a column; that lets a pie be fed a CSV of plain numbers.\n */\nexport function resolvePieSlices(data: readonly Record<string, unknown>[], category: string, value: string, palette: readonly Fill[]): PieSlice[] {\n return data.map((row, i) => ({\n category: text(row as never, category),\n value: num(row as never, value),\n fill: palette.length > 0 ? palette[i % palette.length] : (\"white\" as Fill),\n }))\n}\n\n/** What a {@link PieChart}'s labels say. */\nexport type PieLabelMode =\n /** Two lines, whose order flips with placement: an outside label reads category over percentage, an inside label reads the percentage big over a small category. */\n | \"both\"\n | \"category\"\n | \"percent\"\n /** No labels and no leader lines. */\n | \"none\"\n\n/** `\"inside\"` centres the label in the wedge's band with no leader or gutter, so the ring draws bigger; `\"outside\"` sets it on a leader, which a sliver too narrow for text needs. */\nexport type PieLabelPlacement = \"inside\" | \"outside\" | \"none\"\n\n\n/** A slice's plotted value: negatives and non-finite values count as 0. */\nexport function sliceValue(slice: PieSlice): number {\n return slice.value > 0 && Number.isFinite(slice.value) ? slice.value : 0\n}\n\n/** Sum of every slice's plotted value, the denominator of every share. */\nexport function sliceTotal(slices: PieSlice[]): number {\n let sum = 0\n for (const slice of slices) sum += sliceValue(slice)\n return sum\n}\n\n/** One slice's resolved angular span on the ring. */\nexport interface PieArc {\n /** Index of the slice in the source list. */\n index: number\n /** Radians clockwise from 12 o'clock. */\n a0: number\n a1: number\n /** Where the slice's label and pop-out point. */\n mid: number\n /** Share of the total, `[0, 1]`. */\n fraction: number\n}\n\n/**\n * One arc per positive slice, walking clockwise from `startDegrees` and abutting.\n * Arcs are the undivided shares: a fixed angular gap would pinch shut at the\n * hole, so the gap is applied when the wedge is drawn, as a constant-width inset\n * off both ends.\n */\nexport function pieArcs(slices: PieSlice[], startDegrees: number): PieArc[] {\n const total = sliceTotal(slices)\n if (total <= 0) return []\n\n const arcs: PieArc[] = []\n let cursor = startDegrees * DEG\n slices.forEach((slice, index) => {\n const value = sliceValue(slice)\n if (value <= 0) return\n const fraction = value / total\n const a0 = cursor\n const a1 = a0 + fraction * Math.PI * 2\n cursor = a1\n arcs.push({ index, a0, a1, mid: (a0 + a1) / 2, fraction })\n })\n return arcs\n}\n\ninterface LabelSlot {\n /** Where the label would sit if nothing else were in the way. */\n ideal: number\n /** Written by {@link relaxLabels}. */\n y: number\n}\n\n/**\n * Spread one column of labels so none overlap, each near its `ideal` y and all\n * inside `[bottom, top]`. A top-down pass clears each label from the one above\n * by `minGap`; a reverse pass lifts a tail pushed past `bottom`. When the column\n * cannot hold them all, the reverse pass wins and the crowding is shared evenly.\n * Mutates each `y` and returns `slots` ordered top to bottom.\n */\nexport function relaxLabels<T extends LabelSlot>(slots: T[], minGap: number, top: number, bottom: number): T[] {\n slots.sort((a, b) => b.ideal - a.ideal)\n\n let ceiling = top\n for (const slot of slots) {\n slot.y = Math.min(slot.ideal, ceiling)\n ceiling = slot.y - minGap\n }\n\n let floor = bottom\n for (let i = slots.length - 1; i >= 0; i--) {\n slots[i].y = Math.max(slots[i].y, floor)\n floor = slots[i].y + minGap\n }\n\n return slots\n}\n\n/** The ring's geometry: everything about the wedges but their colour. */\nexport interface RingConfig {\n /** Channel between adjacent slices in px, constant across the band (an angular gap would splay open toward the rim). */\n gap: number\n /** Below 1 a fraction of the outer radius (`0.6` leaves a band 40% thick); 1 and up a pixel radius; `0` draws solid wedges. */\n holeRadius: number\n /** Degrees clockwise from 12 o'clock where the first slice begins. */\n startAngle: number\n /** How far a selected slice's rim reaches, as a multiple of the outer radius so the emphasis scales with the chart. Clamped to `[1, 1.6]`. */\n selectedGrow: number\n /** Rounding of each wedge corner, px. */\n cornerRadius: number\n}\n\n/** How the ring's labels are set, and the leader lines that point at them. */\nexport interface LabelConfig {\n /** The category caption outside the ring. */\n textStyle: TextStyle\n /** The percentage outside the ring. */\n percentStyle: TextStyle\n /** Both lines of a label inside its wedge; its fill is set per wedge, for contrast against the paint. */\n insideStyle: TextStyle\n /** Runs from a wedge out to its label. */\n leaderStroke: Stroke\n}\n\n/** What a pie's `style` resolves to. */\nexport interface PieStyle extends ChartStyleBase {\n readonly labelText: TextStyle\n readonly valueText: TextStyle\n readonly centerText: TextStyle\n readonly innerRadius: number\n readonly sliceGap: number\n readonly sliceRadius: number\n readonly labelPlacement: PieLabelPlacement\n}\n\n/** The groups of a pie's `style`: no grid, as nothing is ruled. */\nexport const PIE_STYLE_GROUPS = {\n series: CHART_SERIES,\n background: CHART_BACKGROUND,\n text: {\n /** Each slice's name. */\n labelText: Types.typography({ fontSize: 28, fontWeight: 500, fill: CHART_MUTED }),\n /** Each slice's share or value, beside its name; inside a wedge both are set larger, inked for contrast. */\n valueText: Types.typography({ fontSize: 28, fontWeight: 700, fill: CHART_FOREGROUND }),\n /** The summary in the hole; its caption is set smaller, in the slice names' ink. */\n centerText: Types.typography({ fontSize: 50, fontWeight: 800, fill: CHART_FOREGROUND }),\n ...LEGEND_TEXT,\n },\n marks: {\n /** Hole radius as a fraction of the outer radius: 0 is a pie, about 0.6 a donut. */\n innerRadius: Types.number(0, { min: 0, max: 0.9, step: 0.05 }),\n /** Channel between neighbouring wedges, px. */\n sliceGap: Types.number(3, { min: 0, max: 40, step: 1, unit: \"px\" }),\n /** Rounding of each wedge corner, px. */\n sliceRadius: Types.number(4, { min: 0, max: 60, step: 1, unit: \"px\" }),\n },\n labels: {\n /** Read as the chart is built: inside the wedge, outside on a leader, or none. */\n labelPlacement: Types.oneOf([\"inside\", \"outside\", \"none\"] as const, { animatable: false }),\n },\n legend: CHART_LEGEND,\n}\n\nexport function legendOf(style: PieStyle): LegendConfig {\n return legendConfigOf(style)\n}\n\nexport function ringConfigOf(style: PieStyle): RingConfig {\n return { gap: style.sliceGap, holeRadius: style.innerRadius, startAngle: 0, selectedGrow: 1.08, cornerRadius: style.sliceRadius }\n}\n\nexport function labelConfigOf(style: PieStyle): LabelConfig {\n const base = placedText(style.labelText)\n const value = placedText(style.valueText)\n return {\n textStyle: base,\n percentStyle: value,\n insideStyle: { ...value, fontSize: Math.round(sizeOf(style.valueText) * 1.9), fill: \"#111113\" },\n leaderStroke: { weight: 2, fill: style.labelText.fill ?? \"white\" },\n }\n}\n\nexport function centerConfigOf(style: PieStyle): CenterConfig {\n const size = sizeOf(style.centerText, 50)\n return {\n labelStyle: placedText(style.centerText),\n captionStyle: placedText(style.labelText, \"center\", { fontSize: Math.round(size * 0.45) }),\n }\n}\n", "import {\n Rect,\n Text,\n Types,\n component2d,\n easeOut,\n type ChildView,\n type DataRecord,\n type NodeOf,\n // Named so this component's emitted type reaches `Node2D` and its props through the sdk, not core.\n type Node2D,\n type Node2DProps as _Node2DProps,\n type TextStyle as _TextStyle,\n type Fill as _Fill,\n type FillResolved as _FillResolved,\n type Stroke as _Stroke,\n type StrokeResolved as _StrokeResolved,\n type Size2D,\n type Vector2,\n} from \"@motionscript/sdk\"\n\nimport { boundText, laidOutSize } from \"../kit/cartesian\"\nimport { ChartLegend } from \"../kit/chart-legend\"\nimport { SERIES_ARG, asParts, fresh } from \"../kit/entries\"\nimport { ENTER_SHARE, LEGEND_SLIDE, beats, type AnyTimeline, type Beat } from \"../kit/motion\"\nimport { SPOTLIGHT_DIM, type ChartSeries } from \"../kit/shared\"\nimport {\n CHART_LEGEND,\n CHART_SERIES,\n CHART_STYLE_FAMILY,\n CHART_STYLE_PRESETS,\n GRID_BACKGROUND,\n legendConfigOf,\n migrateChartStyle,\n placedText,\n seriesFill,\n sizeOf,\n} from \"../kit/style\"\nimport { RadarGrid } from \"./radar-grid\"\nimport { RadarSeries } from \"./radar-series\"\nimport {\n RADAR_GRID,\n RADAR_TEXT,\n RADAR_MARKS,\n categoriesOf,\n fitRadius,\n fractionOf,\n labelAnchor,\n labelPoint,\n scaleOf,\n valuesOf,\n} from \"./shared\"\n\n/** What a radar chart plots, as its entries hold it. */\nexport interface RadarValues {\n readonly data: DataRecord[]\n readonly categoryField: string\n readonly series: ChartSeries[]\n readonly min: number\n readonly max: number\n}\n\n/** The scale the web is drawn to, whether `max` was given or left to the data. */\nexport function radarScale(state: RadarValues): { min: number; max: number } {\n return scaleOf(valuesOf(state.data, state.series), state.min, state.max)\n}\n\n/** Series `index`'s values as fractions of the rim, in spoke order. */\nexport function radarFractions(state: RadarValues, index: number): number[] {\n const series = state.series[index]\n if (!series) return []\n const scale = radarScale(state)\n return state.data.map((row) => {\n const v = row[series.field]\n return fractionOf(typeof v === \"number\" && Number.isFinite(v) ? v : 0, scale)\n })\n}\n\n/** The grid, series, label layer and legend among the children; the last row holding a grid is the one the chart built. */\nfunction partsOf(children: readonly ChildView[]) {\n for (let i = children.length - 1; i >= 0; i--) {\n const row = children[i]\n if (!Rect.is(row)) continue\n const plot = row.children.find((part) => Rect.is(part) && part.children.some(RadarGrid.is))\n if (!plot) continue\n return {\n grid: plot.children.find(RadarGrid.is)!,\n series: plot.children.filter(RadarSeries.is),\n labels: plot.children.find(Rect.is) ?? null,\n legend: row.children.find(ChartLegend.is) ?? null,\n }\n }\n return null\n}\n\nfunction toggling(timeline: AnyTimeline, children: readonly ChildView[], index: number, show: boolean) {\n const parts = partsOf(children)\n const series = parts?.series[index]\n if (!parts || !series) return timeline.wait(timeline.duration)\n return timeline.together([\n series.run(\"enter\", show ? { from: 0, to: 1 } : { from: 1, to: 0 }),\n ...(parts.legend ? [parts.legend.run(show ? \"showSeries\" : \"hideSeries\", { index })] : []),\n ])\n}\n\n/** The share of one series' growth that passes before the next starts. */\nconst STAGGER = 0.3\n\n/**\n * A radar (spider) chart: one spoke per data row, one closed polygon per\n * series, over a web of rings. Composed of a {@link RadarGrid}, a\n * {@link RadarSeries} per series, the category labels and a {@link ChartLegend}.\n *\n * Resting state is the finished chart; `enter` arms every part on its first\n * frame. `max` of 0 (or one not above `min`) is the largest value rounded up.\n */\nexport const RadarChart = component2d({\n key: \"radarChart\",\n state: {\n data: fresh<DataRecord[]>(() => [], { kind: \"dataset\" }),\n /** The column that names each spoke. */\n categoryField: \"\",\n series: fresh<ChartSeries[]>(() => [], { kind: \"series\" }),\n /** The value at the centre of the web. */\n min: 0,\n /** The value at the rim; 0 rounds the largest value up. */\n max: 0,\n style: Types.style(\n CHART_STYLE_FAMILY,\n {\n series: CHART_SERIES,\n background: GRID_BACKGROUND,\n text: RADAR_TEXT,\n grid: RADAR_GRID,\n marks: RADAR_MARKS,\n legend: CHART_LEGEND,\n },\n { presets: CHART_STYLE_PRESETS }\n ),\n },\n // A node made of parts that fill would otherwise hug them.\n defaults: { width: \"fill\", height: \"fill\" },\n migrate: { style: migrateChartStyle(\"radar\") },\n allowedChildren: [],\n children: (state) => {\n const style = () => state.style\n let plot: Node2D | undefined\n const plotSize = (): Size2D => laidOutSize(plot)\n const radius = () => fitRadius(plotSize(), categoriesOf(state.data, state.categoryField), sizeOf(style().spokeText), style().spokeLabels)\n const count = state.data.length\n const enabled = state.series.map((s) => s.enabled ?? true)\n\n const grid = new RadarGrid({\n count: () => state.data.length,\n radius,\n levels: () => style().gridLevels,\n fill: () => style().gridBackground,\n shape: () => style().gridShape,\n stroke: () => style().gridStroke,\n spokeStroke: () => style().spokeStroke,\n }) as unknown as Node2D\n\n const series = state.series.map(\n (s, i) =>\n new RadarSeries({\n fractions: () => radarFractions(state, i),\n radius,\n fill: () => seriesFill(style(), s, i),\n stroke: () => {\n const weight = style().strokeWidth\n return weight > 0 ? { weight, fill: seriesFill(style(), s, i), align: \"center\", join: \"round\" } : []\n },\n areaOpacity: () => style().areaOpacity,\n dots: () => style().dots,\n dotSize: () => style().dotSize,\n enabled: enabled[i],\n }) as unknown as Node2D\n )\n\n const parts: Node2D[] = [grid, ...series]\n\n if (state.style.spokeLabels) {\n const labels: Node2D[] = []\n for (let i = 0; i < count; i++) {\n const anchor = labelAnchor(i, count)\n const align = anchor === \"centerLeft\" ? \"left\" : anchor === \"centerRight\" ? \"right\" : \"center\"\n const at = (): Vector2 => labelPoint(i, count, radius(), sizeOf(style().spokeText))\n labels.push(\n new Text({\n ...boundText(() => placedText(style().spokeText, align)),\n text: () => categoriesOf(state.data, state.categoryField)[i] ?? \"\",\n [anchor]: at,\n }) as unknown as Node2D\n )\n }\n parts.push(new Rect({ width: \"fill\", height: \"fill\", children: labels }) as unknown as Node2D)\n }\n\n plot = new Rect({ width: \"fill\", height: \"fill\", children: parts }) as unknown as Node2D\n\n const row: Node2D[] = [plot]\n const position = state.style.legend\n if (position !== \"none\") {\n const side = position === \"right\"\n const config = legendConfigOf(state.style)\n const legend = new ChartLegend({\n series: state.series,\n swatches: () => state.series.map((s, i) => seriesFill(style(), s, i)),\n legend: () => legendConfigOf(style()),\n flow: side ? \"vertical\" : \"horizontal\",\n // Spacing is fixed as built; a style tween re-paints the swatches and captions only.\n gap: side ? Math.round(config.itemGap / 2) : config.itemGap,\n padding: config.padding,\n }) as unknown as Node2D\n if (position === \"top\") row.unshift(legend)\n else row.push(legend)\n }\n\n const frame = new Rect({\n flow: position === \"right\" ? \"horizontal\" : \"vertical\",\n width: \"fill\",\n height: \"fill\",\n gap: 24,\n align: \"center\",\n fill: () => style().background,\n children: row,\n })\n return asParts([frame as unknown as Node2D])\n },\n commands: {\n /** The web grows out, the polygons grow from the centre one series after another, then the labels and legend come up. */\n enter: {\n args: {},\n // Held from arrival, so it never shows finished ahead of its draw.\n entrance: true,\n easing: easeOut(),\n run: (timeline, _state, children) => {\n const parts = partsOf(children)\n if (!parts) return timeline.wait(timeline.duration)\n const duration = timeline.duration\n const web = duration * ENTER_SHARE.axes\n const marks = duration * ENTER_SHARE.marks\n const last = duration * ENTER_SHARE.legend\n const n = Math.max(1, parts.series.length)\n const each = marks / (1 + STAGGER * (n - 1))\n const { legend, labels } = parts\n const at0 = (piece: Beat[\"piece\"]): Beat => ({ at: 0, duration: 0, piece })\n // The first frame arms what every later beat moves: a beat ahead of the playhead writes nothing.\n return beats(timeline, [\n at0(parts.grid.to({ reveal: 0 })),\n ...parts.series.map((s) => at0(s.to({ progress: 0 }))),\n ...(labels ? [at0(labels.to({ opacity: 0 }))] : []),\n ...(legend ? [at0(legend.to({ opacity: 0, y: -LEGEND_SLIDE }))] : []),\n { at: 0, duration: web, piece: parts.grid.to({ reveal: 1 }) },\n ...parts.series.map((s, i) => ({ at: web + i * each * STAGGER, duration: each, piece: s.to({ progress: 1 }) })),\n ...(labels ? [{ at: web + marks * 0.6, duration: last + marks * 0.4, piece: labels.to({ opacity: 1 }) }] : []),\n ...(legend ? [{ at: web + marks, duration: last, piece: legend.to({ opacity: 1, y: 0 }) }] : []),\n ])\n },\n },\n /** Grow series `index`'s polygon back out of the centre, with its legend entry growing in. */\n showSeries: {\n args: { seriesIndex: SERIES_ARG },\n easing: easeOut(),\n run: (timeline, _state, children) => toggling(timeline, children, timeline.args.seriesIndex, true),\n },\n /** Shrink series `index`'s polygon into the centre as its legend entry shrinks away. */\n hideSeries: {\n args: { seriesIndex: SERIES_ARG },\n easing: easeOut(),\n run: (timeline, _state, children) => toggling(timeline, children, timeline.args.seriesIndex, false),\n },\n /** Fade every other series, polygon and legend entry, to focus on `index`. The legend dims in place, so the row does not reflow. */\n spotlightSeries: {\n args: { seriesIndex: SERIES_ARG },\n easing: easeOut(),\n run: (timeline, _state, children) => {\n const parts = partsOf(children)\n if (!parts) return timeline.wait(timeline.duration)\n const index = timeline.args.seriesIndex\n return timeline.together([\n ...parts.series.map((s, i) => s.to({ opacity: i === index ? 1 : SPOTLIGHT_DIM })),\n ...(parts.legend ? [parts.legend.run(\"spotlightSeries\", { index })] : []),\n ])\n },\n },\n },\n})\n\nexport type RadarChart = NodeOf<typeof RadarChart>\n", "import {\n Graphics2D,\n Types,\n clamp,\n component2d,\n fillOps,\n strokeOps,\n type Fill,\n type FillResolved,\n type NodeOf,\n // Named so this component's emitted type reaches `Node2D` and its props through the sdk, not core.\n type Node2D as _Node2D,\n type Node2DProps as _Node2DProps,\n type Stroke,\n type StrokeResolved,\n type Vector2,\n} from \"@motionscript/sdk\"\n\nimport { loadPaints } from \"../kit/paints\"\nimport { spokeDirection, type GridShape } from \"./shared\"\n\n/**\n * The web of a {@link RadarChart}: `levels` rings and, if asked, a spoke to each\n * of `count` categories, drawn from the node's centre out to `radius`. `reveal`\n * grows the web from nothing.\n */\nexport const RadarGrid = component2d({\n key: \"radarGrid\",\n state: {\n count: 0,\n /** The rim, in px. */\n radius: 0,\n levels: 4,\n /** Inside the outer ring, under the rings and spokes; empty paints nothing. */\n fill: Types.custom<Fill, FillResolved[]>([], { resolve: fillOps.resolve, lerp: fillOps.lerp }),\n shape: Types.custom<GridShape>(\"polygon\"),\n stroke: Types.custom<Stroke, StrokeResolved[]>([], { resolve: strokeOps.resolve, lerp: strokeOps.lerp }),\n /** The line out to each category; empty draws none. */\n spokeStroke: Types.custom<Stroke, StrokeResolved[]>([], { resolve: strokeOps.resolve, lerp: strokeOps.lerp }),\n /** How far the web has grown out, `0`-`1`. Rests at 1 so a paused canvas paints it. */\n reveal: 1,\n },\n defaults: { width: \"fill\", height: \"fill\" },\n load: (loader, state) => loadPaints(loader, { fills: [state.fill], strokes: [state.stroke, state.spokeStroke] }),\n render: (ctx, state) => {\n const grow = clamp(state.reveal, 0, 1)\n const rim = state.radius * grow\n if (rim <= 0 || grow <= 0) return\n const count = Math.max(0, Math.round(state.count))\n const levels = Math.max(1, Math.round(state.levels))\n const round = state.shape === \"circle\" || count < 3\n const outline = (g: Graphics2D, r: number): Graphics2D => {\n if (round) return g.ellipse({ width: r * 2, height: r * 2 })\n const points: Vector2[] = []\n for (let i = 0; i < count; i++) {\n const d = spokeDirection(i, count)\n points.push({ x: d.x * r, y: d.y * r })\n }\n return g.line({ points, closed: true })\n }\n\n if (state.fill.length > 0) ctx.draw(outline(new Graphics2D(), rim).fill(state.fill).opacity(grow))\n\n // One draw per ring: rings chained into one surface would stroke only their union's outline.\n for (let level = 1; state.stroke.length > 0 && level <= levels; level++) {\n const r = (rim * level) / levels\n ctx.draw(outline(new Graphics2D(), r).stroke(state.stroke).opacity(grow))\n }\n\n if (state.spokeStroke.length === 0) return\n for (let i = 0; i < count; i++) {\n const d = spokeDirection(i, count)\n ctx.draw(\n new Graphics2D()\n .line({ points: [{ x: 0, y: 0 }, { x: d.x * rim, y: d.y * rim }] })\n .stroke(state.spokeStroke)\n .opacity(grow)\n )\n }\n },\n})\n\nexport type RadarGrid = NodeOf<typeof RadarGrid>\n", "import { Types, type TextStyle, type DataRecord, type Size2D, type StrokeResolved, type Stroke as _Stroke, type Vector2 } from \"@motionscript/sdk\"\n\nimport { num, text, type ChartSeries } from \"../kit/shared\"\nimport { CHART_MUTED, LEGEND_TEXT } from \"../kit/style\"\n\n/** The radar chart's text: the category names around the rim, and the legend. */\nexport const RADAR_TEXT = {\n spokeText: Types.typography({ fontSize: 28, fontWeight: 500, fill: CHART_MUTED }),\n ...LEGEND_TEXT,\n}\n\nexport type GridShape = \"polygon\" | \"circle\"\n\n/** The radar chart's own grid group: the web the polygons are drawn over. */\nexport const RADAR_GRID = {\n /** Whether the rings are straight-edged (a polygon through the spokes) or round. */\n gridShape: Types.oneOf([\"polygon\", \"circle\"] as const),\n /** How many rings, outermost at the scale's maximum. */\n gridLevels: Types.number(4, { min: 1, max: 10, step: 1 }),\n /** The rings; empty draws none. */\n gridStroke: Types.stroke({ weight: 2, fill: \"white/15\" }),\n /** The line from the centre out to each category; empty draws none. */\n spokeStroke: Types.stroke({ weight: 2, fill: \"white/15\" }),\n /** Read as the chart is built: whether the category names stand around the rim. */\n spokeLabels: Types.boolean(true, { animatable: false }),\n}\n\nexport const RADAR_MARKS = {\n /** Outline weight of each series' polygon. */\n strokeWidth: Types.number(4, { min: 0, max: 24, step: 1, unit: \"px\" }),\n /** How strongly each polygon is filled in its series colour; 0 leaves an outline. */\n areaOpacity: Types.number(0.25, { min: 0, max: 1, step: 0.05 }),\n /** Whether a dot marks each value on its spoke. */\n dots: Types.boolean(true),\n dotSize: Types.number(10, { min: 2, max: 40, step: 1, unit: \"px\" }),\n}\n\n/** The grid and marks fields the parts read, whichever way the chart's style is spelled. */\nexport interface RadarStyle {\n readonly gridShape: GridShape\n readonly gridLevels: number\n readonly gridStroke: StrokeResolved[]\n readonly spokeStroke: StrokeResolved[]\n readonly spokeLabels: boolean\n readonly strokeWidth: number\n readonly areaOpacity: number\n readonly dots: boolean\n readonly dotSize: number\n readonly spokeText: TextStyle\n}\n\n/** Fraction of the label's font size between the rim and the label. */\nconst LABEL_PAD = 0.55\n/** Glyph width as a fraction of the font size, for fitting labels. */\nconst GLYPH = 0.58\n/** Room kept clear around the web when nothing else claims it, in px. */\nconst MARGIN = 10\n/** Below this a spoke counts as vertical, and its label centres over it. */\nconst SIDE = 0.35\n\n/** Spoke `index` of `count`, as a unit direction: 12 o'clock first, clockwise on screen, y up. */\nexport function spokeDirection(index: number, count: number): Vector2 {\n const angle = (index / Math.max(1, count)) * Math.PI * 2\n return { x: Math.sin(angle), y: Math.cos(angle) }\n}\n\n/** One category per data row. */\nexport function categoriesOf(data: readonly DataRecord[], field: string): string[] {\n return data.map((row) => text(row, field))\n}\n\n/** One list of values per series, a value per row. */\nexport function valuesOf(data: readonly DataRecord[], series: readonly ChartSeries[]): number[][] {\n return series.map((s) => data.map((row) => num(row, s.field)))\n}\n\nconst MANTISSAS = [1, 1.2, 1.5, 2, 2.5, 3, 4, 5, 6, 8, 10]\n\n/** `value` rounded up to a tidy 1, 1.5, 2, 2.5, 3, 4, 5, 6, 8 times a power of ten. */\nexport function niceCeil(value: number): number {\n if (!(value > 0)) return 1\n const power = 10 ** Math.floor(Math.log10(value))\n const mantissa = value / power\n const pick = MANTISSAS.find((m) => m >= mantissa - 1e-9) ?? 10\n return pick * power\n}\n\n/**\n * The scale the web is drawn to: `min` (default 0) to `max`, which when unset\n * (or not above `min`) is the largest value rounded up tidily.\n */\nexport function scaleOf(values: readonly (readonly number[])[], min: number, max: number): { min: number; max: number } {\n if (max > min) return { min, max }\n let top = min\n for (const list of values) for (const v of list) top = Math.max(top, v)\n const span = niceCeil(top - min)\n return { min, max: min + span }\n}\n\n/** Where `value` stands between the scale's ends, `0`-`1`. */\nexport function fractionOf(value: number, scale: { min: number; max: number }): number {\n const span = scale.max - scale.min\n if (span <= 0) return 0\n return Math.min(1, Math.max(0, (value - scale.min) / span))\n}\n\nexport type LabelAnchor = \"centerLeft\" | \"centerRight\" | \"bottomCenter\" | \"topCenter\"\n\n/** Which corner of a category's label touches the point beside its spoke's end. */\nexport function labelAnchor(index: number, count: number): LabelAnchor {\n const { x, y } = spokeDirection(index, count)\n if (x > SIDE) return \"centerLeft\"\n if (x < -SIDE) return \"centerRight\"\n return y >= 0 ? \"bottomCenter\" : \"topCenter\"\n}\n\nexport function labelPad(fontSize: number): number {\n return fontSize * LABEL_PAD\n}\n\n/** Rough size of a label, since the web is fitted before any text is measured. */\nexport function labelSize(caption: string, fontSize: number): Size2D {\n return { width: caption.length * fontSize * GLYPH, height: fontSize * 1.25 }\n}\n\n/**\n * The rim's radius for a box: the largest the web can be with every label\n * (when there are labels) still inside it.\n */\nexport function fitRadius(box: Size2D, categories: readonly string[], fontSize: number, labelled: boolean): number {\n let radius = Math.min(box.width, box.height) / 2 - MARGIN\n if (!labelled) return Math.max(0, radius)\n const pad = labelPad(fontSize)\n const count = categories.length\n categories.forEach((caption, i) => {\n const { x, y } = spokeDirection(i, count)\n const size = labelSize(caption, fontSize)\n const side = labelAnchor(i, count)\n // How much of the label hangs past its anchor point on each axis.\n const reachX = side === \"centerLeft\" || side === \"centerRight\" ? size.width : size.width / 2\n const reachY = side === \"bottomCenter\" || side === \"topCenter\" ? size.height : size.height / 2\n if (Math.abs(x) > 1e-6) radius = Math.min(radius, (box.width / 2 - reachX - MARGIN / 2) / Math.abs(x) - pad)\n if (Math.abs(y) > 1e-6) radius = Math.min(radius, (box.height / 2 - reachY - MARGIN / 2) / Math.abs(y) - pad)\n })\n return Math.max(0, radius)\n}\n\n/** Where spoke `index`'s label is pinned: just past the rim, centre-relative, y up. */\nexport function labelPoint(index: number, count: number, radius: number, fontSize: number): Vector2 {\n const { x, y } = spokeDirection(index, count)\n const r = radius + labelPad(fontSize)\n return { x: x * r, y: y * r }\n}\n", "import {\n Graphics2D,\n Types,\n clamp,\n component2d,\n fillOps,\n strokeOps,\n type Fill,\n type FillResolved,\n type NodeOf,\n // Named so this component's emitted type reaches `Node2D` and its props through the sdk, not core.\n type Node2D as _Node2D,\n type Node2DProps as _Node2DProps,\n type Stroke,\n type StrokeResolved,\n type Vector2,\n} from \"@motionscript/sdk\"\n\nimport { fresh } from \"../kit/entries\"\nimport { frameEase } from \"../kit/motion\"\nimport { loadPaints } from \"../kit/paints\"\nimport { spokeDirection } from \"./shared\"\n\n/** The vertices of a series' polygon: spoke `i` at `fractions[i]` of the rim, scaled by `grow` about the centre. */\nexport function seriesVertices(fractions: readonly number[], radius: number, grow = 1): Vector2[] {\n return fractions.map((f, i) => {\n const d = spokeDirection(i, fractions.length)\n const r = radius * f * grow\n return { x: d.x * r, y: d.y * r }\n })\n}\n\n/** One series of a {@link RadarChart}: a closed polygon through its values, washed in its colour, with a dot on each vertex. `progress` grows it out of the centre. */\nexport const RadarSeries = component2d({\n key: \"radarSeries\",\n state: {\n /** Each spoke's value as a fraction of the rim, `0`-`1`, in spoke order. */\n fractions: fresh<number[]>(() => []),\n /** The rim, in px. */\n radius: 0,\n fill: Types.custom<Fill, FillResolved[]>([], { resolve: fillOps.resolve, lerp: fillOps.lerp }),\n stroke: Types.custom<Stroke, StrokeResolved[]>([], { resolve: strokeOps.resolve, lerp: strokeOps.lerp }),\n areaOpacity: 0.25,\n dots: true,\n dotSize: 10,\n /** Growth out of the centre, `0`-`1`. Rests at 1 so a paused canvas paints it; `enter` drives it from 0. */\n progress: 1,\n /** Whether the series is drawn at all, flipped alongside its legend entry. */\n enabled: true,\n },\n defaults: { width: \"fill\", height: \"fill\" },\n load: (loader, state) => loadPaints(loader, { fills: [state.fill], strokes: [state.stroke] }),\n commands: {\n /** Grow the polygon from `from` to `to` (of its full size); `showSeries`/`hideSeries` are this with the ends stated. */\n enter: {\n args: { from: Types.number(0, { min: 0, max: 1 }), to: Types.number(1, { min: 0, max: 1 }) },\n run: (timeline) => {\n const { from, to } = timeline.args\n const ease = frameEase(timeline)\n return timeline.animate((t) => {\n const progress = from + (to - from) * ease(t)\n // Hidden only once fully shrunk, so a hide does not vanish a frame early.\n return { progress, enabled: progress > 0 }\n })\n },\n },\n },\n render: (ctx, state) => {\n if (!state.enabled) return\n const grow = clamp(state.progress, 0, 1)\n if (grow <= 0 || state.radius <= 0 || state.fractions.length === 0) return\n const points = seriesVertices(state.fractions, state.radius, grow)\n\n if (points.length >= 2) {\n const fill = new Graphics2D().line({ points, closed: true })\n if (state.areaOpacity > 0 && state.fill.length > 0) ctx.draw(fill.fill(state.fill).opacity(clamp(state.areaOpacity, 0, 1)))\n if (state.stroke.length > 0) ctx.draw(new Graphics2D().line({ points, closed: true }).stroke(state.stroke))\n }\n\n if (state.dots && state.dotSize > 0 && state.fill.length > 0) {\n const dots = new Graphics2D()\n for (const p of points) dots.ellipse({ x: p.x, y: p.y, width: state.dotSize, height: state.dotSize })\n ctx.draw(dots.fill(state.fill))\n }\n },\n})\n\nexport type RadarSeries = NodeOf<typeof RadarSeries>\n", "import {\n Rect,\n Types,\n clamp,\n component2d,\n easeOut,\n type ChildView,\n type DataRecord,\n type NodeOf,\n // Named so this component's emitted type reaches `Node2D` and its props through the sdk, not core.\n type Node2D,\n type Node2DProps as _Node2DProps,\n type TextStyle as _TextStyle,\n type Fill as _Fill,\n type FillResolved as _FillResolved,\n} from \"@motionscript/sdk\"\n\nimport { SERIES_ARG, asParts, fresh } from \"../kit/entries\"\nimport { beats, type AnyTimeline, type Beat } from \"../kit/motion\"\nimport { CHART_STYLE_FAMILY, CHART_STYLE_PRESETS, migrateChartStyle } from \"../kit/style\"\nimport { PieLegend } from \"../kit/pie-legend\"\nimport { PIE_SPOTLIGHT_DIM, selectionFade } from \"../kit/polar\"\nimport { RadialRings } from \"./radial-rings\"\nimport {\n RADIAL_STYLE_GROUPS,\n centerOf,\n legendOf,\n marksOf,\n resolveRadialRows,\n ringLabelOf,\n type RadialRow,\n type RadialStyle,\n} from \"./shared\"\n\nexport interface RadialChartValues {\n readonly data: DataRecord[]\n readonly categoryField: string\n readonly valueField: string\n readonly max: number\n readonly style: RadialStyle\n readonly pops: number[]\n}\n\n/** How `enter` divides its duration: rings sweeping in, then captions and legend together. Sums to 1. */\nconst SWEEP_SHARE = 0.7\nconst LABEL_SHARE = 0.3\n\nfunction rowsOf(s: RadialChartValues): RadialRow[] {\n return resolveRadialRows(s.data, s.categoryField, s.valueField, s.style)\n}\n\nfunction popAt(s: RadialChartValues, index: number): number {\n return clamp(s.pops[index] ?? 0, 0, 1)\n}\n\n/** Per-row opacity for the legend: 1 while nothing is selected and for the selected ring, falling toward the dim for the rest. */\nfunction ringDims(s: RadialChartValues): number[] {\n let focus = 0\n for (let i = 0; i < s.data.length; i++) focus = Math.max(focus, popAt(s, i))\n return s.data.map((_, i) => selectionFade(focus, RING_DIM, popAt(s, i)))\n}\n\nconst RING_DIM = Math.max(PIE_SPOTLIGHT_DIM, 0.25)\n\nfunction popping(timeline: AnyTimeline, s: RadialChartValues, pop: (index: number) => number) {\n const from = s.data.map((_, i) => popAt(s, i))\n const targets = s.data.map((_, i) => clamp(pop(i), 0, 1))\n if (from.every((value, i) => value === targets[i])) return timeline.wait(timeline.duration)\n return timeline.animate((t) => ({ pops: from.map((value, i) => value + (targets[i] - value) * t) }))\n}\n\n/** The rings and legend among the children; the last row is the one the chart built. */\nfunction partsOf(children: readonly ChildView[]) {\n for (let i = children.length - 1; i >= 0; i--) {\n const row = children[i]\n const rings = Rect.is(row) ? row.children.find(RadialRings.is) : undefined\n if (rings) return { rings, legend: row.children.find(PieLegend.is) ?? null }\n }\n return null\n}\n\n/**\n * A radial bar chart: one concentric ring per row, the first row outermost,\n * each an arc from `startAngle` sweeping `value / max` of `sweep` degrees.\n * Rows are the marks and none can be hidden; `selectRing` thickens a ring and\n * dims the rest.\n */\nexport const RadialChart = component2d({\n key: \"radialChart\",\n state: {\n data: fresh<DataRecord[]>(() => [], { kind: \"dataset\" }),\n /** Ring caption, used on the ring labels and the legend. */\n categoryField: \"\",\n /** Ring magnitude: the arc's share of the full sweep. */\n valueField: \"\",\n /** The value a full sweep stands for. 0 lets the largest value fill its ring. */\n max: Types.number(0, { min: 0, step: 1 }),\n style: Types.style(CHART_STYLE_FAMILY, RADIAL_STYLE_GROUPS, { presets: CHART_STYLE_PRESETS }),\n /** Gap between the rings and the legend, in px. */\n gap: 40,\n /** Text set in the centre hole. */\n centerLabel: \"\",\n /** Smaller second line under `centerLabel`. */\n centerCaption: \"\",\n /** How far each ring is emphasised, `0`-`1` per index. Here because the rings and the legend both read it. */\n pops: fresh<number[]>(() => []),\n /** Read as the chart is built: whether the centre summary is drawn at rest. A scene that wants it to land later sets `false` and runs `revealCenter`. */\n showCenter: Types.boolean(true, { animatable: false }),\n },\n defaults: {\n width: \"fill\",\n height: \"fill\",\n pops: (state) => state.data.map(() => 0),\n },\n migrate: { style: migrateChartStyle(\"radial\") },\n allowedChildren: [],\n children: (state) => {\n const style = () => state.style\n const rows = () => rowsOf(state)\n const parts: Node2D[] = [\n new RadialRings({\n width: \"fill\",\n height: \"fill\",\n rows,\n max: () => state.max,\n marks: () => marksOf(style()),\n label: () => ringLabelOf(style()),\n centerStyle: () => centerOf(style()),\n trackFill: () => style().track,\n ringLabels: () => style().ringLabels,\n pops: () => state.pops,\n dimOpacity: RING_DIM,\n centerLabel: state.centerLabel,\n centerCaption: state.centerCaption,\n centerReveal: state.showCenter === false ? 0 : 1,\n }) as unknown as Node2D,\n ]\n const position = state.style.legend\n if (position !== \"none\") {\n const side = position === \"right\"\n const config = legendOf(state.style)\n const legend = new PieLegend({\n slices: rows,\n legend: () => legendOf(style()),\n dims: () => ringDims(state),\n flow: side ? \"vertical\" : \"horizontal\",\n align: \"center\",\n gap: side ? config.itemGap / 3 : config.itemGap,\n padding: 0,\n }) as unknown as Node2D\n if (position === \"top\") parts.unshift(legend)\n else parts.push(legend)\n }\n const row = new Rect({\n flow: position === \"right\" || position === \"none\" ? \"horizontal\" : \"vertical\",\n width: \"fill\",\n height: \"fill\",\n gap: state.gap,\n padding: 24,\n align: \"center\",\n fill: () => state.style.background,\n children: parts,\n })\n return asParts([row as unknown as Node2D])\n },\n commands: {\n /** Rings sweep in from `startAngle`, outer ring first, then captions fade up and the legend staggers in. `duration` is the whole entrance; the centre summary keeps its own signal. */\n enter: {\n args: {},\n entrance: true,\n easing: easeOut(),\n run: (timeline, _state, children) => {\n const parts = partsOf(children)\n if (!parts) return timeline.wait(timeline.duration)\n const { rings, legend } = parts\n const sweep = timeline.duration * SWEEP_SHARE\n const labels = timeline.duration * LABEL_SHARE\n const at0 = (piece: Beat[\"piece\"]): Beat => ({ at: 0, duration: 0, piece })\n return beats(timeline, [\n at0(rings.to({ growth: 0, labelReveal: 0 })),\n ...(legend ? [at0(legend.run(\"arm\"))] : []),\n { at: 0, duration: sweep, piece: rings.run(\"sweep\") },\n { at: sweep, duration: labels, piece: rings.run(\"revealLabels\") },\n ...(legend ? [{ at: sweep, duration: labels, piece: legend.run(\"enter\") }] : []),\n ])\n },\n },\n /** Fade the centre summary up. Not part of `enter`: it is usually the conclusion, which a scene lands on its own beat. */\n revealCenter: {\n args: {},\n easing: easeOut(),\n run: (timeline, _state, children) => partsOf(children)?.rings.run(\"revealCenter\") ?? timeline.wait(timeline.duration),\n },\n /** Thicken ring `ringIndex` and dim the rest, leaving any other selected ring where it is. */\n selectRing: {\n args: { ringIndex: SERIES_ARG },\n easing: easeOut(),\n run: (timeline, state) => {\n const index = timeline.args.ringIndex\n return popping(timeline, state, (i) => (i === index ? 1 : popAt(state, i)))\n },\n },\n /** Settle every ring and bring the whole chart back to full. */\n clearSelection: {\n args: {},\n easing: easeOut(),\n run: (timeline, state) => popping(timeline, state, () => 0),\n },\n },\n})\n\nexport type RadialChart = NodeOf<typeof RadialChart>\n", "import {\n Graphics2D,\n PathBuilder,\n Rect,\n Text,\n Types,\n clamp,\n component2d,\n fillOps,\n textOps,\n type NodeOf,\n // Named so this component's emitted type reaches `Node2D` and its props through the sdk, not core.\n type Node2D,\n type Node2DProps as _Node2DProps,\n type Fill as _Fill,\n type FillResolved as _FillResolved,\n type TextStyle,\n type Vector2,\n} from \"@motionscript/sdk\"\n\nimport { asParts, fresh } from \"../kit/entries\"\nimport { frameEase } from \"../kit/motion\"\nimport { loadPaints } from \"../kit/paints\"\nimport { DEG, ringFills, ringPoint, selectionFade, type CenterConfig } from \"../kit/polar\"\nimport { radialFractions, type RadialMarks, type RadialRow } from \"./shared\"\n\n/** Share of the entrance one ring's sweep starts after the last. */\nconst STAGGER = 0.12\n/** A selected ring's thickness grows by this share of itself, on each side. */\nconst GROW = 0.12\nconst ARC_STEP = 4 * DEG\nconst LABEL_PAD = 10\nconst CENTER_FIT = 0.78\nconst GLYPH_RATIO = 0.62\n/** How far the radius is held in from the box, for the sake of a ring's growth. */\nconst EDGE = 4\n\nconst DEFAULT_MARKS: RadialMarks = { innerRadius: 0.3, ringGap: 8, sweep: 360, startAngle: 0, track: true, roundCaps: true }\nconst DEFAULT_LABEL: TextStyle = { fontSize: 28, fontWeight: 500, textAlign: \"center\", fill: \"#a1a1aa\" }\nconst DEFAULT_CENTER: CenterConfig = {\n labelStyle: { fontSize: 50, fontWeight: 800, textAlign: \"center\", fill: \"#f4f4f5\" },\n captionStyle: { fontSize: 22, fontWeight: 500, textAlign: \"center\", fill: \"#a1a1aa\" },\n}\n\ninterface RingsState {\n readonly rows: RadialRow[]\n readonly max: number\n readonly marks: RadialMarks\n readonly label: TextStyle\n readonly centerStyle: CenterConfig\n readonly ringLabels: boolean\n readonly pops: readonly number[]\n readonly dimOpacity: number\n readonly centerLabel: string\n readonly centerCaption: string\n}\n\nfunction sizeOf(style: TextStyle, fallback: number): number {\n return typeof style.fontSize === \"number\" ? style.fontSize : fallback\n}\n\n/** Every radius and angle for one box, derived wherever read so the drawing and the labels cannot disagree. */\nexport class RadialGeometry {\n constructor(\n private readonly s: RingsState,\n private readonly box: { readonly width: number; readonly height: number }\n ) {}\n\n get count(): number {\n return this.s.rows.length\n }\n\n get outerRadius(): number {\n return Math.max(0, Math.min(this.box.width, this.box.height) / 2 - EDGE)\n }\n\n get holeRadius(): number {\n return clamp(this.s.marks.innerRadius, 0, 0.9) * this.outerRadius\n }\n\n /** Radial depth of one ring. */\n get thickness(): number {\n const n = this.count\n if (n === 0) return 0\n return Math.max(0, (this.outerRadius - this.holeRadius - (n - 1) * Math.max(0, this.s.marks.ringGap)) / n)\n }\n\n /** Rim of ring `index`; ring 0 is the outermost. */\n ringOuter(index: number): number {\n return this.outerRadius - index * (this.thickness + Math.max(0, this.s.marks.ringGap))\n }\n\n ringMid(index: number): number {\n return this.ringOuter(index) - this.thickness / 2\n }\n\n get fractions(): number[] {\n return radialFractions(this.s.rows, this.s.max)\n }\n\n get startRad(): number {\n return this.s.marks.startAngle * DEG\n }\n\n get sweepRad(): number {\n return clamp(this.s.marks.sweep, 0, 360) * DEG\n }\n\n popOf(index: number): number {\n return clamp(this.s.pops[index] ?? 0, 0, 1)\n }\n\n get selectionStrength(): number {\n let strongest = 0\n for (let i = 0; i < this.count; i++) strongest = Math.max(strongest, this.popOf(i))\n return strongest\n }\n\n ringOpacity(index: number): number {\n return selectionFade(this.selectionStrength, this.s.dimOpacity, this.popOf(index))\n }\n\n /** How far ring `index`'s sweep has come at entrance progress `growth`: rings start in turn, outer first. */\n progress(index: number, growth: number): number {\n const total = 1 + STAGGER * Math.max(0, this.count - 1)\n return clamp(growth * total - index * STAGGER, 0, 1)\n }\n\n get labelFont(): number {\n return Math.max(1, Math.min(sizeOf(this.s.label, 28), this.thickness * 0.62))\n }\n\n /** Where ring `index`'s caption is pinned: just behind its start, reading away from the sweep. */\n labelAnchor(index: number): { at: Vector2; side: 1 | -1 } {\n const a = this.startRad\n const back = { x: -Math.cos(a), y: Math.sin(a) }\n const p = ringPoint(this.ringMid(index), a)\n const side: 1 | -1 = back.x <= 0 ? -1 : 1\n return { at: { x: p.x + back.x * LABEL_PAD, y: p.y + back.y * LABEL_PAD }, side }\n }\n\n get centerFont(): number {\n const { centerStyle, centerLabel, centerCaption } = this.s\n const wanted = sizeOf(centerStyle.labelStyle, 50)\n const hole = this.holeRadius\n if (hole <= 0) return wanted\n const ratio = sizeOf(centerStyle.captionStyle, 22) / Math.max(1, wanted)\n const glyphs = Math.max(1, centerLabel.length, centerCaption.length * ratio)\n return Math.min(wanted, (hole * 2 * CENTER_FIT) / (glyphs * GLYPH_RATIO))\n }\n}\n\n/**\n * An arc band between `rIn` and `rOut` over `a0`..`a1` (radians clockwise from\n * 12 o'clock), the ends squared or capped with half circles. A band shorter\n * than its caps is two overlapping caps, which fill as a pill.\n */\nexport function bandPath(a0: number, a1: number, rIn: number, rOut: number, round: boolean): PathBuilder {\n const path = new PathBuilder()\n const mid = (rIn + rOut) / 2\n const cap = (rOut - rIn) / 2\n const delta = round && mid > 0 ? Math.min(cap / mid, (a1 - a0) / 2) : 0\n const from = a0 + delta\n const to = a1 - delta\n const steps = Math.max(2, Math.ceil(Math.abs(to - from) / ARC_STEP))\n const arc = (r: number, x: number, y: number, first: boolean) => {\n for (let i = 0; i <= steps; i++) {\n const p = ringPoint(r, x + ((y - x) * i) / steps)\n if (first && i === 0) path.moveTo(p.x, p.y)\n else path.lineTo(p.x, p.y)\n }\n }\n // The end at `angle` rounded through a tip `direction` along the sweep.\n const semicircle = (angle: number, direction: 1 | -1, fromOuter: boolean) => {\n const centre = ringPoint(mid, angle)\n const radial = { x: Math.sin(angle), y: Math.cos(angle) }\n const tangent = { x: Math.cos(angle) * direction, y: -Math.sin(angle) * direction }\n const turns = 12\n for (let i = 1; i < turns; i++) {\n const phi = (Math.PI * i) / turns\n const r = fromOuter ? Math.cos(phi) : -Math.cos(phi)\n path.lineTo(centre.x + cap * (radial.x * r + tangent.x * Math.sin(phi)), centre.y + cap * (radial.y * r + tangent.y * Math.sin(phi)))\n }\n }\n arc(rOut, from, to, true)\n if (round) semicircle(to, 1, true)\n arc(rIn, to, from, false)\n if (round) semicircle(from, -1, false)\n path.close()\n return path\n}\n\nconst NO_BOX = { width: 0, height: 0 }\n\nfunction labelBlocks(s: RingsState & { readonly labelReveal: number; readonly centerReveal: number }) {\n const blocks: Node2D[] = []\n const geometry = () => new RadialGeometry(s, (blocks[0]?.parent as Node2D | null | undefined)?.layoutBounds ?? NO_BOX)\n const side = geometry().labelAnchor(0).side\n\n s.rows.forEach((_, index) => {\n const anchor = () => geometry().labelAnchor(index).at\n blocks.push(\n new Rect({\n flow: \"vertical\",\n width: \"hug\",\n height: \"hug\",\n align: side > 0 ? \"centerLeft\" : \"centerRight\",\n opacity: () => (s.ringLabels ? clamp(s.labelReveal, 0, 1) * geometry().ringOpacity(index) : 0),\n centerLeft: side > 0 ? anchor : undefined,\n centerRight: side > 0 ? undefined : anchor,\n children: [\n new Text({\n ...textOps.styleProps(s.label),\n text: () => s.rows[index]?.category ?? \"\",\n textAlign: side > 0 ? \"left\" : \"right\",\n fontSize: () => geometry().labelFont,\n }),\n ],\n })\n )\n })\n\n if (s.centerLabel !== \"\" || s.centerCaption !== \"\") {\n const children: Node2D[] = []\n if (s.centerLabel !== \"\") {\n children.push(new Text({ ...textOps.styleProps(s.centerStyle.labelStyle), text: s.centerLabel, fontSize: () => geometry().centerFont }))\n }\n if (s.centerCaption !== \"\") {\n children.push(\n new Text({\n ...textOps.styleProps(s.centerStyle.captionStyle),\n text: s.centerCaption,\n fontSize: () => geometry().centerFont * (sizeOf(s.centerStyle.captionStyle, 22) / sizeOf(s.centerStyle.labelStyle, 50)),\n })\n )\n }\n blocks.push(\n new Rect({\n flow: \"vertical\",\n width: \"hug\",\n height: \"hug\",\n gap: 2,\n align: \"center\",\n opacity: () => clamp(s.centerReveal, 0, 1),\n center: { x: 0, y: 0 },\n children,\n })\n )\n }\n return asParts(blocks)\n}\n\n/**\n * The rings: row `i` is the `i`-th ring from the outside, an arc from\n * `startAngle` whose sweep is `value / max` of the full sweep, over an\n * optional full-sweep track. A selected ring thickens and the rest dims.\n */\nexport const RadialRings = component2d({\n key: \"radialRings\",\n state: {\n rows: fresh<RadialRow[]>(() => []),\n max: 0,\n marks: Types.custom<RadialMarks>(DEFAULT_MARKS),\n label: Types.custom<TextStyle>(DEFAULT_LABEL),\n centerStyle: Types.custom<CenterConfig>(DEFAULT_CENTER),\n /** The empty-ring colour drawn under each arc. */\n trackFill: Types.fill(\"white/15\"),\n ringLabels: Types.boolean(false),\n /** Entrance progress `[0, 1]`: rings sweep in turn. */\n growth: 1,\n labelReveal: 1,\n pops: fresh<number[]>(() => []),\n dimOpacity: 0.25,\n centerLabel: \"\",\n centerCaption: \"\",\n centerReveal: 1,\n },\n defaults: { width: \"fill\", height: \"fill\" },\n children: (state) => labelBlocks(state),\n load: (loader, state) => loadPaints(loader, { fills: [...ringFills(state.rows), fillOps.resolve(state.trackFill)] }),\n commands: {\n /** Sweep the rings in, outer first. */\n sweep: (timeline) => {\n const ease = frameEase(timeline)\n return timeline.animate((t) => ({ growth: ease(t) }))\n },\n /** Fade the ring captions up. */\n revealLabels: (timeline) => {\n const ease = frameEase(timeline)\n return timeline.animate((t) => ({ labelReveal: ease(t) }))\n },\n /** Fade the centre summary up. */\n revealCenter: (timeline, state) => {\n const ease = frameEase(timeline)\n const from = clamp(state.centerReveal, 0, 1)\n return timeline.animate((t) => ({ centerReveal: from + (1 - from) * ease(t) }))\n },\n },\n render: (ctx, state) => {\n const g = new RadialGeometry(state, ctx.size)\n const thickness = g.thickness\n if (g.outerRadius > 0 && g.count > 0 && thickness > 0) {\n const half = g.outerRadius + EDGE + 1\n const frame = { centerBounds: [-half, -half, half, half] as [number, number, number, number], width: half * 2, height: half * 2 }\n const fills = ringFills(state.rows)\n const fractions = g.fractions\n const a0 = g.startRad\n const round = state.marks.roundCaps\n // Selected rings last, so a thickened ring is never under its neighbour.\n const order = [...state.rows.keys()].sort((a, b) => g.popOf(a) - g.popOf(b))\n for (const i of order) {\n const grow = thickness * GROW * g.popOf(i)\n const rOut = g.ringOuter(i) + grow\n const rIn = g.ringOuter(i) - thickness - grow\n const opacity = g.ringOpacity(i)\n if (state.marks.track && g.sweepRad > 0) {\n ctx.draw(new Graphics2D().path(bandPath(a0, a0 + g.sweepRad, rIn, rOut, round).toPathState(frame)).fill(state.trackFill).opacity(opacity))\n }\n const span = g.sweepRad * fractions[i] * g.progress(i, state.growth)\n if (span <= 1e-4) continue\n ctx.draw(new Graphics2D().path(bandPath(a0, a0 + span, rIn, rOut, round).toPathState(frame)).fill(fills[i] ?? []).opacity(opacity))\n }\n }\n ctx.children()\n },\n})\n\nexport type RadialRings = NodeOf<typeof RadialRings>\n", "import { Types, clamp, type DataRecord, type TextStyle, type Fill as _Fill, type FillResolved as _FillResolved } from \"@motionscript/sdk\"\n\nimport {\n CHART_BACKGROUND,\n CHART_FOREGROUND,\n CHART_LEGEND,\n CHART_MUTED,\n CHART_SERIES,\n LEGEND_TEXT,\n legendConfigOf,\n paletteFill,\n placedText,\n sizeOf,\n type ChartStyleBase,\n} from \"../kit/style\"\nimport type { LegendConfig } from \"../kit/shared\"\nimport { num, text } from \"../kit/shared\"\nimport type { CenterConfig, PieSlice } from \"../kit/polar\"\n\n/** One ring: a row's caption, magnitude and paint. The same shape as a pie's slice, so the legend is shared. */\nexport type RadialRow = PieSlice\n\nexport function resolveRadialRows(data: readonly DataRecord[], category: string, value: string, style: Pick<ChartStyleBase, \"seriesFills\">): RadialRow[] {\n return data.map((row, i) => ({ category: text(row, category), value: num(row, value), fill: paletteFill(style, i) }))\n}\n\n/** A row's plotted value: negatives and non-finite values count as 0. */\nexport function rowValue(row: RadialRow): number {\n return row.value > 0 && Number.isFinite(row.value) ? row.value : 0\n}\n\n/** What a full sweep stands for: `max` when it is positive, else the largest value (1 when every value is 0). */\nexport function radialMax(rows: readonly RadialRow[], max: number): number {\n if (max > 0 && Number.isFinite(max)) return max\n let largest = 0\n for (const row of rows) largest = Math.max(largest, rowValue(row))\n return largest > 0 ? largest : 1\n}\n\n/** The share of a full sweep each row fills, `[0, 1]`. */\nexport function radialFractions(rows: readonly RadialRow[], max: number): number[] {\n const top = radialMax(rows, max)\n return rows.map((row) => clamp(rowValue(row) / top, 0, 1))\n}\n\n/** The ring geometry and look, from `style`. */\nexport interface RadialMarks {\n innerRadius: number\n ringGap: number\n /** Degrees of a full ring. */\n sweep: number\n /** Degrees clockwise from 12 o'clock. */\n startAngle: number\n track: boolean\n roundCaps: boolean\n}\n\nexport interface RadialStyle extends ChartStyleBase {\n readonly innerRadius: number\n readonly ringGap: number\n readonly sweep: number\n readonly startAngle: number\n readonly track: _FillResolved[]\n readonly roundCaps: boolean\n readonly ringLabels: boolean\n readonly labelText: TextStyle\n readonly centerText: TextStyle\n}\n\nexport const RADIAL_STYLE_GROUPS = {\n series: CHART_SERIES,\n background: CHART_BACKGROUND,\n text: {\n /** The category at each ring's start, and the caption under the centre. */\n labelText: Types.typography({ fontSize: 28, fontWeight: 500, fill: CHART_MUTED }),\n /** The summary in the middle. */\n centerText: Types.typography({ fontSize: 50, fontWeight: 800, fill: CHART_FOREGROUND }),\n ...LEGEND_TEXT,\n },\n marks: {\n /** Where the innermost ring starts, as a fraction of the outer radius. */\n innerRadius: Types.number(0.3, { min: 0, max: 0.9, step: 0.05 }),\n /** Space between neighbouring rings, px. */\n ringGap: Types.number(8, { min: 0, max: 60, step: 1, unit: \"px\" }),\n /** Degrees a full ring spans: 360 a circle, 270 a gauge-like open ring. */\n sweep: Types.number(360, { min: 30, max: 360, step: 5, unit: \"deg\" }),\n /** Degrees clockwise from 12 o'clock where every ring begins. */\n startAngle: Types.number(0, { min: -360, max: 360, step: 5, unit: \"deg\" }),\n /** The full ring under each arc; empty draws none. */\n track: Types.fill(\"white/10\"),\n /** Round the ends of the arcs and tracks. */\n roundCaps: Types.boolean(true),\n },\n labels: {\n /** The category written at each ring's start, set in the label text. */\n ringLabels: Types.boolean(false),\n },\n legend: CHART_LEGEND,\n}\n\nexport function marksOf(style: RadialStyle): RadialMarks {\n return {\n innerRadius: style.innerRadius,\n ringGap: style.ringGap,\n sweep: style.sweep,\n startAngle: style.startAngle,\n track: style.track.length > 0,\n roundCaps: style.roundCaps,\n }\n}\n\nexport function legendOf(style: RadialStyle): LegendConfig {\n return legendConfigOf(style)\n}\n\nexport function ringLabelOf(style: RadialStyle): TextStyle {\n return placedText(style.labelText)\n}\n\nexport function centerOf(style: RadialStyle): CenterConfig {\n const size = sizeOf(style.centerText, 50)\n return {\n labelStyle: placedText(style.centerText),\n captionStyle: placedText(style.labelText, \"center\", { fontSize: Math.round(size * 0.45) }),\n }\n}\n", "import { LineChart } from \"./line-chart\";\nimport { BarChart } from \"./bar-chart\";\nimport { PieChart } from \"./pie-chart\";\nimport { RadarChart } from \"./radar-chart\";\nimport { RadialChart } from \"./radial-chart\";\n\n// Typed by name, so the declaration names each component rather than spelling out its type through core.\nexport const NODES: (typeof LineChart | typeof BarChart | typeof PieChart | typeof RadarChart | typeof RadialChart)[] = [\n LineChart,\n BarChart,\n PieChart,\n RadarChart,\n RadialChart,\n];\n"],
5
+ "mappings": "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",
6
+ "names": ["Rect", "Text", "Types", "clamp", "component2d", "easeOut", "formatNumber", "Graphics2D", "Types", "clamp", "component2d", "fillOps", "strokeOps", "Types", "EMPTY_REGION_BOX", "hasRegion", "box", "resolveRegionBox", "region", "plot", "xScale", "yScale", "span", "range", "min", "max", "lo", "hi", "a", "b", "toPx", "left", "right", "xBounded", "bottom", "top", "yBounded", "clipPolylineToBox", "points", "runs", "run", "i", "seg", "clipSegment", "samePoint", "dx", "dy", "t0", "t1", "edges", "p", "q", "r", "seriesPoints", "data", "x", "series", "row", "num", "yExtent", "s", "v", "resolveYScale", "divisions", "niceRange", "stackSeries", "stack", "weights", "order", "_", "weight", "totals", "sum", "running", "base", "k", "value", "stackExtent", "stacks", "y", "SAMPLES", "curvePoints", "curve", "out", "mid", "tangents", "monotoneTangents", "c1", "c2", "t", "u", "n", "slope", "h", "m", "h0", "h1", "s0", "s1", "endTangent", "secant", "inner", "cutAt", "clipPolygonToBox", "polygon", "inside", "input", "cur", "prev", "dc", "dp", "crossing", "da", "db", "LINE_MARKS", "Types", "LINE_LABELS", "traceX", "points", "progress", "first", "last", "traced", "curve", "path", "curvePoints", "cutAt", "curveEntry", "Types", "outlineCommands", "p", "i", "fillOutline", "ctx", "outline", "fill", "opacity", "width", "height", "centerBounds", "Graphics2D", "ChartLine", "component2d", "fresh", "strokeOps", "fillOps", "EMPTY_REGION_BOX", "SPOTLIGHT_DIM", "loader", "state", "loadPaints", "timeline", "from", "to", "ease", "frameEase", "t", "shown", "pts", "clamp", "box", "lit", "hasRegion", "dim", "stroke", "weight", "drawn", "radius", "run", "clipPolylineToBox", "size", "reach", "bright", "dimmed", "brightAny", "dimAny", "pt", "grown", "inside", "ChartArea", "outlineAt", "top", "base", "span", "verticalSpan", "paint", "areaFill", "clipPolygonToBox", "bottom", "colour", "area", "whole", "own", "fade", "r", "g", "b", "a", "middle", "half", "Graphics2D", "Types", "component2d", "fillOps", "strokeOps", "ChartRegion", "component2d", "fresh", "EMPTY_REGION_BOX", "Types", "strokeOps", "fillOps", "loader", "state", "loadPaints", "ctx", "box", "hasRegion", "width", "height", "cx", "cy", "Graphics2D", "half", "x", "rule", "y", "formatNumber", "DAY", "MONTHS", "NOMINAL_YEAR", "monthIndex", "word", "month", "isoWeekStart", "year", "week", "jan4", "weekday", "parseInstant", "raw", "s", "ymd", "day", "n", "named", "y", "dayNamed", "formatInstant", "value", "span", "date", "label", "isNumericColumn", "data", "field", "sawValue", "row", "v", "instantColumn", "parsed", "t", "last", "extentOf", "values", "lo", "hi", "EVERY_SAMPLE", "sampledTicks", "positions", "min", "max", "divisions", "inside", "unique", "a", "b", "markerValues", "evenlySpaced", "nearest", "target", "best", "out", "tick", "sorted", "mean", "i", "labelBySample", "captions", "fallback", "scales", "resolveXScale", "pattern", "byKey", "key", "scale", "xScaleOf", "num", "formatMarker", "text", "instants", "extent", "range", "_", "LINE_STYLE", "Types", "CHART_STYLE_FAMILY", "CHART_SERIES", "GRID_BACKGROUND", "CARTESIAN_TEXT", "CARTESIAN_GRID", "LINE_MARKS", "LINE_LABELS", "CHART_LEGEND", "CHART_STYLE_PRESETS", "REGION_ARG", "PERCENT", "columnOf", "s", "format", "resolveXScale", "stacksOf", "weighted", "stackSeries", "drawnX", "domain", "column", "range", "DEFAULT_MARKERS", "autoY", "divisions", "lo", "hi", "stackExtent", "zero", "niceRange", "drawnY", "even", "markerValues", "niceTicks", "domainsDrawn", "lineChartDomains", "key", "kept", "value", "domains", "settleAxisDomain", "d", "mapper", "plot", "xMin", "xMax", "yMin", "yMax", "x", "y", "NO_PIXELS", "seriesPixels", "index", "stack", "map", "toPx", "k", "baselineValue", "clamp", "overflows", "ylo", "yhi", "xlo", "xhi", "within", "v", "a", "b", "regionBox", "w", "h", "resolveRegionBox", "hasCallout", "region", "regionArg", "span", "rescale", "ticks", "to", "axesAt", "from", "t", "lerpAxisDomain", "yLabel", "formatNumber", "text", "formatMarker", "markerStep", "weightOf", "partsOf", "children", "views", "chartViews", "VerticalAxis", "HorizontalAxis", "ChartLine", "ChartLegend", "clearing", "timeline", "state", "toggling", "show", "parts", "line", "legend", "_", "i", "start", "target", "weights", "LineChart", "component2d", "fresh", "resolveAxisDomain", "lerpAxisEntry", "migrateChartStyle", "style", "plotSize", "laidOutSize", "pixels", "enabled", "built", "yConfig", "axisConfigOf", "xConfig", "yCaptions", "vAxis", "hAxis", "overhang", "ghost", "columnGhost", "axisPads", "spotlight", "dimOpacity", "SPOTLIGHT_DIM", "lines", "seriesFill", "areas", "ChartArea", "labels", "below", "_row", "label", "Text", "boundText", "valueText", "half", "point", "clear", "sizeOf", "reach", "traceX", "legendAt", "legendConfigOf", "Rect", "ChartCanvas", "ChartRegion", "fade", "cartesianFrame", "frameGap", "headroom", "easeOut", "duration", "revealing", "body", "axes", "ENTER_SHARE", "traced", "at0", "piece", "away", "legendAway", "beats", "previous", "home", "SERIES_ARG", "_state", "Rect", "Types", "clamp", "component2d", "easeOut", "formatNumber", "Rect", "Text", "Types", "clamp", "component2d", "enterBudget", "SLIDE", "slotCentre", "index", "count", "length", "CategoryAxis", "component2d", "fresh", "Types", "DEFAULT_X_AXIS", "arrivalsEntry", "state", "n", "dim", "i", "clamp", "captionColumn", "height", "pads", "axisPads", "captions", "caption", "slot", "Rect", "Text", "boundText", "arrivalOf", "children", "timeline", "stagger", "slide", "captioned", "from", "keys", "arm", "armed", "step", "per", "enterBudget", "ease", "frameEase", "_", "arrival", "label", "beats", "Graphics2D", "Text", "Types", "clamp", "component2d", "fillOps", "Types", "fillOps", "barSpans", "row", "series", "stack", "weights", "weight", "i", "s", "value", "num", "values", "total", "sum", "v", "scaled", "lastUp", "lastDown", "up", "down", "from", "barCategories", "data", "field", "text", "barValueExtent", "lo", "hi", "span", "resolveBarScale", "range", "divisions", "niceRange", "inkOn", "fill", "layers", "fillOps", "top", "g", "b", "lift", "c", "BAR_MARKS", "Types", "BAR_LABELS", "INSIDE_ROOM", "dimAt", "s", "index", "clamp", "endsAt", "bar", "g", "sizeOf", "style", "captionAlong", "extent", "ends", "direction", "fitsInside", "across", "room", "ChartBars", "component2d", "fresh", "Types", "fillOps", "state", "_", "i", "caption", "Text", "boundText", "inkOn", "box", "along", "loader", "loadPaints", "timeline", "ease", "frameEase", "t", "ctx", "seam", "length", "forward", "mid", "corners", "barCorners", "Graphics2D", "orient", "c", "horizontal", "grounded", "r", "cap", "fit", "v", "on", "upright", "BAR_STYLE", "Types", "CHART_STYLE_FAMILY", "CHART_SERIES", "GRID_BACKGROUND", "CARTESIAN_TEXT", "CARTESIAN_GRID", "BAR_MARKS", "BAR_LABELS", "CHART_LEGEND", "CHART_STYLE_PRESETS", "drawnValue", "s", "domain", "divisions", "DEFAULT_MARKERS", "range", "resolveBarScale", "even", "markerValues", "niceTicks", "domainsDrawn", "barChartDomain", "key", "kept", "value", "settleAxisDomain", "d", "valueLabel", "pattern", "formatNumber", "text", "formatMarker", "markerStep", "valueToPx", "length", "min", "max", "baselineValue", "lo", "hi", "clamp", "weightAt", "index", "runs", "plot", "slotAt", "row", "across", "centre", "slotCentre", "seriesBars", "series", "along", "n", "inner", "stacked", "total", "i", "unit", "weight", "before", "gap", "values", "rowIndex", "span", "barSpans", "offset", "caption", "num", "categoryDims", "focus", "chosen", "_", "SPOTLIGHT_DIM", "partsOf", "children", "views", "chartViews", "view", "VerticalAxis", "HorizontalAxis", "CategoryAxis", "ChartBars", "ChartLegend", "toggling", "timeline", "state", "target", "parts", "from", "start", "showing", "t", "weights", "shown", "BarChart", "component2d", "fresh", "resolveAxisDomain", "lerpAxisEntry", "lerpAxisDomain", "migrateChartStyle", "style", "plotSize", "laidOutSize", "built", "horizontal", "categories", "barCategories", "valueConfig", "axisConfigOf", "categoryConfig", "valueCaptions", "showValue", "showCategory", "valueAxis", "overhang", "categoryAxis", "left", "bottom", "leftConfig", "ghost", "columnGhost", "axisPads", "barSets", "seriesFill", "valueText", "legendAt", "legend", "legendConfigOf", "boundaries", "slots", "Rect", "ChartCanvas", "cartesianFrame", "frameGap", "headroom", "easeOut", "duration", "axes", "ENTER_SHARE", "rise", "at0", "piece", "beats", "legendAway", "SERIES_ARG", "_state", "bars", "lit", "Rect", "Types", "clamp", "component2d", "easeOut", "Graphics2D", "PathBuilder", "Rect", "Text", "Types", "clamp", "component2d", "strokeOps", "textOps", "Types", "resolvePieSlices", "data", "category", "value", "palette", "row", "text", "num", "sliceValue", "slice", "sliceTotal", "slices", "sum", "pieArcs", "startDegrees", "total", "arcs", "cursor", "DEG", "index", "fraction", "a0", "a1", "relaxLabels", "slots", "minGap", "top", "bottom", "a", "b", "ceiling", "slot", "floor", "i", "PIE_STYLE_GROUPS", "CHART_SERIES", "CHART_BACKGROUND", "Types", "CHART_MUTED", "CHART_FOREGROUND", "LEGEND_TEXT", "CHART_LEGEND", "legendOf", "style", "legendConfigOf", "ringConfigOf", "labelConfigOf", "base", "placedText", "sizeOf", "centerConfigOf", "size", "DEFAULT_RING", "DEFAULT_LABEL", "DEFAULT_CENTER", "onFill", "fill", "solid", "resolvedFill", "layer", "g", "b", "LABEL_GAP", "LABEL_PAD", "GLYPH_RATIO", "LEADER_LIFTOFF", "LEADER_LENGTH", "LABEL_STUB", "TEXT_INSET", "MIN_ELBOW", "ARC_STEPS", "ELBOW_RADIUS", "BARE_PAD", "INSIDE_CAPTION_RATIO", "PIE_LABEL_RADIUS", "CENTER_LABEL_FIT", "INSIDE_LABEL_FIT", "AXIS_EPSILON", "FALLBACK_SIZE", "sizeOf", "style", "fallback", "size", "wedgePath", "a0", "a1", "rInner", "rOuter", "halfGap", "corner", "cx", "path", "PathBuilder", "span", "steps", "insetAt", "r", "at", "a", "p", "ringPoint", "hasHole", "oa0", "oa1", "ia0", "ia1", "O0", "O1", "half", "apex", "I0", "I1", "band", "rho", "rounded", "toward", "from", "to", "d", "len", "k", "dOuter", "dInner", "arc", "i", "round", "next", "first", "beforeI1", "beforeO0", "RingGeometry", "s", "box", "pieArcs", "outer", "hole", "mid", "sin", "cos", "acrossBand", "alongArc", "mode", "category", "percent", "formatPercent", "caption", "fits", "centerStyle", "centerLabel", "centerCaption", "wanted", "captionRatio", "glyphs", "index", "gutters", "glyph", "room", "key", "sideOf", "left", "right", "configured", "px", "clamp", "rim", "point", "strongest", "selectionFade", "arcs", "radius", "rowHeight", "top", "bottom", "side", "ideal", "relaxLabels", "slot", "start", "onCircle", "elbowX", "endX", "placement", "NO_BOX", "ringLabels", "blocks", "geometry", "label", "opacity", "wantsCategory", "wantsPercent", "inside", "Text", "textOps", "Rect", "children", "PieRing", "component2d", "fresh", "Types", "PIE_SPOTLIGHT_DIM", "state", "loader", "loadPaints", "ringFills", "strokeOps", "timeline", "ease", "frameEase", "t", "ctx", "sweep", "revealEnd", "centerBounds", "fills", "wedge", "Graphics2D", "reveal", "SWEEP_SHARE", "LABEL_SHARE", "SLICE_ARG", "Types", "slicesOf", "s", "resolvePieSlices", "_", "i", "paletteFill", "popAt", "index", "clamp", "isSliceSelected", "sliceDims", "focus", "selectionFade", "PIE_SPOTLIGHT_DIM", "popping", "timeline", "pop", "from", "targets", "value", "t", "partsOf", "children", "row", "ring", "Rect", "PieRing", "PieLegend", "PieChart", "component2d", "fresh", "CHART_STYLE_FAMILY", "PIE_STYLE_GROUPS", "CHART_STYLE_PRESETS", "state", "migrateChartStyle", "style", "slices", "parts", "ringConfigOf", "labelConfigOf", "centerConfigOf", "position", "side", "legend", "legendOf", "easeOut", "_state", "sweep", "labels", "at0", "piece", "beats", "Rect", "Text", "Types", "component2d", "easeOut", "Graphics2D", "Types", "clamp", "component2d", "fillOps", "strokeOps", "Types", "RADAR_TEXT", "Types", "CHART_MUTED", "LEGEND_TEXT", "RADAR_GRID", "RADAR_MARKS", "LABEL_PAD", "GLYPH", "MARGIN", "SIDE", "spokeDirection", "index", "count", "angle", "categoriesOf", "data", "field", "row", "text", "valuesOf", "series", "s", "num", "MANTISSAS", "niceCeil", "value", "power", "mantissa", "m", "scaleOf", "values", "min", "max", "top", "list", "v", "span", "fractionOf", "scale", "labelAnchor", "x", "y", "labelPad", "fontSize", "labelSize", "caption", "fitRadius", "box", "categories", "labelled", "radius", "pad", "i", "size", "side", "reachX", "reachY", "labelPoint", "r", "RadarGrid", "component2d", "Types", "fillOps", "strokeOps", "loader", "state", "loadPaints", "ctx", "grow", "clamp", "rim", "count", "levels", "round", "outline", "g", "r", "points", "i", "d", "spokeDirection", "Graphics2D", "level", "Graphics2D", "Types", "clamp", "component2d", "fillOps", "strokeOps", "seriesVertices", "fractions", "radius", "grow", "f", "i", "d", "spokeDirection", "r", "RadarSeries", "component2d", "fresh", "Types", "fillOps", "strokeOps", "loader", "state", "loadPaints", "timeline", "from", "to", "ease", "frameEase", "t", "progress", "ctx", "clamp", "points", "fill", "Graphics2D", "dots", "p", "radarScale", "state", "scaleOf", "valuesOf", "radarFractions", "index", "series", "scale", "row", "v", "fractionOf", "partsOf", "children", "i", "Rect", "plot", "part", "RadarGrid", "RadarSeries", "ChartLegend", "toggling", "timeline", "show", "parts", "STAGGER", "RadarChart", "component2d", "fresh", "Types", "CHART_STYLE_FAMILY", "CHART_SERIES", "GRID_BACKGROUND", "RADAR_TEXT", "RADAR_GRID", "RADAR_MARKS", "CHART_LEGEND", "CHART_STYLE_PRESETS", "migrateChartStyle", "style", "plotSize", "laidOutSize", "radius", "fitRadius", "categoriesOf", "sizeOf", "count", "enabled", "s", "grid", "seriesFill", "weight", "labels", "anchor", "labelAnchor", "align", "at", "labelPoint", "Text", "boundText", "placedText", "position", "side", "config", "legendConfigOf", "legend", "frame", "easeOut", "_state", "duration", "web", "ENTER_SHARE", "marks", "last", "n", "each", "at0", "piece", "beats", "LEGEND_SLIDE", "SERIES_ARG", "SPOTLIGHT_DIM", "Rect", "Types", "clamp", "component2d", "easeOut", "Graphics2D", "PathBuilder", "Rect", "Text", "Types", "clamp", "component2d", "fillOps", "textOps", "Types", "clamp", "resolveRadialRows", "data", "category", "value", "style", "row", "text", "num", "paletteFill", "rowValue", "radialMax", "rows", "max", "largest", "radialFractions", "top", "clamp", "RADIAL_STYLE_GROUPS", "CHART_SERIES", "CHART_BACKGROUND", "Types", "CHART_MUTED", "CHART_FOREGROUND", "LEGEND_TEXT", "CHART_LEGEND", "marksOf", "legendOf", "legendConfigOf", "ringLabelOf", "placedText", "centerOf", "size", "sizeOf", "STAGGER", "GROW", "ARC_STEP", "DEG", "LABEL_PAD", "CENTER_FIT", "GLYPH_RATIO", "EDGE", "DEFAULT_MARKS", "DEFAULT_LABEL", "DEFAULT_CENTER", "sizeOf", "style", "fallback", "RadialGeometry", "s", "box", "clamp", "n", "index", "radialFractions", "strongest", "i", "selectionFade", "growth", "total", "a", "back", "p", "ringPoint", "side", "centerStyle", "centerLabel", "centerCaption", "wanted", "hole", "ratio", "glyphs", "bandPath", "a0", "a1", "rIn", "rOut", "round", "path", "PathBuilder", "mid", "cap", "delta", "from", "to", "steps", "arc", "r", "x", "y", "first", "semicircle", "angle", "direction", "fromOuter", "centre", "radial", "tangent", "turns", "phi", "NO_BOX", "labelBlocks", "blocks", "geometry", "_", "anchor", "Rect", "Text", "textOps", "children", "RadialRings", "component2d", "fresh", "Types", "state", "loader", "loadPaints", "ringFills", "fillOps", "timeline", "ease", "frameEase", "t", "ctx", "g", "thickness", "half", "frame", "fills", "fractions", "order", "b", "grow", "opacity", "Graphics2D", "span", "SWEEP_SHARE", "LABEL_SHARE", "rowsOf", "s", "resolveRadialRows", "popAt", "index", "clamp", "ringDims", "focus", "i", "_", "selectionFade", "RING_DIM", "PIE_SPOTLIGHT_DIM", "popping", "timeline", "pop", "from", "targets", "value", "t", "partsOf", "children", "row", "rings", "Rect", "RadialRings", "PieLegend", "RadialChart", "component2d", "fresh", "Types", "CHART_STYLE_FAMILY", "RADIAL_STYLE_GROUPS", "CHART_STYLE_PRESETS", "state", "migrateChartStyle", "style", "rows", "parts", "marksOf", "ringLabelOf", "centerOf", "position", "side", "config", "legendOf", "legend", "easeOut", "_state", "sweep", "labels", "at0", "piece", "beats", "SERIES_ARG", "NODES", "LineChart", "BarChart", "PieChart", "RadarChart", "RadialChart"]
7
7
  }