@motionscript/charts 0.1.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 (215) hide show
  1. package/CHANGELOG.md +38 -0
  2. package/README.md +98 -28
  3. package/dist/bar-chart/bar-chart.d.ts +242 -119
  4. package/dist/bar-chart/bar-chart.d.ts.map +1 -1
  5. package/dist/bar-chart/bar-chart.js +231 -260
  6. package/dist/bar-chart/bar-chart.js.map +1 -1
  7. package/dist/bar-chart/category-axis.d.ts +16 -38
  8. package/dist/bar-chart/category-axis.d.ts.map +1 -1
  9. package/dist/bar-chart/category-axis.js +59 -68
  10. package/dist/bar-chart/category-axis.js.map +1 -1
  11. package/dist/bar-chart/chart-bars.d.ts +60 -91
  12. package/dist/bar-chart/chart-bars.d.ts.map +1 -1
  13. package/dist/bar-chart/chart-bars.js +88 -125
  14. package/dist/bar-chart/chart-bars.js.map +1 -1
  15. package/dist/bar-chart/index.d.ts +5 -13
  16. package/dist/bar-chart/index.d.ts.map +1 -1
  17. package/dist/bar-chart/index.js +2 -9
  18. package/dist/bar-chart/index.js.map +1 -1
  19. package/dist/bar-chart/shared.d.ts +40 -132
  20. package/dist/bar-chart/shared.d.ts.map +1 -1
  21. package/dist/bar-chart/shared.js +70 -158
  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 +8 -17
  30. package/dist/engine.d.ts.map +1 -1
  31. package/dist/engine.js +8 -17
  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 -35
  38. package/dist/kit/cartesian.d.ts.map +1 -1
  39. package/dist/kit/cartesian.js +80 -42
  40. package/dist/kit/cartesian.js.map +1 -1
  41. package/dist/kit/chart-canvas.d.ts +37 -40
  42. package/dist/kit/chart-canvas.d.ts.map +1 -1
  43. package/dist/kit/chart-canvas.js +53 -47
  44. package/dist/kit/chart-canvas.js.map +1 -1
  45. package/dist/kit/chart-legend.d.ts +16 -59
  46. package/dist/kit/chart-legend.d.ts.map +1 -1
  47. package/dist/kit/chart-legend.js +38 -76
  48. package/dist/kit/chart-legend.js.map +1 -1
  49. package/dist/kit/entries.d.ts +2 -0
  50. package/dist/kit/entries.d.ts.map +1 -1
  51. package/dist/kit/entries.js +2 -0
  52. package/dist/kit/entries.js.map +1 -1
  53. package/dist/kit/horizontal-axis.d.ts +77 -0
  54. package/dist/kit/horizontal-axis.d.ts.map +1 -0
  55. package/dist/kit/horizontal-axis.js +99 -0
  56. package/dist/kit/horizontal-axis.js.map +1 -0
  57. package/dist/kit/motion.d.ts +16 -3
  58. package/dist/kit/motion.d.ts.map +1 -1
  59. package/dist/kit/motion.js +15 -1
  60. package/dist/kit/motion.js.map +1 -1
  61. package/dist/{pie-chart → kit}/pie-legend.d.ts +14 -29
  62. package/dist/kit/pie-legend.d.ts.map +1 -0
  63. package/dist/kit/pie-legend.js +93 -0
  64. package/dist/kit/pie-legend.js.map +1 -0
  65. package/dist/kit/polar.d.ts +31 -0
  66. package/dist/kit/polar.d.ts.map +1 -0
  67. package/dist/kit/polar.js +33 -0
  68. package/dist/kit/polar.js.map +1 -0
  69. package/dist/kit/shared.d.ts +60 -214
  70. package/dist/kit/shared.d.ts.map +1 -1
  71. package/dist/kit/shared.js +91 -291
  72. package/dist/kit/shared.js.map +1 -1
  73. package/dist/kit/style.d.ts +254 -0
  74. package/dist/kit/style.d.ts.map +1 -0
  75. package/dist/kit/style.js +197 -0
  76. package/dist/kit/style.js.map +1 -0
  77. package/dist/kit/vertical-axis.d.ts +36 -45
  78. package/dist/kit/vertical-axis.d.ts.map +1 -1
  79. package/dist/kit/vertical-axis.js +69 -81
  80. package/dist/kit/vertical-axis.js.map +1 -1
  81. package/dist/line-chart/chart-line.d.ts +107 -40
  82. package/dist/line-chart/chart-line.d.ts.map +1 -1
  83. package/dist/line-chart/chart-line.js +172 -89
  84. package/dist/line-chart/chart-line.js.map +1 -1
  85. package/dist/line-chart/chart-region.d.ts +14 -27
  86. package/dist/line-chart/chart-region.d.ts.map +1 -1
  87. package/dist/line-chart/chart-region.js +13 -28
  88. package/dist/line-chart/chart-region.js.map +1 -1
  89. package/dist/line-chart/index.d.ts +5 -18
  90. package/dist/line-chart/index.d.ts.map +1 -1
  91. package/dist/line-chart/index.js +3 -16
  92. package/dist/line-chart/index.js.map +1 -1
  93. package/dist/line-chart/line-chart.d.ts +272 -119
  94. package/dist/line-chart/line-chart.d.ts.map +1 -1
  95. package/dist/line-chart/line-chart.js +309 -257
  96. package/dist/line-chart/line-chart.js.map +1 -1
  97. package/dist/line-chart/shared.d.ts +73 -130
  98. package/dist/line-chart/shared.d.ts.map +1 -1
  99. package/dist/line-chart/shared.js +195 -156
  100. package/dist/line-chart/shared.js.map +1 -1
  101. package/dist/line-chart/x-scale.d.ts +16 -55
  102. package/dist/line-chart/x-scale.d.ts.map +1 -1
  103. package/dist/line-chart/x-scale.js +44 -111
  104. package/dist/line-chart/x-scale.js.map +1 -1
  105. package/dist/nodes.d.ts +3 -13
  106. package/dist/nodes.d.ts.map +1 -1
  107. package/dist/nodes.js +9 -13
  108. package/dist/nodes.js.map +1 -1
  109. package/dist/pie-chart/index.d.ts +3 -15
  110. package/dist/pie-chart/index.d.ts.map +1 -1
  111. package/dist/pie-chart/index.js +1 -11
  112. package/dist/pie-chart/index.js.map +1 -1
  113. package/dist/pie-chart/pie-chart.d.ts +147 -85
  114. package/dist/pie-chart/pie-chart.d.ts.map +1 -1
  115. package/dist/pie-chart/pie-chart.js +65 -86
  116. package/dist/pie-chart/pie-chart.js.map +1 -1
  117. package/dist/pie-chart/pie-ring.d.ts +65 -196
  118. package/dist/pie-chart/pie-ring.d.ts.map +1 -1
  119. package/dist/pie-chart/pie-ring.js +154 -292
  120. package/dist/pie-chart/pie-ring.js.map +1 -1
  121. package/dist/pie-chart/shared.d.ts +78 -172
  122. package/dist/pie-chart/shared.d.ts.map +1 -1
  123. package/dist/pie-chart/shared.js +54 -177
  124. package/dist/pie-chart/shared.js.map +1 -1
  125. package/dist/radar-chart/index.d.ts +5 -0
  126. package/dist/radar-chart/index.d.ts.map +1 -0
  127. package/dist/radar-chart/index.js +5 -0
  128. package/dist/radar-chart/index.js.map +1 -0
  129. package/dist/radar-chart/radar-chart.d.ts +218 -0
  130. package/dist/radar-chart/radar-chart.d.ts.map +1 -0
  131. package/dist/radar-chart/radar-chart.js +224 -0
  132. package/dist/radar-chart/radar-chart.js.map +1 -0
  133. package/dist/radar-chart/radar-grid.d.ts +43 -0
  134. package/dist/radar-chart/radar-grid.d.ts.map +1 -0
  135. package/dist/radar-chart/radar-grid.js +61 -0
  136. package/dist/radar-chart/radar-grid.js.map +1 -0
  137. package/dist/radar-chart/radar-series.d.ts +59 -0
  138. package/dist/radar-chart/radar-series.d.ts.map +1 -0
  139. package/dist/radar-chart/radar-series.js +71 -0
  140. package/dist/radar-chart/radar-series.js.map +1 -0
  141. package/dist/radar-chart/shared.d.ts +73 -0
  142. package/dist/radar-chart/shared.d.ts.map +1 -0
  143. package/dist/radar-chart/shared.js +123 -0
  144. package/dist/radar-chart/shared.js.map +1 -0
  145. package/dist/radial-chart/index.d.ts +6 -0
  146. package/dist/radial-chart/index.d.ts.map +1 -0
  147. package/dist/radial-chart/index.js +4 -0
  148. package/dist/radial-chart/index.js.map +1 -0
  149. package/dist/radial-chart/radial-chart.d.ts +216 -0
  150. package/dist/radial-chart/radial-chart.d.ts.map +1 -0
  151. package/dist/radial-chart/radial-chart.js +174 -0
  152. package/dist/radial-chart/radial-chart.js.map +1 -0
  153. package/dist/radial-chart/radial-rings.d.ts +121 -0
  154. package/dist/radial-chart/radial-rings.d.ts.map +1 -0
  155. package/dist/radial-chart/radial-rings.js +273 -0
  156. package/dist/radial-chart/radial-rings.js.map +1 -0
  157. package/dist/radial-chart/shared.d.ts +73 -0
  158. package/dist/radial-chart/shared.d.ts.map +1 -0
  159. package/dist/radial-chart/shared.js +79 -0
  160. package/dist/radial-chart/shared.js.map +1 -0
  161. package/package.json +4 -4
  162. package/registry.json +21 -6
  163. package/src/bar-chart/bar-chart.ts +274 -315
  164. package/src/bar-chart/category-axis.ts +53 -88
  165. package/src/bar-chart/chart-bars.ts +108 -205
  166. package/src/bar-chart/index.ts +8 -19
  167. package/src/bar-chart/shared.ts +81 -309
  168. package/src/engine.ts +8 -17
  169. package/src/index.ts +2 -0
  170. package/src/kit/cartesian.ts +118 -55
  171. package/src/kit/chart-canvas.ts +50 -80
  172. package/src/kit/chart-legend.ts +36 -97
  173. package/src/kit/entries.ts +4 -1
  174. package/src/kit/horizontal-axis.ts +114 -0
  175. package/src/kit/motion.ts +18 -2
  176. package/src/{pie-chart → kit}/pie-legend.ts +25 -65
  177. package/src/kit/polar.ts +54 -0
  178. package/src/kit/shared.ts +104 -487
  179. package/src/kit/style.ts +257 -0
  180. package/src/kit/vertical-axis.ts +81 -115
  181. package/src/line-chart/chart-line.ts +185 -91
  182. package/src/line-chart/chart-region.ts +14 -31
  183. package/src/line-chart/index.ts +14 -22
  184. package/src/line-chart/line-chart.ts +377 -315
  185. package/src/line-chart/shared.ts +229 -304
  186. package/src/line-chart/x-scale.ts +44 -121
  187. package/src/nodes.ts +9 -13
  188. package/src/pie-chart/index.ts +3 -35
  189. package/src/pie-chart/pie-chart.ts +83 -134
  190. package/src/pie-chart/pie-ring.ts +162 -368
  191. package/src/pie-chart/shared.ts +92 -379
  192. package/src/radar-chart/index.ts +4 -0
  193. package/src/radar-chart/radar-chart.ts +287 -0
  194. package/src/radar-chart/radar-grid.ts +78 -0
  195. package/src/radar-chart/radar-series.ts +88 -0
  196. package/src/radar-chart/shared.ts +146 -0
  197. package/src/radial-chart/index.ts +5 -0
  198. package/src/radial-chart/radial-chart.ts +210 -0
  199. package/src/radial-chart/radial-rings.ts +328 -0
  200. package/src/radial-chart/shared.ts +114 -0
  201. package/dist/browser/chunks/chunk-TJNHLQGV.js +0 -2
  202. package/dist/browser/chunks/chunk-TJNHLQGV.js.map +0 -7
  203. package/dist/kit/chart-border.d.ts +0 -27
  204. package/dist/kit/chart-border.d.ts.map +0 -1
  205. package/dist/kit/chart-border.js +0 -28
  206. package/dist/kit/chart-border.js.map +0 -1
  207. package/dist/line-chart/horizontal-axis.d.ts +0 -79
  208. package/dist/line-chart/horizontal-axis.d.ts.map +0 -1
  209. package/dist/line-chart/horizontal-axis.js +0 -129
  210. package/dist/line-chart/horizontal-axis.js.map +0 -1
  211. package/dist/pie-chart/pie-legend.d.ts.map +0 -1
  212. package/dist/pie-chart/pie-legend.js +0 -117
  213. package/dist/pie-chart/pie-legend.js.map +0 -1
  214. package/src/kit/chart-border.ts +0 -50
  215. package/src/line-chart/horizontal-axis.ts +0 -151
@@ -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"]}
@@ -0,0 +1,43 @@
1
+ import { type NodeOf, type Node2D as _Node2D, type Node2DProps as _Node2DProps, type Stroke, type StrokeResolved } from "@motionscript/sdk";
2
+ import { type GridShape } from "./shared.js";
3
+ /**
4
+ * The web of a {@link RadarChart}: `levels` rings and, if asked, a spoke to each
5
+ * of `count` categories, drawn from the node's centre out to `radius`. `reveal`
6
+ * grows the web from nothing.
7
+ */
8
+ export declare const RadarGrid: import("@motionscript/sdk").Component<"radarGrid", import("@motionscript/sdk").Merge<import("@motionscript/sdk").Box2DState, {
9
+ readonly count: 0;
10
+ /** The rim, in px. */
11
+ readonly radius: 0;
12
+ readonly levels: 4;
13
+ readonly shape: import("@motionscript/sdk").Type<GridShape, GridShape, false>;
14
+ readonly stroke: import("@motionscript/sdk").Type<Stroke, StrokeResolved[], false>;
15
+ /** The line out to each category; empty draws none. */
16
+ readonly spokeStroke: import("@motionscript/sdk").Type<Stroke, StrokeResolved[], false>;
17
+ /** How far the web has grown out, `0`-`1`. Rests at 1 so a paused canvas paints it. */
18
+ readonly reveal: 1;
19
+ }>, {}, null, _Node2D<_Node2DProps>, import("@motionscript/sdk").CallProps<import("@motionscript/sdk").Merge<import("@motionscript/sdk").Box2DState, {
20
+ readonly count: 0;
21
+ /** The rim, in px. */
22
+ readonly radius: 0;
23
+ readonly levels: 4;
24
+ readonly shape: import("@motionscript/sdk").Type<GridShape, GridShape, false>;
25
+ readonly stroke: import("@motionscript/sdk").Type<Stroke, StrokeResolved[], false>;
26
+ /** The line out to each category; empty draws none. */
27
+ readonly spokeStroke: import("@motionscript/sdk").Type<Stroke, StrokeResolved[], false>;
28
+ /** How far the web has grown out, `0`-`1`. Rests at 1 so a paused canvas paints it. */
29
+ readonly reveal: 1;
30
+ }>, null, import("@motionscript/sdk").BuiltNode<import("@motionscript/sdk").Merge<import("@motionscript/sdk").Box2DState, {
31
+ readonly count: 0;
32
+ /** The rim, in px. */
33
+ readonly radius: 0;
34
+ readonly levels: 4;
35
+ readonly shape: import("@motionscript/sdk").Type<GridShape, GridShape, false>;
36
+ readonly stroke: import("@motionscript/sdk").Type<Stroke, StrokeResolved[], false>;
37
+ /** The line out to each category; empty draws none. */
38
+ readonly spokeStroke: import("@motionscript/sdk").Type<Stroke, StrokeResolved[], false>;
39
+ /** How far the web has grown out, `0`-`1`. Rests at 1 so a paused canvas paints it. */
40
+ readonly reveal: 1;
41
+ }>, {}, _Node2D<_Node2DProps>>>>;
42
+ export type RadarGrid = NodeOf<typeof RadarGrid>;
43
+ //# sourceMappingURL=radar-grid.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"radar-grid.d.ts","sourceRoot":"","sources":["../../src/radar-chart/radar-grid.ts"],"names":[],"mappings":"AAAA,OAAO,EAML,KAAK,MAAM,EAEX,KAAK,MAAM,IAAI,OAAO,EACtB,KAAK,WAAW,IAAI,YAAY,EAChC,KAAK,MAAM,EACX,KAAK,cAAc,EAEpB,MAAM,mBAAmB,CAAA;AAG1B,OAAO,EAAkB,KAAK,SAAS,EAAE,MAAM,UAAU,CAAA;AAEzD;;;;GAIG;AACH,eAAO,MAAM,SAAS;;IAIlB,sBAAsB;;;;;IAKtB,uDAAuD;;IAEvD,uFAAuF;;;;IAPvF,sBAAsB;;;;;IAKtB,uDAAuD;;IAEvD,uFAAuF;;;;IAPvF,sBAAsB;;;;;IAKtB,uDAAuD;;IAEvD,uFAAuF;;gCAyCzF,CAAA;AAEF,MAAM,MAAM,SAAS,GAAG,MAAM,CAAC,OAAO,SAAS,CAAC,CAAA"}
@@ -0,0 +1,61 @@
1
+ import { Graphics2D, Types, clamp, component2d, strokeOps, } from "@motionscript/sdk";
2
+ import { loadPaints } from "../kit/paints.js";
3
+ import { spokeDirection } from "./shared.js";
4
+ /**
5
+ * The web of a {@link RadarChart}: `levels` rings and, if asked, a spoke to each
6
+ * of `count` categories, drawn from the node's centre out to `radius`. `reveal`
7
+ * grows the web from nothing.
8
+ */
9
+ export const RadarGrid = component2d({
10
+ key: "radarGrid",
11
+ state: {
12
+ count: 0,
13
+ /** The rim, in px. */
14
+ radius: 0,
15
+ levels: 4,
16
+ shape: Types.custom("polygon"),
17
+ stroke: Types.custom([], { resolve: strokeOps.resolve, lerp: strokeOps.lerp }),
18
+ /** The line out to each category; empty draws none. */
19
+ spokeStroke: Types.custom([], { resolve: strokeOps.resolve, lerp: strokeOps.lerp }),
20
+ /** How far the web has grown out, `0`-`1`. Rests at 1 so a paused canvas paints it. */
21
+ reveal: 1,
22
+ },
23
+ defaults: { width: "fill", height: "fill" },
24
+ load: (loader, state) => loadPaints(loader, { strokes: [state.stroke, state.spokeStroke] }),
25
+ render: (ctx, state) => {
26
+ const grow = clamp(state.reveal, 0, 1);
27
+ const rim = state.radius * grow;
28
+ if (rim <= 0 || grow <= 0)
29
+ return;
30
+ const count = Math.max(0, Math.round(state.count));
31
+ const levels = Math.max(1, Math.round(state.levels));
32
+ const round = state.shape === "circle" || count < 3;
33
+ // One draw per ring: rings chained into one surface would stroke only their union's outline.
34
+ for (let level = 1; state.stroke.length > 0 && level <= levels; level++) {
35
+ const r = (rim * level) / levels;
36
+ const ring = new Graphics2D();
37
+ if (round) {
38
+ ring.ellipse({ width: r * 2, height: r * 2 });
39
+ }
40
+ else {
41
+ const points = [];
42
+ for (let i = 0; i < count; i++) {
43
+ const d = spokeDirection(i, count);
44
+ points.push({ x: d.x * r, y: d.y * r });
45
+ }
46
+ ring.line({ points, closed: true });
47
+ }
48
+ ctx.draw(ring.stroke(state.stroke).opacity(grow));
49
+ }
50
+ if (state.spokeStroke.length === 0)
51
+ return;
52
+ for (let i = 0; i < count; i++) {
53
+ const d = spokeDirection(i, count);
54
+ ctx.draw(new Graphics2D()
55
+ .line({ points: [{ x: 0, y: 0 }, { x: d.x * rim, y: d.y * rim }] })
56
+ .stroke(state.spokeStroke)
57
+ .opacity(grow));
58
+ }
59
+ },
60
+ });
61
+ //# sourceMappingURL=radar-grid.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"radar-grid.js","sourceRoot":"","sources":["../../src/radar-chart/radar-grid.ts"],"names":[],"mappings":"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","sourcesContent":["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"]}
@@ -0,0 +1,59 @@
1
+ import { type Fill, type FillResolved, type NodeOf, type Node2D as _Node2D, type Node2DProps as _Node2DProps, type Stroke, type StrokeResolved, type Vector2 } from "@motionscript/sdk";
2
+ /** The vertices of a series' polygon: spoke `i` at `fractions[i]` of the rim, scaled by `grow` about the centre. */
3
+ export declare function seriesVertices(fractions: readonly number[], radius: number, grow?: number): Vector2[];
4
+ /** 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. */
5
+ export declare const RadarSeries: import("@motionscript/sdk").Component<"radarSeries", import("@motionscript/sdk").Merge<import("@motionscript/sdk").Box2DState, {
6
+ /** Each spoke's value as a fraction of the rim, `0`-`1`, in spoke order. */
7
+ readonly fractions: import("@motionscript/sdk").Type<number[], number[], false>;
8
+ /** The rim, in px. */
9
+ readonly radius: 0;
10
+ readonly fill: import("@motionscript/sdk").Type<Fill, FillResolved[], false>;
11
+ readonly stroke: import("@motionscript/sdk").Type<Stroke, StrokeResolved[], false>;
12
+ readonly areaOpacity: 0.25;
13
+ readonly dots: true;
14
+ readonly dotSize: 10;
15
+ /** Growth out of the centre, `0`-`1`. Rests at 1 so a paused canvas paints it; `enter` drives it from 0. */
16
+ readonly progress: 1;
17
+ /** Whether the series is drawn at all, flipped alongside its legend entry. */
18
+ readonly enabled: true;
19
+ }>, {
20
+ readonly enter: {
21
+ readonly from: import("@motionscript/sdk").Type<number, number, false>;
22
+ readonly to: import("@motionscript/sdk").Type<number, number, false>;
23
+ };
24
+ }, null, _Node2D<_Node2DProps>, import("@motionscript/sdk").CallProps<import("@motionscript/sdk").Merge<import("@motionscript/sdk").Box2DState, {
25
+ /** Each spoke's value as a fraction of the rim, `0`-`1`, in spoke order. */
26
+ readonly fractions: import("@motionscript/sdk").Type<number[], number[], false>;
27
+ /** The rim, in px. */
28
+ readonly radius: 0;
29
+ readonly fill: import("@motionscript/sdk").Type<Fill, FillResolved[], false>;
30
+ readonly stroke: import("@motionscript/sdk").Type<Stroke, StrokeResolved[], false>;
31
+ readonly areaOpacity: 0.25;
32
+ readonly dots: true;
33
+ readonly dotSize: 10;
34
+ /** Growth out of the centre, `0`-`1`. Rests at 1 so a paused canvas paints it; `enter` drives it from 0. */
35
+ readonly progress: 1;
36
+ /** Whether the series is drawn at all, flipped alongside its legend entry. */
37
+ readonly enabled: true;
38
+ }>, null, import("@motionscript/sdk").BuiltNode<import("@motionscript/sdk").Merge<import("@motionscript/sdk").Box2DState, {
39
+ /** Each spoke's value as a fraction of the rim, `0`-`1`, in spoke order. */
40
+ readonly fractions: import("@motionscript/sdk").Type<number[], number[], false>;
41
+ /** The rim, in px. */
42
+ readonly radius: 0;
43
+ readonly fill: import("@motionscript/sdk").Type<Fill, FillResolved[], false>;
44
+ readonly stroke: import("@motionscript/sdk").Type<Stroke, StrokeResolved[], false>;
45
+ readonly areaOpacity: 0.25;
46
+ readonly dots: true;
47
+ readonly dotSize: 10;
48
+ /** Growth out of the centre, `0`-`1`. Rests at 1 so a paused canvas paints it; `enter` drives it from 0. */
49
+ readonly progress: 1;
50
+ /** Whether the series is drawn at all, flipped alongside its legend entry. */
51
+ readonly enabled: true;
52
+ }>, {
53
+ readonly enter: {
54
+ readonly from: import("@motionscript/sdk").Type<number, number, false>;
55
+ readonly to: import("@motionscript/sdk").Type<number, number, false>;
56
+ };
57
+ }, _Node2D<_Node2DProps>>>>;
58
+ export type RadarSeries = NodeOf<typeof RadarSeries>;
59
+ //# sourceMappingURL=radar-series.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"radar-series.d.ts","sourceRoot":"","sources":["../../src/radar-chart/radar-series.ts"],"names":[],"mappings":"AAAA,OAAO,EAOL,KAAK,IAAI,EACT,KAAK,YAAY,EACjB,KAAK,MAAM,EAEX,KAAK,MAAM,IAAI,OAAO,EACtB,KAAK,WAAW,IAAI,YAAY,EAChC,KAAK,MAAM,EACX,KAAK,cAAc,EACnB,KAAK,OAAO,EACb,MAAM,mBAAmB,CAAA;AAO1B,oHAAoH;AACpH,wBAAgB,cAAc,CAAC,SAAS,EAAE,SAAS,MAAM,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,SAAI,GAAG,OAAO,EAAE,CAMhG;AAED,uKAAuK;AACvK,eAAO,MAAM,WAAW;IAGpB,4EAA4E;;IAE5E,sBAAsB;;;;;;;IAOtB,4GAA4G;;IAE5G,8EAA8E;;;;;;;;IAX9E,4EAA4E;;IAE5E,sBAAsB;;;;;;;IAOtB,4GAA4G;;IAE5G,8EAA8E;;;IAX9E,4EAA4E;;IAE5E,sBAAsB;;;;;;;IAOtB,4GAA4G;;IAE5G,8EAA8E;;;;;;;2BAsChF,CAAA;AAEF,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC,OAAO,WAAW,CAAC,CAAA"}
@@ -0,0 +1,71 @@
1
+ import { Graphics2D, Types, clamp, component2d, fillOps, strokeOps, } from "@motionscript/sdk";
2
+ import { fresh } from "../kit/entries.js";
3
+ import { frameEase } from "../kit/motion.js";
4
+ import { loadPaints } from "../kit/paints.js";
5
+ import { spokeDirection } from "./shared.js";
6
+ /** The vertices of a series' polygon: spoke `i` at `fractions[i]` of the rim, scaled by `grow` about the centre. */
7
+ export function seriesVertices(fractions, radius, grow = 1) {
8
+ return fractions.map((f, i) => {
9
+ const d = spokeDirection(i, fractions.length);
10
+ const r = radius * f * grow;
11
+ return { x: d.x * r, y: d.y * r };
12
+ });
13
+ }
14
+ /** 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. */
15
+ export const RadarSeries = component2d({
16
+ key: "radarSeries",
17
+ state: {
18
+ /** Each spoke's value as a fraction of the rim, `0`-`1`, in spoke order. */
19
+ fractions: fresh(() => []),
20
+ /** The rim, in px. */
21
+ radius: 0,
22
+ fill: Types.custom([], { resolve: fillOps.resolve, lerp: fillOps.lerp }),
23
+ stroke: Types.custom([], { resolve: strokeOps.resolve, lerp: strokeOps.lerp }),
24
+ areaOpacity: 0.25,
25
+ dots: true,
26
+ dotSize: 10,
27
+ /** Growth out of the centre, `0`-`1`. Rests at 1 so a paused canvas paints it; `enter` drives it from 0. */
28
+ progress: 1,
29
+ /** Whether the series is drawn at all, flipped alongside its legend entry. */
30
+ enabled: true,
31
+ },
32
+ defaults: { width: "fill", height: "fill" },
33
+ load: (loader, state) => loadPaints(loader, { fills: [state.fill], strokes: [state.stroke] }),
34
+ commands: {
35
+ /** Grow the polygon from `from` to `to` (of its full size); `showSeries`/`hideSeries` are this with the ends stated. */
36
+ enter: {
37
+ args: { from: Types.number(0, { min: 0, max: 1 }), to: Types.number(1, { min: 0, max: 1 }) },
38
+ run: (timeline) => {
39
+ const { from, to } = timeline.args;
40
+ const ease = frameEase(timeline);
41
+ return timeline.animate((t) => {
42
+ const progress = from + (to - from) * ease(t);
43
+ // Hidden only once fully shrunk, so a hide does not vanish a frame early.
44
+ return { progress, enabled: progress > 0 };
45
+ });
46
+ },
47
+ },
48
+ },
49
+ render: (ctx, state) => {
50
+ if (!state.enabled)
51
+ return;
52
+ const grow = clamp(state.progress, 0, 1);
53
+ if (grow <= 0 || state.radius <= 0 || state.fractions.length === 0)
54
+ return;
55
+ const points = seriesVertices(state.fractions, state.radius, grow);
56
+ if (points.length >= 2) {
57
+ const fill = new Graphics2D().line({ points, closed: true });
58
+ if (state.areaOpacity > 0 && state.fill.length > 0)
59
+ ctx.draw(fill.fill(state.fill).opacity(clamp(state.areaOpacity, 0, 1)));
60
+ if (state.stroke.length > 0)
61
+ ctx.draw(new Graphics2D().line({ points, closed: true }).stroke(state.stroke));
62
+ }
63
+ if (state.dots && state.dotSize > 0 && state.fill.length > 0) {
64
+ const dots = new Graphics2D();
65
+ for (const p of points)
66
+ dots.ellipse({ x: p.x, y: p.y, width: state.dotSize, height: state.dotSize });
67
+ ctx.draw(dots.fill(state.fill));
68
+ }
69
+ },
70
+ });
71
+ //# sourceMappingURL=radar-series.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"radar-series.js","sourceRoot":"","sources":["../../src/radar-chart/radar-series.ts"],"names":[],"mappings":"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","sourcesContent":["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"]}
@@ -0,0 +1,73 @@
1
+ import { type DataRecord, type Size2D, type StrokeResolved, type Stroke as _Stroke, type Vector2 } from "@motionscript/sdk";
2
+ import { type ChartSeries } from "../kit/shared.js";
3
+ export type GridShape = "polygon" | "circle";
4
+ /** The radar chart's own grid group: the web the polygons are drawn over. */
5
+ export declare const RADAR_GRID: {
6
+ /** Whether the rings are straight-edged (a polygon through the spokes) or round. */
7
+ gridShape: import("@motionscript/sdk").Type<"circle" | "polygon", "circle" | "polygon", false>;
8
+ /** How many rings, outermost at the scale's maximum. */
9
+ gridLevels: import("@motionscript/sdk").Type<number, number, false>;
10
+ /** The rings; empty draws none. */
11
+ gridStroke: import("@motionscript/sdk").Type<_Stroke, StrokeResolved[], false>;
12
+ /** The line from the centre out to each category; empty draws none. */
13
+ spokeStroke: import("@motionscript/sdk").Type<_Stroke, StrokeResolved[], false>;
14
+ /** Read as the chart is built: whether the category names stand around the rim. */
15
+ spokeLabels: import("@motionscript/sdk").Type<boolean, boolean, false>;
16
+ };
17
+ export declare const RADAR_MARKS: {
18
+ /** Outline weight of each series' polygon. */
19
+ strokeWidth: import("@motionscript/sdk").Type<number, number, false>;
20
+ /** How strongly each polygon is filled in its series colour; 0 leaves an outline. */
21
+ areaOpacity: import("@motionscript/sdk").Type<number, number, false>;
22
+ /** Whether a dot marks each value on its spoke. */
23
+ dots: import("@motionscript/sdk").Type<boolean, boolean, false>;
24
+ dotSize: import("@motionscript/sdk").Type<number, number, false>;
25
+ };
26
+ /** The grid and marks fields the parts read, whichever way the chart's style is spelled. */
27
+ export interface RadarStyle {
28
+ readonly gridShape: GridShape;
29
+ readonly gridLevels: number;
30
+ readonly gridStroke: StrokeResolved[];
31
+ readonly spokeStroke: StrokeResolved[];
32
+ readonly spokeLabels: boolean;
33
+ readonly strokeWidth: number;
34
+ readonly areaOpacity: number;
35
+ readonly dots: boolean;
36
+ readonly dotSize: number;
37
+ readonly fontSize: number;
38
+ }
39
+ /** Spoke `index` of `count`, as a unit direction: 12 o'clock first, clockwise on screen, y up. */
40
+ export declare function spokeDirection(index: number, count: number): Vector2;
41
+ /** One category per data row. */
42
+ export declare function categoriesOf(data: readonly DataRecord[], field: string): string[];
43
+ /** One list of values per series, a value per row. */
44
+ export declare function valuesOf(data: readonly DataRecord[], series: readonly ChartSeries[]): number[][];
45
+ /** `value` rounded up to a tidy 1, 1.5, 2, 2.5, 3, 4, 5, 6, 8 times a power of ten. */
46
+ export declare function niceCeil(value: number): number;
47
+ /**
48
+ * The scale the web is drawn to: `min` (default 0) to `max`, which when unset
49
+ * (or not above `min`) is the largest value rounded up tidily.
50
+ */
51
+ export declare function scaleOf(values: readonly (readonly number[])[], min: number, max: number): {
52
+ min: number;
53
+ max: number;
54
+ };
55
+ /** Where `value` stands between the scale's ends, `0`-`1`. */
56
+ export declare function fractionOf(value: number, scale: {
57
+ min: number;
58
+ max: number;
59
+ }): number;
60
+ export type LabelAnchor = "centerLeft" | "centerRight" | "bottomCenter" | "topCenter";
61
+ /** Which corner of a category's label touches the point beside its spoke's end. */
62
+ export declare function labelAnchor(index: number, count: number): LabelAnchor;
63
+ export declare function labelPad(fontSize: number): number;
64
+ /** Rough size of a label, since the web is fitted before any text is measured. */
65
+ export declare function labelSize(caption: string, fontSize: number): Size2D;
66
+ /**
67
+ * The rim's radius for a box: the largest the web can be with every label
68
+ * (when there are labels) still inside it.
69
+ */
70
+ export declare function fitRadius(box: Size2D, categories: readonly string[], fontSize: number, labelled: boolean): number;
71
+ /** Where spoke `index`'s label is pinned: just past the rim, centre-relative, y up. */
72
+ export declare function labelPoint(index: number, count: number, radius: number, fontSize: number): Vector2;
73
+ //# sourceMappingURL=shared.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../../src/radar-chart/shared.ts"],"names":[],"mappings":"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"}