@motionscript/charts 0.1.0-alpha.0 → 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 +59 -0
- package/LICENSE +201 -201
- package/NOTICE +48 -0
- package/README.md +85 -0
- package/dist/bar-chart/bar-chart.d.ts +33 -19
- package/dist/bar-chart/bar-chart.d.ts.map +1 -1
- package/dist/bar-chart/bar-chart.js +68 -64
- package/dist/bar-chart/bar-chart.js.map +1 -1
- package/dist/bar-chart/category-axis.d.ts +2 -2
- package/dist/bar-chart/category-axis.d.ts.map +1 -1
- package/dist/bar-chart/category-axis.js +2 -2
- package/dist/bar-chart/category-axis.js.map +1 -1
- package/dist/bar-chart/chart-bars.d.ts +1 -1
- package/dist/bar-chart/chart-bars.d.ts.map +1 -1
- package/dist/bar-chart/chart-bars.js +2 -2
- 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 +4 -4
- package/dist/bar-chart/shared.d.ts.map +1 -1
- package/dist/bar-chart/shared.js +4 -4
- 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 +4 -3
- package/dist/engine.d.ts +1 -1
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +1 -1
- package/dist/engine.js.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/kit/chart-border.d.ts +1 -1
- package/dist/kit/chart-border.d.ts.map +1 -1
- package/dist/kit/chart-border.js +2 -2
- package/dist/kit/chart-border.js.map +1 -1
- package/dist/kit/chart-canvas.d.ts +1 -1
- package/dist/kit/chart-canvas.d.ts.map +1 -1
- package/dist/kit/chart-canvas.js +2 -2
- package/dist/kit/chart-canvas.js.map +1 -1
- package/dist/kit/chart-legend.d.ts +6 -27
- package/dist/kit/chart-legend.d.ts.map +1 -1
- package/dist/kit/chart-legend.js +33 -57
- package/dist/kit/chart-legend.js.map +1 -1
- package/dist/kit/shared.d.ts +31 -8
- package/dist/kit/shared.d.ts.map +1 -1
- package/dist/kit/shared.js +67 -11
- package/dist/kit/shared.js.map +1 -1
- package/dist/kit/vertical-axis.d.ts +2 -2
- package/dist/kit/vertical-axis.d.ts.map +1 -1
- package/dist/kit/vertical-axis.js +2 -2
- package/dist/kit/vertical-axis.js.map +1 -1
- package/dist/line-chart/chart-line.d.ts +3 -3
- package/dist/line-chart/chart-line.d.ts.map +1 -1
- package/dist/line-chart/chart-line.js +2 -2
- package/dist/line-chart/chart-line.js.map +1 -1
- package/dist/line-chart/chart-region.d.ts +1 -1
- package/dist/line-chart/chart-region.d.ts.map +1 -1
- package/dist/line-chart/chart-region.js +2 -2
- package/dist/line-chart/chart-region.js.map +1 -1
- package/dist/line-chart/horizontal-axis.d.ts +2 -2
- package/dist/line-chart/horizontal-axis.d.ts.map +1 -1
- package/dist/line-chart/horizontal-axis.js +2 -2
- 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 +25 -9
- package/dist/line-chart/line-chart.d.ts.map +1 -1
- package/dist/line-chart/line-chart.js +66 -43
- package/dist/line-chart/line-chart.js.map +1 -1
- package/dist/line-chart/shared.d.ts +4 -4
- package/dist/line-chart/shared.d.ts.map +1 -1
- package/dist/line-chart/shared.js +20 -5
- package/dist/line-chart/shared.js.map +1 -1
- package/dist/line-chart/x-scale.d.ts +2 -2
- package/dist/line-chart/x-scale.d.ts.map +1 -1
- package/dist/line-chart/x-scale.js +2 -2
- 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 +16 -10
- package/dist/pie-chart/pie-chart.d.ts.map +1 -1
- package/dist/pie-chart/pie-chart.js +15 -16
- package/dist/pie-chart/pie-chart.js.map +1 -1
- package/dist/pie-chart/pie-legend.d.ts +2 -2
- package/dist/pie-chart/pie-legend.d.ts.map +1 -1
- package/dist/pie-chart/pie-legend.js +6 -6
- package/dist/pie-chart/pie-legend.js.map +1 -1
- package/dist/pie-chart/pie-ring.d.ts +14 -5
- package/dist/pie-chart/pie-ring.d.ts.map +1 -1
- package/dist/pie-chart/pie-ring.js +45 -15
- package/dist/pie-chart/pie-ring.js.map +1 -1
- package/dist/pie-chart/shared.d.ts +4 -4
- package/dist/pie-chart/shared.d.ts.map +1 -1
- package/dist/pie-chart/shared.js +4 -4
- package/dist/pie-chart/shared.js.map +1 -1
- package/package.json +6 -4
- package/registry.json +23 -23
- package/src/bar-chart/bar-chart.ts +820 -804
- 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 -894
- 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 -374
- 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-ZMBOBHYL.js +0 -2
- package/dist/browser/chunks/chunk-ZMBOBHYL.js.map +0 -7
|
@@ -1,159 +1,159 @@
|
|
|
1
|
-
import {
|
|
2
|
-
command,
|
|
3
|
-
Rect,
|
|
4
|
-
Text,
|
|
5
|
-
easeOut,
|
|
6
|
-
property,
|
|
7
|
-
textOps,
|
|
8
|
-
type CommandArgs,
|
|
9
|
-
type NodeConfig,
|
|
10
|
-
type RectProps,
|
|
11
|
-
} from "@motionscript/
|
|
12
|
-
|
|
13
|
-
import {
|
|
14
|
-
DEFAULT_LEGEND,
|
|
15
|
-
clampUnit,
|
|
16
|
-
type LegendConfig,
|
|
17
|
-
} from "../kit/shared"
|
|
18
|
-
import { at, compose, hold, type Seekable } from "@motionscript/
|
|
19
|
-
import type { PieSlice } from "./shared"
|
|
20
|
-
|
|
21
|
-
export interface PieLegendProps extends RectProps {
|
|
22
|
-
/** One entry per slice, in ring order. */
|
|
23
|
-
slices: PieSlice[]
|
|
24
|
-
/** Padding, caption style, gaps, and swatch geometry — see {@link LegendConfig}. */
|
|
25
|
-
legend: LegendConfig
|
|
26
|
-
/**
|
|
27
|
-
* Per-slice opacity multiplier, by index — the same signal that dims the ring,
|
|
28
|
-
* so an entry fades in step with the wedge it names. Missing entries read as 1.
|
|
29
|
-
*/
|
|
30
|
-
dims: number[]
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
/** How far an entry starts to the right of its slot when it enters, in px. */
|
|
34
|
-
const SLIDE = 16
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* The legend of a {@link PieChart}: a **vertical-flow column** of entries, one per
|
|
38
|
-
* slice, each pairing the slice's caption with its colour swatch.
|
|
39
|
-
*
|
|
40
|
-
* A column rather than the cartesian charts' row, because it sits *beside* the
|
|
41
|
-
* ring rather than beneath the plot — a pie is as tall as it is wide, so the
|
|
42
|
-
* space it leaves over is a vertical strip. It is otherwise the same entry: the
|
|
43
|
-
* swatch carries the colour, the caption reads in the legend's neutral ink, and
|
|
44
|
-
* both take the shared {@link LegendConfig}.
|
|
45
|
-
*
|
|
46
|
-
* There is no show/hide here. A pie's marks are its *rows*, and a row that
|
|
47
|
-
* shouldn't be in the chart shouldn't be in the table — removing one would
|
|
48
|
-
* silently re-cut every other wedge's share, which is a different chart rather
|
|
49
|
-
* than the same chart with something hidden. Selection is what a pie has
|
|
50
|
-
* instead, and it arrives through {@link dims}.
|
|
51
|
-
*/
|
|
52
|
-
export class PieLegend extends Rect {
|
|
53
|
-
@property({ default: () => [] as PieSlice[] }) declare slices: PieSlice[]
|
|
54
|
-
@property({ default: DEFAULT_LEGEND }) declare legend: LegendConfig
|
|
55
|
-
@property({ default: () => [] as number[] }) declare dims: number[]
|
|
56
|
-
|
|
57
|
-
/** One entry per slice, ordered top → bottom, for the staggered entrance. */
|
|
58
|
-
private items: Rect[] = []
|
|
59
|
-
|
|
60
|
-
constructor(props?: NodeConfig<PieLegend, PieLegendProps>) {
|
|
61
|
-
// `flow` with the rest of the fixed geometry, and for the reason
|
|
62
|
-
// {@link ChartLegend} spells out: a `Rect` given none lays its children out
|
|
63
|
-
// `freeform`, so an unstated column is every caption drawn on top of the
|
|
64
|
-
// last one.
|
|
65
|
-
super({
|
|
66
|
-
...(props as RectProps),
|
|
67
|
-
flow: "vertical",
|
|
68
|
-
align: "centerLeft",
|
|
69
|
-
width: "hug",
|
|
70
|
-
height: "hug",
|
|
71
|
-
})
|
|
72
|
-
|
|
73
|
-
// Fixed column geometry last, so it wins over what super() applied.
|
|
74
|
-
this.set({ gap: this.legend.itemGap / 3, padding: this.legend.padding })
|
|
75
|
-
|
|
76
|
-
for (let i = 0; i < this.slices.length; i++) {
|
|
77
|
-
const item = this.buildItem(
|
|
78
|
-
this.items.push(item)
|
|
79
|
-
// The selection dim rides a wrapper rather than the entry itself, so the
|
|
80
|
-
// entrance can animate the entry's own opacity without the two fighting
|
|
81
|
-
// over one value — opacity multiplies down the tree, which is exactly the
|
|
82
|
-
// composition wanted here.
|
|
83
|
-
this.add(
|
|
84
|
-
new Rect({
|
|
85
|
-
width: "hug",
|
|
86
|
-
height: "hug",
|
|
87
|
-
flow: "freeform",
|
|
88
|
-
opacity: () => clampUnit(this.dims[i] ?? 1),
|
|
89
|
-
children: [item],
|
|
90
|
-
})
|
|
91
|
-
)
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
/** One entry: the slice's colour swatch beside its caption. */
|
|
96
|
-
private buildItem(
|
|
97
|
-
const marker = this.legend.markerStyle
|
|
98
|
-
return new Rect({ flow: "horizontal",
|
|
99
|
-
gap: 12,
|
|
100
|
-
align: "center",
|
|
101
|
-
width: "hug",
|
|
102
|
-
height: "hug",
|
|
103
|
-
children: [
|
|
104
|
-
new Rect({
|
|
105
|
-
width: marker.height,
|
|
106
|
-
height: marker.height,
|
|
107
|
-
cornerRadius: marker.borderRadius,
|
|
108
|
-
fill:
|
|
109
|
-
stroke: marker.stroke,
|
|
110
|
-
shadow: marker.shadow,
|
|
111
|
-
}),
|
|
112
|
-
new Text({
|
|
113
|
-
...textOps.styleProps(this.legend.textStyle),
|
|
114
|
-
text:
|
|
115
|
-
}),
|
|
116
|
-
],
|
|
117
|
-
})
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
/**
|
|
121
|
-
* Prime every entry at its pre-entrance state: shifted right and transparent.
|
|
122
|
-
*
|
|
123
|
-
* Idempotent, and separate from {@link enter} so the chart can arm its whole
|
|
124
|
-
* composition before the first frame is drawn — the resting state is the
|
|
125
|
-
* finished legend, so there is nothing hidden to reveal unless a scene asks.
|
|
126
|
-
*/
|
|
127
|
-
arm(slide = SLIDE): void {
|
|
128
|
-
for (const item of this.items) item.set({ opacity: 0, x: slide })
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
/**
|
|
132
|
-
* Slide + fade every entry in from the right, staggered top-to-bottom.
|
|
133
|
-
*
|
|
134
|
-
* `duration` is the **whole** entrance: the stagger is carved out of it rather
|
|
135
|
-
* than added on top, so the command takes exactly the time the timeline laid
|
|
136
|
-
* out for it.
|
|
137
|
-
*/
|
|
138
|
-
@command()
|
|
139
|
-
enter(
|
|
140
|
-
args: CommandArgs<Record<string, never>> & { duration: number }
|
|
141
|
-
): Seekable {
|
|
142
|
-
const duration = args.duration
|
|
143
|
-
const easing = args.easing ?? easeOut()
|
|
144
|
-
const items = this.items
|
|
145
|
-
if (items.length === 0) return hold(duration)
|
|
146
|
-
this.arm()
|
|
147
|
-
|
|
148
|
-
// Each gap is a fifth of an entry's own move, the rhythm the axes use;
|
|
149
|
-
// solved for from the budget rather than added to it. The offsets were
|
|
150
|
-
// always `i * step` — written as `wait` inside a generator they merely only
|
|
151
|
-
// existed while it ran.
|
|
152
|
-
const per = duration / (1 + Math.max(0, items.length - 1) / 5)
|
|
153
|
-
const step = per / 5
|
|
154
|
-
|
|
155
|
-
return compose(
|
|
156
|
-
items.map((item, i) => at(i * step, item.to({ data: { opacity: 1, x: 0 }, duration: per, easing })))
|
|
157
|
-
)
|
|
158
|
-
}
|
|
159
|
-
}
|
|
1
|
+
import {
|
|
2
|
+
command,
|
|
3
|
+
Rect,
|
|
4
|
+
Text,
|
|
5
|
+
easeOut,
|
|
6
|
+
property,
|
|
7
|
+
textOps,
|
|
8
|
+
type CommandArgs,
|
|
9
|
+
type NodeConfig,
|
|
10
|
+
type RectProps,
|
|
11
|
+
} from "@motionscript/sdk"
|
|
12
|
+
|
|
13
|
+
import {
|
|
14
|
+
DEFAULT_LEGEND,
|
|
15
|
+
clampUnit,
|
|
16
|
+
type LegendConfig,
|
|
17
|
+
} from "../kit/shared"
|
|
18
|
+
import { at, compose, hold, type Seekable } from "@motionscript/sdk/component"
|
|
19
|
+
import type { PieSlice } from "./shared"
|
|
20
|
+
|
|
21
|
+
export interface PieLegendProps extends RectProps {
|
|
22
|
+
/** One entry per slice, in ring order. */
|
|
23
|
+
slices: PieSlice[]
|
|
24
|
+
/** Padding, caption style, gaps, and swatch geometry — see {@link LegendConfig}. */
|
|
25
|
+
legend: LegendConfig
|
|
26
|
+
/**
|
|
27
|
+
* Per-slice opacity multiplier, by index — the same signal that dims the ring,
|
|
28
|
+
* so an entry fades in step with the wedge it names. Missing entries read as 1.
|
|
29
|
+
*/
|
|
30
|
+
dims: number[]
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** How far an entry starts to the right of its slot when it enters, in px. */
|
|
34
|
+
const SLIDE = 16
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* The legend of a {@link PieChart}: a **vertical-flow column** of entries, one per
|
|
38
|
+
* slice, each pairing the slice's caption with its colour swatch.
|
|
39
|
+
*
|
|
40
|
+
* A column rather than the cartesian charts' row, because it sits *beside* the
|
|
41
|
+
* ring rather than beneath the plot — a pie is as tall as it is wide, so the
|
|
42
|
+
* space it leaves over is a vertical strip. It is otherwise the same entry: the
|
|
43
|
+
* swatch carries the colour, the caption reads in the legend's neutral ink, and
|
|
44
|
+
* both take the shared {@link LegendConfig}.
|
|
45
|
+
*
|
|
46
|
+
* There is no show/hide here. A pie's marks are its *rows*, and a row that
|
|
47
|
+
* shouldn't be in the chart shouldn't be in the table — removing one would
|
|
48
|
+
* silently re-cut every other wedge's share, which is a different chart rather
|
|
49
|
+
* than the same chart with something hidden. Selection is what a pie has
|
|
50
|
+
* instead, and it arrives through {@link dims}.
|
|
51
|
+
*/
|
|
52
|
+
export class PieLegend extends Rect {
|
|
53
|
+
@property({ default: () => [] as PieSlice[] }) declare slices: PieSlice[]
|
|
54
|
+
@property({ default: DEFAULT_LEGEND }) declare legend: LegendConfig
|
|
55
|
+
@property({ default: () => [] as number[] }) declare dims: number[]
|
|
56
|
+
|
|
57
|
+
/** One entry per slice, ordered top → bottom, for the staggered entrance. */
|
|
58
|
+
private items: Rect[] = []
|
|
59
|
+
|
|
60
|
+
constructor(props?: NodeConfig<PieLegend, PieLegendProps>) {
|
|
61
|
+
// `flow` with the rest of the fixed geometry, and for the reason
|
|
62
|
+
// {@link ChartLegend} spells out: a `Rect` given none lays its children out
|
|
63
|
+
// `freeform`, so an unstated column is every caption drawn on top of the
|
|
64
|
+
// last one.
|
|
65
|
+
super({
|
|
66
|
+
...(props as RectProps),
|
|
67
|
+
flow: "vertical",
|
|
68
|
+
align: "centerLeft",
|
|
69
|
+
width: "hug",
|
|
70
|
+
height: "hug",
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
// Fixed column geometry last, so it wins over what super() applied.
|
|
74
|
+
this.set({ gap: this.legend.itemGap / 3, padding: this.legend.padding })
|
|
75
|
+
|
|
76
|
+
for (let i = 0; i < this.slices.length; i++) {
|
|
77
|
+
const item = this.buildItem(i)
|
|
78
|
+
this.items.push(item)
|
|
79
|
+
// The selection dim rides a wrapper rather than the entry itself, so the
|
|
80
|
+
// entrance can animate the entry's own opacity without the two fighting
|
|
81
|
+
// over one value — opacity multiplies down the tree, which is exactly the
|
|
82
|
+
// composition wanted here.
|
|
83
|
+
this.add(
|
|
84
|
+
new Rect({
|
|
85
|
+
width: "hug",
|
|
86
|
+
height: "hug",
|
|
87
|
+
flow: "freeform",
|
|
88
|
+
opacity: () => clampUnit(this.dims[i] ?? 1),
|
|
89
|
+
children: [item],
|
|
90
|
+
})
|
|
91
|
+
)
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/** One entry: the slice's colour swatch beside its caption. */
|
|
96
|
+
private buildItem(index: number): Rect {
|
|
97
|
+
const marker = this.legend.markerStyle
|
|
98
|
+
return new Rect({ flow: "horizontal",
|
|
99
|
+
gap: 12,
|
|
100
|
+
align: "center",
|
|
101
|
+
width: "hug",
|
|
102
|
+
height: "hug",
|
|
103
|
+
children: [
|
|
104
|
+
new Rect({
|
|
105
|
+
width: marker.height,
|
|
106
|
+
height: marker.height,
|
|
107
|
+
cornerRadius: marker.borderRadius,
|
|
108
|
+
fill: () => this.slices[index]?.fill ?? "white",
|
|
109
|
+
stroke: marker.stroke,
|
|
110
|
+
shadow: marker.shadow,
|
|
111
|
+
}),
|
|
112
|
+
new Text({
|
|
113
|
+
...textOps.styleProps(this.legend.textStyle),
|
|
114
|
+
text: () => this.slices[index]?.category ?? "",
|
|
115
|
+
}),
|
|
116
|
+
],
|
|
117
|
+
})
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Prime every entry at its pre-entrance state: shifted right and transparent.
|
|
122
|
+
*
|
|
123
|
+
* Idempotent, and separate from {@link enter} so the chart can arm its whole
|
|
124
|
+
* composition before the first frame is drawn — the resting state is the
|
|
125
|
+
* finished legend, so there is nothing hidden to reveal unless a scene asks.
|
|
126
|
+
*/
|
|
127
|
+
arm(slide = SLIDE): void {
|
|
128
|
+
for (const item of this.items) item.set({ opacity: 0, x: slide })
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Slide + fade every entry in from the right, staggered top-to-bottom.
|
|
133
|
+
*
|
|
134
|
+
* `duration` is the **whole** entrance: the stagger is carved out of it rather
|
|
135
|
+
* than added on top, so the command takes exactly the time the timeline laid
|
|
136
|
+
* out for it.
|
|
137
|
+
*/
|
|
138
|
+
@command()
|
|
139
|
+
enter(
|
|
140
|
+
args: CommandArgs<Record<string, never>> & { duration: number }
|
|
141
|
+
): Seekable {
|
|
142
|
+
const duration = args.duration
|
|
143
|
+
const easing = args.easing ?? easeOut()
|
|
144
|
+
const items = this.items
|
|
145
|
+
if (items.length === 0) return hold(duration)
|
|
146
|
+
this.arm()
|
|
147
|
+
|
|
148
|
+
// Each gap is a fifth of an entry's own move, the rhythm the axes use;
|
|
149
|
+
// solved for from the budget rather than added to it. The offsets were
|
|
150
|
+
// always `i * step` — written as `wait` inside a generator they merely only
|
|
151
|
+
// existed while it ran.
|
|
152
|
+
const per = duration / (1 + Math.max(0, items.length - 1) / 5)
|
|
153
|
+
const step = per / 5
|
|
154
|
+
|
|
155
|
+
return compose(
|
|
156
|
+
items.map((item, i) => at(i * step, item.to({ data: { opacity: 1, x: 0 }, duration: per, easing })))
|
|
157
|
+
)
|
|
158
|
+
}
|
|
159
|
+
}
|