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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (207) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/README.md +109 -28
  3. package/dist/bar-chart/bar-chart.d.ts +265 -39
  4. package/dist/bar-chart/bar-chart.d.ts.map +1 -1
  5. package/dist/bar-chart/bar-chart.js +219 -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 +76 -52
  12. package/dist/bar-chart/chart-bars.d.ts.map +1 -1
  13. package/dist/bar-chart/chart-bars.js +105 -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 +41 -65
  20. package/dist/bar-chart/shared.d.ts.map +1 -1
  21. package/dist/bar-chart/shared.js +73 -117
  22. package/dist/bar-chart/shared.js.map +1 -1
  23. package/dist/browser/chunks/chunk-7XCRX6GE.js +2 -0
  24. package/dist/browser/chunks/chunk-7XCRX6GE.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 +51 -15
  38. package/dist/kit/cartesian.d.ts.map +1 -1
  39. package/dist/kit/cartesian.js +81 -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 +517 -0
  70. package/dist/kit/style.d.ts.map +1 -0
  71. package/dist/kit/style.js +292 -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 +281 -18
  90. package/dist/line-chart/line-chart.d.ts.map +1 -1
  91. package/dist/line-chart/line-chart.js +284 -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 +38 -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 +61 -62
  118. package/dist/pie-chart/shared.d.ts.map +1 -1
  119. package/dist/pie-chart/shared.js +44 -123
  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 +212 -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 +49 -0
  130. package/dist/radar-chart/radar-grid.d.ts.map +1 -0
  131. package/dist/radar-chart/radar-grid.js +63 -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 +78 -0
  138. package/dist/radar-chart/shared.d.ts.map +1 -0
  139. package/dist/radar-chart/shared.js +129 -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 +210 -0
  146. package/dist/radial-chart/radial-chart.d.ts.map +1 -0
  147. package/dist/radial-chart/radial-chart.js +175 -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 +77 -0
  154. package/dist/radial-chart/shared.d.ts.map +1 -0
  155. package/dist/radial-chart/shared.js +78 -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 +263 -179
  160. package/src/bar-chart/category-axis.ts +46 -40
  161. package/src/bar-chart/chart-bars.ts +136 -117
  162. package/src/bar-chart/index.ts +7 -10
  163. package/src/bar-chart/shared.ts +88 -233
  164. package/src/engine.ts +5 -2
  165. package/src/index.ts +2 -0
  166. package/src/kit/cartesian.ts +121 -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 +353 -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 +353 -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 +54 -35
  185. package/src/pie-chart/pie-ring.ts +92 -71
  186. package/src/pie-chart/shared.ts +80 -270
  187. package/src/radar-chart/index.ts +4 -0
  188. package/src/radar-chart/radar-chart.ts +290 -0
  189. package/src/radar-chart/radar-grid.ts +83 -0
  190. package/src/radar-chart/radar-series.ts +88 -0
  191. package/src/radar-chart/shared.ts +153 -0
  192. package/src/radial-chart/index.ts +5 -0
  193. package/src/radial-chart/radial-chart.ts +212 -0
  194. package/src/radial-chart/radial-rings.ts +328 -0
  195. package/src/radial-chart/shared.ts +126 -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,7 +1,10 @@
1
- import { clamp, lerpNumber, shadowOps, strokeOps, textOps, } from "@motionscript/sdk";
2
- import { CHART_PALETTE, DEFAULT_LEGEND, DEFAULT_SERIES_FILLS, lerpLegendConfig, lerpSeriesFills, num, resolveLegendConfig, resolveSeriesFills, text, } from "../kit/shared.js";
1
+ import { Types } from "@motionscript/sdk";
2
+ import { CHART_BACKGROUND, CHART_FOREGROUND, CHART_LEGEND, CHART_MUTED, CHART_SERIES, LEGEND_TEXT, legendConfigOf, placedText, sizeOf, } from "../kit/style.js";
3
+ import { num, text } from "../kit/shared.js";
4
+ import { DEG, PIE_SPOTLIGHT_DIM, ringPoint, selectionFade } from "../kit/polar.js";
5
+ export { DEG, PIE_SPOTLIGHT_DIM, ringPoint, selectionFade };
3
6
  /**
4
- * One slice per row, painted from `palette` by row order (cycling). Paint comes
7
+ * One slice per row, painted from `seriesFills` by row order (cycling). Paint comes
5
8
  * from the palette, not the rows, because a pie's mark is a row where a line's
6
9
  * colour belongs to a column; that lets a pie be fed a CSV of plain numbers.
7
10
  */
@@ -12,17 +15,6 @@ export function resolvePieSlices(data, category, value, palette) {
12
15
  fill: palette.length > 0 ? palette[i % palette.length] : "white",
13
16
  }));
14
17
  }
15
- export const DEG = Math.PI / 180;
16
- /**
17
- * Opacity of a slice under the selection: 1 while nothing is out (`focus` is the
18
- * most-grown pop) and for the selected slice itself, falling toward `dimOpacity`
19
- * for the rest as the selection grows.
20
- */
21
- export function selectionFade(focus, dimOpacity, pop) {
22
- if (focus <= 0)
23
- return 1;
24
- return 1 - (1 - clamp(dimOpacity, 0, 1)) * focus * (1 - pop);
25
- }
26
18
  /** A slice's plotted value: negatives and non-finite values count as 0. */
27
19
  export function sliceValue(slice) {
28
20
  return slice.value > 0 && Number.isFinite(slice.value) ? slice.value : 0;
@@ -34,10 +26,6 @@ export function sliceTotal(slices) {
34
26
  sum += sliceValue(slice);
35
27
  return sum;
36
28
  }
37
- /** 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. */
38
- export function ringPoint(r, a) {
39
- return { x: r * Math.sin(a), y: r * Math.cos(a) };
40
- }
41
29
  /**
42
30
  * One arc per positive slice, walking clockwise from `startDegrees` and abutting.
43
31
  * Arcs are the undivided shares: a fixed angular gap would pinch shut at the
@@ -83,121 +71,54 @@ export function relaxLabels(slots, minGap, top, bottom) {
83
71
  }
84
72
  return slots;
85
73
  }
86
- const LABEL_TEXT_STYLE = {
87
- fontSize: 26,
88
- fontWeight: 600,
89
- textAlign: "center",
90
- fill: CHART_PALETTE.markerColor,
91
- };
92
- /** Fainter than `SPOTLIGHT_DIM`: a ring's slices touch, so at that a selected slice barely separates. */
93
- export const PIE_SPOTLIGHT_DIM = 0.1;
94
- export const DEFAULT_PIE_CHART_THEME = {
95
- sliceFills: DEFAULT_SERIES_FILLS,
96
- ring: {
97
- gap: 6,
98
- // A donut by default: the hole is the one place a conclusion can be set.
99
- holeRadius: 0.6,
100
- startAngle: 0,
101
- selectedGrow: 1.08,
102
- stroke: [],
103
- shadow: [],
74
+ /** The groups of a pie's `style`: no grid, as nothing is ruled. */
75
+ export const PIE_STYLE_GROUPS = {
76
+ series: CHART_SERIES,
77
+ background: CHART_BACKGROUND,
78
+ text: {
79
+ /** Each slice's name. */
80
+ labelText: Types.typography({ fontSize: 28, fontWeight: 500, fill: CHART_MUTED }),
81
+ /** Each slice's share or value, beside its name; inside a wedge both are set larger, inked for contrast. */
82
+ valueText: Types.typography({ fontSize: 28, fontWeight: 700, fill: CHART_FOREGROUND }),
83
+ /** The summary in the hole; its caption is set smaller, in the slice names' ink. */
84
+ centerText: Types.typography({ fontSize: 50, fontWeight: 800, fill: CHART_FOREGROUND }),
85
+ ...LEGEND_TEXT,
104
86
  },
105
- label: {
106
- textStyle: LABEL_TEXT_STYLE,
107
- percentStyle: { ...LABEL_TEXT_STYLE, fontWeight: 700 },
108
- // On a mid-tone wedge, so the panel colour rather than the axis ink.
109
- insideStyle: { ...LABEL_TEXT_STYLE, fontWeight: 800, fill: "#15130e" },
110
- leaderStroke: { weight: 2, fill: CHART_PALETTE.markerColor },
87
+ marks: {
88
+ /** Hole radius as a fraction of the outer radius: 0 is a pie, about 0.6 a donut. */
89
+ innerRadius: Types.number(0, { min: 0, max: 0.9, step: 0.05 }),
90
+ /** Channel between neighbouring wedges, px. */
91
+ sliceGap: Types.number(3, { min: 0, max: 40, step: 1, unit: "px" }),
92
+ /** Rounding of each wedge corner, px. */
93
+ sliceRadius: Types.number(4, { min: 0, max: 60, step: 1, unit: "px" }),
111
94
  },
112
- center: {
113
- labelStyle: {
114
- fontSize: 46,
115
- fontWeight: 800,
116
- textAlign: "center",
117
- fill: CHART_PALETTE.markerColor,
118
- },
119
- captionStyle: {
120
- fontSize: 22,
121
- fontWeight: 500,
122
- textAlign: "center",
123
- fill: CHART_PALETTE.markerColor,
124
- },
95
+ labels: {
96
+ /** Read as the chart is built: inside the wedge, outside on a leader, or none. */
97
+ labelPlacement: Types.oneOf(["inside", "outside", "none"], { animatable: false }),
125
98
  },
126
- legend: DEFAULT_LEGEND,
127
- spotlight: { dimOpacity: PIE_SPOTLIGHT_DIM },
99
+ legend: CHART_LEGEND,
128
100
  };
129
- function resolveRingConfig(ring, previous) {
130
- return {
131
- gap: ring?.gap ?? previous.gap,
132
- holeRadius: ring?.holeRadius ?? previous.holeRadius,
133
- startAngle: ring?.startAngle ?? previous.startAngle,
134
- selectedGrow: ring?.selectedGrow ?? previous.selectedGrow,
135
- stroke: strokeOps.resolve(ring?.stroke ?? previous.stroke),
136
- shadow: shadowOps.resolve(ring?.shadow ?? previous.shadow),
137
- };
101
+ export function legendOf(style) {
102
+ return legendConfigOf(style);
138
103
  }
139
- function lerpRingConfig(from, to, t) {
140
- return {
141
- gap: lerpNumber(from.gap, to.gap, t),
142
- holeRadius: lerpNumber(from.holeRadius, to.holeRadius, t),
143
- startAngle: lerpNumber(from.startAngle, to.startAngle, t),
144
- selectedGrow: lerpNumber(from.selectedGrow, to.selectedGrow, t),
145
- stroke: strokeOps.lerp(from.stroke, to.stroke, t),
146
- shadow: shadowOps.lerp(from.shadow, to.shadow, t),
147
- };
148
- }
149
- function resolveLabelConfig(label, previous) {
150
- return {
151
- textStyle: textOps.resolveStyle(label?.textStyle, previous.textStyle),
152
- percentStyle: textOps.resolveStyle(label?.percentStyle, previous.percentStyle),
153
- insideStyle: textOps.resolveStyle(label?.insideStyle, previous.insideStyle),
154
- leaderStroke: strokeOps.resolve(label?.leaderStroke ?? previous.leaderStroke),
155
- };
156
- }
157
- function lerpLabelConfig(from, to, t) {
158
- return {
159
- textStyle: textOps.lerpStyle(from.textStyle, to.textStyle, t),
160
- percentStyle: textOps.lerpStyle(from.percentStyle, to.percentStyle, t),
161
- insideStyle: textOps.lerpStyle(from.insideStyle, to.insideStyle, t),
162
- leaderStroke: strokeOps.lerp(from.leaderStroke, to.leaderStroke, t),
163
- };
164
- }
165
- function resolveCenterConfig(center, previous) {
166
- return {
167
- labelStyle: textOps.resolveStyle(center?.labelStyle, previous.labelStyle),
168
- captionStyle: textOps.resolveStyle(center?.captionStyle, previous.captionStyle),
169
- };
170
- }
171
- function lerpCenterConfig(from, to, t) {
172
- return {
173
- labelStyle: textOps.lerpStyle(from.labelStyle, to.labelStyle, t),
174
- captionStyle: textOps.lerpStyle(from.captionStyle, to.captionStyle, t),
175
- };
104
+ export function ringConfigOf(style) {
105
+ return { gap: style.sliceGap, holeRadius: style.innerRadius, startAngle: 0, selectedGrow: 1.08, cornerRadius: style.sliceRadius };
176
106
  }
177
- /** The `theme` entry's resolve: merges a partial {@link PieChartTheme} onto `previous` (first resolution: the default). */
178
- export function resolvePieChartTheme(theme, previous) {
179
- const base = previous ?? DEFAULT_PIE_CHART_THEME;
107
+ export function labelConfigOf(style) {
108
+ const base = placedText(style.labelText);
109
+ const value = placedText(style.valueText);
180
110
  return {
181
- sliceFills: resolveSeriesFills(theme?.sliceFills, base.sliceFills),
182
- ring: resolveRingConfig(theme?.ring, base.ring),
183
- label: resolveLabelConfig(theme?.label, base.label),
184
- center: resolveCenterConfig(theme?.center, base.center),
185
- legend: resolveLegendConfig(theme?.legend, base.legend),
186
- spotlight: {
187
- dimOpacity: theme?.spotlight?.dimOpacity ?? base.spotlight.dimOpacity,
188
- },
111
+ textStyle: base,
112
+ percentStyle: value,
113
+ insideStyle: { ...value, fontSize: Math.round(sizeOf(style.valueText) * 1.9), fill: "#111113" },
114
+ leaderStroke: { weight: 2, fill: style.labelText.fill ?? "white" },
189
115
  };
190
116
  }
191
- export function lerpPieChartTheme(from, to, t) {
117
+ export function centerConfigOf(style) {
118
+ const size = sizeOf(style.centerText, 50);
192
119
  return {
193
- sliceFills: lerpSeriesFills(from.sliceFills, to.sliceFills, t),
194
- ring: lerpRingConfig(from.ring, to.ring, t),
195
- label: lerpLabelConfig(from.label, to.label, t),
196
- center: lerpCenterConfig(from.center, to.center, t),
197
- legend: lerpLegendConfig(from.legend, to.legend, t),
198
- spotlight: {
199
- dimOpacity: lerpNumber(from.spotlight.dimOpacity, to.spotlight.dimOpacity, t),
200
- },
120
+ labelStyle: placedText(style.centerText),
121
+ captionStyle: placedText(style.labelText, "center", { fontSize: Math.round(size * 0.45) }),
201
122
  };
202
123
  }
203
124
  //# sourceMappingURL=shared.js.map
@@ -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_BACKGROUND,\n CHART_FOREGROUND,\n CHART_LEGEND,\n CHART_MUTED,\n CHART_SERIES,\n LEGEND_TEXT,\n legendConfigOf,\n placedText,\n sizeOf,\n type ChartStyleBase,\n} from \"../kit/style\"\nimport { num, text, type LegendConfig } from \"../kit/shared\"\nimport { DEG, PIE_SPOTLIGHT_DIM, ringPoint, selectionFade, type CenterConfig, type PieSlice } from \"../kit/polar\"\n\nexport { DEG, PIE_SPOTLIGHT_DIM, ringPoint, selectionFade, type CenterConfig, type PieSlice }\n\n/**\n * One slice per row, painted from `seriesFills` by row order (cycling). Paint comes\n * from the palette, not the rows, because a pie's mark is a row where a line's\n * colour belongs to a column; that lets a pie be fed a CSV of plain numbers.\n */\nexport function resolvePieSlices(data: readonly Record<string, unknown>[], category: string, value: string, palette: readonly Fill[]): PieSlice[] {\n return data.map((row, i) => ({\n category: text(row as never, category),\n value: num(row as never, value),\n fill: palette.length > 0 ? palette[i % palette.length] : (\"white\" as Fill),\n }))\n}\n\n/** What a {@link PieChart}'s labels say. */\nexport type PieLabelMode =\n /** Two lines, whose order flips with placement: an outside label reads category over percentage, an inside label reads the percentage big over a small category. */\n | \"both\"\n | \"category\"\n | \"percent\"\n /** No labels and no leader lines. */\n | \"none\"\n\n/** `\"inside\"` centres the label in the wedge's band with no leader or gutter, so the ring draws bigger; `\"outside\"` sets it on a leader, which a sliver too narrow for text needs. */\nexport type PieLabelPlacement = \"inside\" | \"outside\" | \"none\"\n\n\n/** A slice's plotted value: negatives and non-finite values count as 0. */\nexport function sliceValue(slice: PieSlice): number {\n return slice.value > 0 && Number.isFinite(slice.value) ? slice.value : 0\n}\n\n/** Sum of every slice's plotted value, the denominator of every share. */\nexport function sliceTotal(slices: PieSlice[]): number {\n let sum = 0\n for (const slice of slices) sum += sliceValue(slice)\n return sum\n}\n\n/** One slice's resolved angular span on the ring. */\nexport interface PieArc {\n /** Index of the slice in the source list. */\n index: number\n /** Radians clockwise from 12 o'clock. */\n a0: number\n a1: number\n /** Where the slice's label and pop-out point. */\n mid: number\n /** Share of the total, `[0, 1]`. */\n fraction: number\n}\n\n/**\n * One arc per positive slice, walking clockwise from `startDegrees` and abutting.\n * Arcs are the undivided shares: a fixed angular gap would pinch shut at the\n * hole, so the gap is applied when the wedge is drawn, as a constant-width inset\n * off both ends.\n */\nexport function pieArcs(slices: PieSlice[], startDegrees: number): PieArc[] {\n const total = sliceTotal(slices)\n if (total <= 0) return []\n\n const arcs: PieArc[] = []\n let cursor = startDegrees * DEG\n slices.forEach((slice, index) => {\n const value = sliceValue(slice)\n if (value <= 0) return\n const fraction = value / total\n const a0 = cursor\n const a1 = a0 + fraction * Math.PI * 2\n cursor = a1\n arcs.push({ index, a0, a1, mid: (a0 + a1) / 2, fraction })\n })\n return arcs\n}\n\ninterface LabelSlot {\n /** Where the label would sit if nothing else were in the way. */\n ideal: number\n /** Written by {@link relaxLabels}. */\n y: number\n}\n\n/**\n * Spread one column of labels so none overlap, each near its `ideal` y and all\n * inside `[bottom, top]`. A top-down pass clears each label from the one above\n * by `minGap`; a reverse pass lifts a tail pushed past `bottom`. When the column\n * cannot hold them all, the reverse pass wins and the crowding is shared evenly.\n * Mutates each `y` and returns `slots` ordered top to bottom.\n */\nexport function relaxLabels<T extends LabelSlot>(slots: T[], minGap: number, top: number, bottom: number): T[] {\n slots.sort((a, b) => b.ideal - a.ideal)\n\n let ceiling = top\n for (const slot of slots) {\n slot.y = Math.min(slot.ideal, ceiling)\n ceiling = slot.y - minGap\n }\n\n let floor = bottom\n for (let i = slots.length - 1; i >= 0; i--) {\n slots[i].y = Math.max(slots[i].y, floor)\n floor = slots[i].y + minGap\n }\n\n return slots\n}\n\n/** The ring's geometry: everything about the wedges but their colour. */\nexport interface RingConfig {\n /** Channel between adjacent slices in px, constant across the band (an angular gap would splay open toward the rim). */\n gap: number\n /** Below 1 a fraction of the outer radius (`0.6` leaves a band 40% thick); 1 and up a pixel radius; `0` draws solid wedges. */\n holeRadius: number\n /** Degrees clockwise from 12 o'clock where the first slice begins. */\n startAngle: number\n /** How far a selected slice's rim reaches, as a multiple of the outer radius so the emphasis scales with the chart. Clamped to `[1, 1.6]`. */\n selectedGrow: number\n /** Rounding of each wedge corner, px. */\n cornerRadius: number\n}\n\n/** How the ring's labels are set, and the leader lines that point at them. */\nexport interface LabelConfig {\n /** The category caption outside the ring. */\n textStyle: TextStyle\n /** The percentage outside the ring. */\n percentStyle: TextStyle\n /** Both lines of a label inside its wedge; its fill is set per wedge, for contrast against the paint. */\n insideStyle: TextStyle\n /** Runs from a wedge out to its label. */\n leaderStroke: Stroke\n}\n\n/** What a pie's `style` resolves to. */\nexport interface PieStyle extends ChartStyleBase {\n readonly labelText: TextStyle\n readonly valueText: TextStyle\n readonly centerText: TextStyle\n readonly innerRadius: number\n readonly sliceGap: number\n readonly sliceRadius: number\n readonly labelPlacement: PieLabelPlacement\n}\n\n/** The groups of a pie's `style`: no grid, as nothing is ruled. */\nexport const PIE_STYLE_GROUPS = {\n series: CHART_SERIES,\n background: CHART_BACKGROUND,\n text: {\n /** Each slice's name. */\n labelText: Types.typography({ fontSize: 28, fontWeight: 500, fill: CHART_MUTED }),\n /** Each slice's share or value, beside its name; inside a wedge both are set larger, inked for contrast. */\n valueText: Types.typography({ fontSize: 28, fontWeight: 700, fill: CHART_FOREGROUND }),\n /** The summary in the hole; its caption is set smaller, in the slice names' ink. */\n centerText: Types.typography({ fontSize: 50, fontWeight: 800, fill: CHART_FOREGROUND }),\n ...LEGEND_TEXT,\n },\n marks: {\n /** Hole radius as a fraction of the outer radius: 0 is a pie, about 0.6 a donut. */\n innerRadius: Types.number(0, { min: 0, max: 0.9, step: 0.05 }),\n /** Channel between neighbouring wedges, px. */\n sliceGap: Types.number(3, { min: 0, max: 40, step: 1, unit: \"px\" }),\n /** Rounding of each wedge corner, px. */\n sliceRadius: Types.number(4, { min: 0, max: 60, step: 1, unit: \"px\" }),\n },\n labels: {\n /** Read as the chart is built: inside the wedge, outside on a leader, or none. */\n labelPlacement: Types.oneOf([\"inside\", \"outside\", \"none\"] as const, { animatable: false }),\n },\n legend: CHART_LEGEND,\n}\n\nexport function legendOf(style: PieStyle): LegendConfig {\n return legendConfigOf(style)\n}\n\nexport function ringConfigOf(style: PieStyle): RingConfig {\n return { gap: style.sliceGap, holeRadius: style.innerRadius, startAngle: 0, selectedGrow: 1.08, cornerRadius: style.sliceRadius }\n}\n\nexport function labelConfigOf(style: PieStyle): LabelConfig {\n const base = placedText(style.labelText)\n const value = placedText(style.valueText)\n return {\n textStyle: base,\n percentStyle: value,\n insideStyle: { ...value, fontSize: Math.round(sizeOf(style.valueText) * 1.9), fill: \"#111113\" },\n leaderStroke: { weight: 2, fill: style.labelText.fill ?? \"white\" },\n }\n}\n\nexport function centerConfigOf(style: PieStyle): CenterConfig {\n const size = sizeOf(style.centerText, 50)\n return {\n labelStyle: placedText(style.centerText),\n captionStyle: placedText(style.labelText, \"center\", { fontSize: Math.round(size * 0.45) }),\n }\n}\n"]}
@@ -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, RADAR_TEXT, 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,UAAU,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, RADAR_TEXT, 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,UAAU,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, RADAR_TEXT, fitRadius, niceCeil, spokeDirection } from \"./shared\"\n"]}
@@ -0,0 +1,212 @@
1
+ import { type DataRecord, type NodeOf, type Node2D, type Node2DProps as _Node2DProps, type TextStyle as _TextStyle, 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
+ gridBackground: import("@motionscript/sdk").Type<_Fill, _FillResolved[], false>;
37
+ background: import("@motionscript/sdk").Type<_Fill, _FillResolved[], false>;
38
+ } & {
39
+ legend: import("@motionscript/sdk").Type<"right" | "top" | "bottom" | "none", "right" | "top" | "bottom" | "none", false>;
40
+ swatch: import("@motionscript/sdk").Type<"square" | "circle" | "line", "square" | "circle" | "line", false>;
41
+ } & {
42
+ gridShape: import("@motionscript/sdk").Type<"circle" | "polygon", "circle" | "polygon", false>;
43
+ gridLevels: import("@motionscript/sdk").Type<number, number, false>;
44
+ gridStroke: import("@motionscript/sdk").Type<_Stroke, _StrokeResolved[], false>;
45
+ spokeStroke: import("@motionscript/sdk").Type<_Stroke, _StrokeResolved[], false>;
46
+ spokeLabels: import("@motionscript/sdk").Type<boolean, boolean, false>;
47
+ } & {
48
+ legendText: import("@motionscript/sdk").Type<_TextStyle, _TextStyle, false>;
49
+ spokeText: import("@motionscript/sdk").Type<_TextStyle, _TextStyle, false>;
50
+ } & {
51
+ seriesFills: import("@motionscript/sdk").Type<_Fill[], _FillResolved[][], false>;
52
+ } & {
53
+ strokeWidth: import("@motionscript/sdk").Type<number, number, false>;
54
+ areaOpacity: import("@motionscript/sdk").Type<number, number, false>;
55
+ dots: import("@motionscript/sdk").Type<boolean, boolean, false>;
56
+ dotSize: import("@motionscript/sdk").Type<number, number, false>;
57
+ }>, import("@motionscript/sdk").StyleValues<{
58
+ gridBackground: import("@motionscript/sdk").Type<_Fill, _FillResolved[], false>;
59
+ background: import("@motionscript/sdk").Type<_Fill, _FillResolved[], false>;
60
+ } & {
61
+ legend: import("@motionscript/sdk").Type<"right" | "top" | "bottom" | "none", "right" | "top" | "bottom" | "none", false>;
62
+ swatch: import("@motionscript/sdk").Type<"square" | "circle" | "line", "square" | "circle" | "line", false>;
63
+ } & {
64
+ gridShape: import("@motionscript/sdk").Type<"circle" | "polygon", "circle" | "polygon", false>;
65
+ gridLevels: import("@motionscript/sdk").Type<number, number, false>;
66
+ gridStroke: import("@motionscript/sdk").Type<_Stroke, _StrokeResolved[], false>;
67
+ spokeStroke: import("@motionscript/sdk").Type<_Stroke, _StrokeResolved[], false>;
68
+ spokeLabels: import("@motionscript/sdk").Type<boolean, boolean, false>;
69
+ } & {
70
+ legendText: import("@motionscript/sdk").Type<_TextStyle, _TextStyle, false>;
71
+ spokeText: import("@motionscript/sdk").Type<_TextStyle, _TextStyle, false>;
72
+ } & {
73
+ seriesFills: import("@motionscript/sdk").Type<_Fill[], _FillResolved[][], false>;
74
+ } & {
75
+ strokeWidth: import("@motionscript/sdk").Type<number, number, false>;
76
+ areaOpacity: import("@motionscript/sdk").Type<number, number, false>;
77
+ dots: import("@motionscript/sdk").Type<boolean, boolean, false>;
78
+ dotSize: import("@motionscript/sdk").Type<number, number, false>;
79
+ }>, false>;
80
+ }>, {
81
+ readonly enter: {};
82
+ readonly showSeries: {
83
+ readonly seriesIndex: import("@motionscript/sdk").Type<number, number, false>;
84
+ };
85
+ readonly hideSeries: {
86
+ readonly seriesIndex: import("@motionscript/sdk").Type<number, number, false>;
87
+ };
88
+ readonly spotlightSeries: {
89
+ readonly seriesIndex: import("@motionscript/sdk").Type<number, number, false>;
90
+ };
91
+ }, readonly [], Node2D<_Node2DProps>, import("@motionscript/sdk").CallProps<import("@motionscript/sdk").Merge<import("@motionscript/sdk").Box2DState, {
92
+ readonly data: import("@motionscript/sdk").Type<DataRecord[], DataRecord[], false>;
93
+ /** The column that names each spoke. */
94
+ readonly categoryField: "";
95
+ readonly series: import("@motionscript/sdk").Type<ChartSeries[], ChartSeries[], false>;
96
+ /** The value at the centre of the web. */
97
+ readonly min: 0;
98
+ /** The value at the rim; 0 rounds the largest value up. */
99
+ readonly max: 0;
100
+ readonly style: import("@motionscript/sdk").Type<import("@motionscript/sdk").StyleInput<{
101
+ gridBackground: import("@motionscript/sdk").Type<_Fill, _FillResolved[], false>;
102
+ background: import("@motionscript/sdk").Type<_Fill, _FillResolved[], false>;
103
+ } & {
104
+ legend: import("@motionscript/sdk").Type<"right" | "top" | "bottom" | "none", "right" | "top" | "bottom" | "none", false>;
105
+ swatch: import("@motionscript/sdk").Type<"square" | "circle" | "line", "square" | "circle" | "line", false>;
106
+ } & {
107
+ gridShape: import("@motionscript/sdk").Type<"circle" | "polygon", "circle" | "polygon", false>;
108
+ gridLevels: import("@motionscript/sdk").Type<number, number, false>;
109
+ gridStroke: import("@motionscript/sdk").Type<_Stroke, _StrokeResolved[], false>;
110
+ spokeStroke: import("@motionscript/sdk").Type<_Stroke, _StrokeResolved[], false>;
111
+ spokeLabels: import("@motionscript/sdk").Type<boolean, boolean, false>;
112
+ } & {
113
+ legendText: import("@motionscript/sdk").Type<_TextStyle, _TextStyle, false>;
114
+ spokeText: import("@motionscript/sdk").Type<_TextStyle, _TextStyle, false>;
115
+ } & {
116
+ seriesFills: import("@motionscript/sdk").Type<_Fill[], _FillResolved[][], false>;
117
+ } & {
118
+ strokeWidth: import("@motionscript/sdk").Type<number, number, false>;
119
+ areaOpacity: import("@motionscript/sdk").Type<number, number, false>;
120
+ dots: import("@motionscript/sdk").Type<boolean, boolean, false>;
121
+ dotSize: import("@motionscript/sdk").Type<number, number, false>;
122
+ }>, import("@motionscript/sdk").StyleValues<{
123
+ gridBackground: import("@motionscript/sdk").Type<_Fill, _FillResolved[], false>;
124
+ background: import("@motionscript/sdk").Type<_Fill, _FillResolved[], false>;
125
+ } & {
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
+ legendText: import("@motionscript/sdk").Type<_TextStyle, _TextStyle, false>;
136
+ spokeText: import("@motionscript/sdk").Type<_TextStyle, _TextStyle, false>;
137
+ } & {
138
+ seriesFills: import("@motionscript/sdk").Type<_Fill[], _FillResolved[][], false>;
139
+ } & {
140
+ strokeWidth: import("@motionscript/sdk").Type<number, number, false>;
141
+ areaOpacity: import("@motionscript/sdk").Type<number, number, false>;
142
+ dots: import("@motionscript/sdk").Type<boolean, boolean, false>;
143
+ dotSize: import("@motionscript/sdk").Type<number, number, false>;
144
+ }>, false>;
145
+ }>, readonly [], import("@motionscript/sdk").BuiltNode<import("@motionscript/sdk").Merge<import("@motionscript/sdk").Box2DState, {
146
+ readonly data: import("@motionscript/sdk").Type<DataRecord[], DataRecord[], false>;
147
+ /** The column that names each spoke. */
148
+ readonly categoryField: "";
149
+ readonly series: import("@motionscript/sdk").Type<ChartSeries[], ChartSeries[], false>;
150
+ /** The value at the centre of the web. */
151
+ readonly min: 0;
152
+ /** The value at the rim; 0 rounds the largest value up. */
153
+ readonly max: 0;
154
+ readonly style: import("@motionscript/sdk").Type<import("@motionscript/sdk").StyleInput<{
155
+ gridBackground: import("@motionscript/sdk").Type<_Fill, _FillResolved[], false>;
156
+ background: import("@motionscript/sdk").Type<_Fill, _FillResolved[], false>;
157
+ } & {
158
+ legend: import("@motionscript/sdk").Type<"right" | "top" | "bottom" | "none", "right" | "top" | "bottom" | "none", false>;
159
+ swatch: import("@motionscript/sdk").Type<"square" | "circle" | "line", "square" | "circle" | "line", false>;
160
+ } & {
161
+ gridShape: import("@motionscript/sdk").Type<"circle" | "polygon", "circle" | "polygon", false>;
162
+ gridLevels: import("@motionscript/sdk").Type<number, number, false>;
163
+ gridStroke: import("@motionscript/sdk").Type<_Stroke, _StrokeResolved[], false>;
164
+ spokeStroke: import("@motionscript/sdk").Type<_Stroke, _StrokeResolved[], false>;
165
+ spokeLabels: import("@motionscript/sdk").Type<boolean, boolean, false>;
166
+ } & {
167
+ legendText: import("@motionscript/sdk").Type<_TextStyle, _TextStyle, false>;
168
+ spokeText: import("@motionscript/sdk").Type<_TextStyle, _TextStyle, false>;
169
+ } & {
170
+ seriesFills: import("@motionscript/sdk").Type<_Fill[], _FillResolved[][], false>;
171
+ } & {
172
+ strokeWidth: import("@motionscript/sdk").Type<number, number, false>;
173
+ areaOpacity: import("@motionscript/sdk").Type<number, number, false>;
174
+ dots: import("@motionscript/sdk").Type<boolean, boolean, false>;
175
+ dotSize: import("@motionscript/sdk").Type<number, number, false>;
176
+ }>, import("@motionscript/sdk").StyleValues<{
177
+ gridBackground: import("@motionscript/sdk").Type<_Fill, _FillResolved[], false>;
178
+ background: import("@motionscript/sdk").Type<_Fill, _FillResolved[], false>;
179
+ } & {
180
+ legend: import("@motionscript/sdk").Type<"right" | "top" | "bottom" | "none", "right" | "top" | "bottom" | "none", false>;
181
+ swatch: import("@motionscript/sdk").Type<"square" | "circle" | "line", "square" | "circle" | "line", false>;
182
+ } & {
183
+ gridShape: import("@motionscript/sdk").Type<"circle" | "polygon", "circle" | "polygon", false>;
184
+ gridLevels: import("@motionscript/sdk").Type<number, number, false>;
185
+ gridStroke: import("@motionscript/sdk").Type<_Stroke, _StrokeResolved[], false>;
186
+ spokeStroke: import("@motionscript/sdk").Type<_Stroke, _StrokeResolved[], false>;
187
+ spokeLabels: import("@motionscript/sdk").Type<boolean, boolean, false>;
188
+ } & {
189
+ legendText: import("@motionscript/sdk").Type<_TextStyle, _TextStyle, false>;
190
+ spokeText: import("@motionscript/sdk").Type<_TextStyle, _TextStyle, false>;
191
+ } & {
192
+ seriesFills: import("@motionscript/sdk").Type<_Fill[], _FillResolved[][], false>;
193
+ } & {
194
+ strokeWidth: import("@motionscript/sdk").Type<number, number, false>;
195
+ areaOpacity: import("@motionscript/sdk").Type<number, number, false>;
196
+ dots: import("@motionscript/sdk").Type<boolean, boolean, false>;
197
+ dotSize: import("@motionscript/sdk").Type<number, number, false>;
198
+ }>, false>;
199
+ }>, {
200
+ readonly enter: {};
201
+ readonly showSeries: {
202
+ readonly seriesIndex: import("@motionscript/sdk").Type<number, number, false>;
203
+ };
204
+ readonly hideSeries: {
205
+ readonly seriesIndex: import("@motionscript/sdk").Type<number, number, false>;
206
+ };
207
+ readonly spotlightSeries: {
208
+ readonly seriesIndex: import("@motionscript/sdk").Type<number, number, false>;
209
+ };
210
+ }, Node2D<_Node2DProps>>>>;
211
+ export type RadarChart = NodeOf<typeof RadarChart>;
212
+ //# 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,EAOL,KAAK,UAAU,EACf,KAAK,MAAM,EAEX,KAAK,MAAM,EACX,KAAK,WAAW,IAAI,YAAY,EAChC,KAAK,SAAS,IAAI,UAAU,EAC5B,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;AA4B/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"}