@motionscript/charts 0.1.1-alpha.1 → 0.1.1-alpha.3
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.
- package/CHANGELOG.md +23 -0
- package/README.md +21 -12
- package/dist/bar-chart/bar-chart.d.ts +113 -81
- package/dist/bar-chart/bar-chart.d.ts.map +1 -1
- package/dist/bar-chart/bar-chart.js +9 -5
- package/dist/bar-chart/bar-chart.js.map +1 -1
- package/dist/bar-chart/chart-bars.d.ts +29 -5
- package/dist/bar-chart/chart-bars.d.ts.map +1 -1
- package/dist/bar-chart/chart-bars.js +33 -8
- package/dist/bar-chart/chart-bars.js.map +1 -1
- package/dist/bar-chart/shared.d.ts +10 -4
- package/dist/bar-chart/shared.d.ts.map +1 -1
- package/dist/bar-chart/shared.js +12 -5
- package/dist/bar-chart/shared.js.map +1 -1
- package/dist/browser/chunks/chunk-FJHNBNPQ.js +2 -0
- package/dist/browser/chunks/chunk-FJHNBNPQ.js.map +7 -0
- package/dist/browser/index.js +1 -1
- package/dist/browser/index.js.map +3 -3
- package/dist/browser/kit.js +1 -1
- package/dist/browser/manifest.json +1 -1
- package/dist/kit/cartesian.d.ts +6 -4
- package/dist/kit/cartesian.d.ts.map +1 -1
- package/dist/kit/cartesian.js +5 -3
- package/dist/kit/cartesian.js.map +1 -1
- package/dist/kit/style.d.ts +344 -76
- package/dist/kit/style.d.ts.map +1 -1
- package/dist/kit/style.js +198 -101
- package/dist/kit/style.js.map +1 -1
- package/dist/line-chart/line-chart.d.ts +97 -73
- package/dist/line-chart/line-chart.d.ts.map +1 -1
- package/dist/line-chart/line-chart.js +9 -7
- package/dist/line-chart/line-chart.js.map +1 -1
- package/dist/line-chart/shared.d.ts +2 -1
- package/dist/line-chart/shared.d.ts.map +1 -1
- package/dist/line-chart/shared.js +2 -0
- package/dist/line-chart/shared.js.map +1 -1
- package/dist/pie-chart/pie-chart.d.ts +43 -49
- package/dist/pie-chart/pie-chart.d.ts.map +1 -1
- package/dist/pie-chart/pie-chart.js +2 -1
- package/dist/pie-chart/pie-chart.js.map +1 -1
- package/dist/pie-chart/shared.d.ts +15 -10
- package/dist/pie-chart/shared.d.ts.map +1 -1
- package/dist/pie-chart/shared.js +18 -20
- package/dist/pie-chart/shared.js.map +1 -1
- package/dist/radar-chart/radar-chart.d.ts +37 -49
- package/dist/radar-chart/radar-chart.d.ts.map +1 -1
- package/dist/radar-chart/radar-chart.js +10 -11
- package/dist/radar-chart/radar-chart.js.map +1 -1
- package/dist/radar-chart/radar-grid.d.ts +7 -1
- package/dist/radar-chart/radar-grid.d.ts.map +1 -1
- package/dist/radar-chart/radar-grid.js +17 -15
- package/dist/radar-chart/radar-grid.js.map +1 -1
- package/dist/radar-chart/shared.d.ts +4 -2
- package/dist/radar-chart/shared.d.ts.map +1 -1
- package/dist/radar-chart/shared.js +3 -0
- package/dist/radar-chart/shared.js.map +1 -1
- package/dist/radial-chart/radial-chart.d.ts +37 -49
- package/dist/radial-chart/radial-chart.d.ts.map +1 -1
- package/dist/radial-chart/radial-chart.js +2 -1
- package/dist/radial-chart/radial-chart.js.map +1 -1
- package/dist/radial-chart/shared.d.ts +13 -11
- package/dist/radial-chart/shared.d.ts.map +1 -1
- package/dist/radial-chart/shared.js +12 -16
- package/dist/radial-chart/shared.js.map +1 -1
- package/package.json +4 -4
- package/src/bar-chart/bar-chart.ts +17 -6
- package/src/bar-chart/chart-bars.ts +48 -9
- package/src/bar-chart/shared.ts +23 -5
- package/src/kit/cartesian.ts +10 -7
- package/src/kit/style.ts +216 -118
- package/src/line-chart/line-chart.ts +14 -8
- package/src/line-chart/shared.ts +3 -1
- package/src/pie-chart/pie-chart.ts +3 -1
- package/src/pie-chart/shared.ts +26 -22
- package/src/radar-chart/radar-chart.ts +14 -13
- package/src/radar-chart/radar-grid.ts +18 -13
- package/src/radar-chart/shared.ts +5 -2
- package/src/radial-chart/radial-chart.ts +3 -1
- package/src/radial-chart/shared.ts +26 -18
- package/dist/browser/chunks/chunk-R3Q5EE6E.js +0 -2
- package/dist/browser/chunks/chunk-R3Q5EE6E.js.map +0 -7
|
@@ -11,6 +11,11 @@ import {
|
|
|
11
11
|
// Named so this component's emitted type reaches `Node2D` and its props through the sdk, not core.
|
|
12
12
|
type Node2D,
|
|
13
13
|
type Node2DProps as _Node2DProps,
|
|
14
|
+
type TextStyle as _TextStyle,
|
|
15
|
+
type CornerRadiusResolved as _CornerRadiusResolved,
|
|
16
|
+
type CornerStyleResolved as _CornerStyleResolved,
|
|
17
|
+
type RectCornerRadius as _RectCornerRadius,
|
|
18
|
+
type RectCornerStyle as _RectCornerStyle,
|
|
14
19
|
type Fill as _Fill,
|
|
15
20
|
type FillResolved as _FillResolved,
|
|
16
21
|
type Stroke as _Stroke,
|
|
@@ -44,12 +49,14 @@ import {
|
|
|
44
49
|
} from "../kit/shared"
|
|
45
50
|
import {
|
|
46
51
|
CARTESIAN_GRID,
|
|
47
|
-
|
|
52
|
+
CARTESIAN_AXES,
|
|
48
53
|
CHART_LEGEND,
|
|
54
|
+
CHART_SERIES,
|
|
49
55
|
CHART_STYLE_FAMILY,
|
|
50
56
|
CHART_STYLE_PRESETS,
|
|
51
|
-
|
|
57
|
+
GRID_BACKGROUND,
|
|
52
58
|
axisConfigOf,
|
|
59
|
+
migrateChartStyle,
|
|
53
60
|
legendConfigOf,
|
|
54
61
|
seriesFill,
|
|
55
62
|
valueText,
|
|
@@ -70,7 +77,7 @@ import {
|
|
|
70
77
|
|
|
71
78
|
const BAR_STYLE = Types.style(
|
|
72
79
|
CHART_STYLE_FAMILY,
|
|
73
|
-
{
|
|
80
|
+
{ series: CHART_SERIES, background: GRID_BACKGROUND, grid: CARTESIAN_GRID, axes: CARTESIAN_AXES, marks: BAR_MARKS, labels: BAR_LABELS, legend: CHART_LEGEND },
|
|
74
81
|
{ presets: CHART_STYLE_PRESETS }
|
|
75
82
|
)
|
|
76
83
|
|
|
@@ -195,6 +202,7 @@ function seriesBars(s: BarState, index: number, plot: Size2D): BarGeometry[] {
|
|
|
195
202
|
from: valueToPx(domain, along, span.from),
|
|
196
203
|
to: valueToPx(domain, along, span.to),
|
|
197
204
|
round: span.outer,
|
|
205
|
+
grounded: !stacked || span.from === 0,
|
|
198
206
|
caption,
|
|
199
207
|
}
|
|
200
208
|
})
|
|
@@ -283,6 +291,7 @@ export const BarChart = component2d({
|
|
|
283
291
|
weights: (state) => state.series.map((s) => ((s.enabled ?? true) ? 1 : 0)),
|
|
284
292
|
showing: (state) => state.series.map((s) => s.enabled ?? true),
|
|
285
293
|
},
|
|
294
|
+
migrate: { style: migrateChartStyle("cartesian") },
|
|
286
295
|
allowedChildren: [],
|
|
287
296
|
children: (state) => {
|
|
288
297
|
const style = () => state.style
|
|
@@ -358,12 +367,13 @@ export const BarChart = component2d({
|
|
|
358
367
|
baseline: () => valueToPx(domain(), runs(state, plotSize()).along, baselineValue(domain())),
|
|
359
368
|
horizontal,
|
|
360
369
|
fill: () => seriesFill(style(), s, i),
|
|
361
|
-
cornerRadius: () => style().
|
|
370
|
+
cornerRadius: () => style().barCornerRadius,
|
|
371
|
+
cornerStyle: () => style().barCornerStyle,
|
|
362
372
|
growth: () => state.growth,
|
|
363
373
|
dims: () => categoryDims(state),
|
|
364
374
|
// A figure past a stack's end prints the stack's total; a percent stack has none worth printing, so prints its shares inside.
|
|
365
375
|
values: () => (built.values === "end" && state.stack === "percent" ? "inside" : built.values),
|
|
366
|
-
valueStyle: () =>
|
|
376
|
+
valueStyle: () => valueText(style()),
|
|
367
377
|
enabled: () => state.showing[i] ?? (s.enabled ?? true),
|
|
368
378
|
}) as unknown as Node2D
|
|
369
379
|
)
|
|
@@ -385,7 +395,7 @@ export const BarChart = component2d({
|
|
|
385
395
|
plot = new Rect({
|
|
386
396
|
children: [
|
|
387
397
|
new ChartCanvas({
|
|
388
|
-
fill: () => style().
|
|
398
|
+
fill: () => style().gridBackground,
|
|
389
399
|
xGridStroke: () => style().verticalGrid,
|
|
390
400
|
yGridStroke: () => style().horizontalGrid,
|
|
391
401
|
xMarkers: horizontal ? () => domain().ticks : boundaries,
|
|
@@ -402,6 +412,7 @@ export const BarChart = component2d({
|
|
|
402
412
|
|
|
403
413
|
return asParts([
|
|
404
414
|
cartesianFrame({
|
|
415
|
+
background: () => style().background,
|
|
405
416
|
left,
|
|
406
417
|
ghost,
|
|
407
418
|
plot,
|
|
@@ -11,7 +11,11 @@ import {
|
|
|
11
11
|
// Named so this component's emitted type reaches `Node2D` and its props through the sdk, not core.
|
|
12
12
|
type Node2D,
|
|
13
13
|
type Node2DProps as _Node2DProps,
|
|
14
|
+
type RectCornerRadius as _RectCornerRadius,
|
|
15
|
+
type RectCornerStyle as _RectCornerStyle,
|
|
14
16
|
type TextStyle,
|
|
17
|
+
type CornerRadiusResolved,
|
|
18
|
+
type CornerStyleResolved,
|
|
15
19
|
} from "@motionscript/sdk"
|
|
16
20
|
|
|
17
21
|
import { boundText } from "../kit/cartesian"
|
|
@@ -35,8 +39,10 @@ export interface BarGeometry {
|
|
|
35
39
|
from: number
|
|
36
40
|
/** The far end at full growth. */
|
|
37
41
|
to: number
|
|
38
|
-
/** Whether the far end takes the
|
|
42
|
+
/** Whether the far end takes the far corners (the stack's last segment on its side). */
|
|
39
43
|
round: boolean
|
|
44
|
+
/** Whether the base takes the base corners (it stands on the baseline: every grouped bar, a stack's first segment). */
|
|
45
|
+
grounded?: boolean
|
|
40
46
|
/** The figure printed by the bar; empty for none. */
|
|
41
47
|
caption: string
|
|
42
48
|
}
|
|
@@ -106,7 +112,9 @@ export const ChartBars = component2d({
|
|
|
106
112
|
/** Bars grow along x from a category column rather than along y from a row. */
|
|
107
113
|
horizontal: false,
|
|
108
114
|
fill: Types.custom<Fill, FillResolved[]>([], { resolve: fillOps.resolve, lerp: fillOps.lerp }),
|
|
109
|
-
|
|
115
|
+
/** As for a bar standing up from the baseline: `topLeft`/`topRight` round its far end, the bottom pair its base. */
|
|
116
|
+
cornerRadius: Types.cornerRadius(8),
|
|
117
|
+
cornerStyle: Types.cornerStyle("rounded"),
|
|
110
118
|
/**
|
|
111
119
|
* Rise of every bar in `[0, 1]` about the baseline, not each bar's own base:
|
|
112
120
|
* every segment travels by the same factor, so a stack stays flush
|
|
@@ -163,17 +171,13 @@ export const ChartBars = component2d({
|
|
|
163
171
|
const seam = bar.round ? 0 : 1
|
|
164
172
|
const length = Math.abs(ends.end - ends.base) + seam
|
|
165
173
|
if (length <= seam) continue
|
|
166
|
-
const radius = bar.round ? Math.max(0, Math.min(state.cornerRadius, length, bar.thickness / 2)) : 0
|
|
167
174
|
const forward = ends.end >= ends.base
|
|
168
175
|
const mid = (ends.base + ends.end) / 2 + (forward ? seam : -seam) / 2
|
|
169
|
-
|
|
170
|
-
const far = state.horizontal
|
|
171
|
-
? (forward ? { topRight: radius, bottomRight: radius, topLeft: 0, bottomLeft: 0 } : { topLeft: radius, bottomLeft: radius, topRight: 0, bottomRight: 0 })
|
|
172
|
-
: (forward ? { topLeft: radius, topRight: radius, bottomLeft: 0, bottomRight: 0 } : { bottomLeft: radius, bottomRight: radius, topLeft: 0, topRight: 0 })
|
|
176
|
+
const corners = barCorners(state, bar, forward, length)
|
|
173
177
|
// One `Graphics2D` per bar: opacity belongs to the command list, and the spotlight dims single bars.
|
|
174
178
|
const g = new Graphics2D().rect(state.horizontal
|
|
175
|
-
? { x: mid, y: bar.center, width: length, height: bar.thickness,
|
|
176
|
-
: { x: bar.center, y: mid, width: bar.thickness, height: length,
|
|
179
|
+
? { x: mid, y: bar.center, width: length, height: bar.thickness, ...corners }
|
|
180
|
+
: { x: bar.center, y: mid, width: bar.thickness, height: length, ...corners })
|
|
177
181
|
g.fill(state.fill)
|
|
178
182
|
ctx.draw(g.opacity(dimAt(state, i)))
|
|
179
183
|
}
|
|
@@ -184,6 +188,41 @@ export const ChartBars = component2d({
|
|
|
184
188
|
|
|
185
189
|
export type ChartBars = NodeOf<typeof ChartBars>
|
|
186
190
|
|
|
191
|
+
type Corners<T> = { topLeft: T; topRight: T; bottomRight: T; bottomLeft: T }
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Turns corners written for a bar standing up into the drawn bar's visual
|
|
195
|
+
* (y-up) corners: mirrored for a bar below zero, turned a quarter clockwise
|
|
196
|
+
* for one growing right, and both for one growing left.
|
|
197
|
+
*/
|
|
198
|
+
function orient<T>(c: Corners<T>, horizontal: boolean, forward: boolean): Corners<T> {
|
|
199
|
+
if (!horizontal) return forward ? c : { topLeft: c.bottomLeft, topRight: c.bottomRight, bottomRight: c.topRight, bottomLeft: c.topLeft }
|
|
200
|
+
return forward
|
|
201
|
+
? { topLeft: c.bottomLeft, topRight: c.topLeft, bottomRight: c.topRight, bottomLeft: c.bottomRight }
|
|
202
|
+
: { topLeft: c.topLeft, topRight: c.bottomLeft, bottomRight: c.bottomRight, bottomLeft: c.topRight }
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/** Bar `bar`'s rect corners: the far pair only where its stack ends, the base pair only on the baseline, each held inside the bar. */
|
|
206
|
+
export function barCorners(
|
|
207
|
+
state: { readonly cornerRadius: CornerRadiusResolved; readonly cornerStyle: CornerStyleResolved; readonly horizontal: boolean },
|
|
208
|
+
bar: BarGeometry,
|
|
209
|
+
forward: boolean,
|
|
210
|
+
length: number
|
|
211
|
+
): { cornerRadius: Corners<number>; cornerStyle: CornerStyleResolved } {
|
|
212
|
+
const grounded = bar.grounded ?? true
|
|
213
|
+
const r = state.cornerRadius
|
|
214
|
+
const ends = (bar.round ? 1 : 0) + (grounded ? 1 : 0)
|
|
215
|
+
const cap = Math.max(0, Math.min(bar.thickness / 2, ends > 1 ? length / 2 : length))
|
|
216
|
+
const fit = (v: number, on: boolean) => (on ? Math.max(0, Math.min(v, cap)) : 0)
|
|
217
|
+
const upright: Corners<number> = {
|
|
218
|
+
topLeft: fit(r.topLeft, bar.round),
|
|
219
|
+
topRight: fit(r.topRight, bar.round),
|
|
220
|
+
bottomRight: fit(r.bottomRight, grounded),
|
|
221
|
+
bottomLeft: fit(r.bottomLeft, grounded),
|
|
222
|
+
}
|
|
223
|
+
return { cornerRadius: orient(upright, state.horizontal, forward), cornerStyle: orient(state.cornerStyle, state.horizontal, forward) }
|
|
224
|
+
}
|
|
225
|
+
|
|
187
226
|
/** A figure as the bar prints it when the chart gives no caption. */
|
|
188
227
|
export function barCaption(value: number): string {
|
|
189
228
|
return value === 0 ? "" : formatMarker(value)
|
package/src/bar-chart/shared.ts
CHANGED
|
@@ -1,6 +1,18 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
Types,
|
|
3
|
+
fillOps,
|
|
4
|
+
type DataRecord,
|
|
5
|
+
type Fill,
|
|
6
|
+
// Named so the emitted marks types reach these through the sdk, not core.
|
|
7
|
+
type CornerRadiusResolved as _CornerRadiusResolved,
|
|
8
|
+
type CornerStyleResolved as _CornerStyleResolved,
|
|
9
|
+
type RectCornerRadius as _RectCornerRadius,
|
|
10
|
+
type RectCornerStyle as _RectCornerStyle,
|
|
11
|
+
type TextStyle as _TextStyle,
|
|
12
|
+
} from "@motionscript/sdk"
|
|
2
13
|
|
|
3
14
|
import { niceRange, num, text, type ChartSeries, type Range } from "../kit/shared"
|
|
15
|
+
import { VALUE_TEXT } from "../kit/style"
|
|
4
16
|
|
|
5
17
|
/** One bar per row, beside its siblings in the category slot or stacked on them: {@link ChartSeries} under the name for what it draws here. */
|
|
6
18
|
export type BarSeries = ChartSeries
|
|
@@ -110,12 +122,17 @@ export function inkOn(fill: Fill): string {
|
|
|
110
122
|
return luminance > 0.4 ? "#0a0a0a" : "white"
|
|
111
123
|
}
|
|
112
124
|
|
|
113
|
-
/** A bar chart's own look:
|
|
125
|
+
/** A bar chart's own look: its corners, and how wide the bars are. */
|
|
114
126
|
export const BAR_MARKS = {
|
|
115
|
-
/**
|
|
116
|
-
|
|
127
|
+
/**
|
|
128
|
+
* Each corner as for a bar standing up from the baseline: the top pair round
|
|
129
|
+
* its far end, the bottom pair its base. Inside a stack, a segment's far end
|
|
130
|
+
* stays square unless it ends the stack, and its base unless it starts it.
|
|
131
|
+
*/
|
|
132
|
+
barCornerRadius: Types.cornerRadius({ topLeft: 10, topRight: 10, bottomRight: 0, bottomLeft: 0 }),
|
|
133
|
+
barCornerStyle: Types.cornerStyle("rounded"),
|
|
117
134
|
/** How much of its category slot a bar group fills, the rest spacing the groups. */
|
|
118
|
-
barWidth: Types.number(0.7, { min: 0.05, max: 1, step: 0.05 }),
|
|
135
|
+
barWidth: Types.number(0.7, { min: 0.05, max: 1, step: 0.05, unit: "%", scale: 100 }),
|
|
119
136
|
/** Space between the bars of one group, side by side. */
|
|
120
137
|
barGap: Types.number(6, { min: 0, max: 40, step: 1, unit: "px" }),
|
|
121
138
|
}
|
|
@@ -123,4 +140,5 @@ export const BAR_MARKS = {
|
|
|
123
140
|
export const BAR_LABELS = {
|
|
124
141
|
/** Read as the chart is built: each bar's value past its end, inside it, or none. */
|
|
125
142
|
values: Types.oneOf(["none", "end", "inside"] as const, { animatable: false }),
|
|
143
|
+
...VALUE_TEXT,
|
|
126
144
|
}
|
package/src/kit/cartesian.ts
CHANGED
|
@@ -12,24 +12,26 @@ import {
|
|
|
12
12
|
type TextStyle,
|
|
13
13
|
} from "@motionscript/sdk"
|
|
14
14
|
|
|
15
|
-
import type
|
|
15
|
+
import { sizeOf, type CartesianStyle, type LegendPosition } from "./style"
|
|
16
16
|
|
|
17
17
|
/** Space between the frame's rows and columns: the plot and the legend, the axes and the legend. */
|
|
18
|
-
export function frameGap(style: Pick<CartesianStyle, "
|
|
19
|
-
return Math.round(style.
|
|
18
|
+
export function frameGap(style: Pick<CartesianStyle, "legendText">): number {
|
|
19
|
+
return Math.round(sizeOf(style.legendText) * 0.9)
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
/** Room above the plot for the top value marker, which is centred on the top grid line. */
|
|
23
|
-
export function headroom(style: Pick<CartesianStyle, "
|
|
24
|
-
return Math.ceil(style.
|
|
23
|
+
export function headroom(style: Pick<CartesianStyle, "yLabelText">): number {
|
|
24
|
+
return Math.ceil(sizeOf(style.yLabelText) * 0.7)
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
/** How far an end marker of a horizontal value axis may hang past the plot: half a short caption. */
|
|
28
|
-
export function overhang(style: Pick<CartesianStyle, "
|
|
29
|
-
return Math.ceil(style.
|
|
28
|
+
export function overhang(style: Pick<CartesianStyle, "xLabelText">): number {
|
|
29
|
+
return Math.ceil(sizeOf(style.xLabelText) * 1.1)
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
interface CartesianParts {
|
|
33
|
+
/** Behind the whole chart, axes and legend included. */
|
|
34
|
+
readonly background?: () => Fill
|
|
33
35
|
/** The axis beside the plot, on its left. */
|
|
34
36
|
readonly left?: Node2D
|
|
35
37
|
/** An invisible twin of `left` under the plot, so the row there starts at the plot's left edge. */
|
|
@@ -72,6 +74,7 @@ export function cartesianFrame(parts: CartesianParts): Node2D {
|
|
|
72
74
|
height: "fill",
|
|
73
75
|
gap: parts.gap,
|
|
74
76
|
padding: parts.padding,
|
|
77
|
+
...(parts.background ? { fill: parts.background } : {}),
|
|
75
78
|
children: [
|
|
76
79
|
...(legend && parts.legendAt === "top" ? [across(legend)] : []),
|
|
77
80
|
main,
|