@motionscript/charts 0.1.0-alpha.3 → 0.1.0-alpha.5
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 +41 -0
- package/LICENSE +201 -201
- package/NOTICE +48 -0
- package/README.md +85 -0
- package/dist/bar-chart/bar-chart.d.ts +28 -13
- package/dist/bar-chart/bar-chart.d.ts.map +1 -1
- package/dist/bar-chart/bar-chart.js +60 -56
- package/dist/bar-chart/bar-chart.js.map +1 -1
- package/dist/bar-chart/category-axis.js.map +1 -1
- package/dist/bar-chart/chart-bars.js.map +1 -1
- package/dist/bar-chart/index.js.map +1 -1
- package/dist/bar-chart/shared.d.ts +3 -3
- package/dist/bar-chart/shared.js +3 -3
- package/dist/bar-chart/shared.js.map +1 -1
- package/dist/browser/chunks/chunk-5ZPBV6BU.js +2 -0
- package/dist/browser/chunks/chunk-5ZPBV6BU.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 +3 -2
- package/dist/engine.js.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/kit/chart-border.js.map +1 -1
- package/dist/kit/chart-canvas.js.map +1 -1
- package/dist/kit/chart-legend.d.ts +4 -25
- package/dist/kit/chart-legend.d.ts.map +1 -1
- package/dist/kit/chart-legend.js +31 -55
- package/dist/kit/chart-legend.js.map +1 -1
- package/dist/kit/shared.d.ts +29 -6
- package/dist/kit/shared.d.ts.map +1 -1
- package/dist/kit/shared.js +64 -8
- package/dist/kit/shared.js.map +1 -1
- package/dist/kit/vertical-axis.js.map +1 -1
- package/dist/line-chart/chart-line.d.ts +2 -2
- package/dist/line-chart/chart-line.js.map +1 -1
- package/dist/line-chart/chart-region.js.map +1 -1
- package/dist/line-chart/horizontal-axis.js.map +1 -1
- package/dist/line-chart/index.js.map +1 -1
- package/dist/line-chart/line-chart.d.ts +9 -1
- package/dist/line-chart/line-chart.d.ts.map +1 -1
- package/dist/line-chart/line-chart.js +32 -8
- package/dist/line-chart/line-chart.js.map +1 -1
- package/dist/line-chart/shared.d.ts +3 -3
- package/dist/line-chart/shared.d.ts.map +1 -1
- package/dist/line-chart/shared.js +19 -4
- package/dist/line-chart/shared.js.map +1 -1
- package/dist/line-chart/x-scale.d.ts +1 -1
- package/dist/line-chart/x-scale.js +1 -1
- package/dist/line-chart/x-scale.js.map +1 -1
- package/dist/nodes.js.map +1 -1
- package/dist/pie-chart/index.js.map +1 -1
- package/dist/pie-chart/pie-chart.d.ts +2 -2
- package/dist/pie-chart/pie-chart.d.ts.map +1 -1
- package/dist/pie-chart/pie-chart.js +9 -7
- package/dist/pie-chart/pie-chart.js.map +1 -1
- package/dist/pie-chart/pie-legend.js +4 -4
- package/dist/pie-chart/pie-legend.js.map +1 -1
- package/dist/pie-chart/pie-ring.d.ts +13 -4
- package/dist/pie-chart/pie-ring.d.ts.map +1 -1
- package/dist/pie-chart/pie-ring.js +44 -14
- package/dist/pie-chart/pie-ring.js.map +1 -1
- package/dist/pie-chart/shared.d.ts +3 -3
- package/dist/pie-chart/shared.js +3 -3
- package/dist/pie-chart/shared.js.map +1 -1
- package/package.json +6 -5
- package/registry.json +23 -23
- package/src/bar-chart/bar-chart.ts +820 -814
- package/src/bar-chart/category-axis.ts +177 -177
- package/src/bar-chart/chart-bars.ts +310 -310
- package/src/bar-chart/index.ts +31 -31
- package/src/bar-chart/shared.ts +354 -354
- package/src/engine.ts +26 -26
- package/src/index.ts +5 -5
- package/src/kit/chart-border.ts +61 -61
- package/src/kit/chart-canvas.ts +157 -157
- package/src/kit/chart-legend.ts +245 -250
- package/src/kit/shared.ts +733 -675
- package/src/kit/vertical-axis.ts +224 -224
- package/src/line-chart/chart-line.ts +208 -208
- package/src/line-chart/chart-region.ts +135 -135
- package/src/line-chart/horizontal-axis.ts +202 -202
- package/src/line-chart/index.ts +39 -39
- package/src/line-chart/line-chart.ts +961 -929
- package/src/line-chart/shared.ts +473 -459
- package/src/line-chart/x-scale.ts +367 -367
- package/src/nodes.ts +20 -20
- package/src/pie-chart/index.ts +37 -37
- package/src/pie-chart/pie-chart.ts +383 -381
- package/src/pie-chart/pie-legend.ts +159 -159
- package/src/pie-chart/pie-ring.ts +935 -903
- package/src/pie-chart/shared.ts +490 -490
- package/dist/browser/chunks/chunk-RMHQ6GYU.js +0 -2
- package/dist/browser/chunks/chunk-RMHQ6GYU.js.map +0 -7
|
@@ -65,14 +65,14 @@ type CategorySpotlight = {
|
|
|
65
65
|
* - `ChartLegend` — a row of entries below the chart, one per series.
|
|
66
66
|
*
|
|
67
67
|
* The parts are laid out from this node's `layoutBounds` exactly as the line
|
|
68
|
-
* chart's are:
|
|
69
|
-
*
|
|
70
|
-
*
|
|
71
|
-
*
|
|
72
|
-
*
|
|
68
|
+
* chart's are: the value axis on the left, the category captions below, the
|
|
69
|
+
* plot filling what's left, and the legend row beneath the whole thing. The
|
|
70
|
+
* columns are mapped across the plot panel's own laid-out box and read the same
|
|
71
|
+
* resolved scale the axis does, so a column's end lands exactly on its marker
|
|
72
|
+
* and the chart re-flows if its box changes.
|
|
73
73
|
*
|
|
74
74
|
* **Resting state is the finished chart** — the same bargain the line chart
|
|
75
|
-
* makes:
|
|
75
|
+
* makes: an editor paints a node's Initial state on a paused canvas, so a chart
|
|
76
76
|
* that only appeared once a command had run would be edited blind. {@link enter}
|
|
77
77
|
* arms every part back to its pre-entrance state before animating.
|
|
78
78
|
*
|
|
@@ -131,6 +131,8 @@ export declare class BarChart extends Node2D<BarChartProps> {
|
|
|
131
131
|
private cAxis;
|
|
132
132
|
private legend;
|
|
133
133
|
private barSets;
|
|
134
|
+
/** The plot panel: the box the grid, the columns and the border all share. */
|
|
135
|
+
private plotRect;
|
|
134
136
|
/**
|
|
135
137
|
* `this.theme` read back through its *resolved* shape — the same
|
|
136
138
|
* loose-declared/resolved-stored idiom as a shape's `fill`/`stroke`, and as
|
|
@@ -148,13 +150,18 @@ export declare class BarChart extends Node2D<BarChartProps> {
|
|
|
148
150
|
private valueLabel;
|
|
149
151
|
/** The value axis ticks: the explicit ones, else five across the scale. */
|
|
150
152
|
private get resolvedMarkers();
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
153
|
+
/**
|
|
154
|
+
* The plot panel's size, **as laid out**.
|
|
155
|
+
*
|
|
156
|
+
* The value axis is `width: "hug"` and the category row and legend are as tall
|
|
157
|
+
* as their text, so the panel's real box is whatever the layout makes it. An
|
|
158
|
+
* estimate built from gutter constants never matched it, and the columns sat a
|
|
159
|
+
* few percent off the grid line they were supposed to end on. Asking the panel
|
|
160
|
+
* is exact by construction: the grid, the columns and the border all resolve
|
|
161
|
+
* against the one box they are drawn in. Zero until the first layout pass, like
|
|
162
|
+
* any other `layoutBounds` read; the bindings that call this re-run on the
|
|
163
|
+
* next frame.
|
|
164
|
+
*/
|
|
158
165
|
private plotSize;
|
|
159
166
|
/** Map a value onto the plot's **centred** pixel space (origin at its centre, y-up). */
|
|
160
167
|
private valueToY;
|
|
@@ -223,6 +230,14 @@ export declare class BarChart extends Node2D<BarChartProps> {
|
|
|
223
230
|
enter(args: CommandArgs<Record<string, never>> & {
|
|
224
231
|
duration: number;
|
|
225
232
|
}): Command<Record<string, never>>;
|
|
233
|
+
/**
|
|
234
|
+
* Move props to new values; a restated value-axis `range` or `ticks` tweens
|
|
235
|
+
* from the domain as drawn, so an auto axis (the default) rescales the columns
|
|
236
|
+
* continuously instead of cutting at the midpoint of the move.
|
|
237
|
+
*/
|
|
238
|
+
to<D extends Partial<BarChartProps> = Partial<BarChartProps>>(args: CommandArgs<D> & {
|
|
239
|
+
duration: number;
|
|
240
|
+
}): Command<BarChartProps>;
|
|
226
241
|
/** Tween {@link growth} `0 → 1`, raising every column about the baseline. */
|
|
227
242
|
private riseBars;
|
|
228
243
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bar-chart.d.ts","sourceRoot":"","sources":["../../src/bar-chart/bar-chart.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,MAAM,EAIN,KAAK,WAAW,EAChB,KAAK,UAAU,EACf,KAAK,OAAO,EAEZ,KAAK,UAAU,EACf,KAAK,WAAW,EACjB,MAAM,mBAAmB,CAAA;AAM1B,OAAO,
|
|
1
|
+
{"version":3,"file":"bar-chart.d.ts","sourceRoot":"","sources":["../../src/bar-chart/bar-chart.ts"],"names":[],"mappings":"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"}
|
|
@@ -10,30 +10,19 @@ import { ChartBorder } from "../kit/chart-border.js";
|
|
|
10
10
|
import { ChartCanvas } from "../kit/chart-canvas.js";
|
|
11
11
|
import { ChartLegend } from "../kit/chart-legend.js";
|
|
12
12
|
import { VerticalAxis } from "../kit/vertical-axis.js";
|
|
13
|
-
import { clampUnit, formatMarker, lerpAxisDomain, markerValues, num, resolveAxisDomain, } from "../kit/shared.js";
|
|
13
|
+
import { clampUnit, formatMarker, markerStep, axisTweenTarget, lerpAxisDomain, markerValues, num, resolveAxisDomain, } from "../kit/shared.js";
|
|
14
14
|
import { formatNumber } from "@motionscript/sdk/component";
|
|
15
15
|
import { asCommand, drive, hold, sequence as sequenceOf, together, } from "@motionscript/sdk/component";
|
|
16
16
|
import { CategoryAxis } from "./category-axis.js";
|
|
17
17
|
import { ChartBars } from "./chart-bars.js";
|
|
18
18
|
import { DEFAULT_BAR_CHART_THEME, barCategories, barSpans, lerpBarChartTheme, resolveBarChartTheme, resolveBarFill, resolveBarScale, stackCapIndex, } from "./shared.js";
|
|
19
19
|
/**
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
20
|
+
* Headroom above the plot, in px — the line chart's, so the two sit at the same
|
|
21
|
+
* size in the same box and a scene can swap one for the other without re-tuning
|
|
22
|
+
* its layout. The plot's top grid line is the one place a marker would
|
|
23
|
+
* otherwise be drawn outside the chart's own box.
|
|
23
24
|
*/
|
|
24
|
-
/** Left gutter reserved for the value axis markers. */
|
|
25
|
-
const Y_AXIS_GUTTER = 64;
|
|
26
|
-
/** Bottom gutter (within the chart area) reserved for the category captions. */
|
|
27
|
-
const X_AXIS_GUTTER = 40;
|
|
28
|
-
/** Height reserved below the chart area for the legend row. */
|
|
29
|
-
const LEGEND_GUTTER = 56;
|
|
30
|
-
/** Extra left/bottom room when an axis caption is shown. */
|
|
31
|
-
const Y_LABEL_GUTTER = 34;
|
|
32
|
-
const X_LABEL_GUTTER = 30;
|
|
33
|
-
/** Headroom above the plot, so a column reaching the top marker isn't flush to it. */
|
|
34
25
|
const TOP_HEADROOM = 24;
|
|
35
|
-
/** Right gutter so the last slot isn't flush with the box edge. */
|
|
36
|
-
const RIGHT_GUTTER = 20;
|
|
37
26
|
/** How far the legend starts below its slot when it enters, in px. */
|
|
38
27
|
const LEGEND_SLIDE = 20;
|
|
39
28
|
const AXES_SHARE = 0.35;
|
|
@@ -53,14 +42,14 @@ const LEGEND_SHARE = 0.15;
|
|
|
53
42
|
* - `ChartLegend` — a row of entries below the chart, one per series.
|
|
54
43
|
*
|
|
55
44
|
* The parts are laid out from this node's `layoutBounds` exactly as the line
|
|
56
|
-
* chart's are:
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
*
|
|
45
|
+
* chart's are: the value axis on the left, the category captions below, the
|
|
46
|
+
* plot filling what's left, and the legend row beneath the whole thing. The
|
|
47
|
+
* columns are mapped across the plot panel's own laid-out box and read the same
|
|
48
|
+
* resolved scale the axis does, so a column's end lands exactly on its marker
|
|
49
|
+
* and the chart re-flows if its box changes.
|
|
61
50
|
*
|
|
62
51
|
* **Resting state is the finished chart** — the same bargain the line chart
|
|
63
|
-
* makes:
|
|
52
|
+
* makes: an editor paints a node's Initial state on a paused canvas, so a chart
|
|
64
53
|
* that only appeared once a command had run would be edited blind. {@link enter}
|
|
65
54
|
* arms every part back to its pre-entrance state before animating.
|
|
66
55
|
*
|
|
@@ -82,6 +71,8 @@ let BarChart = class BarChart extends Node2D {
|
|
|
82
71
|
cAxis;
|
|
83
72
|
legend = null;
|
|
84
73
|
barSets = [];
|
|
74
|
+
/** The plot panel: the box the grid, the columns and the border all share. */
|
|
75
|
+
plotRect;
|
|
85
76
|
/**
|
|
86
77
|
* `this.theme` read back through its *resolved* shape — the same
|
|
87
78
|
* loose-declared/resolved-stored idiom as a shape's `fill`/`stroke`, and as
|
|
@@ -105,7 +96,7 @@ let BarChart = class BarChart extends Node2D {
|
|
|
105
96
|
valueLabel(value) {
|
|
106
97
|
const pattern = this.valueAxis.format;
|
|
107
98
|
return pattern === undefined
|
|
108
|
-
? formatMarker(value)
|
|
99
|
+
? formatMarker(value, markerStep(this.resolvedMarkers))
|
|
109
100
|
: formatNumber(value, pattern);
|
|
110
101
|
}
|
|
111
102
|
/** The value axis ticks: the explicit ones, else five across the scale. */
|
|
@@ -113,35 +104,22 @@ let BarChart = class BarChart extends Node2D {
|
|
|
113
104
|
return (this.valueAxis.ticks ??
|
|
114
105
|
markerValues(this.valueScale, BarChart_1.DEFAULT_MARKERS - 1));
|
|
115
106
|
}
|
|
116
|
-
// ---- Plot geometry
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
/** The plot rectangle in node space: `{ left, right, top, bottom }` (y-up). */
|
|
130
|
-
plotBox() {
|
|
131
|
-
const W = this.layoutBounds.width;
|
|
132
|
-
const H = this.layoutBounds.height;
|
|
133
|
-
const areaTop = H / 2;
|
|
134
|
-
const areaBottom = -H / 2 + (this.legend ? LEGEND_GUTTER : 0);
|
|
135
|
-
const left = -W / 2 + this.leftInset;
|
|
136
|
-
const right = W / 2 - RIGHT_GUTTER;
|
|
137
|
-
const top = areaTop - TOP_HEADROOM;
|
|
138
|
-
const bottom = areaBottom + this.bottomInset;
|
|
139
|
-
return { left, right, top, bottom };
|
|
140
|
-
}
|
|
141
|
-
/** Width and height of the plot, in px. */
|
|
107
|
+
// ---- Plot geometry ------------------------------------------------------
|
|
108
|
+
/**
|
|
109
|
+
* The plot panel's size, **as laid out**.
|
|
110
|
+
*
|
|
111
|
+
* The value axis is `width: "hug"` and the category row and legend are as tall
|
|
112
|
+
* as their text, so the panel's real box is whatever the layout makes it. An
|
|
113
|
+
* estimate built from gutter constants never matched it, and the columns sat a
|
|
114
|
+
* few percent off the grid line they were supposed to end on. Asking the panel
|
|
115
|
+
* is exact by construction: the grid, the columns and the border all resolve
|
|
116
|
+
* against the one box they are drawn in. Zero until the first layout pass, like
|
|
117
|
+
* any other `layoutBounds` read; the bindings that call this re-run on the
|
|
118
|
+
* next frame.
|
|
119
|
+
*/
|
|
142
120
|
plotSize() {
|
|
143
|
-
const {
|
|
144
|
-
return { w:
|
|
121
|
+
const { width, height } = this.plotRect.layoutBounds;
|
|
122
|
+
return { w: width, h: height };
|
|
145
123
|
}
|
|
146
124
|
/** Map a value onto the plot's **centred** pixel space (origin at its centre, y-up). */
|
|
147
125
|
valueToY(value) {
|
|
@@ -317,7 +295,7 @@ let BarChart = class BarChart extends Node2D {
|
|
|
317
295
|
legend: () => this.resolvedTheme.legend,
|
|
318
296
|
});
|
|
319
297
|
}
|
|
320
|
-
|
|
298
|
+
this.plotRect = new Rect({
|
|
321
299
|
clip: true,
|
|
322
300
|
children: [
|
|
323
301
|
new ChartCanvas({
|
|
@@ -357,11 +335,13 @@ let BarChart = class BarChart extends Node2D {
|
|
|
357
335
|
this.add(new Rect({ flow: "vertical",
|
|
358
336
|
width: "fill",
|
|
359
337
|
height: "fill",
|
|
338
|
+
// See {@link TOP_HEADROOM}.
|
|
339
|
+
padding: { top: TOP_HEADROOM },
|
|
360
340
|
children: [
|
|
361
341
|
new Rect({ flow: "horizontal",
|
|
362
342
|
height: "fill",
|
|
363
343
|
width: "fill",
|
|
364
|
-
children: [this.vAxis,
|
|
344
|
+
children: [this.vAxis, this.plotRect],
|
|
365
345
|
}),
|
|
366
346
|
new Rect({ flow: "horizontal",
|
|
367
347
|
width: "fill",
|
|
@@ -403,9 +383,33 @@ let BarChart = class BarChart extends Node2D {
|
|
|
403
383
|
const { duration } = args;
|
|
404
384
|
const easing = args.easing ?? easeOut();
|
|
405
385
|
this.arm();
|
|
406
|
-
return asCommand(sequenceOf(together(this.vAxis.enter({ data: { slide: 24 }, duration: duration * AXES_SHARE, easing }), this.cAxis.enter({ data: { slide: 24 }, duration: duration * AXES_SHARE, easing })), this.riseBars(duration * BARS_SHARE, easing),
|
|
407
|
-
|
|
408
|
-
|
|
386
|
+
return asCommand(sequenceOf(together(this.vAxis.enter({ data: { slide: 24 }, duration: duration * AXES_SHARE, easing }), this.cAxis.enter({ data: { slide: 24 }, duration: duration * AXES_SHARE, easing })), this.riseBars(duration * BARS_SHARE, easing),
|
|
387
|
+
// Without a legend the beat is still its share of the whole, so the
|
|
388
|
+
// entrance ends exactly when it was laid out to.
|
|
389
|
+
this.legend
|
|
390
|
+
? this.legend.to({ data: { opacity: 1, y: 0 }, duration: duration * LEGEND_SHARE, easing })
|
|
391
|
+
: hold(duration * LEGEND_SHARE)), duration);
|
|
392
|
+
}
|
|
393
|
+
/**
|
|
394
|
+
* Move props to new values; a restated value-axis `range` or `ticks` tweens
|
|
395
|
+
* from the domain as drawn, so an auto axis (the default) rescales the columns
|
|
396
|
+
* continuously instead of cutting at the midpoint of the move.
|
|
397
|
+
*/
|
|
398
|
+
to(args) {
|
|
399
|
+
const data = (args.data ?? {});
|
|
400
|
+
const drawn = {
|
|
401
|
+
...this.valueAxis,
|
|
402
|
+
range: this.valueScale,
|
|
403
|
+
ticks: this.resolvedMarkers,
|
|
404
|
+
};
|
|
405
|
+
const target = axisTweenTarget(drawn, data.valueAxis);
|
|
406
|
+
if (!target)
|
|
407
|
+
return super.to(args);
|
|
408
|
+
const { valueAxis: _valueAxis, ...rest } = data;
|
|
409
|
+
const axis = this.command((t) => ({ valueAxis: lerpAxisDomain(drawn, target, t) }), args.duration, args.easing);
|
|
410
|
+
if (Object.keys(rest).length === 0)
|
|
411
|
+
return axis;
|
|
412
|
+
return asCommand(together(super.to({ ...args, data: rest }), axis), args.duration);
|
|
409
413
|
}
|
|
410
414
|
/** Tween {@link growth} `0 → 1`, raising every column about the baseline. */
|
|
411
415
|
riseBars(duration, easing) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bar-chart.js","sourceRoot":"","sources":["../../src/bar-chart/bar-chart.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n command,\n node,\n Node2D,\n Rect,\n easeOut,\n property,\n type CommandArgs,\n type DataRecord,\n type Command,\n type EasingFunction,\n type NodeConfig,\n type Node2DProps,\n} from \"@motionscript/sdk\"\n\nimport { ChartBorder } from \"../kit/chart-border\"\nimport { ChartCanvas } from \"../kit/chart-canvas\"\nimport { ChartLegend } from \"../kit/chart-legend\"\nimport { VerticalAxis } from \"../kit/vertical-axis\"\nimport {\n clampUnit,\n formatMarker,\n lerpAxisDomain,\n markerValues,\n num,\n resolveAxisDomain,\n type AxisDomainConfig,\n type Range,\n} from \"../kit/shared\"\nimport { formatNumber } from \"@motionscript/sdk/component\"\nimport {\n asCommand,\n drive,\n hold,\n sequence as sequenceOf,\n together,\n type Seekable,\n} from \"@motionscript/sdk/component\"\nimport { CategoryAxis } from \"./category-axis\"\nimport { ChartBars, type BarGeometry } from \"./chart-bars\"\nimport {\n DEFAULT_BAR_CHART_THEME,\n barCategories,\n barSpans,\n lerpBarChartTheme,\n resolveBarChartTheme,\n resolveBarFill,\n resolveBarScale,\n stackCapIndex,\n type BarChartConfig,\n type BarChartTheme,\n type BarSeries,\n} from \"./shared\"\n\nexport interface BarChartProps extends Node2DProps {\n /** One row per category — a plain record of field name to value. */\n data: DataRecord[]\n /**\n * Key into each row for its category caption, drawn beneath the baseline.\n * Named `categoryField` rather than `category` for the same reason the line\n * chart's is `xField`: it names a *column*, not a value.\n */\n categoryField: string\n /** One entry per bar series: which column it plots, its `label`, its `fill`. */\n series: BarSeries[]\n /**\n * When `true` every category's series stack into one column; when `false`\n * (the default) each series gets its own bar, grouped side by side within the\n * category's slot.\n */\n stacked?: boolean\n /** The value axis's domain: caption, scale range, and tick placement. */\n valueAxis?: AxisDomainConfig\n /** The category axis's domain. Only its `label` is read — the slots are the rows. */\n categoryAxis?: AxisDomainConfig\n /**\n * The chart's visual theme — bar palette and geometry, axis furniture, plot\n * panel paint, legend, value figures. Every branch is optional and deep-merged\n * onto {@link DEFAULT_BAR_CHART_THEME}.\n */\n theme?: BarChartTheme\n /** Whether the legend row below the plot is drawn at all. */\n showLegend?: boolean\n /** Whether each column prints the figure it plots. */\n showValues?: boolean\n}\n\n/**\n * Layout constants for the composition, all in px — the line chart's, so the two\n * sit at the same size in the same box and a scene can swap one for the other\n * without re-tuning its layout.\n */\n/** Left gutter reserved for the value axis markers. */\nconst Y_AXIS_GUTTER = 64\n/** Bottom gutter (within the chart area) reserved for the category captions. */\nconst X_AXIS_GUTTER = 40\n/** Height reserved below the chart area for the legend row. */\nconst LEGEND_GUTTER = 56\n/** Extra left/bottom room when an axis caption is shown. */\nconst Y_LABEL_GUTTER = 34\nconst X_LABEL_GUTTER = 30\n/** Headroom above the plot, so a column reaching the top marker isn't flush to it. */\nconst TOP_HEADROOM = 24\n/** Right gutter so the last slot isn't flush with the box edge. */\nconst RIGHT_GUTTER = 20\n\n/** How far the legend starts below its slot when it enters, in px. */\nconst LEGEND_SLIDE = 20\n\n/**\n * How {@link BarChart.enter} divides its duration between its three beats: the\n * axes arriving, the columns rising, and the legend coming up. Shares of the\n * whole, so they must sum to 1 — the entrance takes exactly the time it was\n * given, for the reason spelt out on `LineChart.enter`.\n */\n/**\n * The signals the bar chart's own commands move, as props types.\n *\n * Written out rather than reusing `BarChartProps` because these are signals of\n * the chart's own — how far the columns have risen, and which category is lit —\n * rather than part of what an author states about it. Same reason the line chart\n * types its `RegionState` separately.\n */\ntype CategorySpotlight = { spotlight: number | null; spotlightReveal: number }\ntype BarGrowth = { growth: number }\n\nconst AXES_SHARE = 0.35\nconst BARS_SHARE = 0.5\nconst LEGEND_SHARE = 0.15\n\n/**\n * A grouped or stacked bar chart, composed from independent parts rather than\n * one monolithic draw — the sibling of the {@link LineChart} family, built the\n * same way and out of several of the same pieces:\n *\n * - `ChartCanvas` — the plot panel with a horizontal grid, under everything.\n * - `VerticalAxis` — the numeric value markers, staggering in bottom-to-top.\n * - {@link CategoryAxis} — the row of names beneath the baseline, one per row of\n * the data, staggering in left-to-right.\n * - {@link ChartBars} (one per series) — that series' column in every category,\n * plus the figures printed on them.\n * - `ChartLegend` — a row of entries below the chart, one per series.\n *\n * The parts are laid out from this node's `layoutBounds` exactly as the line\n * chart's are: a left gutter for the value axis, a bottom gutter for the\n * captions, the plot filling what's left, and the legend row beneath the whole\n * thing. Every child's position and size is bound reactively, so the chart\n * re-flows if its box changes, and the bars read the same resolved scale the\n * axis does, so a column's end lands exactly on its marker.\n *\n * **Resting state is the finished chart** — the same bargain the line chart\n * makes: the studio paints a node's Initial state on a paused canvas, so a chart\n * that only appeared once a command had run would be edited blind. {@link enter}\n * arms every part back to its pre-entrance state before animating.\n *\n * **Zero is always on the scale** (see `barValueExtent`), and the columns\n * grow about it rather than about the plot floor, so a negative value draws\n * downward out of the same `growth` signal that draws a positive one up.\n *\n * Past the entrance, two things move the chart:\n * {@link showSeries}/{@link hideSeries}/{@link spotlightSeries} pick out a\n * *series* — and hiding one **reflows the group**, the remaining columns\n * widening into the space as it goes, rather than leaving a hole where it was —\n * while {@link spotlightCategory}/{@link clearCategory} pick out a *column of\n * the table*, dimming every other category and its caption with it.\n */\n@node({\n key: \"barChart\",\n parentKey: \"node\",\n forkable: true,\n layout: {\n children: \"freeform\",\n defaultWidthMode: \"fixed\",\n defaultHeightMode: \"fixed\",\n acceptsChildren: true,\n },\n seed: {\n width: 760,\n height: 460,\n },\n})\nexport class BarChart extends Node2D<BarChartProps> {\n @property({ default: () => [] as DataRecord[] }) declare data: DataRecord[]\n @property({ default: \"\" }) declare categoryField: string\n @property({ default: () => [] as BarSeries[] }) declare series: BarSeries[]\n @property({ default: false }) declare stacked: boolean\n /**\n * The value axis's domain (label/range/ticks), tweenable and mappable exactly\n * as the line chart's axes are: the mapper merges a partial input onto the\n * previous resolved domain and the tween interpolates numerically, so\n * `chart.to({ data: { valueAxis: { range: [0, 10] } }, duration: 1 })` smoothly\n * rescales every column. The axis *label* text is captured once at construction.\n */\n @property({\n default: {},\n mapper: resolveAxisDomain,\n tween: lerpAxisDomain,\n })\n declare valueAxis: AxisDomainConfig\n @property({\n default: {},\n mapper: resolveAxisDomain,\n tween: lerpAxisDomain,\n })\n declare categoryAxis: AxisDomainConfig\n @property({\n default: DEFAULT_BAR_CHART_THEME,\n mapper: resolveBarChartTheme,\n tween: lerpBarChartTheme,\n })\n declare theme: BarChartTheme\n\n /**\n * Global rise of every column in `[0, 1]`, measured about the baseline: 0\n * collapses them all onto it, 1 draws them at full length. Each\n * {@link ChartBars}' own `growth` is bound to this, so tweening this one\n * signal raises the whole chart in proportion.\n */\n @property({ default: 1 }) declare growth: number\n\n /**\n * How much of the slot each series currently claims, one entry per series.\n *\n * A *weight* rather than a boolean, because that is what makes hiding a series\n * an animation instead of a jump: the grouped columns divide the slot in\n * proportion to these, so tweening one to 0 has the remaining columns widen\n * into the space as it shrinks away, and a stacked segment's contribution to\n * the stack fades out with it. Seeded from each series' `enabled` field.\n */\n @property({ default: () => [] as number[] }) declare weights: number[]\n\n /**\n * The category currently spotlit, or `null` for none. Held as a plain reactive\n * value rather than a tweened one: the *choice* snaps, and the animation is\n * {@link spotlightReveal} dimming everything else.\n */\n @property({ default: null }) declare spotlight: number | null\n\n /** How far the category spotlight is drawn in, `[0, 1]`. */\n @property({ default: 0 }) declare spotlightReveal: number\n\n // ---- Part handles (built in the constructor) --------------------------\n private vAxis: VerticalAxis\n private cAxis: CategoryAxis\n private legend: ChartLegend | null = null\n private barSets: ChartBars[] = []\n\n /**\n * `this.theme` read back through its *resolved* shape — the same\n * loose-declared/resolved-stored idiom as a shape's `fill`/`stroke`, and as\n * the line chart's own theme.\n */\n private get resolvedTheme(): BarChartConfig {\n return this.theme as unknown as BarChartConfig\n }\n\n // ---- Derived scale ----------------------------------------------------\n\n /** Fallback marker count when the value axis states no ticks. */\n private static readonly DEFAULT_MARKERS = 5\n\n private get valueScale(): Range {\n const divisions =\n (this.valueAxis.ticks?.length ?? BarChart.DEFAULT_MARKERS) - 1\n return resolveBarScale(\n this.data,\n this.series,\n this.stacked,\n this.valueAxis.range,\n divisions\n )\n }\n\n /**\n * A value written down as this chart's value axis says — the axis ticks and\n * the figures printed on the columns both read through here, so the two\n * cannot disagree about what a number looks like.\n */\n private valueLabel(value: number): string {\n const pattern = this.valueAxis.format\n return pattern === undefined\n ? formatMarker(value)\n : formatNumber(value, pattern)\n }\n\n /** The value axis ticks: the explicit ones, else five across the scale. */\n private get resolvedMarkers(): number[] {\n return (\n this.valueAxis.ticks ??\n markerValues(this.valueScale, BarChart.DEFAULT_MARKERS - 1)\n )\n }\n\n // ---- Plot geometry, all derived from layoutBounds -----------------------\n\n private get hasValueLabel(): boolean {\n return this.valueAxis.label !== \"\"\n }\n private get hasCategoryLabel(): boolean {\n return this.categoryAxis.label !== \"\"\n }\n\n private get leftInset(): number {\n return Y_AXIS_GUTTER + (this.hasValueLabel ? Y_LABEL_GUTTER : 0)\n }\n private get bottomInset(): number {\n return X_AXIS_GUTTER + (this.hasCategoryLabel ? X_LABEL_GUTTER : 0)\n }\n\n /** The plot rectangle in node space: `{ left, right, top, bottom }` (y-up). */\n private plotBox(): {\n left: number\n right: number\n top: number\n bottom: number\n } {\n const W = this.layoutBounds.width\n const H = this.layoutBounds.height\n const areaTop = H / 2\n const areaBottom = -H / 2 + (this.legend ? LEGEND_GUTTER : 0)\n const left = -W / 2 + this.leftInset\n const right = W / 2 - RIGHT_GUTTER\n const top = areaTop - TOP_HEADROOM\n const bottom = areaBottom + this.bottomInset\n return { left, right, top, bottom }\n }\n\n /** Width and height of the plot, in px. */\n private plotSize(): { w: number; h: number } {\n const { left, right, top, bottom } = this.plotBox()\n return { w: right - left, h: top - bottom }\n }\n\n /** Map a value onto the plot's **centred** pixel space (origin at its centre, y-up). */\n private valueToY(value: number): number {\n const [min, max] = this.valueScale\n const { h } = this.plotSize()\n if (max <= min) return -h / 2\n return ((value - min) / (max - min) - 0.5) * h\n }\n\n /**\n * Pixel y of the line every column grows from.\n *\n * Zero, clamped onto the scale — so an author who *did* crop the axis to\n * `[40, 100]` gets columns rising from the plot floor rather than from a\n * baseline off the bottom of the panel.\n */\n private get baselinePx(): number {\n const [min, max] = this.valueScale\n return this.valueToY(Math.min(Math.max(0, min), max))\n }\n\n // ---- Slot geometry ----------------------------------------------------\n\n /** Width of one category's slot across the plot. */\n private get slotWidth(): number {\n const n = this.data.length\n return n > 0 ? this.plotSize().w / n : 0\n }\n\n /** Centre x of category `i`'s slot, in the plot's centred space. */\n private slotCenter(index: number): number {\n return -this.plotSize().w / 2 + this.slotWidth * (index + 0.5)\n }\n\n /** The part of a slot the columns fill — the rest is the channel between categories. */\n private get slotInner(): number {\n return this.slotWidth * clampUnit(this.resolvedTheme.bar.slotFill)\n }\n\n /** Series `i`'s live share of the slot; 0 once it has been hidden. */\n private weightAt(index: number): number {\n return Math.max(0, this.weights[index] ?? 1)\n }\n\n /** Total live share across the series — the slot's inner width divides by this. */\n private get totalWeight(): number {\n let sum = 0\n for (let i = 0; i < this.series.length; i++) sum += this.weightAt(i)\n return sum > 0 ? sum : 1\n }\n\n /** Live share of every series *before* `index`, for the grouped offset. */\n private weightBefore(index: number): number {\n let sum = 0\n for (let i = 0; i < index; i++) sum += this.weightAt(i)\n return sum\n }\n\n /**\n * Series `index`'s columns, mapped into the plot's centred pixel space.\n *\n * Both modes come out of one walk over the rows: a grouped series divides the\n * slot with its siblings and every column runs from zero, a stacked one takes\n * the whole slot and each column runs from the running total below it. The\n * live {@link weights} scale the grouped widths and the stacked contributions\n * alike, which is what lets `hideSeries` reflow rather than punch a hole.\n */\n private seriesBars(index: number): BarGeometry[] {\n const series = this.series[index]\n if (!series) return []\n const stacked = this.stacked\n const inner = this.slotInner\n const gap = this.resolvedTheme.bar.groupGap\n const unit = inner / this.totalWeight\n const weight = this.weightAt(index)\n\n return this.data.map((row, rowIndex) => {\n // The stack is built from the *live* contributions, so a series fading out\n // lowers the segments above it as it goes instead of dropping them by a\n // step when it finally switches off. A grouped row needs no such scaling —\n // there its weight moves the column's width, not its length.\n const spans = barSpans(\n stacked ? this.weightedRow(row) : row,\n this.series,\n stacked\n )\n const span = spans[index] ?? { from: 0, to: 0, value: 0 }\n const cap = stacked ? stackCapIndex(row, this.series) : index\n\n const slotLeft = this.slotCenter(rowIndex) - inner / 2\n const x = stacked\n ? this.slotCenter(rowIndex)\n : slotLeft + unit * this.weightBefore(index) + (unit * weight) / 2\n const width = stacked\n ? inner\n : Math.max(0, unit * weight - (this.series.length > 1 ? gap : 0))\n\n return {\n x,\n width,\n from: this.valueToY(span.from),\n to: this.valueToY(span.to),\n round: cap === index,\n // The figure printed is the row's own value, not the weighted one — a\n // series on its way out should not be seen counting down.\n value: num(row, series.field),\n }\n })\n }\n\n /**\n * `row` with each series' value scaled by that series' live {@link weights}\n * entry — what the stacked spans are measured from.\n */\n private weightedRow(row: DataRecord): DataRecord {\n const scaled: DataRecord = { ...row }\n this.series.forEach((s, i) => {\n const value = row[s.field]\n if (typeof value === \"number\") scaled[s.field] = value * this.weightAt(i)\n })\n return scaled\n }\n\n /**\n * How far each category is dimmed by the spotlight, one entry per row —\n * 1 while nothing is spotlit, falling to the theme's `dimOpacity` for every\n * category but the chosen one as the reveal climbs.\n */\n private categoryDims(): number[] {\n const focus = clampUnit(this.spotlightReveal)\n const dim = this.resolvedTheme.spotlight.dimOpacity\n const chosen = this.spotlight\n return this.data.map((_, i) =>\n focus <= 0 || chosen === i ? 1 : 1 - (1 - dim) * focus\n )\n }\n\n // ---- Build ------------------------------------------------------------\n\n constructor(props?: NodeConfig<BarChart, BarChartProps>) {\n super(props)\n\n // The whole chart is composed from plain props/`data` — no context needed,\n // so the parts are built here (super() applied the props above). Everything\n // a *leaf* reads live in `renderSelf` — each series' geometry, paint and\n // dim, the panel's fill, the border's stroke — is passed as a closure rather\n // than a snapshot, so `chart.to({ theme })` and\n // `chart.to({ valueAxis: { range } })` genuinely animate the drawn chart.\n const enabled = this.series.map((s) => s.enabled ?? true)\n this.weights = enabled.map((on) => (on ? 1 : 0))\n const showLegend = props?.showLegend !== false\n const showValues = props?.showValues === true\n\n this.vAxis = new VerticalAxis({\n range: () => this.valueScale,\n markers: () => this.resolvedMarkers,\n axis: () => this.resolvedTheme.yAxis,\n label: this.valueAxis.label ?? \"\",\n width: \"hug\",\n height: \"fill\",\n })\n this.vAxis.labelFor = (value) => this.valueLabel(value)\n\n this.cAxis = new CategoryAxis({\n categories: barCategories(this.data, this.categoryField),\n axis: () => this.resolvedTheme.xAxis,\n label: this.categoryAxis.label ?? \"\",\n dims: () => this.categoryDims(),\n width: \"fill\",\n height: \"hug\",\n })\n\n this.barSets = this.series.map(\n (s, i) =>\n new ChartBars({\n bars: () => this.seriesBars(i),\n baseline: () => this.baselinePx,\n fill: () => resolveBarFill(this.resolvedTheme.seriesFills, s, i),\n barStroke: () => this.resolvedTheme.bar.stroke,\n barShadow: () => this.resolvedTheme.bar.shadow,\n cornerRadius: () => this.resolvedTheme.bar.cornerRadius,\n growth: () => this.growth,\n dims: () => this.categoryDims(),\n showValues,\n valueStyle: this.resolvedTheme.valueStyle,\n enabled: enabled[i],\n })\n )\n // The figures on the columns are the same numbers the value axis ticks, so\n // they read through the same format.\n for (const set of this.barSets) set.labelFor = (value) => this.valueLabel(value)\n\n if (showLegend) {\n this.legend = new ChartLegend({\n series: this.series,\n swatches: () =>\n this.series.map((s, i) =>\n resolveBarFill(this.resolvedTheme.seriesFills, s, i)\n ),\n legend: () => this.resolvedTheme.legend,\n })\n }\n\n const plot = new Rect({\n clip: true,\n children: [\n new ChartCanvas({\n fill: () => this.resolvedTheme.plotArea.fill,\n shadow: () => this.resolvedTheme.plotArea.shadow,\n xGridStroke: () => this.resolvedTheme.xAxis.lineStyle,\n yGridStroke: () => this.resolvedTheme.yAxis.lineStyle,\n // No vertical rules: the horizontal axis is categorical, so there is\n // no numeric position along it for a grid line to mark. The channel\n // between slots does that job, and better.\n xMarkers: [],\n yMarkers: () => this.resolvedMarkers,\n xExtent: () => [0, 1] as Range,\n yExtent: () => this.valueScale,\n }),\n ...this.barSets,\n new ChartBorder({\n stroke: () => this.resolvedTheme.plotArea.stroke,\n }),\n ],\n })\n\n // Invisible twin of the value axis, reserving the same left gutter under the\n // plot so the category row starts at the plot's left edge rather than the\n // chart's — and so a caption lands under the columns it names.\n const gutterSpacer = new VerticalAxis({\n opacity: 0,\n range: () => this.valueScale,\n markers: () => this.resolvedMarkers,\n axis: () => this.resolvedTheme.yAxis,\n label: this.valueAxis.label ?? \"\",\n width: \"hug\",\n height: 0,\n })\n\n const below: Node2D[] = [this.cAxis]\n if (this.legend) below.push(this.legend)\n\n this.add(\n new Rect({ flow: \"vertical\",\n width: \"fill\",\n height: \"fill\",\n children: [\n new Rect({ flow: \"horizontal\",\n height: \"fill\",\n width: \"fill\",\n children: [this.vAxis, plot],\n }),\n new Rect({ flow: \"horizontal\",\n width: \"fill\",\n children: [\n gutterSpacer,\n new Rect({ flow: \"vertical\", width: \"fill\", gap: 20, children: below }),\n ],\n }),\n ],\n })\n )\n }\n\n // ---- Orchestrated entrance --------------------------------------------\n\n /**\n * Prime every part at its pre-entrance state — axis markers and captions\n * shifted and transparent, columns collapsed onto the baseline, legend dropped\n * and transparent.\n *\n * Called by {@link enter} before its first frame so nothing flashes ahead of\n * its beat. Idempotent, and public so a scene can hide a chart ahead of time\n * without starting the entrance.\n */\n arm(): void {\n this.vAxis.arm()\n this.cAxis.arm()\n this.growth = 0\n this.legend?.set({ opacity: 0, y: -LEGEND_SLIDE })\n }\n\n /**\n * Animate the whole chart in: the two axes stagger their markers and captions\n * in, the columns rise from the baseline, and the legend fades up last.\n *\n * `duration` is the **whole** entrance. The phases are shares of it, not\n * multiples — a command that declares 1.4 seconds has to take 1.4 seconds,\n * because that is the slot the timeline lays out for it, the length its\n * parallel siblings are timed against, and its contribution to the scene's own\n * duration.\n */\n @command()\n enter(args: CommandArgs<Record<string, never>> & { duration: number }): Command<Record<string, never>> {\n const { duration } = args\n const easing = args.easing ?? easeOut()\n this.arm()\n\n return asCommand(\n sequenceOf(\n together(\n this.vAxis.enter({ data: { slide: 24 }, duration: duration * AXES_SHARE, easing }),\n this.cAxis.enter({ data: { slide: 24 }, duration: duration * AXES_SHARE, easing })\n ),\n this.riseBars(duration * BARS_SHARE, easing),\n ...(this.legend\n ? [this.legend.to({ data: { opacity: 1, y: 0 }, duration: duration * LEGEND_SHARE, easing })]\n : [])\n ),\n duration\n )\n }\n\n /** Tween {@link growth} `0 → 1`, raising every column about the baseline. */\n private riseBars(\n duration: number,\n easing: EasingFunction\n ): Command<BarGrowth> {\n // No priming to 0 first: the value at `t` is a function of `t`, so a repeat\n // call re-raises by definition rather than by having reset something.\n return this.command<BarGrowth>((t) => ({ growth: t }), duration, easing)\n }\n\n /**\n * Show series `index`: bring its columns back, the group reflowing to make\n * room as they arrive, in lockstep with its legend entry growing in.\n */\n @command({ args: [{ key: \"seriesIndex\", kind: \"series\", default: 0, min: 0, step: 1 }] })\n showSeries(args: CommandArgs<{ seriesIndex: number }>): Command<Record<string, never>> {\n const { seriesIndex = 0 } = args.data ?? {}\n return this.toggleSeries(seriesIndex, 1, args.duration ?? 0.35, args.easing ?? easeOut())\n }\n\n /**\n * Hide series `index`: its columns narrow away (or, stacked, sink out of the\n * stack) while the rest of the group widens into the space, its legend entry\n * shrinking beside them — the mirror of {@link showSeries}.\n */\n @command({ args: [{ key: \"seriesIndex\", kind: \"series\", default: 0, min: 0, step: 1 }] })\n hideSeries(args: CommandArgs<{ seriesIndex: number }>): Command<Record<string, never>> {\n const { seriesIndex = 0 } = args.data ?? {}\n return this.toggleSeries(seriesIndex, 0, args.duration ?? 0.35, args.easing ?? easeOut())\n }\n\n /**\n * Move series `index`'s slot share to `target`, with its legend entry.\n *\n * One method for both directions, so the pair cannot drift apart. `enabled`\n * rides in the same value as the weight rather than being set before or after,\n * which is what makes arriving at a time backwards show what arriving forwards\n * does.\n */\n private toggleSeries(\n index: number,\n target: number,\n duration: number,\n easing: EasingFunction\n ): Command<Record<string, never>> {\n const bars = this.barSets[index]\n if (!bars) return asCommand(hold(duration))\n\n return asCommand(\n together(\n this.tweenWeight(index, target, duration, easing),\n drive(duration, (t) => {\n const share = t >= 1 ? target : Math.max(target, 1 - t)\n bars.set({ enabled: target > 0 || share > 0 })\n }),\n ...(this.legend\n ? [\n target > 0\n ? this.legend.showSeries({ data: { index }, duration, easing })\n : this.legend.hideSeries({ data: { index }, duration, easing }),\n ]\n : [])\n ),\n duration\n )\n }\n\n /**\n * Fade out every other series — its columns **and its legend entry** — to\n * focus attention on `index`, which comes back to full. Nothing moves, so the\n * group doesn't reflow.\n */\n @command({ args: [{ key: \"seriesIndex\", kind: \"series\", default: 0, min: 0, step: 1 }] })\n spotlightSeries(args: CommandArgs<{ seriesIndex: number }>): Command<Record<string, never>> {\n const { seriesIndex = 0 } = args.data ?? {}\n const duration = args.duration ?? 0.35\n const easing = args.easing ?? easeOut()\n const dim = this.resolvedTheme.spotlight.dimOpacity\n return asCommand(\n together(\n ...this.barSets.map((bars, i) =>\n bars.to({ data: { opacity: i === seriesIndex ? 1 : dim }, duration, easing })\n ),\n ...(this.legend\n ? [this.legend.spotlightSeries({ data: { index: seriesIndex }, duration, easing })]\n : [])\n ),\n duration\n )\n }\n\n /** Ease series `index`'s slot share toward `target`, reflowing the group. */\n private tweenWeight(\n index: number,\n target: number,\n duration: number,\n easing: EasingFunction\n ): Seekable {\n // Read through `weightAt` rather than off the array, so a chart whose stored\n // weights are short (or absent) still tweens from the 1 it is drawing at.\n const from = this.series.map((_, i) => this.weightAt(i))\n const start = from[index] ?? 1\n if (start === target) return hold(duration)\n\n return drive(duration, (t) => {\n const next = [...from]\n next[index] = start + (target - start) * easing(t)\n this.weights = next\n })\n }\n\n // ---- Per-category ------------------------------------------------------\n\n /**\n * Spotlight one **category** — one column of the table rather than one series:\n * every other category's bars and its caption fade to the theme's\n * `dimOpacity`, and the chosen one stays full.\n *\n * The counterpart of the line chart's `spotlightRegion`, and the same shape of\n * thing: it picks out a slice of the plot without changing what is drawn.\n * Calling it while another category is already lit moves the focus directly —\n * only the dimming changes, so there is nothing to retract first.\n */\n @command({ args: [{ key: \"categoryIndex\", kind: \"number\", default: 0, min: 0, step: 1 }] })\n spotlightCategory(args: CommandArgs<{ categoryIndex: number }>): Command<CategorySpotlight> {\n const { categoryIndex = 0 } = args.data ?? {}\n const duration = args.duration ?? 0.4\n const easing = args.easing ?? easeOut()\n if (categoryIndex < 0 || categoryIndex >= this.data.length) return this.holdSpotlight(duration)\n const from = this.spotlightReveal\n // Which category is lit is part of the value, set from the first frame: the\n // focus moves directly, so unlike the line chart's region there is nothing to\n // retract before it.\n return this.command<CategorySpotlight>(\n (t) => ({ spotlight: categoryIndex, spotlightReveal: from + (1 - from) * t }),\n duration,\n easing\n )\n }\n\n /**\n * Drop the category spotlight, bringing every category back to full. A no-op\n * when nothing is lit — but it still takes its slot on the timeline, for the\n * reason `LineChart.clearRegion` does.\n */\n @command()\n clearCategory(args: CommandArgs<Record<string, never>>): Command<CategorySpotlight> {\n const duration = args.duration ?? 0.4\n const easing = args.easing ?? easeOut()\n const from = this.spotlightReveal\n if (from === 0) return this.holdSpotlight(duration)\n\n // The lit category is held until the fade lands — cleared at `t === 1` rather\n // than up front, or there would be nothing left to fade.\n return this.command<CategorySpotlight>(\n (t) =>\n t >= 1\n ? { spotlight: null, spotlightReveal: 0 }\n : { spotlightReveal: from * (1 - t) },\n duration,\n easing\n )\n }\n\n /** The no-op both of the above return — see {@link hold}. */\n private holdSpotlight(duration: number): Command<CategorySpotlight> {\n return this.command<CategorySpotlight>(() => ({}), duration)\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"bar-chart.js","sourceRoot":"","sources":["../../src/bar-chart/bar-chart.ts"],"names":[],"mappings":"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","sourcesContent":["import {\r\n command,\r\n node,\r\n Node2D,\r\n Rect,\r\n easeOut,\r\n property,\r\n type CommandArgs,\r\n type DataRecord,\r\n type Command,\r\n type EasingFunction,\r\n type NodeConfig,\r\n type Node2DProps,\r\n} from \"@motionscript/sdk\"\r\n\r\nimport { ChartBorder } from \"../kit/chart-border\"\r\nimport { ChartCanvas } from \"../kit/chart-canvas\"\r\nimport { ChartLegend } from \"../kit/chart-legend\"\r\nimport { VerticalAxis } from \"../kit/vertical-axis\"\r\nimport {\r\n clampUnit,\r\n formatMarker,\r\n markerStep,\r\n axisTweenTarget,\r\n lerpAxisDomain,\r\n markerValues,\r\n num,\r\n resolveAxisDomain,\r\n type AxisDomainConfig,\r\n type Range,\r\n} from \"../kit/shared\"\r\nimport { formatNumber } from \"@motionscript/sdk/component\"\r\nimport {\r\n asCommand,\r\n drive,\r\n hold,\r\n sequence as sequenceOf,\r\n together,\r\n type Seekable,\r\n} from \"@motionscript/sdk/component\"\r\nimport { CategoryAxis } from \"./category-axis\"\r\nimport { ChartBars, type BarGeometry } from \"./chart-bars\"\r\nimport {\r\n DEFAULT_BAR_CHART_THEME,\r\n barCategories,\r\n barSpans,\r\n lerpBarChartTheme,\r\n resolveBarChartTheme,\r\n resolveBarFill,\r\n resolveBarScale,\r\n stackCapIndex,\r\n type BarChartConfig,\r\n type BarChartTheme,\r\n type BarSeries,\r\n} from \"./shared\"\r\n\r\nexport interface BarChartProps extends Node2DProps {\r\n /** One row per category — a plain record of field name to value. */\r\n data: DataRecord[]\r\n /**\r\n * Key into each row for its category caption, drawn beneath the baseline.\r\n * Named `categoryField` rather than `category` for the same reason the line\r\n * chart's is `xField`: it names a *column*, not a value.\r\n */\r\n categoryField: string\r\n /** One entry per bar series: which column it plots, its `label`, its `fill`. */\r\n series: BarSeries[]\r\n /**\r\n * When `true` every category's series stack into one column; when `false`\r\n * (the default) each series gets its own bar, grouped side by side within the\r\n * category's slot.\r\n */\r\n stacked?: boolean\r\n /** The value axis's domain: caption, scale range, and tick placement. */\r\n valueAxis?: AxisDomainConfig\r\n /** The category axis's domain. Only its `label` is read — the slots are the rows. */\r\n categoryAxis?: AxisDomainConfig\r\n /**\r\n * The chart's visual theme — bar palette and geometry, axis furniture, plot\r\n * panel paint, legend, value figures. Every branch is optional and deep-merged\r\n * onto {@link DEFAULT_BAR_CHART_THEME}.\r\n */\r\n theme?: BarChartTheme\r\n /** Whether the legend row below the plot is drawn at all. */\r\n showLegend?: boolean\r\n /** Whether each column prints the figure it plots. */\r\n showValues?: boolean\r\n}\r\n\r\n/**\r\n * Headroom above the plot, in px — the line chart's, so the two sit at the same\r\n * size in the same box and a scene can swap one for the other without re-tuning\r\n * its layout. The plot's top grid line is the one place a marker would\r\n * otherwise be drawn outside the chart's own box.\r\n */\r\nconst TOP_HEADROOM = 24\r\n\r\n/** How far the legend starts below its slot when it enters, in px. */\r\nconst LEGEND_SLIDE = 20\r\n\r\n/**\r\n * How {@link BarChart.enter} divides its duration between its three beats: the\r\n * axes arriving, the columns rising, and the legend coming up. Shares of the\r\n * whole, so they must sum to 1 — the entrance takes exactly the time it was\r\n * given, for the reason spelt out on `LineChart.enter`.\r\n */\r\n/**\r\n * The signals the bar chart's own commands move, as props types.\r\n *\r\n * Written out rather than reusing `BarChartProps` because these are signals of\r\n * the chart's own — how far the columns have risen, and which category is lit —\r\n * rather than part of what an author states about it. Same reason the line chart\r\n * types its `RegionState` separately.\r\n */\r\ntype CategorySpotlight = { spotlight: number | null; spotlightReveal: number }\r\ntype BarGrowth = { growth: number }\r\n\r\nconst AXES_SHARE = 0.35\r\nconst BARS_SHARE = 0.5\r\nconst LEGEND_SHARE = 0.15\r\n\r\n/**\r\n * A grouped or stacked bar chart, composed from independent parts rather than\r\n * one monolithic draw — the sibling of the {@link LineChart} family, built the\r\n * same way and out of several of the same pieces:\r\n *\r\n * - `ChartCanvas` — the plot panel with a horizontal grid, under everything.\r\n * - `VerticalAxis` — the numeric value markers, staggering in bottom-to-top.\r\n * - {@link CategoryAxis} — the row of names beneath the baseline, one per row of\r\n * the data, staggering in left-to-right.\r\n * - {@link ChartBars} (one per series) — that series' column in every category,\r\n * plus the figures printed on them.\r\n * - `ChartLegend` — a row of entries below the chart, one per series.\r\n *\r\n * The parts are laid out from this node's `layoutBounds` exactly as the line\r\n * chart's are: the value axis on the left, the category captions below, the\r\n * plot filling what's left, and the legend row beneath the whole thing. The\r\n * columns are mapped across the plot panel's own laid-out box and read the same\r\n * resolved scale the axis does, so a column's end lands exactly on its marker\r\n * and the chart re-flows if its box changes.\r\n *\r\n * **Resting state is the finished chart** — the same bargain the line chart\r\n * makes: an editor paints a node's Initial state on a paused canvas, so a chart\r\n * that only appeared once a command had run would be edited blind. {@link enter}\r\n * arms every part back to its pre-entrance state before animating.\r\n *\r\n * **Zero is always on the scale** (see `barValueExtent`), and the columns\r\n * grow about it rather than about the plot floor, so a negative value draws\r\n * downward out of the same `growth` signal that draws a positive one up.\r\n *\r\n * Past the entrance, two things move the chart:\r\n * {@link showSeries}/{@link hideSeries}/{@link spotlightSeries} pick out a\r\n * *series* — and hiding one **reflows the group**, the remaining columns\r\n * widening into the space as it goes, rather than leaving a hole where it was —\r\n * while {@link spotlightCategory}/{@link clearCategory} pick out a *column of\r\n * the table*, dimming every other category and its caption with it.\r\n */\r\n@node({\r\n key: \"barChart\",\r\n parentKey: \"node\",\r\n forkable: true,\r\n layout: {\r\n children: \"freeform\",\r\n defaultWidthMode: \"fixed\",\r\n defaultHeightMode: \"fixed\",\r\n acceptsChildren: true,\r\n },\r\n seed: {\r\n width: 760,\r\n height: 460,\r\n },\r\n})\r\nexport class BarChart extends Node2D<BarChartProps> {\r\n @property({ default: () => [] as DataRecord[] }) declare data: DataRecord[]\r\n @property({ default: \"\" }) declare categoryField: string\r\n @property({ default: () => [] as BarSeries[] }) declare series: BarSeries[]\r\n @property({ default: false }) declare stacked: boolean\r\n /**\r\n * The value axis's domain (label/range/ticks), tweenable and mappable exactly\r\n * as the line chart's axes are: the mapper merges a partial input onto the\r\n * previous resolved domain and the tween interpolates numerically, so\r\n * `chart.to({ data: { valueAxis: { range: [0, 10] } }, duration: 1 })` smoothly\r\n * rescales every column. The axis *label* text is captured once at construction.\r\n */\r\n @property({\r\n default: {},\r\n mapper: resolveAxisDomain,\r\n tween: lerpAxisDomain,\r\n })\r\n declare valueAxis: AxisDomainConfig\r\n @property({\r\n default: {},\r\n mapper: resolveAxisDomain,\r\n tween: lerpAxisDomain,\r\n })\r\n declare categoryAxis: AxisDomainConfig\r\n @property({\r\n default: DEFAULT_BAR_CHART_THEME,\r\n mapper: resolveBarChartTheme,\r\n tween: lerpBarChartTheme,\r\n })\r\n declare theme: BarChartTheme\r\n\r\n /**\r\n * Global rise of every column in `[0, 1]`, measured about the baseline: 0\r\n * collapses them all onto it, 1 draws them at full length. Each\r\n * {@link ChartBars}' own `growth` is bound to this, so tweening this one\r\n * signal raises the whole chart in proportion.\r\n */\r\n @property({ default: 1 }) declare growth: number\r\n\r\n /**\r\n * How much of the slot each series currently claims, one entry per series.\r\n *\r\n * A *weight* rather than a boolean, because that is what makes hiding a series\r\n * an animation instead of a jump: the grouped columns divide the slot in\r\n * proportion to these, so tweening one to 0 has the remaining columns widen\r\n * into the space as it shrinks away, and a stacked segment's contribution to\r\n * the stack fades out with it. Seeded from each series' `enabled` field.\r\n */\r\n @property({ default: () => [] as number[] }) declare weights: number[]\r\n\r\n /**\r\n * The category currently spotlit, or `null` for none. Held as a plain reactive\r\n * value rather than a tweened one: the *choice* snaps, and the animation is\r\n * {@link spotlightReveal} dimming everything else.\r\n */\r\n @property({ default: null }) declare spotlight: number | null\r\n\r\n /** How far the category spotlight is drawn in, `[0, 1]`. */\r\n @property({ default: 0 }) declare spotlightReveal: number\r\n\r\n // ---- Part handles (built in the constructor) --------------------------\r\n private vAxis: VerticalAxis\r\n private cAxis: CategoryAxis\r\n private legend: ChartLegend | null = null\r\n private barSets: ChartBars[] = []\r\n /** The plot panel: the box the grid, the columns and the border all share. */\r\n private plotRect: Rect\r\n\r\n /**\r\n * `this.theme` read back through its *resolved* shape — the same\r\n * loose-declared/resolved-stored idiom as a shape's `fill`/`stroke`, and as\r\n * the line chart's own theme.\r\n */\r\n private get resolvedTheme(): BarChartConfig {\r\n return this.theme as unknown as BarChartConfig\r\n }\r\n\r\n // ---- Derived scale ----------------------------------------------------\r\n\r\n /** Fallback marker count when the value axis states no ticks. */\r\n private static readonly DEFAULT_MARKERS = 5\r\n\r\n private get valueScale(): Range {\r\n const divisions =\r\n (this.valueAxis.ticks?.length ?? BarChart.DEFAULT_MARKERS) - 1\r\n return resolveBarScale(\r\n this.data,\r\n this.series,\r\n this.stacked,\r\n this.valueAxis.range,\r\n divisions\r\n )\r\n }\r\n\r\n /**\r\n * A value written down as this chart's value axis says — the axis ticks and\r\n * the figures printed on the columns both read through here, so the two\r\n * cannot disagree about what a number looks like.\r\n */\r\n private valueLabel(value: number): string {\r\n const pattern = this.valueAxis.format\r\n return pattern === undefined\r\n ? formatMarker(value, markerStep(this.resolvedMarkers))\r\n : formatNumber(value, pattern)\r\n }\r\n\r\n /** The value axis ticks: the explicit ones, else five across the scale. */\r\n private get resolvedMarkers(): number[] {\r\n return (\r\n this.valueAxis.ticks ??\r\n markerValues(this.valueScale, BarChart.DEFAULT_MARKERS - 1)\r\n )\r\n }\r\n\r\n // ---- Plot geometry ------------------------------------------------------\r\n\r\n /**\r\n * The plot panel's size, **as laid out**.\r\n *\r\n * The value axis is `width: \"hug\"` and the category row and legend are as tall\r\n * as their text, so the panel's real box is whatever the layout makes it. An\r\n * estimate built from gutter constants never matched it, and the columns sat a\r\n * few percent off the grid line they were supposed to end on. Asking the panel\r\n * is exact by construction: the grid, the columns and the border all resolve\r\n * against the one box they are drawn in. Zero until the first layout pass, like\r\n * any other `layoutBounds` read; the bindings that call this re-run on the\r\n * next frame.\r\n */\r\n private plotSize(): { w: number; h: number } {\r\n const { width, height } = this.plotRect.layoutBounds\r\n return { w: width, h: height }\r\n }\r\n\r\n /** Map a value onto the plot's **centred** pixel space (origin at its centre, y-up). */\r\n private valueToY(value: number): number {\r\n const [min, max] = this.valueScale\r\n const { h } = this.plotSize()\r\n if (max <= min) return -h / 2\r\n return ((value - min) / (max - min) - 0.5) * h\r\n }\r\n\r\n /**\r\n * Pixel y of the line every column grows from.\r\n *\r\n * Zero, clamped onto the scale — so an author who *did* crop the axis to\r\n * `[40, 100]` gets columns rising from the plot floor rather than from a\r\n * baseline off the bottom of the panel.\r\n */\r\n private get baselinePx(): number {\r\n const [min, max] = this.valueScale\r\n return this.valueToY(Math.min(Math.max(0, min), max))\r\n }\r\n\r\n // ---- Slot geometry ----------------------------------------------------\r\n\r\n /** Width of one category's slot across the plot. */\r\n private get slotWidth(): number {\r\n const n = this.data.length\r\n return n > 0 ? this.plotSize().w / n : 0\r\n }\r\n\r\n /** Centre x of category `i`'s slot, in the plot's centred space. */\r\n private slotCenter(index: number): number {\r\n return -this.plotSize().w / 2 + this.slotWidth * (index + 0.5)\r\n }\r\n\r\n /** The part of a slot the columns fill — the rest is the channel between categories. */\r\n private get slotInner(): number {\r\n return this.slotWidth * clampUnit(this.resolvedTheme.bar.slotFill)\r\n }\r\n\r\n /** Series `i`'s live share of the slot; 0 once it has been hidden. */\r\n private weightAt(index: number): number {\r\n return Math.max(0, this.weights[index] ?? 1)\r\n }\r\n\r\n /** Total live share across the series — the slot's inner width divides by this. */\r\n private get totalWeight(): number {\r\n let sum = 0\r\n for (let i = 0; i < this.series.length; i++) sum += this.weightAt(i)\r\n return sum > 0 ? sum : 1\r\n }\r\n\r\n /** Live share of every series *before* `index`, for the grouped offset. */\r\n private weightBefore(index: number): number {\r\n let sum = 0\r\n for (let i = 0; i < index; i++) sum += this.weightAt(i)\r\n return sum\r\n }\r\n\r\n /**\r\n * Series `index`'s columns, mapped into the plot's centred pixel space.\r\n *\r\n * Both modes come out of one walk over the rows: a grouped series divides the\r\n * slot with its siblings and every column runs from zero, a stacked one takes\r\n * the whole slot and each column runs from the running total below it. The\r\n * live {@link weights} scale the grouped widths and the stacked contributions\r\n * alike, which is what lets `hideSeries` reflow rather than punch a hole.\r\n */\r\n private seriesBars(index: number): BarGeometry[] {\r\n const series = this.series[index]\r\n if (!series) return []\r\n const stacked = this.stacked\r\n const inner = this.slotInner\r\n const gap = this.resolvedTheme.bar.groupGap\r\n const unit = inner / this.totalWeight\r\n const weight = this.weightAt(index)\r\n\r\n return this.data.map((row, rowIndex) => {\r\n // The stack is built from the *live* contributions, so a series fading out\r\n // lowers the segments above it as it goes instead of dropping them by a\r\n // step when it finally switches off. A grouped row needs no such scaling —\r\n // there its weight moves the column's width, not its length.\r\n const spans = barSpans(\r\n stacked ? this.weightedRow(row) : row,\r\n this.series,\r\n stacked\r\n )\r\n const span = spans[index] ?? { from: 0, to: 0, value: 0 }\r\n const cap = stacked ? stackCapIndex(row, this.series) : index\r\n\r\n const slotLeft = this.slotCenter(rowIndex) - inner / 2\r\n const x = stacked\r\n ? this.slotCenter(rowIndex)\r\n : slotLeft + unit * this.weightBefore(index) + (unit * weight) / 2\r\n const width = stacked\r\n ? inner\r\n : Math.max(0, unit * weight - (this.series.length > 1 ? gap : 0))\r\n\r\n return {\r\n x,\r\n width,\r\n from: this.valueToY(span.from),\r\n to: this.valueToY(span.to),\r\n round: cap === index,\r\n // The figure printed is the row's own value, not the weighted one — a\r\n // series on its way out should not be seen counting down.\r\n value: num(row, series.field),\r\n }\r\n })\r\n }\r\n\r\n /**\r\n * `row` with each series' value scaled by that series' live {@link weights}\r\n * entry — what the stacked spans are measured from.\r\n */\r\n private weightedRow(row: DataRecord): DataRecord {\r\n const scaled: DataRecord = { ...row }\r\n this.series.forEach((s, i) => {\r\n const value = row[s.field]\r\n if (typeof value === \"number\") scaled[s.field] = value * this.weightAt(i)\r\n })\r\n return scaled\r\n }\r\n\r\n /**\r\n * How far each category is dimmed by the spotlight, one entry per row —\r\n * 1 while nothing is spotlit, falling to the theme's `dimOpacity` for every\r\n * category but the chosen one as the reveal climbs.\r\n */\r\n private categoryDims(): number[] {\r\n const focus = clampUnit(this.spotlightReveal)\r\n const dim = this.resolvedTheme.spotlight.dimOpacity\r\n const chosen = this.spotlight\r\n return this.data.map((_, i) =>\r\n focus <= 0 || chosen === i ? 1 : 1 - (1 - dim) * focus\r\n )\r\n }\r\n\r\n // ---- Build ------------------------------------------------------------\r\n\r\n constructor(props?: NodeConfig<BarChart, BarChartProps>) {\r\n super(props)\r\n\r\n // The whole chart is composed from plain props/`data` — no context needed,\r\n // so the parts are built here (super() applied the props above). Everything\r\n // a *leaf* reads live in `renderSelf` — each series' geometry, paint and\r\n // dim, the panel's fill, the border's stroke — is passed as a closure rather\r\n // than a snapshot, so `chart.to({ theme })` and\r\n // `chart.to({ valueAxis: { range } })` genuinely animate the drawn chart.\r\n const enabled = this.series.map((s) => s.enabled ?? true)\r\n this.weights = enabled.map((on) => (on ? 1 : 0))\r\n const showLegend = props?.showLegend !== false\r\n const showValues = props?.showValues === true\r\n\r\n this.vAxis = new VerticalAxis({\r\n range: () => this.valueScale,\r\n markers: () => this.resolvedMarkers,\r\n axis: () => this.resolvedTheme.yAxis,\r\n label: this.valueAxis.label ?? \"\",\r\n width: \"hug\",\r\n height: \"fill\",\r\n })\r\n this.vAxis.labelFor = (value) => this.valueLabel(value)\r\n\r\n this.cAxis = new CategoryAxis({\r\n categories: barCategories(this.data, this.categoryField),\r\n axis: () => this.resolvedTheme.xAxis,\r\n label: this.categoryAxis.label ?? \"\",\r\n dims: () => this.categoryDims(),\r\n width: \"fill\",\r\n height: \"hug\",\r\n })\r\n\r\n this.barSets = this.series.map(\r\n (s, i) =>\r\n new ChartBars({\r\n bars: () => this.seriesBars(i),\r\n baseline: () => this.baselinePx,\r\n fill: () => resolveBarFill(this.resolvedTheme.seriesFills, s, i),\r\n barStroke: () => this.resolvedTheme.bar.stroke,\r\n barShadow: () => this.resolvedTheme.bar.shadow,\r\n cornerRadius: () => this.resolvedTheme.bar.cornerRadius,\r\n growth: () => this.growth,\r\n dims: () => this.categoryDims(),\r\n showValues,\r\n valueStyle: this.resolvedTheme.valueStyle,\r\n enabled: enabled[i],\r\n })\r\n )\r\n // The figures on the columns are the same numbers the value axis ticks, so\r\n // they read through the same format.\r\n for (const set of this.barSets) set.labelFor = (value) => this.valueLabel(value)\r\n\r\n if (showLegend) {\r\n this.legend = new ChartLegend({\r\n series: this.series,\r\n swatches: () =>\r\n this.series.map((s, i) =>\r\n resolveBarFill(this.resolvedTheme.seriesFills, s, i)\r\n ),\r\n legend: () => this.resolvedTheme.legend,\r\n })\r\n }\r\n\r\n this.plotRect = new Rect({\r\n clip: true,\r\n children: [\r\n new ChartCanvas({\r\n fill: () => this.resolvedTheme.plotArea.fill,\r\n shadow: () => this.resolvedTheme.plotArea.shadow,\r\n xGridStroke: () => this.resolvedTheme.xAxis.lineStyle,\r\n yGridStroke: () => this.resolvedTheme.yAxis.lineStyle,\r\n // No vertical rules: the horizontal axis is categorical, so there is\r\n // no numeric position along it for a grid line to mark. The channel\r\n // between slots does that job, and better.\r\n xMarkers: [],\r\n yMarkers: () => this.resolvedMarkers,\r\n xExtent: () => [0, 1] as Range,\r\n yExtent: () => this.valueScale,\r\n }),\r\n ...this.barSets,\r\n new ChartBorder({\r\n stroke: () => this.resolvedTheme.plotArea.stroke,\r\n }),\r\n ],\r\n })\r\n\r\n // Invisible twin of the value axis, reserving the same left gutter under the\r\n // plot so the category row starts at the plot's left edge rather than the\r\n // chart's — and so a caption lands under the columns it names.\r\n const gutterSpacer = new VerticalAxis({\r\n opacity: 0,\r\n range: () => this.valueScale,\r\n markers: () => this.resolvedMarkers,\r\n axis: () => this.resolvedTheme.yAxis,\r\n label: this.valueAxis.label ?? \"\",\r\n width: \"hug\",\r\n height: 0,\r\n })\r\n\r\n const below: Node2D[] = [this.cAxis]\r\n if (this.legend) below.push(this.legend)\r\n\r\n this.add(\r\n new Rect({ flow: \"vertical\",\r\n width: \"fill\",\r\n height: \"fill\",\r\n // See {@link TOP_HEADROOM}.\r\n padding: { top: TOP_HEADROOM },\r\n children: [\r\n new Rect({ flow: \"horizontal\",\r\n height: \"fill\",\r\n width: \"fill\",\r\n children: [this.vAxis, this.plotRect],\r\n }),\r\n new Rect({ flow: \"horizontal\",\r\n width: \"fill\",\r\n children: [\r\n gutterSpacer,\r\n new Rect({ flow: \"vertical\", width: \"fill\", gap: 20, children: below }),\r\n ],\r\n }),\r\n ],\r\n })\r\n )\r\n }\r\n\r\n // ---- Orchestrated entrance --------------------------------------------\r\n\r\n /**\r\n * Prime every part at its pre-entrance state — axis markers and captions\r\n * shifted and transparent, columns collapsed onto the baseline, legend dropped\r\n * and transparent.\r\n *\r\n * Called by {@link enter} before its first frame so nothing flashes ahead of\r\n * its beat. Idempotent, and public so a scene can hide a chart ahead of time\r\n * without starting the entrance.\r\n */\r\n arm(): void {\r\n this.vAxis.arm()\r\n this.cAxis.arm()\r\n this.growth = 0\r\n this.legend?.set({ opacity: 0, y: -LEGEND_SLIDE })\r\n }\r\n\r\n /**\r\n * Animate the whole chart in: the two axes stagger their markers and captions\r\n * in, the columns rise from the baseline, and the legend fades up last.\r\n *\r\n * `duration` is the **whole** entrance. The phases are shares of it, not\r\n * multiples — a command that declares 1.4 seconds has to take 1.4 seconds,\r\n * because that is the slot the timeline lays out for it, the length its\r\n * parallel siblings are timed against, and its contribution to the scene's own\r\n * duration.\r\n */\r\n @command()\r\n enter(args: CommandArgs<Record<string, never>> & { duration: number }): Command<Record<string, never>> {\r\n const { duration } = args\r\n const easing = args.easing ?? easeOut()\r\n this.arm()\r\n\r\n return asCommand(\r\n sequenceOf(\r\n together(\r\n this.vAxis.enter({ data: { slide: 24 }, duration: duration * AXES_SHARE, easing }),\r\n this.cAxis.enter({ data: { slide: 24 }, duration: duration * AXES_SHARE, easing })\r\n ),\r\n this.riseBars(duration * BARS_SHARE, easing),\r\n // Without a legend the beat is still its share of the whole, so the\r\n // entrance ends exactly when it was laid out to.\r\n this.legend\r\n ? this.legend.to({ data: { opacity: 1, y: 0 }, duration: duration * LEGEND_SHARE, easing })\r\n : hold(duration * LEGEND_SHARE)\r\n ),\r\n duration\r\n )\r\n }\r\n\r\n /**\r\n * Move props to new values; a restated value-axis `range` or `ticks` tweens\r\n * from the domain as drawn, so an auto axis (the default) rescales the columns\r\n * continuously instead of cutting at the midpoint of the move.\r\n */\r\n override to<D extends Partial<BarChartProps> = Partial<BarChartProps>>(\r\n args: CommandArgs<D> & { duration: number }\r\n ): Command<BarChartProps> {\r\n const data = (args.data ?? {}) as Partial<BarChartProps>\r\n const drawn: AxisDomainConfig = {\r\n ...this.valueAxis,\r\n range: this.valueScale,\r\n ticks: this.resolvedMarkers,\r\n }\r\n const target = axisTweenTarget(drawn, data.valueAxis)\r\n if (!target) return super.to(args)\r\n\r\n const { valueAxis: _valueAxis, ...rest } = data\r\n const axis = this.command<{ valueAxis: AxisDomainConfig }>(\r\n (t) => ({ valueAxis: lerpAxisDomain(drawn, target, t) }),\r\n args.duration,\r\n args.easing\r\n )\r\n if (Object.keys(rest).length === 0) return axis as unknown as Command<BarChartProps>\r\n return asCommand(\r\n together(super.to({ ...args, data: rest } as typeof args), axis),\r\n args.duration\r\n ) as unknown as Command<BarChartProps>\r\n }\r\n\r\n /** Tween {@link growth} `0 → 1`, raising every column about the baseline. */\r\n private riseBars(\r\n duration: number,\r\n easing: EasingFunction\r\n ): Command<BarGrowth> {\r\n // No priming to 0 first: the value at `t` is a function of `t`, so a repeat\r\n // call re-raises by definition rather than by having reset something.\r\n return this.command<BarGrowth>((t) => ({ growth: t }), duration, easing)\r\n }\r\n\r\n /**\r\n * Show series `index`: bring its columns back, the group reflowing to make\r\n * room as they arrive, in lockstep with its legend entry growing in.\r\n */\r\n @command({ args: [{ key: \"seriesIndex\", kind: \"series\", default: 0, min: 0, step: 1 }] })\r\n showSeries(args: CommandArgs<{ seriesIndex: number }>): Command<Record<string, never>> {\r\n const { seriesIndex = 0 } = args.data ?? {}\r\n return this.toggleSeries(seriesIndex, 1, args.duration ?? 0.35, args.easing ?? easeOut())\r\n }\r\n\r\n /**\r\n * Hide series `index`: its columns narrow away (or, stacked, sink out of the\r\n * stack) while the rest of the group widens into the space, its legend entry\r\n * shrinking beside them — the mirror of {@link showSeries}.\r\n */\r\n @command({ args: [{ key: \"seriesIndex\", kind: \"series\", default: 0, min: 0, step: 1 }] })\r\n hideSeries(args: CommandArgs<{ seriesIndex: number }>): Command<Record<string, never>> {\r\n const { seriesIndex = 0 } = args.data ?? {}\r\n return this.toggleSeries(seriesIndex, 0, args.duration ?? 0.35, args.easing ?? easeOut())\r\n }\r\n\r\n /**\r\n * Move series `index`'s slot share to `target`, with its legend entry.\r\n *\r\n * One method for both directions, so the pair cannot drift apart. `enabled`\r\n * rides in the same value as the weight rather than being set before or after,\r\n * which is what makes arriving at a time backwards show what arriving forwards\r\n * does.\r\n */\r\n private toggleSeries(\r\n index: number,\r\n target: number,\r\n duration: number,\r\n easing: EasingFunction\r\n ): Command<Record<string, never>> {\r\n const bars = this.barSets[index]\r\n if (!bars) return asCommand(hold(duration))\r\n\r\n return asCommand(\r\n together(\r\n this.tweenWeight(index, target, duration, easing),\r\n drive(duration, (t) => {\r\n const share = t >= 1 ? target : Math.max(target, 1 - t)\r\n bars.set({ enabled: target > 0 || share > 0 })\r\n }),\r\n ...(this.legend\r\n ? [\r\n target > 0\r\n ? this.legend.showSeries({ data: { index }, duration, easing })\r\n : this.legend.hideSeries({ data: { index }, duration, easing }),\r\n ]\r\n : [])\r\n ),\r\n duration\r\n )\r\n }\r\n\r\n /**\r\n * Fade out every other series — its columns **and its legend entry** — to\r\n * focus attention on `index`, which comes back to full. Nothing moves, so the\r\n * group doesn't reflow.\r\n */\r\n @command({ args: [{ key: \"seriesIndex\", kind: \"series\", default: 0, min: 0, step: 1 }] })\r\n spotlightSeries(args: CommandArgs<{ seriesIndex: number }>): Command<Record<string, never>> {\r\n const { seriesIndex = 0 } = args.data ?? {}\r\n const duration = args.duration ?? 0.35\r\n const easing = args.easing ?? easeOut()\r\n const dim = this.resolvedTheme.spotlight.dimOpacity\r\n return asCommand(\r\n together(\r\n ...this.barSets.map((bars, i) =>\r\n bars.to({ data: { opacity: i === seriesIndex ? 1 : dim }, duration, easing })\r\n ),\r\n ...(this.legend\r\n ? [this.legend.spotlightSeries({ data: { index: seriesIndex }, duration, easing })]\r\n : [])\r\n ),\r\n duration\r\n )\r\n }\r\n\r\n /** Ease series `index`'s slot share toward `target`, reflowing the group. */\r\n private tweenWeight(\r\n index: number,\r\n target: number,\r\n duration: number,\r\n easing: EasingFunction\r\n ): Seekable {\r\n // Read through `weightAt` rather than off the array, so a chart whose stored\r\n // weights are short (or absent) still tweens from the 1 it is drawing at.\r\n const from = this.series.map((_, i) => this.weightAt(i))\r\n const start = from[index] ?? 1\r\n if (start === target) return hold(duration)\r\n\r\n return drive(duration, (t) => {\r\n const next = [...from]\r\n next[index] = start + (target - start) * easing(t)\r\n this.weights = next\r\n })\r\n }\r\n\r\n // ---- Per-category ------------------------------------------------------\r\n\r\n /**\r\n * Spotlight one **category** — one column of the table rather than one series:\r\n * every other category's bars and its caption fade to the theme's\r\n * `dimOpacity`, and the chosen one stays full.\r\n *\r\n * The counterpart of the line chart's `spotlightRegion`, and the same shape of\r\n * thing: it picks out a slice of the plot without changing what is drawn.\r\n * Calling it while another category is already lit moves the focus directly —\r\n * only the dimming changes, so there is nothing to retract first.\r\n */\r\n @command({ args: [{ key: \"categoryIndex\", kind: \"number\", default: 0, min: 0, step: 1 }] })\r\n spotlightCategory(args: CommandArgs<{ categoryIndex: number }>): Command<CategorySpotlight> {\r\n const { categoryIndex = 0 } = args.data ?? {}\r\n const duration = args.duration ?? 0.4\r\n const easing = args.easing ?? easeOut()\r\n if (categoryIndex < 0 || categoryIndex >= this.data.length) return this.holdSpotlight(duration)\r\n const from = this.spotlightReveal\r\n // Which category is lit is part of the value, set from the first frame: the\r\n // focus moves directly, so unlike the line chart's region there is nothing to\r\n // retract before it.\r\n return this.command<CategorySpotlight>(\r\n (t) => ({ spotlight: categoryIndex, spotlightReveal: from + (1 - from) * t }),\r\n duration,\r\n easing\r\n )\r\n }\r\n\r\n /**\r\n * Drop the category spotlight, bringing every category back to full. A no-op\r\n * when nothing is lit — but it still takes its slot on the timeline, for the\r\n * reason `LineChart.clearRegion` does.\r\n */\r\n @command()\r\n clearCategory(args: CommandArgs<Record<string, never>>): Command<CategorySpotlight> {\r\n const duration = args.duration ?? 0.4\r\n const easing = args.easing ?? easeOut()\r\n const from = this.spotlightReveal\r\n if (from === 0) return this.holdSpotlight(duration)\r\n\r\n // The lit category is held until the fade lands — cleared at `t === 1` rather\r\n // than up front, or there would be nothing left to fade.\r\n return this.command<CategorySpotlight>(\r\n (t) =>\r\n t >= 1\r\n ? { spotlight: null, spotlightReveal: 0 }\r\n : { spotlightReveal: from * (1 - t) },\r\n duration,\r\n easing\r\n )\r\n }\r\n\r\n /** The no-op both of the above return — see {@link hold}. */\r\n private holdSpotlight(duration: number): Command<CategorySpotlight> {\r\n return this.command<CategorySpotlight>(() => ({}), duration)\r\n }\r\n}\r\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"category-axis.js","sourceRoot":"","sources":["../../src/bar-chart/category-axis.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n command,\n Node2D,\n Rect,\n Text,\n easeOut,\n property,\n insetsOps,\n textOps,\n type CommandArgs,\n type NodeConfig,\n type Node2DProps,\n} from \"@motionscript/sdk\"\n\nimport {\n DEFAULT_X_AXIS,\n clampUnit,\n enterBudget,\n type AxisConfig,\n} from \"../kit/shared\"\nimport { at, compose, hold, type Seekable } from \"@motionscript/sdk/component\"\n\nexport interface CategoryAxisProps extends Node2DProps {\n /** One caption per category slot, left to right — the chart's rows, in order. */\n categories: string[]\n /** Caption/title text style and gutters — see {@link AxisConfig}. */\n axis: AxisConfig\n /**\n * Caption drawn centred in the gutter beneath the category row. Empty string\n * (the default) hides it.\n */\n label: string\n /**\n * Per-category opacity multiplier — how the chart's category spotlight reaches\n * the captions, so the name under a dimmed column dims with it. Missing\n * entries read as 1.\n */\n dims: number[]\n}\n\n/** How far a caption starts above its slot when it enters, in px. */\nconst SLIDE = 24\n\n/**\n * The **categorical** horizontal axis of a {@link BarChart}: a row of\n * {@link Text} captions, one per row of the data, each centred on its slot\n * beneath the baseline.\n *\n * Not a variant of the line chart's `HorizontalAxis` and deliberately not\n * folded into it: that axis places markers by *value* across a numeric range,\n * this one divides its width into equal slots and centres a name in each. The\n * two look alike on screen and share nothing underneath — one reads a scale,\n * the other counts rows.\n *\n * The slot arithmetic is the same as the plot's, because this node is laid out\n * to exactly the plot's width (the chart reserves the axis gutter with an\n * invisible twin of the value axis, as the line chart does), so a caption lands\n * under the columns it names without either side being told about the other.\n *\n * {@link enter} staggers the captions in left-to-right, each lifted a little\n * above its slot and transparent; the resting state is the landed one, so a\n * chart that is never told to enter still reads as finished.\n */\nexport class CategoryAxis extends Node2D<CategoryAxisProps> {\n @property({ default: () => [] as string[] }) declare categories: string[]\n @property({ default: DEFAULT_X_AXIS }) declare axis: AxisConfig\n @property({ default: \"\" }) declare label: string\n @property({ default: () => [] as number[] }) declare dims: number[]\n\n /** One caption per category, ordered left → right, for the staggered enter. */\n private captionNodes: Text[] = []\n /** The axis title, or null when `label` is empty. */\n private labelNode: Text | null = null\n\n /** Centre x of slot `i`, in the node's centred space. */\n private slotCenter(index: number): number {\n const n = this.categories.length\n if (n <= 0) return 0\n const width = this.layoutBounds.width\n return -width / 2 + (width / n) * (index + 0.5)\n }\n\n constructor(props?: NodeConfig<CategoryAxis, CategoryAxisProps>) {\n super(props)\n\n const tickPad = insetsOps.resolve(this.axis.tickPadding).top\n const titlePad = insetsOps.resolve(this.axis.titlePadding).top\n\n // Each caption sits in a hug box carrying the spotlight dim, so the\n // entrance can animate the text's own opacity without the two fighting over\n // one value — opacity multiplies down the tree, which is exactly the\n // composition wanted here.\n const slots = this.categories.map((caption, i) => {\n const text = new Text({\n ...textOps.styleProps(this.axis.labelStyle),\n text: caption,\n })\n this.captionNodes.push(text)\n return new Rect({\n width: \"hug\",\n height: \"hug\",\n flow: \"freeform\",\n opacity: () => clampUnit(this.dims[i] ?? 1),\n x: () => this.slotCenter(i),\n children: [text],\n })\n })\n\n const children: Node2D[] = [\n new Rect({\n width: \"fill\",\n height: \"hug\",\n padding: { top: tickPad },\n children: slots,\n }),\n ]\n if (this.label !== \"\") {\n this.labelNode = new Text({\n ...textOps.styleProps(this.axis.titleStyle),\n text: this.label,\n })\n children.push(this.labelNode)\n }\n\n this.add(new Rect({ flow: \"vertical\", gap: titlePad, height: \"hug\", width: \"fill\", children }))\n }\n\n /**\n * Primes every caption (and the title) at its pre-entrance state: lifted above\n * its slot and transparent. Idempotent, so the chart can arm its whole\n * composition before the first frame is drawn.\n */\n arm(slide = SLIDE): void {\n for (const caption of this.captionNodes) caption.set({ opacity: 0, y: slide })\n this.labelNode?.set({ opacity: 0, y: slide })\n }\n\n /**\n * Slide + fade every caption in from above, staggered left-to-right, then\n * bring the title down behind them.\n *\n * `args.duration` is the **whole** entrance — the stagger and the title are\n * carved out of it rather than added on top. See {@link enterBudget}.\n *\n * `args.data.stagger` is seconds between successive captions (derived when\n * omitted); `args.data.slide` is the starting upward offset in px (node space\n * is y-up, so a positive start slides *down* into place).\n */\n @command()\n enter(args: CommandArgs<{ stagger?: number; slide?: number }> & { duration: number }): Seekable {\n const { stagger, slide = SLIDE } = args.data ?? {}\n const easing = args.easing ?? easeOut()\n const nodes = this.captionNodes\n if (nodes.length === 0) return hold(args.duration)\n const { step, per, caption } = enterBudget(\n args.duration,\n nodes.length,\n this.labelNode !== null,\n stagger\n )\n\n this.arm(slide)\n\n // The stagger was `wait(i * step)` inside a generator, so its offsets only\n // existed while it ran. They were always `i * step`; placed, the same\n // entrance can be asked what it looks like partway through.\n const lastCaptionEnds = (nodes.length - 1) * step + per\n return compose([\n ...nodes.map((node, i) =>\n at(i * step, node.to({ data: { opacity: 1, y: 0 }, duration: per, easing }))\n ),\n ...(this.labelNode\n ? [at(lastCaptionEnds, this.labelNode.to({ data: { opacity: 1, y: 0 }, duration: caption, easing }))]\n : []),\n ])\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"category-axis.js","sourceRoot":"","sources":["../../src/bar-chart/category-axis.ts"],"names":[],"mappings":"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","sourcesContent":["import {\r\n command,\r\n Node2D,\r\n Rect,\r\n Text,\r\n easeOut,\r\n property,\r\n insetsOps,\r\n textOps,\r\n type CommandArgs,\r\n type NodeConfig,\r\n type Node2DProps,\r\n} from \"@motionscript/sdk\"\r\n\r\nimport {\r\n DEFAULT_X_AXIS,\r\n clampUnit,\r\n enterBudget,\r\n type AxisConfig,\r\n} from \"../kit/shared\"\r\nimport { at, compose, hold, type Seekable } from \"@motionscript/sdk/component\"\r\n\r\nexport interface CategoryAxisProps extends Node2DProps {\r\n /** One caption per category slot, left to right — the chart's rows, in order. */\r\n categories: string[]\r\n /** Caption/title text style and gutters — see {@link AxisConfig}. */\r\n axis: AxisConfig\r\n /**\r\n * Caption drawn centred in the gutter beneath the category row. Empty string\r\n * (the default) hides it.\r\n */\r\n label: string\r\n /**\r\n * Per-category opacity multiplier — how the chart's category spotlight reaches\r\n * the captions, so the name under a dimmed column dims with it. Missing\r\n * entries read as 1.\r\n */\r\n dims: number[]\r\n}\r\n\r\n/** How far a caption starts above its slot when it enters, in px. */\r\nconst SLIDE = 24\r\n\r\n/**\r\n * The **categorical** horizontal axis of a {@link BarChart}: a row of\r\n * {@link Text} captions, one per row of the data, each centred on its slot\r\n * beneath the baseline.\r\n *\r\n * Not a variant of the line chart's `HorizontalAxis` and deliberately not\r\n * folded into it: that axis places markers by *value* across a numeric range,\r\n * this one divides its width into equal slots and centres a name in each. The\r\n * two look alike on screen and share nothing underneath — one reads a scale,\r\n * the other counts rows.\r\n *\r\n * The slot arithmetic is the same as the plot's, because this node is laid out\r\n * to exactly the plot's width (the chart reserves the axis gutter with an\r\n * invisible twin of the value axis, as the line chart does), so a caption lands\r\n * under the columns it names without either side being told about the other.\r\n *\r\n * {@link enter} staggers the captions in left-to-right, each lifted a little\r\n * above its slot and transparent; the resting state is the landed one, so a\r\n * chart that is never told to enter still reads as finished.\r\n */\r\nexport class CategoryAxis extends Node2D<CategoryAxisProps> {\r\n @property({ default: () => [] as string[] }) declare categories: string[]\r\n @property({ default: DEFAULT_X_AXIS }) declare axis: AxisConfig\r\n @property({ default: \"\" }) declare label: string\r\n @property({ default: () => [] as number[] }) declare dims: number[]\r\n\r\n /** One caption per category, ordered left → right, for the staggered enter. */\r\n private captionNodes: Text[] = []\r\n /** The axis title, or null when `label` is empty. */\r\n private labelNode: Text | null = null\r\n\r\n /** Centre x of slot `i`, in the node's centred space. */\r\n private slotCenter(index: number): number {\r\n const n = this.categories.length\r\n if (n <= 0) return 0\r\n const width = this.layoutBounds.width\r\n return -width / 2 + (width / n) * (index + 0.5)\r\n }\r\n\r\n constructor(props?: NodeConfig<CategoryAxis, CategoryAxisProps>) {\r\n super(props)\r\n\r\n const tickPad = insetsOps.resolve(this.axis.tickPadding).top\r\n const titlePad = insetsOps.resolve(this.axis.titlePadding).top\r\n\r\n // Each caption sits in a hug box carrying the spotlight dim, so the\r\n // entrance can animate the text's own opacity without the two fighting over\r\n // one value — opacity multiplies down the tree, which is exactly the\r\n // composition wanted here.\r\n const slots = this.categories.map((caption, i) => {\r\n const text = new Text({\r\n ...textOps.styleProps(this.axis.labelStyle),\r\n text: caption,\r\n })\r\n this.captionNodes.push(text)\r\n return new Rect({\r\n width: \"hug\",\r\n height: \"hug\",\r\n flow: \"freeform\",\r\n opacity: () => clampUnit(this.dims[i] ?? 1),\r\n x: () => this.slotCenter(i),\r\n children: [text],\r\n })\r\n })\r\n\r\n const children: Node2D[] = [\r\n new Rect({\r\n width: \"fill\",\r\n height: \"hug\",\r\n padding: { top: tickPad },\r\n children: slots,\r\n }),\r\n ]\r\n if (this.label !== \"\") {\r\n this.labelNode = new Text({\r\n ...textOps.styleProps(this.axis.titleStyle),\r\n text: this.label,\r\n })\r\n children.push(this.labelNode)\r\n }\r\n\r\n this.add(new Rect({ flow: \"vertical\", gap: titlePad, height: \"hug\", width: \"fill\", children }))\r\n }\r\n\r\n /**\r\n * Primes every caption (and the title) at its pre-entrance state: lifted above\r\n * its slot and transparent. Idempotent, so the chart can arm its whole\r\n * composition before the first frame is drawn.\r\n */\r\n arm(slide = SLIDE): void {\r\n for (const caption of this.captionNodes) caption.set({ opacity: 0, y: slide })\r\n this.labelNode?.set({ opacity: 0, y: slide })\r\n }\r\n\r\n /**\r\n * Slide + fade every caption in from above, staggered left-to-right, then\r\n * bring the title down behind them.\r\n *\r\n * `args.duration` is the **whole** entrance — the stagger and the title are\r\n * carved out of it rather than added on top. See {@link enterBudget}.\r\n *\r\n * `args.data.stagger` is seconds between successive captions (derived when\r\n * omitted); `args.data.slide` is the starting upward offset in px (node space\r\n * is y-up, so a positive start slides *down* into place).\r\n */\r\n @command()\r\n enter(args: CommandArgs<{ stagger?: number; slide?: number }> & { duration: number }): Seekable {\r\n const { stagger, slide = SLIDE } = args.data ?? {}\r\n const easing = args.easing ?? easeOut()\r\n const nodes = this.captionNodes\r\n if (nodes.length === 0) return hold(args.duration)\r\n const { step, per, caption } = enterBudget(\r\n args.duration,\r\n nodes.length,\r\n this.labelNode !== null,\r\n stagger\r\n )\r\n\r\n this.arm(slide)\r\n\r\n // The stagger was `wait(i * step)` inside a generator, so its offsets only\r\n // existed while it ran. They were always `i * step`; placed, the same\r\n // entrance can be asked what it looks like partway through.\r\n const lastCaptionEnds = (nodes.length - 1) * step + per\r\n return compose([\r\n ...nodes.map((node, i) =>\r\n at(i * step, node.to({ data: { opacity: 1, y: 0 }, duration: per, easing }))\r\n ),\r\n ...(this.labelNode\r\n ? [at(lastCaptionEnds, this.labelNode.to({ data: { opacity: 1, y: 0 }, duration: caption, easing }))]\r\n : []),\r\n ])\r\n }\r\n}\r\n"]}
|