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

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 (207) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/README.md +98 -28
  3. package/dist/bar-chart/bar-chart.d.ts +233 -39
  4. package/dist/bar-chart/bar-chart.d.ts.map +1 -1
  5. package/dist/bar-chart/bar-chart.js +215 -171
  6. package/dist/bar-chart/bar-chart.js.map +1 -1
  7. package/dist/bar-chart/category-axis.d.ts +12 -7
  8. package/dist/bar-chart/category-axis.d.ts.map +1 -1
  9. package/dist/bar-chart/category-axis.js +56 -42
  10. package/dist/bar-chart/category-axis.js.map +1 -1
  11. package/dist/bar-chart/chart-bars.d.ts +52 -52
  12. package/dist/bar-chart/chart-bars.d.ts.map +1 -1
  13. package/dist/bar-chart/chart-bars.js +80 -89
  14. package/dist/bar-chart/chart-bars.js.map +1 -1
  15. package/dist/bar-chart/index.d.ts +4 -4
  16. package/dist/bar-chart/index.d.ts.map +1 -1
  17. package/dist/bar-chart/index.js +2 -2
  18. package/dist/bar-chart/index.js.map +1 -1
  19. package/dist/bar-chart/shared.d.ts +36 -65
  20. package/dist/bar-chart/shared.d.ts.map +1 -1
  21. package/dist/bar-chart/shared.js +68 -117
  22. package/dist/bar-chart/shared.js.map +1 -1
  23. package/dist/browser/chunks/chunk-R3Q5EE6E.js +2 -0
  24. package/dist/browser/chunks/chunk-R3Q5EE6E.js.map +7 -0
  25. package/dist/browser/index.js +1 -1
  26. package/dist/browser/index.js.map +4 -4
  27. package/dist/browser/kit.js +1 -1
  28. package/dist/browser/manifest.json +1 -1
  29. package/dist/engine.d.ts +5 -2
  30. package/dist/engine.d.ts.map +1 -1
  31. package/dist/engine.js +5 -2
  32. package/dist/engine.js.map +1 -1
  33. package/dist/index.d.ts +2 -0
  34. package/dist/index.d.ts.map +1 -1
  35. package/dist/index.js +2 -0
  36. package/dist/index.js.map +1 -1
  37. package/dist/kit/cartesian.d.ts +49 -15
  38. package/dist/kit/cartesian.d.ts.map +1 -1
  39. package/dist/kit/cartesian.js +79 -29
  40. package/dist/kit/cartesian.js.map +1 -1
  41. package/dist/kit/chart-canvas.d.ts +32 -24
  42. package/dist/kit/chart-canvas.d.ts.map +1 -1
  43. package/dist/kit/chart-canvas.js +52 -46
  44. package/dist/kit/chart-canvas.js.map +1 -1
  45. package/dist/kit/chart-legend.d.ts +8 -4
  46. package/dist/kit/chart-legend.d.ts.map +1 -1
  47. package/dist/kit/chart-legend.js +30 -20
  48. package/dist/kit/chart-legend.js.map +1 -1
  49. package/dist/{line-chart → kit}/horizontal-axis.d.ts +31 -6
  50. package/dist/kit/horizontal-axis.d.ts.map +1 -0
  51. package/dist/{line-chart → kit}/horizontal-axis.js +23 -24
  52. package/dist/kit/horizontal-axis.js.map +1 -0
  53. package/dist/kit/motion.d.ts +5 -0
  54. package/dist/kit/motion.d.ts.map +1 -1
  55. package/dist/kit/motion.js +8 -0
  56. package/dist/kit/motion.js.map +1 -1
  57. package/dist/{pie-chart → kit}/pie-legend.d.ts +3 -3
  58. package/dist/kit/pie-legend.d.ts.map +1 -0
  59. package/dist/{pie-chart → kit}/pie-legend.js +11 -10
  60. package/dist/kit/pie-legend.js.map +1 -0
  61. package/dist/kit/polar.d.ts +31 -0
  62. package/dist/kit/polar.d.ts.map +1 -0
  63. package/dist/kit/polar.js +33 -0
  64. package/dist/kit/polar.js.map +1 -0
  65. package/dist/kit/shared.d.ts +11 -50
  66. package/dist/kit/shared.d.ts.map +1 -1
  67. package/dist/kit/shared.js +58 -141
  68. package/dist/kit/shared.js.map +1 -1
  69. package/dist/kit/style.d.ts +254 -0
  70. package/dist/kit/style.d.ts.map +1 -0
  71. package/dist/kit/style.js +197 -0
  72. package/dist/kit/style.js.map +1 -0
  73. package/dist/kit/vertical-axis.d.ts +22 -2
  74. package/dist/kit/vertical-axis.d.ts.map +1 -1
  75. package/dist/kit/vertical-axis.js +56 -43
  76. package/dist/kit/vertical-axis.js.map +1 -1
  77. package/dist/line-chart/chart-line.d.ts +95 -3
  78. package/dist/line-chart/chart-line.d.ts.map +1 -1
  79. package/dist/line-chart/chart-line.js +165 -53
  80. package/dist/line-chart/chart-line.js.map +1 -1
  81. package/dist/line-chart/chart-region.d.ts +1 -1
  82. package/dist/line-chart/chart-region.d.ts.map +1 -1
  83. package/dist/line-chart/chart-region.js +7 -8
  84. package/dist/line-chart/chart-region.js.map +1 -1
  85. package/dist/line-chart/index.d.ts +5 -6
  86. package/dist/line-chart/index.d.ts.map +1 -1
  87. package/dist/line-chart/index.js +3 -4
  88. package/dist/line-chart/index.js.map +1 -1
  89. package/dist/line-chart/line-chart.d.ts +257 -18
  90. package/dist/line-chart/line-chart.d.ts.map +1 -1
  91. package/dist/line-chart/line-chart.js +282 -134
  92. package/dist/line-chart/line-chart.js.map +1 -1
  93. package/dist/line-chart/shared.d.ts +51 -34
  94. package/dist/line-chart/shared.d.ts.map +1 -1
  95. package/dist/line-chart/shared.js +175 -83
  96. package/dist/line-chart/shared.js.map +1 -1
  97. package/dist/line-chart/x-scale.d.ts +2 -0
  98. package/dist/line-chart/x-scale.d.ts.map +1 -1
  99. package/dist/line-chart/x-scale.js +15 -0
  100. package/dist/line-chart/x-scale.js.map +1 -1
  101. package/dist/nodes.d.ts +3 -1
  102. package/dist/nodes.d.ts.map +1 -1
  103. package/dist/nodes.js +9 -1
  104. package/dist/nodes.js.map +1 -1
  105. package/dist/pie-chart/index.d.ts +2 -3
  106. package/dist/pie-chart/index.d.ts.map +1 -1
  107. package/dist/pie-chart/index.js +1 -2
  108. package/dist/pie-chart/index.js.map +1 -1
  109. package/dist/pie-chart/pie-chart.d.ts +114 -18
  110. package/dist/pie-chart/pie-chart.d.ts.map +1 -1
  111. package/dist/pie-chart/pie-chart.js +37 -24
  112. package/dist/pie-chart/pie-chart.js.map +1 -1
  113. package/dist/pie-chart/pie-ring.d.ts +16 -5
  114. package/dist/pie-chart/pie-ring.d.ts.map +1 -1
  115. package/dist/pie-chart/pie-ring.js +89 -55
  116. package/dist/pie-chart/pie-ring.js.map +1 -1
  117. package/dist/pie-chart/shared.d.ts +53 -61
  118. package/dist/pie-chart/shared.d.ts.map +1 -1
  119. package/dist/pie-chart/shared.js +41 -121
  120. package/dist/pie-chart/shared.js.map +1 -1
  121. package/dist/radar-chart/index.d.ts +5 -0
  122. package/dist/radar-chart/index.d.ts.map +1 -0
  123. package/dist/radar-chart/index.js +5 -0
  124. package/dist/radar-chart/index.js.map +1 -0
  125. package/dist/radar-chart/radar-chart.d.ts +218 -0
  126. package/dist/radar-chart/radar-chart.d.ts.map +1 -0
  127. package/dist/radar-chart/radar-chart.js +224 -0
  128. package/dist/radar-chart/radar-chart.js.map +1 -0
  129. package/dist/radar-chart/radar-grid.d.ts +43 -0
  130. package/dist/radar-chart/radar-grid.d.ts.map +1 -0
  131. package/dist/radar-chart/radar-grid.js +61 -0
  132. package/dist/radar-chart/radar-grid.js.map +1 -0
  133. package/dist/radar-chart/radar-series.d.ts +59 -0
  134. package/dist/radar-chart/radar-series.d.ts.map +1 -0
  135. package/dist/radar-chart/radar-series.js +71 -0
  136. package/dist/radar-chart/radar-series.js.map +1 -0
  137. package/dist/radar-chart/shared.d.ts +73 -0
  138. package/dist/radar-chart/shared.d.ts.map +1 -0
  139. package/dist/radar-chart/shared.js +123 -0
  140. package/dist/radar-chart/shared.js.map +1 -0
  141. package/dist/radial-chart/index.d.ts +6 -0
  142. package/dist/radial-chart/index.d.ts.map +1 -0
  143. package/dist/radial-chart/index.js +4 -0
  144. package/dist/radial-chart/index.js.map +1 -0
  145. package/dist/radial-chart/radial-chart.d.ts +216 -0
  146. package/dist/radial-chart/radial-chart.d.ts.map +1 -0
  147. package/dist/radial-chart/radial-chart.js +174 -0
  148. package/dist/radial-chart/radial-chart.js.map +1 -0
  149. package/dist/radial-chart/radial-rings.d.ts +121 -0
  150. package/dist/radial-chart/radial-rings.d.ts.map +1 -0
  151. package/dist/radial-chart/radial-rings.js +273 -0
  152. package/dist/radial-chart/radial-rings.js.map +1 -0
  153. package/dist/radial-chart/shared.d.ts +73 -0
  154. package/dist/radial-chart/shared.d.ts.map +1 -0
  155. package/dist/radial-chart/shared.js +79 -0
  156. package/dist/radial-chart/shared.js.map +1 -0
  157. package/package.json +4 -4
  158. package/registry.json +21 -6
  159. package/src/bar-chart/bar-chart.ts +252 -179
  160. package/src/bar-chart/category-axis.ts +46 -40
  161. package/src/bar-chart/chart-bars.ts +97 -117
  162. package/src/bar-chart/index.ts +7 -10
  163. package/src/bar-chart/shared.ts +78 -238
  164. package/src/engine.ts +5 -2
  165. package/src/index.ts +2 -0
  166. package/src/kit/cartesian.ts +118 -40
  167. package/src/kit/chart-canvas.ts +49 -54
  168. package/src/kit/chart-legend.ts +28 -20
  169. package/src/kit/horizontal-axis.ts +114 -0
  170. package/src/kit/motion.ts +7 -0
  171. package/src/{pie-chart → kit}/pie-legend.ts +12 -11
  172. package/src/kit/polar.ts +54 -0
  173. package/src/kit/shared.ts +55 -277
  174. package/src/kit/style.ts +257 -0
  175. package/src/kit/vertical-axis.ts +67 -48
  176. package/src/line-chart/chart-line.ts +176 -54
  177. package/src/line-chart/chart-region.ts +6 -10
  178. package/src/line-chart/index.ts +14 -10
  179. package/src/line-chart/line-chart.ts +347 -151
  180. package/src/line-chart/shared.ts +193 -174
  181. package/src/line-chart/x-scale.ts +13 -0
  182. package/src/nodes.ts +9 -1
  183. package/src/pie-chart/index.ts +2 -23
  184. package/src/pie-chart/pie-chart.ts +52 -35
  185. package/src/pie-chart/pie-ring.ts +92 -71
  186. package/src/pie-chart/shared.ts +68 -266
  187. package/src/radar-chart/index.ts +4 -0
  188. package/src/radar-chart/radar-chart.ts +287 -0
  189. package/src/radar-chart/radar-grid.ts +78 -0
  190. package/src/radar-chart/radar-series.ts +88 -0
  191. package/src/radar-chart/shared.ts +146 -0
  192. package/src/radial-chart/index.ts +5 -0
  193. package/src/radial-chart/radial-chart.ts +210 -0
  194. package/src/radial-chart/radial-rings.ts +328 -0
  195. package/src/radial-chart/shared.ts +114 -0
  196. package/dist/browser/chunks/chunk-4SMRCU24.js +0 -2
  197. package/dist/browser/chunks/chunk-4SMRCU24.js.map +0 -7
  198. package/dist/kit/chart-border.d.ts +0 -18
  199. package/dist/kit/chart-border.d.ts.map +0 -1
  200. package/dist/kit/chart-border.js +0 -23
  201. package/dist/kit/chart-border.js.map +0 -1
  202. package/dist/line-chart/horizontal-axis.d.ts.map +0 -1
  203. package/dist/line-chart/horizontal-axis.js.map +0 -1
  204. package/dist/pie-chart/pie-legend.d.ts.map +0 -1
  205. package/dist/pie-chart/pie-legend.js.map +0 -1
  206. package/src/kit/chart-border.ts +0 -36
  207. package/src/line-chart/horizontal-axis.ts +0 -122
@@ -1 +1 @@
1
- {"version":3,"file":"shared.js","sourceRoot":"","sources":["../../src/pie-chart/shared.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n clamp,\n lerpNumber,\n shadowOps,\n strokeOps,\n textOps,\n type DataRecord,\n type Fill,\n type Shadow,\n type ShadowResolved,\n type Stroke,\n type StrokeResolved,\n type TextStyle,\n type Vector2,\n} from \"@motionscript/sdk\"\n\nimport {\n CHART_PALETTE,\n DEFAULT_LEGEND,\n DEFAULT_SERIES_FILLS,\n lerpLegendConfig,\n lerpSeriesFills,\n num,\n resolveLegendConfig,\n resolveSeriesFills,\n text,\n type LegendConfig,\n type LegendTheme,\n} from \"../kit/shared\"\n\n/** One resolved slice, which the ring and legend consume; the chart resolves it from `data` and two field names. */\nexport interface PieSlice {\n /** Label and legend caption. */\n category: string\n /** The wedge covers `value / (sum of all values)`. */\n value: number\n /** Wedge and swatch paint. */\n fill: Fill\n}\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(\n data: DataRecord[],\n category: string,\n value: string,\n palette: Fill[]\n): PieSlice[] {\n return data.map((row, i) => ({\n category: text(row, category),\n value: num(row, value),\n fill:\n 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: a leader 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; `\"leader\"` is what a sliver too narrow for text needs. */\nexport type PieLabelPlacement = \"inside\" | \"leader\" | \"none\"\n\nexport const DEG = Math.PI / 180\n\n/**\n * Opacity of a slice under the selection: 1 while nothing is out (`focus` is the\n * most-grown pop) and for the selected slice itself, falling toward `dimOpacity`\n * for the rest as the selection grows.\n */\nexport function selectionFade(focus: number, dimOpacity: number, pop: number): number {\n if (focus <= 0) return 1\n return 1 - (1 - clamp(dimOpacity, 0, 1)) * focus * (1 - pop)\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/** The point at radius `r`, angle `a` on a ring about the origin in centred y-up space. Angles run clockwise from 12 o'clock. */\nexport function ringPoint(r: number, a: number): Vector2 {\n return { x: r * Math.sin(a), y: r * Math.cos(a) }\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>(\n slots: T[],\n minGap: number,\n top: number,\n bottom: number\n): 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 and paint: 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 stroke: Stroke\n shadow: Shadow\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. */\n textStyle: TextStyle\n /** The percentage. */\n percentStyle: TextStyle\n /** Both lines of a label inside its wedge: it sits on the wedge's paint, so it usually wants the opposite end of the value range from everything else. */\n insideStyle: TextStyle\n /** Runs from a wedge out to its label. */\n leaderStroke: Stroke\n}\n\n/** The summary set in the ring's hole. */\nexport interface CenterConfig {\n labelStyle: TextStyle\n captionStyle: TextStyle\n}\n\n/** A {@link PieChart}'s full, resolved visual theme. */\nexport interface PieChartConfig {\n /** Wedge and swatch paint, cycled by **row** index (`i % length`). */\n sliceFills: Fill[]\n ring: RingConfig\n label: LabelConfig\n center: CenterConfig\n legend: LegendConfig\n /** How far everything outside the selection fades while any slice is selected. */\n spotlight: { dimOpacity: number }\n}\n\n/** The author's partial theme, deep-merged onto {@link DEFAULT_PIE_CHART_THEME}. */\nexport type PieChartTheme = {\n sliceFills?: Fill[]\n ring?: Partial<RingConfig>\n label?: Partial<LabelConfig>\n center?: Partial<CenterConfig>\n legend?: LegendTheme\n spotlight?: Partial<PieChartConfig[\"spotlight\"]>\n}\n\nconst LABEL_TEXT_STYLE: TextStyle = {\n fontSize: 26,\n fontWeight: 600,\n textAlign: \"center\",\n fill: CHART_PALETTE.markerColor,\n}\n\n/** Fainter than `SPOTLIGHT_DIM`: a ring's slices touch, so at that a selected slice barely separates. */\nexport const PIE_SPOTLIGHT_DIM = 0.1\n\nexport const DEFAULT_PIE_CHART_THEME: PieChartConfig = {\n sliceFills: DEFAULT_SERIES_FILLS,\n ring: {\n gap: 6,\n // A donut by default: the hole is the one place a conclusion can be set.\n holeRadius: 0.6,\n startAngle: 0,\n selectedGrow: 1.08,\n stroke: [],\n shadow: [],\n },\n label: {\n textStyle: LABEL_TEXT_STYLE,\n percentStyle: { ...LABEL_TEXT_STYLE, fontWeight: 700 },\n // On a mid-tone wedge, so the panel colour rather than the axis ink.\n insideStyle: { ...LABEL_TEXT_STYLE, fontWeight: 800, fill: \"#15130e\" },\n leaderStroke: { weight: 2, fill: CHART_PALETTE.markerColor },\n },\n center: {\n labelStyle: {\n fontSize: 46,\n fontWeight: 800,\n textAlign: \"center\",\n fill: CHART_PALETTE.markerColor,\n },\n captionStyle: {\n fontSize: 22,\n fontWeight: 500,\n textAlign: \"center\",\n fill: CHART_PALETTE.markerColor,\n },\n },\n legend: DEFAULT_LEGEND,\n spotlight: { dimOpacity: PIE_SPOTLIGHT_DIM },\n}\n\nfunction resolveRingConfig(\n ring: Partial<RingConfig> | undefined,\n previous: RingConfig\n): RingConfig {\n return {\n gap: ring?.gap ?? previous.gap,\n holeRadius: ring?.holeRadius ?? previous.holeRadius,\n startAngle: ring?.startAngle ?? previous.startAngle,\n selectedGrow: ring?.selectedGrow ?? previous.selectedGrow,\n stroke: strokeOps.resolve(ring?.stroke ?? previous.stroke),\n shadow: shadowOps.resolve(ring?.shadow ?? previous.shadow),\n }\n}\n\nfunction lerpRingConfig(\n from: RingConfig,\n to: RingConfig,\n t: number\n): RingConfig {\n return {\n gap: lerpNumber(from.gap, to.gap, t),\n holeRadius: lerpNumber(from.holeRadius, to.holeRadius, t),\n startAngle: lerpNumber(from.startAngle, to.startAngle, t),\n selectedGrow: lerpNumber(from.selectedGrow, to.selectedGrow, t),\n stroke: strokeOps.lerp(\n from.stroke as StrokeResolved[],\n to.stroke as StrokeResolved[],\n t\n ),\n shadow: shadowOps.lerp(\n from.shadow as ShadowResolved[],\n to.shadow as ShadowResolved[],\n t\n ),\n }\n}\n\nfunction resolveLabelConfig(\n label: Partial<LabelConfig> | undefined,\n previous: LabelConfig\n): LabelConfig {\n return {\n textStyle: textOps.resolveStyle(label?.textStyle, previous.textStyle),\n percentStyle: textOps.resolveStyle(\n label?.percentStyle,\n previous.percentStyle\n ),\n insideStyle: textOps.resolveStyle(label?.insideStyle, previous.insideStyle),\n leaderStroke: strokeOps.resolve(\n label?.leaderStroke ?? previous.leaderStroke\n ),\n }\n}\n\nfunction lerpLabelConfig(\n from: LabelConfig,\n to: LabelConfig,\n t: number\n): LabelConfig {\n return {\n textStyle: textOps.lerpStyle(from.textStyle, to.textStyle, t),\n percentStyle: textOps.lerpStyle(from.percentStyle, to.percentStyle, t),\n insideStyle: textOps.lerpStyle(from.insideStyle, to.insideStyle, t),\n leaderStroke: strokeOps.lerp(\n from.leaderStroke as StrokeResolved[],\n to.leaderStroke as StrokeResolved[],\n t\n ),\n }\n}\n\nfunction resolveCenterConfig(\n center: Partial<CenterConfig> | undefined,\n previous: CenterConfig\n): CenterConfig {\n return {\n labelStyle: textOps.resolveStyle(center?.labelStyle, previous.labelStyle),\n captionStyle: textOps.resolveStyle(\n center?.captionStyle,\n previous.captionStyle\n ),\n }\n}\n\nfunction lerpCenterConfig(\n from: CenterConfig,\n to: CenterConfig,\n t: number\n): CenterConfig {\n return {\n labelStyle: textOps.lerpStyle(from.labelStyle, to.labelStyle, t),\n captionStyle: textOps.lerpStyle(from.captionStyle, to.captionStyle, t),\n }\n}\n\n/** The `theme` entry's resolve: merges a partial {@link PieChartTheme} onto `previous` (first resolution: the default). */\nexport function resolvePieChartTheme(\n theme: PieChartTheme | undefined,\n previous?: PieChartConfig\n): PieChartConfig {\n const base = previous ?? DEFAULT_PIE_CHART_THEME\n return {\n sliceFills: resolveSeriesFills(theme?.sliceFills, base.sliceFills),\n ring: resolveRingConfig(theme?.ring, base.ring),\n label: resolveLabelConfig(theme?.label, base.label),\n center: resolveCenterConfig(theme?.center, base.center),\n legend: resolveLegendConfig(theme?.legend, base.legend),\n spotlight: {\n dimOpacity: theme?.spotlight?.dimOpacity ?? base.spotlight.dimOpacity,\n },\n }\n}\n\nexport function lerpPieChartTheme(\n from: PieChartConfig,\n to: PieChartConfig,\n t: number\n): PieChartConfig {\n return {\n sliceFills: lerpSeriesFills(from.sliceFills, to.sliceFills, t),\n ring: lerpRingConfig(from.ring, to.ring, t),\n label: lerpLabelConfig(from.label, to.label, t),\n center: lerpCenterConfig(from.center, to.center, t),\n legend: lerpLegendConfig(from.legend, to.legend, t),\n spotlight: {\n dimOpacity: lerpNumber(\n from.spotlight.dimOpacity,\n to.spotlight.dimOpacity,\n t\n ),\n },\n }\n}\n"]}
1
+ {"version":3,"file":"shared.js","sourceRoot":"","sources":["../../src/pie-chart/shared.ts"],"names":[],"mappings":"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","sourcesContent":["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"]}
@@ -0,0 +1,5 @@
1
+ export { RadarChart, radarFractions, radarScale, type RadarValues } from "./radar-chart.js";
2
+ export { RadarGrid } from "./radar-grid.js";
3
+ export { RadarSeries, seriesVertices } from "./radar-series.js";
4
+ export { RADAR_GRID, RADAR_MARKS, fitRadius, niceCeil, spokeDirection } from "./shared.js";
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/radar-chart/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,UAAU,EAAE,KAAK,WAAW,EAAE,MAAM,eAAe,CAAA;AACxF,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAA;AACxC,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAC5D,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,SAAS,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,UAAU,CAAA"}
@@ -0,0 +1,5 @@
1
+ export { RadarChart, radarFractions, radarScale } from "./radar-chart.js";
2
+ export { RadarGrid } from "./radar-grid.js";
3
+ export { RadarSeries, seriesVertices } from "./radar-series.js";
4
+ export { RADAR_GRID, RADAR_MARKS, fitRadius, niceCeil, spokeDirection } from "./shared.js";
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/radar-chart/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,UAAU,EAAoB,MAAM,eAAe,CAAA;AACxF,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAA;AACxC,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAC5D,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,SAAS,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,UAAU,CAAA","sourcesContent":["export { RadarChart, radarFractions, radarScale, type RadarValues } from \"./radar-chart\"\nexport { RadarGrid } from \"./radar-grid\"\nexport { RadarSeries, seriesVertices } from \"./radar-series\"\nexport { RADAR_GRID, RADAR_MARKS, fitRadius, niceCeil, spokeDirection } from \"./shared\"\n"]}
@@ -0,0 +1,218 @@
1
+ import { type DataRecord, type NodeOf, type Node2D, type Node2DProps as _Node2DProps, type Fill as _Fill, type FillResolved as _FillResolved, type Stroke as _Stroke, type StrokeResolved as _StrokeResolved } from "@motionscript/sdk";
2
+ import { type ChartSeries } from "../kit/shared.js";
3
+ /** What a radar chart plots, as its entries hold it. */
4
+ export interface RadarValues {
5
+ readonly data: DataRecord[];
6
+ readonly categoryField: string;
7
+ readonly series: ChartSeries[];
8
+ readonly min: number;
9
+ readonly max: number;
10
+ }
11
+ /** The scale the web is drawn to, whether `max` was given or left to the data. */
12
+ export declare function radarScale(state: RadarValues): {
13
+ min: number;
14
+ max: number;
15
+ };
16
+ /** Series `index`'s values as fractions of the rim, in spoke order. */
17
+ export declare function radarFractions(state: RadarValues, index: number): number[];
18
+ /**
19
+ * A radar (spider) chart: one spoke per data row, one closed polygon per
20
+ * series, over a web of rings. Composed of a {@link RadarGrid}, a
21
+ * {@link RadarSeries} per series, the category labels and a {@link ChartLegend}.
22
+ *
23
+ * Resting state is the finished chart; `enter` arms every part on its first
24
+ * frame. `max` of 0 (or one not above `min`) is the largest value rounded up.
25
+ */
26
+ export declare const RadarChart: import("@motionscript/sdk").Component<"radarChart", import("@motionscript/sdk").Merge<import("@motionscript/sdk").Box2DState, {
27
+ readonly data: import("@motionscript/sdk").Type<DataRecord[], DataRecord[], false>;
28
+ /** The column that names each spoke. */
29
+ readonly categoryField: "";
30
+ readonly series: import("@motionscript/sdk").Type<ChartSeries[], ChartSeries[], false>;
31
+ /** The value at the centre of the web. */
32
+ readonly min: 0;
33
+ /** The value at the rim; 0 rounds the largest value up. */
34
+ readonly max: 0;
35
+ readonly style: import("@motionscript/sdk").Type<import("@motionscript/sdk").StyleInput<{
36
+ legend: import("@motionscript/sdk").Type<"right" | "top" | "bottom" | "none", "right" | "top" | "bottom" | "none", false>;
37
+ swatch: import("@motionscript/sdk").Type<"square" | "circle" | "line", "square" | "circle" | "line", false>;
38
+ } & {
39
+ gridShape: import("@motionscript/sdk").Type<"circle" | "polygon", "circle" | "polygon", false>;
40
+ gridLevels: import("@motionscript/sdk").Type<number, number, false>;
41
+ gridStroke: import("@motionscript/sdk").Type<_Stroke, _StrokeResolved[], false>;
42
+ spokeStroke: import("@motionscript/sdk").Type<_Stroke, _StrokeResolved[], false>;
43
+ spokeLabels: import("@motionscript/sdk").Type<boolean, boolean, false>;
44
+ } & {
45
+ fontFamily: import("@motionscript/sdk").Type<string, string, false>;
46
+ fontSize: import("@motionscript/sdk").Type<number, number, false>;
47
+ fontWeight: import("@motionscript/sdk").Type<number, number, false>;
48
+ } & {
49
+ palette: import("@motionscript/sdk").Type<_Fill[], _FillResolved[][], false>;
50
+ foreground: import("@motionscript/sdk").Type<_Fill, _FillResolved[], false>;
51
+ muted: import("@motionscript/sdk").Type<_Fill, _FillResolved[], false>;
52
+ background: import("@motionscript/sdk").Type<_Fill, _FillResolved[], false>;
53
+ } & {
54
+ strokeWidth: import("@motionscript/sdk").Type<number, number, false>;
55
+ areaOpacity: import("@motionscript/sdk").Type<number, number, false>;
56
+ dots: import("@motionscript/sdk").Type<boolean, boolean, false>;
57
+ dotSize: import("@motionscript/sdk").Type<number, number, false>;
58
+ }>, import("@motionscript/sdk").StyleValues<{
59
+ legend: import("@motionscript/sdk").Type<"right" | "top" | "bottom" | "none", "right" | "top" | "bottom" | "none", false>;
60
+ swatch: import("@motionscript/sdk").Type<"square" | "circle" | "line", "square" | "circle" | "line", false>;
61
+ } & {
62
+ gridShape: import("@motionscript/sdk").Type<"circle" | "polygon", "circle" | "polygon", false>;
63
+ gridLevels: import("@motionscript/sdk").Type<number, number, false>;
64
+ gridStroke: import("@motionscript/sdk").Type<_Stroke, _StrokeResolved[], false>;
65
+ spokeStroke: import("@motionscript/sdk").Type<_Stroke, _StrokeResolved[], false>;
66
+ spokeLabels: import("@motionscript/sdk").Type<boolean, boolean, false>;
67
+ } & {
68
+ fontFamily: import("@motionscript/sdk").Type<string, string, false>;
69
+ fontSize: import("@motionscript/sdk").Type<number, number, false>;
70
+ fontWeight: import("@motionscript/sdk").Type<number, number, false>;
71
+ } & {
72
+ palette: import("@motionscript/sdk").Type<_Fill[], _FillResolved[][], false>;
73
+ foreground: import("@motionscript/sdk").Type<_Fill, _FillResolved[], false>;
74
+ muted: import("@motionscript/sdk").Type<_Fill, _FillResolved[], false>;
75
+ background: import("@motionscript/sdk").Type<_Fill, _FillResolved[], false>;
76
+ } & {
77
+ strokeWidth: import("@motionscript/sdk").Type<number, number, false>;
78
+ areaOpacity: import("@motionscript/sdk").Type<number, number, false>;
79
+ dots: import("@motionscript/sdk").Type<boolean, boolean, false>;
80
+ dotSize: import("@motionscript/sdk").Type<number, number, false>;
81
+ }>, false>;
82
+ }>, {
83
+ readonly enter: {};
84
+ readonly showSeries: {
85
+ readonly seriesIndex: import("@motionscript/sdk").Type<number, number, false>;
86
+ };
87
+ readonly hideSeries: {
88
+ readonly seriesIndex: import("@motionscript/sdk").Type<number, number, false>;
89
+ };
90
+ readonly spotlightSeries: {
91
+ readonly seriesIndex: import("@motionscript/sdk").Type<number, number, false>;
92
+ };
93
+ }, readonly [], Node2D<_Node2DProps>, import("@motionscript/sdk").CallProps<import("@motionscript/sdk").Merge<import("@motionscript/sdk").Box2DState, {
94
+ readonly data: import("@motionscript/sdk").Type<DataRecord[], DataRecord[], false>;
95
+ /** The column that names each spoke. */
96
+ readonly categoryField: "";
97
+ readonly series: import("@motionscript/sdk").Type<ChartSeries[], ChartSeries[], false>;
98
+ /** The value at the centre of the web. */
99
+ readonly min: 0;
100
+ /** The value at the rim; 0 rounds the largest value up. */
101
+ readonly max: 0;
102
+ readonly style: import("@motionscript/sdk").Type<import("@motionscript/sdk").StyleInput<{
103
+ legend: import("@motionscript/sdk").Type<"right" | "top" | "bottom" | "none", "right" | "top" | "bottom" | "none", false>;
104
+ swatch: import("@motionscript/sdk").Type<"square" | "circle" | "line", "square" | "circle" | "line", false>;
105
+ } & {
106
+ gridShape: import("@motionscript/sdk").Type<"circle" | "polygon", "circle" | "polygon", false>;
107
+ gridLevels: import("@motionscript/sdk").Type<number, number, false>;
108
+ gridStroke: import("@motionscript/sdk").Type<_Stroke, _StrokeResolved[], false>;
109
+ spokeStroke: import("@motionscript/sdk").Type<_Stroke, _StrokeResolved[], false>;
110
+ spokeLabels: import("@motionscript/sdk").Type<boolean, boolean, false>;
111
+ } & {
112
+ fontFamily: import("@motionscript/sdk").Type<string, string, false>;
113
+ fontSize: import("@motionscript/sdk").Type<number, number, false>;
114
+ fontWeight: import("@motionscript/sdk").Type<number, number, false>;
115
+ } & {
116
+ palette: import("@motionscript/sdk").Type<_Fill[], _FillResolved[][], false>;
117
+ foreground: import("@motionscript/sdk").Type<_Fill, _FillResolved[], false>;
118
+ muted: import("@motionscript/sdk").Type<_Fill, _FillResolved[], false>;
119
+ background: import("@motionscript/sdk").Type<_Fill, _FillResolved[], false>;
120
+ } & {
121
+ strokeWidth: import("@motionscript/sdk").Type<number, number, false>;
122
+ areaOpacity: import("@motionscript/sdk").Type<number, number, false>;
123
+ dots: import("@motionscript/sdk").Type<boolean, boolean, false>;
124
+ dotSize: import("@motionscript/sdk").Type<number, number, false>;
125
+ }>, import("@motionscript/sdk").StyleValues<{
126
+ legend: import("@motionscript/sdk").Type<"right" | "top" | "bottom" | "none", "right" | "top" | "bottom" | "none", false>;
127
+ swatch: import("@motionscript/sdk").Type<"square" | "circle" | "line", "square" | "circle" | "line", false>;
128
+ } & {
129
+ gridShape: import("@motionscript/sdk").Type<"circle" | "polygon", "circle" | "polygon", false>;
130
+ gridLevels: import("@motionscript/sdk").Type<number, number, false>;
131
+ gridStroke: import("@motionscript/sdk").Type<_Stroke, _StrokeResolved[], false>;
132
+ spokeStroke: import("@motionscript/sdk").Type<_Stroke, _StrokeResolved[], false>;
133
+ spokeLabels: import("@motionscript/sdk").Type<boolean, boolean, false>;
134
+ } & {
135
+ fontFamily: import("@motionscript/sdk").Type<string, string, false>;
136
+ fontSize: import("@motionscript/sdk").Type<number, number, false>;
137
+ fontWeight: import("@motionscript/sdk").Type<number, number, false>;
138
+ } & {
139
+ palette: import("@motionscript/sdk").Type<_Fill[], _FillResolved[][], false>;
140
+ foreground: import("@motionscript/sdk").Type<_Fill, _FillResolved[], false>;
141
+ muted: import("@motionscript/sdk").Type<_Fill, _FillResolved[], false>;
142
+ background: import("@motionscript/sdk").Type<_Fill, _FillResolved[], false>;
143
+ } & {
144
+ strokeWidth: import("@motionscript/sdk").Type<number, number, false>;
145
+ areaOpacity: import("@motionscript/sdk").Type<number, number, false>;
146
+ dots: import("@motionscript/sdk").Type<boolean, boolean, false>;
147
+ dotSize: import("@motionscript/sdk").Type<number, number, false>;
148
+ }>, false>;
149
+ }>, readonly [], import("@motionscript/sdk").BuiltNode<import("@motionscript/sdk").Merge<import("@motionscript/sdk").Box2DState, {
150
+ readonly data: import("@motionscript/sdk").Type<DataRecord[], DataRecord[], false>;
151
+ /** The column that names each spoke. */
152
+ readonly categoryField: "";
153
+ readonly series: import("@motionscript/sdk").Type<ChartSeries[], ChartSeries[], false>;
154
+ /** The value at the centre of the web. */
155
+ readonly min: 0;
156
+ /** The value at the rim; 0 rounds the largest value up. */
157
+ readonly max: 0;
158
+ readonly style: import("@motionscript/sdk").Type<import("@motionscript/sdk").StyleInput<{
159
+ legend: import("@motionscript/sdk").Type<"right" | "top" | "bottom" | "none", "right" | "top" | "bottom" | "none", false>;
160
+ swatch: import("@motionscript/sdk").Type<"square" | "circle" | "line", "square" | "circle" | "line", false>;
161
+ } & {
162
+ gridShape: import("@motionscript/sdk").Type<"circle" | "polygon", "circle" | "polygon", false>;
163
+ gridLevels: import("@motionscript/sdk").Type<number, number, false>;
164
+ gridStroke: import("@motionscript/sdk").Type<_Stroke, _StrokeResolved[], false>;
165
+ spokeStroke: import("@motionscript/sdk").Type<_Stroke, _StrokeResolved[], false>;
166
+ spokeLabels: import("@motionscript/sdk").Type<boolean, boolean, false>;
167
+ } & {
168
+ fontFamily: import("@motionscript/sdk").Type<string, string, false>;
169
+ fontSize: import("@motionscript/sdk").Type<number, number, false>;
170
+ fontWeight: import("@motionscript/sdk").Type<number, number, false>;
171
+ } & {
172
+ palette: import("@motionscript/sdk").Type<_Fill[], _FillResolved[][], false>;
173
+ foreground: import("@motionscript/sdk").Type<_Fill, _FillResolved[], false>;
174
+ muted: import("@motionscript/sdk").Type<_Fill, _FillResolved[], false>;
175
+ background: import("@motionscript/sdk").Type<_Fill, _FillResolved[], false>;
176
+ } & {
177
+ strokeWidth: import("@motionscript/sdk").Type<number, number, false>;
178
+ areaOpacity: import("@motionscript/sdk").Type<number, number, false>;
179
+ dots: import("@motionscript/sdk").Type<boolean, boolean, false>;
180
+ dotSize: import("@motionscript/sdk").Type<number, number, false>;
181
+ }>, import("@motionscript/sdk").StyleValues<{
182
+ legend: import("@motionscript/sdk").Type<"right" | "top" | "bottom" | "none", "right" | "top" | "bottom" | "none", false>;
183
+ swatch: import("@motionscript/sdk").Type<"square" | "circle" | "line", "square" | "circle" | "line", false>;
184
+ } & {
185
+ gridShape: import("@motionscript/sdk").Type<"circle" | "polygon", "circle" | "polygon", false>;
186
+ gridLevels: import("@motionscript/sdk").Type<number, number, false>;
187
+ gridStroke: import("@motionscript/sdk").Type<_Stroke, _StrokeResolved[], false>;
188
+ spokeStroke: import("@motionscript/sdk").Type<_Stroke, _StrokeResolved[], false>;
189
+ spokeLabels: import("@motionscript/sdk").Type<boolean, boolean, false>;
190
+ } & {
191
+ fontFamily: import("@motionscript/sdk").Type<string, string, false>;
192
+ fontSize: import("@motionscript/sdk").Type<number, number, false>;
193
+ fontWeight: import("@motionscript/sdk").Type<number, number, false>;
194
+ } & {
195
+ palette: import("@motionscript/sdk").Type<_Fill[], _FillResolved[][], false>;
196
+ foreground: import("@motionscript/sdk").Type<_Fill, _FillResolved[], false>;
197
+ muted: import("@motionscript/sdk").Type<_Fill, _FillResolved[], false>;
198
+ background: import("@motionscript/sdk").Type<_Fill, _FillResolved[], false>;
199
+ } & {
200
+ strokeWidth: import("@motionscript/sdk").Type<number, number, false>;
201
+ areaOpacity: import("@motionscript/sdk").Type<number, number, false>;
202
+ dots: import("@motionscript/sdk").Type<boolean, boolean, false>;
203
+ dotSize: import("@motionscript/sdk").Type<number, number, false>;
204
+ }>, false>;
205
+ }>, {
206
+ readonly enter: {};
207
+ readonly showSeries: {
208
+ readonly seriesIndex: import("@motionscript/sdk").Type<number, number, false>;
209
+ };
210
+ readonly hideSeries: {
211
+ readonly seriesIndex: import("@motionscript/sdk").Type<number, number, false>;
212
+ };
213
+ readonly spotlightSeries: {
214
+ readonly seriesIndex: import("@motionscript/sdk").Type<number, number, false>;
215
+ };
216
+ }, Node2D<_Node2DProps>>>>;
217
+ export type RadarChart = NodeOf<typeof RadarChart>;
218
+ //# sourceMappingURL=radar-chart.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"radar-chart.d.ts","sourceRoot":"","sources":["../../src/radar-chart/radar-chart.ts"],"names":[],"mappings":"AAAA,OAAO,EAQL,KAAK,UAAU,EACf,KAAK,MAAM,EAEX,KAAK,MAAM,EACX,KAAK,WAAW,IAAI,YAAY,EAChC,KAAK,IAAI,IAAI,KAAK,EAClB,KAAK,YAAY,IAAI,aAAa,EAClC,KAAK,MAAM,IAAI,OAAO,EACtB,KAAK,cAAc,IAAI,eAAe,EAGvC,MAAM,mBAAmB,CAAA;AAM1B,OAAO,EAAiB,KAAK,WAAW,EAAE,MAAM,eAAe,CAAA;AAyB/D,wDAAwD;AACxD,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,IAAI,EAAE,UAAU,EAAE,CAAA;IAC3B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAA;IAC9B,QAAQ,CAAC,MAAM,EAAE,WAAW,EAAE,CAAA;IAC9B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;CACrB;AAED,kFAAkF;AAClF,wBAAgB,UAAU,CAAC,KAAK,EAAE,WAAW,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAE3E;AAED,uEAAuE;AACvE,wBAAgB,cAAc,CAAC,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAQ1E;AAgCD;;;;;;;GAOG;AACH,eAAO,MAAM,UAAU;;IAInB,wCAAwC;;;IAGxC,0CAA0C;;IAE1C,2DAA2D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAL3D,wCAAwC;;;IAGxC,0CAA0C;;IAE1C,2DAA2D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAL3D,wCAAwC;;;IAGxC,0CAA0C;;IAE1C,2DAA2D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;0BAkK7D,CAAA;AAEF,MAAM,MAAM,UAAU,GAAG,MAAM,CAAC,OAAO,UAAU,CAAC,CAAA"}
@@ -0,0 +1,224 @@
1
+ import { Rect, Text, Types, component2d, easeOut, textOps, } from "@motionscript/sdk";
2
+ import { laidOutSize } from "../kit/cartesian.js";
3
+ import { ChartLegend } from "../kit/chart-legend.js";
4
+ import { SERIES_ARG, asParts, fresh } from "../kit/entries.js";
5
+ import { ENTER_SHARE, LEGEND_SLIDE, beats } from "../kit/motion.js";
6
+ import { SPOTLIGHT_DIM } from "../kit/shared.js";
7
+ import { CHART_COLORS, CHART_LEGEND, CHART_STYLE_FAMILY, CHART_STYLE_PRESETS, CHART_TEXT, legendConfigOf, markerText, seriesFill, } from "../kit/style.js";
8
+ import { RadarGrid } from "./radar-grid.js";
9
+ import { RadarSeries } from "./radar-series.js";
10
+ import { RADAR_GRID, RADAR_MARKS, categoriesOf, fitRadius, fractionOf, labelAnchor, labelPoint, scaleOf, valuesOf, } from "./shared.js";
11
+ /** The scale the web is drawn to, whether `max` was given or left to the data. */
12
+ export function radarScale(state) {
13
+ return scaleOf(valuesOf(state.data, state.series), state.min, state.max);
14
+ }
15
+ /** Series `index`'s values as fractions of the rim, in spoke order. */
16
+ export function radarFractions(state, index) {
17
+ const series = state.series[index];
18
+ if (!series)
19
+ return [];
20
+ const scale = radarScale(state);
21
+ return state.data.map((row) => {
22
+ const v = row[series.field];
23
+ return fractionOf(typeof v === "number" && Number.isFinite(v) ? v : 0, scale);
24
+ });
25
+ }
26
+ /** The grid, series, label layer and legend among the children; the last row holding a grid is the one the chart built. */
27
+ function partsOf(children) {
28
+ for (let i = children.length - 1; i >= 0; i--) {
29
+ const row = children[i];
30
+ if (!Rect.is(row))
31
+ continue;
32
+ const plot = row.children.find((part) => Rect.is(part) && part.children.some(RadarGrid.is));
33
+ if (!plot)
34
+ continue;
35
+ return {
36
+ grid: plot.children.find(RadarGrid.is),
37
+ series: plot.children.filter(RadarSeries.is),
38
+ labels: plot.children.find(Rect.is) ?? null,
39
+ legend: row.children.find(ChartLegend.is) ?? null,
40
+ };
41
+ }
42
+ return null;
43
+ }
44
+ function toggling(timeline, children, index, show) {
45
+ const parts = partsOf(children);
46
+ const series = parts?.series[index];
47
+ if (!parts || !series)
48
+ return timeline.wait(timeline.duration);
49
+ return timeline.together([
50
+ series.run("enter", show ? { from: 0, to: 1 } : { from: 1, to: 0 }),
51
+ ...(parts.legend ? [parts.legend.run(show ? "showSeries" : "hideSeries", { index })] : []),
52
+ ]);
53
+ }
54
+ /** The share of one series' growth that passes before the next starts. */
55
+ const STAGGER = 0.3;
56
+ /**
57
+ * A radar (spider) chart: one spoke per data row, one closed polygon per
58
+ * series, over a web of rings. Composed of a {@link RadarGrid}, a
59
+ * {@link RadarSeries} per series, the category labels and a {@link ChartLegend}.
60
+ *
61
+ * Resting state is the finished chart; `enter` arms every part on its first
62
+ * frame. `max` of 0 (or one not above `min`) is the largest value rounded up.
63
+ */
64
+ export const RadarChart = component2d({
65
+ key: "radarChart",
66
+ state: {
67
+ data: fresh(() => [], { kind: "dataset" }),
68
+ /** The column that names each spoke. */
69
+ categoryField: "",
70
+ series: fresh(() => [], { kind: "series" }),
71
+ /** The value at the centre of the web. */
72
+ min: 0,
73
+ /** The value at the rim; 0 rounds the largest value up. */
74
+ max: 0,
75
+ style: Types.style(CHART_STYLE_FAMILY, {
76
+ colors: CHART_COLORS,
77
+ text: CHART_TEXT,
78
+ grid: RADAR_GRID,
79
+ marks: RADAR_MARKS,
80
+ legend: CHART_LEGEND,
81
+ }, { presets: CHART_STYLE_PRESETS }),
82
+ },
83
+ // A node made of parts that fill would otherwise hug them.
84
+ defaults: { width: "fill", height: "fill" },
85
+ allowedChildren: [],
86
+ children: (state) => {
87
+ const style = () => state.style;
88
+ let plot;
89
+ const plotSize = () => laidOutSize(plot);
90
+ const radius = () => fitRadius(plotSize(), categoriesOf(state.data, state.categoryField), style().fontSize, style().spokeLabels);
91
+ const count = state.data.length;
92
+ const enabled = state.series.map((s) => s.enabled ?? true);
93
+ const grid = new RadarGrid({
94
+ count: () => state.data.length,
95
+ radius,
96
+ levels: () => style().gridLevels,
97
+ shape: () => style().gridShape,
98
+ stroke: () => style().gridStroke,
99
+ spokeStroke: () => style().spokeStroke,
100
+ });
101
+ const series = state.series.map((s, i) => new RadarSeries({
102
+ fractions: () => radarFractions(state, i),
103
+ radius,
104
+ fill: () => seriesFill(style(), s, i),
105
+ stroke: () => {
106
+ const weight = style().strokeWidth;
107
+ return weight > 0 ? { weight, fill: seriesFill(style(), s, i), align: "center", join: "round" } : [];
108
+ },
109
+ areaOpacity: () => style().areaOpacity,
110
+ dots: () => style().dots,
111
+ dotSize: () => style().dotSize,
112
+ enabled: enabled[i],
113
+ }));
114
+ const parts = [grid, ...series];
115
+ if (state.style.spokeLabels) {
116
+ const labels = [];
117
+ for (let i = 0; i < count; i++) {
118
+ const anchor = labelAnchor(i, count);
119
+ const align = anchor === "centerLeft" ? "left" : anchor === "centerRight" ? "right" : "center";
120
+ const at = () => labelPoint(i, count, radius(), style().fontSize);
121
+ labels.push(new Text({
122
+ ...textOps.styleProps(markerText(state.style, align)),
123
+ text: () => categoriesOf(state.data, state.categoryField)[i] ?? "",
124
+ fontSize: () => style().fontSize,
125
+ fontWeight: () => style().fontWeight,
126
+ fill: () => style().muted,
127
+ [anchor]: at,
128
+ }));
129
+ }
130
+ parts.push(new Rect({ width: "fill", height: "fill", children: labels }));
131
+ }
132
+ plot = new Rect({ width: "fill", height: "fill", children: parts });
133
+ const row = [plot];
134
+ const position = state.style.legend;
135
+ if (position !== "none") {
136
+ const side = position === "right";
137
+ const config = legendConfigOf(state.style);
138
+ const legend = new ChartLegend({
139
+ series: state.series,
140
+ swatches: () => state.series.map((s, i) => seriesFill(style(), s, i)),
141
+ legend: () => legendConfigOf(style()),
142
+ flow: side ? "vertical" : "horizontal",
143
+ // Spacing is fixed as built; a style tween re-paints the swatches and captions only.
144
+ gap: side ? Math.round(config.itemGap / 2) : config.itemGap,
145
+ padding: config.padding,
146
+ });
147
+ if (position === "top")
148
+ row.unshift(legend);
149
+ else
150
+ row.push(legend);
151
+ }
152
+ const frame = new Rect({
153
+ flow: position === "right" ? "horizontal" : "vertical",
154
+ width: "fill",
155
+ height: "fill",
156
+ gap: 24,
157
+ align: "center",
158
+ fill: () => style().background,
159
+ children: row,
160
+ });
161
+ return asParts([frame]);
162
+ },
163
+ commands: {
164
+ /** The web grows out, the polygons grow from the centre one series after another, then the labels and legend come up. */
165
+ enter: {
166
+ args: {},
167
+ // Held from arrival, so it never shows finished ahead of its draw.
168
+ entrance: true,
169
+ easing: easeOut(),
170
+ run: (timeline, _state, children) => {
171
+ const parts = partsOf(children);
172
+ if (!parts)
173
+ return timeline.wait(timeline.duration);
174
+ const duration = timeline.duration;
175
+ const web = duration * ENTER_SHARE.axes;
176
+ const marks = duration * ENTER_SHARE.marks;
177
+ const last = duration * ENTER_SHARE.legend;
178
+ const n = Math.max(1, parts.series.length);
179
+ const each = marks / (1 + STAGGER * (n - 1));
180
+ const { legend, labels } = parts;
181
+ const at0 = (piece) => ({ at: 0, duration: 0, piece });
182
+ // The first frame arms what every later beat moves: a beat ahead of the playhead writes nothing.
183
+ return beats(timeline, [
184
+ at0(parts.grid.to({ reveal: 0 })),
185
+ ...parts.series.map((s) => at0(s.to({ progress: 0 }))),
186
+ ...(labels ? [at0(labels.to({ opacity: 0 }))] : []),
187
+ ...(legend ? [at0(legend.to({ opacity: 0, y: -LEGEND_SLIDE }))] : []),
188
+ { at: 0, duration: web, piece: parts.grid.to({ reveal: 1 }) },
189
+ ...parts.series.map((s, i) => ({ at: web + i * each * STAGGER, duration: each, piece: s.to({ progress: 1 }) })),
190
+ ...(labels ? [{ at: web + marks * 0.6, duration: last + marks * 0.4, piece: labels.to({ opacity: 1 }) }] : []),
191
+ ...(legend ? [{ at: web + marks, duration: last, piece: legend.to({ opacity: 1, y: 0 }) }] : []),
192
+ ]);
193
+ },
194
+ },
195
+ /** Grow series `index`'s polygon back out of the centre, with its legend entry growing in. */
196
+ showSeries: {
197
+ args: { seriesIndex: SERIES_ARG },
198
+ easing: easeOut(),
199
+ run: (timeline, _state, children) => toggling(timeline, children, timeline.args.seriesIndex, true),
200
+ },
201
+ /** Shrink series `index`'s polygon into the centre as its legend entry shrinks away. */
202
+ hideSeries: {
203
+ args: { seriesIndex: SERIES_ARG },
204
+ easing: easeOut(),
205
+ run: (timeline, _state, children) => toggling(timeline, children, timeline.args.seriesIndex, false),
206
+ },
207
+ /** Fade every other series, polygon and legend entry, to focus on `index`. The legend dims in place, so the row does not reflow. */
208
+ spotlightSeries: {
209
+ args: { seriesIndex: SERIES_ARG },
210
+ easing: easeOut(),
211
+ run: (timeline, _state, children) => {
212
+ const parts = partsOf(children);
213
+ if (!parts)
214
+ return timeline.wait(timeline.duration);
215
+ const index = timeline.args.seriesIndex;
216
+ return timeline.together([
217
+ ...parts.series.map((s, i) => s.to({ opacity: i === index ? 1 : SPOTLIGHT_DIM })),
218
+ ...(parts.legend ? [parts.legend.run("spotlightSeries", { index })] : []),
219
+ ]);
220
+ },
221
+ },
222
+ },
223
+ });
224
+ //# sourceMappingURL=radar-chart.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"radar-chart.js","sourceRoot":"","sources":["../../src/radar-chart/radar-chart.ts"],"names":[],"mappings":"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","sourcesContent":["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"]}