@motionscript/charts 0.1.1-alpha.0 → 0.1.1-alpha.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +34 -0
- package/README.md +109 -28
- package/dist/bar-chart/bar-chart.d.ts +265 -39
- package/dist/bar-chart/bar-chart.d.ts.map +1 -1
- package/dist/bar-chart/bar-chart.js +219 -171
- package/dist/bar-chart/bar-chart.js.map +1 -1
- package/dist/bar-chart/category-axis.d.ts +12 -7
- package/dist/bar-chart/category-axis.d.ts.map +1 -1
- package/dist/bar-chart/category-axis.js +56 -42
- package/dist/bar-chart/category-axis.js.map +1 -1
- package/dist/bar-chart/chart-bars.d.ts +76 -52
- package/dist/bar-chart/chart-bars.d.ts.map +1 -1
- package/dist/bar-chart/chart-bars.js +105 -89
- package/dist/bar-chart/chart-bars.js.map +1 -1
- package/dist/bar-chart/index.d.ts +4 -4
- package/dist/bar-chart/index.d.ts.map +1 -1
- package/dist/bar-chart/index.js +2 -2
- package/dist/bar-chart/index.js.map +1 -1
- package/dist/bar-chart/shared.d.ts +41 -65
- package/dist/bar-chart/shared.d.ts.map +1 -1
- package/dist/bar-chart/shared.js +73 -117
- package/dist/bar-chart/shared.js.map +1 -1
- package/dist/browser/chunks/chunk-7XCRX6GE.js +2 -0
- package/dist/browser/chunks/chunk-7XCRX6GE.js.map +7 -0
- package/dist/browser/index.js +1 -1
- package/dist/browser/index.js.map +4 -4
- package/dist/browser/kit.js +1 -1
- package/dist/browser/manifest.json +1 -1
- package/dist/engine.d.ts +5 -2
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +5 -2
- package/dist/engine.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/kit/cartesian.d.ts +51 -15
- package/dist/kit/cartesian.d.ts.map +1 -1
- package/dist/kit/cartesian.js +81 -29
- package/dist/kit/cartesian.js.map +1 -1
- package/dist/kit/chart-canvas.d.ts +32 -24
- package/dist/kit/chart-canvas.d.ts.map +1 -1
- package/dist/kit/chart-canvas.js +52 -46
- package/dist/kit/chart-canvas.js.map +1 -1
- package/dist/kit/chart-legend.d.ts +8 -4
- package/dist/kit/chart-legend.d.ts.map +1 -1
- package/dist/kit/chart-legend.js +30 -20
- package/dist/kit/chart-legend.js.map +1 -1
- package/dist/{line-chart → kit}/horizontal-axis.d.ts +31 -6
- package/dist/kit/horizontal-axis.d.ts.map +1 -0
- package/dist/{line-chart → kit}/horizontal-axis.js +23 -24
- package/dist/kit/horizontal-axis.js.map +1 -0
- package/dist/kit/motion.d.ts +5 -0
- package/dist/kit/motion.d.ts.map +1 -1
- package/dist/kit/motion.js +8 -0
- package/dist/kit/motion.js.map +1 -1
- package/dist/{pie-chart → kit}/pie-legend.d.ts +3 -3
- package/dist/kit/pie-legend.d.ts.map +1 -0
- package/dist/{pie-chart → kit}/pie-legend.js +11 -10
- package/dist/kit/pie-legend.js.map +1 -0
- package/dist/kit/polar.d.ts +31 -0
- package/dist/kit/polar.d.ts.map +1 -0
- package/dist/kit/polar.js +33 -0
- package/dist/kit/polar.js.map +1 -0
- package/dist/kit/shared.d.ts +11 -50
- package/dist/kit/shared.d.ts.map +1 -1
- package/dist/kit/shared.js +58 -141
- package/dist/kit/shared.js.map +1 -1
- package/dist/kit/style.d.ts +517 -0
- package/dist/kit/style.d.ts.map +1 -0
- package/dist/kit/style.js +292 -0
- package/dist/kit/style.js.map +1 -0
- package/dist/kit/vertical-axis.d.ts +22 -2
- package/dist/kit/vertical-axis.d.ts.map +1 -1
- package/dist/kit/vertical-axis.js +56 -43
- package/dist/kit/vertical-axis.js.map +1 -1
- package/dist/line-chart/chart-line.d.ts +95 -3
- package/dist/line-chart/chart-line.d.ts.map +1 -1
- package/dist/line-chart/chart-line.js +165 -53
- 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 +7 -8
- package/dist/line-chart/chart-region.js.map +1 -1
- package/dist/line-chart/index.d.ts +5 -6
- package/dist/line-chart/index.d.ts.map +1 -1
- package/dist/line-chart/index.js +3 -4
- package/dist/line-chart/index.js.map +1 -1
- package/dist/line-chart/line-chart.d.ts +281 -18
- package/dist/line-chart/line-chart.d.ts.map +1 -1
- package/dist/line-chart/line-chart.js +284 -134
- package/dist/line-chart/line-chart.js.map +1 -1
- package/dist/line-chart/shared.d.ts +51 -34
- package/dist/line-chart/shared.d.ts.map +1 -1
- package/dist/line-chart/shared.js +175 -83
- package/dist/line-chart/shared.js.map +1 -1
- package/dist/line-chart/x-scale.d.ts +2 -0
- package/dist/line-chart/x-scale.d.ts.map +1 -1
- package/dist/line-chart/x-scale.js +15 -0
- package/dist/line-chart/x-scale.js.map +1 -1
- package/dist/nodes.d.ts +3 -1
- package/dist/nodes.d.ts.map +1 -1
- package/dist/nodes.js +9 -1
- package/dist/nodes.js.map +1 -1
- package/dist/pie-chart/index.d.ts +2 -3
- package/dist/pie-chart/index.d.ts.map +1 -1
- package/dist/pie-chart/index.js +1 -2
- package/dist/pie-chart/index.js.map +1 -1
- package/dist/pie-chart/pie-chart.d.ts +114 -18
- package/dist/pie-chart/pie-chart.d.ts.map +1 -1
- package/dist/pie-chart/pie-chart.js +38 -24
- package/dist/pie-chart/pie-chart.js.map +1 -1
- package/dist/pie-chart/pie-ring.d.ts +16 -5
- package/dist/pie-chart/pie-ring.d.ts.map +1 -1
- package/dist/pie-chart/pie-ring.js +89 -55
- package/dist/pie-chart/pie-ring.js.map +1 -1
- package/dist/pie-chart/shared.d.ts +61 -62
- package/dist/pie-chart/shared.d.ts.map +1 -1
- package/dist/pie-chart/shared.js +44 -123
- package/dist/pie-chart/shared.js.map +1 -1
- package/dist/radar-chart/index.d.ts +5 -0
- package/dist/radar-chart/index.d.ts.map +1 -0
- package/dist/radar-chart/index.js +5 -0
- package/dist/radar-chart/index.js.map +1 -0
- package/dist/radar-chart/radar-chart.d.ts +212 -0
- package/dist/radar-chart/radar-chart.d.ts.map +1 -0
- package/dist/radar-chart/radar-chart.js +224 -0
- package/dist/radar-chart/radar-chart.js.map +1 -0
- package/dist/radar-chart/radar-grid.d.ts +49 -0
- package/dist/radar-chart/radar-grid.d.ts.map +1 -0
- package/dist/radar-chart/radar-grid.js +63 -0
- package/dist/radar-chart/radar-grid.js.map +1 -0
- package/dist/radar-chart/radar-series.d.ts +59 -0
- package/dist/radar-chart/radar-series.d.ts.map +1 -0
- package/dist/radar-chart/radar-series.js +71 -0
- package/dist/radar-chart/radar-series.js.map +1 -0
- package/dist/radar-chart/shared.d.ts +78 -0
- package/dist/radar-chart/shared.d.ts.map +1 -0
- package/dist/radar-chart/shared.js +129 -0
- package/dist/radar-chart/shared.js.map +1 -0
- package/dist/radial-chart/index.d.ts +6 -0
- package/dist/radial-chart/index.d.ts.map +1 -0
- package/dist/radial-chart/index.js +4 -0
- package/dist/radial-chart/index.js.map +1 -0
- package/dist/radial-chart/radial-chart.d.ts +210 -0
- package/dist/radial-chart/radial-chart.d.ts.map +1 -0
- package/dist/radial-chart/radial-chart.js +175 -0
- package/dist/radial-chart/radial-chart.js.map +1 -0
- package/dist/radial-chart/radial-rings.d.ts +121 -0
- package/dist/radial-chart/radial-rings.d.ts.map +1 -0
- package/dist/radial-chart/radial-rings.js +273 -0
- package/dist/radial-chart/radial-rings.js.map +1 -0
- package/dist/radial-chart/shared.d.ts +77 -0
- package/dist/radial-chart/shared.d.ts.map +1 -0
- package/dist/radial-chart/shared.js +78 -0
- package/dist/radial-chart/shared.js.map +1 -0
- package/package.json +4 -4
- package/registry.json +21 -6
- package/src/bar-chart/bar-chart.ts +263 -179
- package/src/bar-chart/category-axis.ts +46 -40
- package/src/bar-chart/chart-bars.ts +136 -117
- package/src/bar-chart/index.ts +7 -10
- package/src/bar-chart/shared.ts +88 -233
- package/src/engine.ts +5 -2
- package/src/index.ts +2 -0
- package/src/kit/cartesian.ts +121 -40
- package/src/kit/chart-canvas.ts +49 -54
- package/src/kit/chart-legend.ts +28 -20
- package/src/kit/horizontal-axis.ts +114 -0
- package/src/kit/motion.ts +7 -0
- package/src/{pie-chart → kit}/pie-legend.ts +12 -11
- package/src/kit/polar.ts +54 -0
- package/src/kit/shared.ts +55 -277
- package/src/kit/style.ts +353 -0
- package/src/kit/vertical-axis.ts +67 -48
- package/src/line-chart/chart-line.ts +176 -54
- package/src/line-chart/chart-region.ts +6 -10
- package/src/line-chart/index.ts +14 -10
- package/src/line-chart/line-chart.ts +353 -151
- package/src/line-chart/shared.ts +193 -174
- package/src/line-chart/x-scale.ts +13 -0
- package/src/nodes.ts +9 -1
- package/src/pie-chart/index.ts +2 -23
- package/src/pie-chart/pie-chart.ts +54 -35
- package/src/pie-chart/pie-ring.ts +92 -71
- package/src/pie-chart/shared.ts +80 -270
- package/src/radar-chart/index.ts +4 -0
- package/src/radar-chart/radar-chart.ts +290 -0
- package/src/radar-chart/radar-grid.ts +83 -0
- package/src/radar-chart/radar-series.ts +88 -0
- package/src/radar-chart/shared.ts +153 -0
- package/src/radial-chart/index.ts +5 -0
- package/src/radial-chart/radial-chart.ts +212 -0
- package/src/radial-chart/radial-rings.ts +328 -0
- package/src/radial-chart/shared.ts +126 -0
- package/dist/browser/chunks/chunk-4SMRCU24.js +0 -2
- package/dist/browser/chunks/chunk-4SMRCU24.js.map +0 -7
- package/dist/kit/chart-border.d.ts +0 -18
- package/dist/kit/chart-border.d.ts.map +0 -1
- package/dist/kit/chart-border.js +0 -23
- package/dist/kit/chart-border.js.map +0 -1
- package/dist/line-chart/horizontal-axis.d.ts.map +0 -1
- package/dist/line-chart/horizontal-axis.js.map +0 -1
- package/dist/pie-chart/pie-legend.d.ts.map +0 -1
- package/dist/pie-chart/pie-legend.js.map +0 -1
- package/src/kit/chart-border.ts +0 -36
- package/src/line-chart/horizontal-axis.ts +0 -122
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chart-canvas.js","sourceRoot":"","sources":["../../src/kit/chart-canvas.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,EACV,KAAK,EACL,WAAW,EACX,OAAO,EACP,SAAS,
|
|
1
|
+
{"version":3,"file":"chart-canvas.js","sourceRoot":"","sources":["../../src/kit/chart-canvas.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n Graphics2D,\n Types,\n component2d,\n fillOps,\n strokeOps,\n type Fill,\n type FillResolved,\n type NodeOf,\n // Named so this component's emitted type reaches `Node2D` and its props through the sdk, not core.\n type Node2D as _Node2D,\n type Node2DProps as _Node2DProps,\n type RenderContext,\n type Stroke,\n type StrokeResolved,\n type Vector2,\n} from \"@motionscript/sdk\"\n\nimport { fresh } from \"./entries\"\nimport { loadPaints } from \"./paints\"\nimport type { Range } from \"./shared\"\n\nconst strokeEntry = () => Types.custom<Stroke, StrokeResolved[]>([], { resolve: strokeOps.resolve, lerp: strokeOps.lerp })\n\n/** Where along a scale a fraction lands in a run of `length` px centred on 0. */\nfunction along(value: number, [min, max]: Range, length: number): number {\n return (max <= min ? 0 : (value - min) / (max - min) - 0.5) * length\n}\n\n/** One rule per draw: stroking a union of open paths paints nothing, and a dashed rule keeps its own phase. */\nexport function rule(ctx: RenderContext, from: Vector2, to: Vector2, stroke: StrokeResolved[], opacity = 1): void {\n ctx.draw(new Graphics2D().line({ points: [from, to] }).stroke(stroke).opacity(opacity))\n}\n\n/**\n * The plot backdrop: the panel fill, the grid and the axis rules, sized from its\n * box. Grid lines are placed from data-unit marker positions mapped through the\n * extents, so each lands under its marker however the markers are spaced; a line\n * on an edge is drawn just inside it.\n */\nexport const ChartCanvas = component2d({\n key: \"chartCanvas\",\n state: {\n fill: Types.custom<Fill, FillResolved[]>([], { resolve: fillOps.resolve, lerp: fillOps.lerp }),\n /** The vertical grid lines, one per `xMarkers` entry. */\n xGridStroke: strokeEntry(),\n /** The horizontal grid lines, one per `yMarkers` entry. */\n yGridStroke: strokeEntry(),\n xMarkers: fresh<number[]>(() => []),\n yMarkers: fresh<number[]>(() => []),\n /** `[min, max]` of each scale, mapping the markers into the panel. */\n xExtent: fresh<Range>(() => [0, 1]),\n yExtent: fresh<Range>(() => [0, 1]),\n /** The baseline and the value-axis rule. */\n axisStroke: strokeEntry(),\n /** Where the horizontal axis rule sits on the y scale, or `null` for none. */\n xAxisAt: Types.custom<number | null>(null),\n /** Where the vertical axis rule sits on the x scale, or `null` for none. */\n yAxisAt: Types.custom<number | null>(null),\n },\n load: (loader, state) => loadPaints(loader, { fills: [state.fill], strokes: [state.xGridStroke, state.yGridStroke, state.axisStroke] }),\n render: (ctx, state) => {\n const { width: W, height: H } = ctx.size\n if (W <= 0 || H <= 0) return\n if (state.fill.length > 0) ctx.draw(new Graphics2D().rect({ x: 0, y: 0, width: W, height: H }).fill(state.fill))\n\n const inside = (at: number, length: number, weight: number) => Math.max(-length / 2 + weight / 2, Math.min(length / 2 - weight / 2, at))\n const verticals = (values: readonly number[], stroke: StrokeResolved[]) => {\n const weight = stroke[0]?.weight ?? 0\n if (weight <= 0) return\n for (const v of values) {\n const x = inside(along(v, state.xExtent, W), W, weight)\n rule(ctx, { x, y: -H / 2 }, { x, y: H / 2 }, stroke)\n }\n }\n const horizontals = (values: readonly number[], stroke: StrokeResolved[]) => {\n const weight = stroke[0]?.weight ?? 0\n if (weight <= 0) return\n for (const v of values) {\n const y = inside(along(v, state.yExtent, H), H, weight)\n rule(ctx, { x: -W / 2, y }, { x: W / 2, y }, stroke)\n }\n }\n const within = ([min, max]: Range) => (v: number) => v >= Math.min(min, max) - 1e-9 && v <= Math.max(min, max) + 1e-9\n verticals(state.xMarkers.filter(within(state.xExtent)), state.xGridStroke)\n horizontals(state.yMarkers.filter(within(state.yExtent)), state.yGridStroke)\n if (state.xAxisAt !== null) horizontals([state.xAxisAt], state.axisStroke)\n if (state.yAxisAt !== null) verticals([state.yAxisAt], state.axisStroke)\n },\n})\n\nexport type ChartCanvas = NodeOf<typeof ChartCanvas>\n"]}
|
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
import { type Fill, type NodeOf, type Alignment as _Alignment, type CornerRadiusResolved as _CornerRadiusResolved, type CornerStyleResolved as _CornerStyleResolved, type FillResolved as _FillResolved, type FlowMode as _FlowMode, type FlowResolved as _FlowResolved, type GapSize as _GapSize, type Node2D as _Node2D, type Node2DProps as _Node2DProps, type RectCornerRadius as _RectCornerRadius, type RectCornerStyle as _RectCornerStyle, type Shadow as _Shadow, type ShadowResolved as _ShadowResolved, type Stroke as _Stroke, type StrokeResolved as _StrokeResolved, type Vector2 as _Vector2 } from "@motionscript/sdk";
|
|
2
2
|
import { type ChartSeries, type LegendConfig } from "./shared.js";
|
|
3
|
-
/**
|
|
3
|
+
/**
|
|
4
|
+
* A chart's legend: one entry per series, a colour swatch then its caption, in
|
|
5
|
+
* a row (`flow: "horizontal"`) or a column (`"vertical"`, for a legend beside
|
|
6
|
+
* the plot). This node is the row, so the parent places it.
|
|
7
|
+
*/
|
|
4
8
|
export declare const ChartLegend: import("@motionscript/sdk").Component<"chartLegend", import("@motionscript/sdk").Merge<import("@motionscript/sdk").Box2DState, {
|
|
5
9
|
readonly series: import("@motionscript/sdk").Type<ChartSeries[], ChartSeries[], false>;
|
|
6
10
|
/** Swatch colour by series index, resolved by the chart; a missing entry is white. */
|
|
7
11
|
readonly swatches: import("@motionscript/sdk").Type<Fill[], Fill[], false>;
|
|
8
12
|
readonly legend: import("@motionscript/sdk").Type<LegendConfig, LegendConfig, false>;
|
|
9
13
|
/**
|
|
10
|
-
* How far each entry is shown, `0`-`1`, driving its
|
|
14
|
+
* How far each entry is shown, `0`-`1`, driving its length, opacity and gap
|
|
11
15
|
* together. Entries are never added or removed: "is this node a child" is not
|
|
12
16
|
* a function of time, while collapsed-but-present is.
|
|
13
17
|
*/
|
|
@@ -50,7 +54,7 @@ export declare const ChartLegend: import("@motionscript/sdk").Component<"chartLe
|
|
|
50
54
|
readonly swatches: import("@motionscript/sdk").Type<Fill[], Fill[], false>;
|
|
51
55
|
readonly legend: import("@motionscript/sdk").Type<LegendConfig, LegendConfig, false>;
|
|
52
56
|
/**
|
|
53
|
-
* How far each entry is shown, `0`-`1`, driving its
|
|
57
|
+
* How far each entry is shown, `0`-`1`, driving its length, opacity and gap
|
|
54
58
|
* together. Entries are never added or removed: "is this node a child" is not
|
|
55
59
|
* a function of time, while collapsed-but-present is.
|
|
56
60
|
*/
|
|
@@ -75,7 +79,7 @@ export declare const ChartLegend: import("@motionscript/sdk").Component<"chartLe
|
|
|
75
79
|
readonly swatches: import("@motionscript/sdk").Type<Fill[], Fill[], false>;
|
|
76
80
|
readonly legend: import("@motionscript/sdk").Type<LegendConfig, LegendConfig, false>;
|
|
77
81
|
/**
|
|
78
|
-
* How far each entry is shown, `0`-`1`, driving its
|
|
82
|
+
* How far each entry is shown, `0`-`1`, driving its length, opacity and gap
|
|
79
83
|
* together. Entries are never added or removed: "is this node a child" is not
|
|
80
84
|
* a function of time, while collapsed-but-present is.
|
|
81
85
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chart-legend.d.ts","sourceRoot":"","sources":["../../src/kit/chart-legend.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"chart-legend.d.ts","sourceRoot":"","sources":["../../src/kit/chart-legend.ts"],"names":[],"mappings":"AAAA,OAAO,EAQL,KAAK,IAAI,EACT,KAAK,MAAM,EAEX,KAAK,SAAS,IAAI,UAAU,EAC5B,KAAK,oBAAoB,IAAI,qBAAqB,EAClD,KAAK,mBAAmB,IAAI,oBAAoB,EAChD,KAAK,YAAY,IAAI,aAAa,EAClC,KAAK,QAAQ,IAAI,SAAS,EAC1B,KAAK,YAAY,IAAI,aAAa,EAClC,KAAK,OAAO,IAAI,QAAQ,EACxB,KAAK,MAAM,IAAI,OAAO,EACtB,KAAK,WAAW,IAAI,YAAY,EAChC,KAAK,gBAAgB,IAAI,iBAAiB,EAC1C,KAAK,eAAe,IAAI,gBAAgB,EACxC,KAAK,MAAM,IAAI,OAAO,EACtB,KAAK,cAAc,IAAI,eAAe,EACtC,KAAK,MAAM,IAAI,OAAO,EACtB,KAAK,cAAc,IAAI,eAAe,EACtC,KAAK,OAAO,IAAI,QAAQ,EACzB,MAAM,mBAAmB,CAAA;AAK1B,OAAO,EAGL,KAAK,WAAW,EAChB,KAAK,YAAY,EAClB,MAAM,UAAU,CAAA;AA+BjB;;;;GAIG;AACH,eAAO,MAAM,WAAW;;IAKpB,sFAAsF;;;IAGtF;;;;OAIG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAPH,sFAAsF;;;IAGtF;;;;OAIG;;;;;;;;;;;;;;;;;;IAPH,sFAAsF;;;IAGtF;;;;OAIG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2BA0EL,CAAA;AAQF,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC,OAAO,WAAW,CAAC,CAAA"}
|
package/dist/kit/chart-legend.js
CHANGED
|
@@ -1,21 +1,24 @@
|
|
|
1
|
-
import { Flow, Paint, Rect, Shapes, Text, Types, component2d,
|
|
1
|
+
import { Flow, Paint, Rect, Shapes, Text, Types, component2d, } from "@motionscript/sdk";
|
|
2
|
+
import { boundText } from "./cartesian.js";
|
|
2
3
|
import { fresh } from "./entries.js";
|
|
3
4
|
import { frameEase } from "./motion.js";
|
|
4
5
|
import { DEFAULT_LEGEND, SPOTLIGHT_DIM, } from "./shared.js";
|
|
5
6
|
const row = { ...Paint.state, ...Flow.state, ...Shapes.corners };
|
|
6
7
|
/**
|
|
7
|
-
* One legend entry, hugging its
|
|
8
|
-
* from nothing. The
|
|
9
|
-
* never depends on the entry once having been
|
|
10
|
-
*
|
|
8
|
+
* One legend entry, hugging its swatch and caption; `shown` scales its length
|
|
9
|
+
* along the legend (`along`) from nothing. The length is measured from the
|
|
10
|
+
* content at any reveal, so a frame never depends on the entry once having been
|
|
11
|
+
* fully shown.
|
|
11
12
|
*/
|
|
12
13
|
const LegendEntry = component2d({
|
|
13
14
|
key: "legendEntry",
|
|
14
|
-
state: { ...row, shown: Types.number(1) },
|
|
15
|
+
state: { ...row, shown: Types.number(1), along: Types.oneOf(["horizontal", "vertical"]) },
|
|
15
16
|
commands: { ...Paint.commands },
|
|
16
17
|
measure: (measurer, state, children) => {
|
|
17
18
|
const size = Flow.measure(measurer, state, children, Paint.inset(state));
|
|
18
|
-
|
|
19
|
+
if (state.shown >= 1)
|
|
20
|
+
return size;
|
|
21
|
+
return state.along === "vertical" ? { ...size, height: state.shown * size.height } : { ...size, width: state.shown * size.width };
|
|
19
22
|
},
|
|
20
23
|
layout: (box, state, children) => Flow.layout(box, state, children, Paint.inset(state)),
|
|
21
24
|
render: (ctx, state) => Paint.draw(ctx, state, Shapes.rect(ctx.size, state)),
|
|
@@ -29,7 +32,11 @@ function revealOf(value, previous) {
|
|
|
29
32
|
next[Number(index)] = reveal;
|
|
30
33
|
return next;
|
|
31
34
|
}
|
|
32
|
-
/**
|
|
35
|
+
/**
|
|
36
|
+
* A chart's legend: one entry per series, a colour swatch then its caption, in
|
|
37
|
+
* a row (`flow: "horizontal"`) or a column (`"vertical"`, for a legend beside
|
|
38
|
+
* the plot). This node is the row, so the parent places it.
|
|
39
|
+
*/
|
|
33
40
|
export const ChartLegend = component2d({
|
|
34
41
|
key: "chartLegend",
|
|
35
42
|
state: {
|
|
@@ -39,7 +46,7 @@ export const ChartLegend = component2d({
|
|
|
39
46
|
swatches: fresh(() => []),
|
|
40
47
|
legend: Types.custom(DEFAULT_LEGEND),
|
|
41
48
|
/**
|
|
42
|
-
* How far each entry is shown, `0`-`1`, driving its
|
|
49
|
+
* How far each entry is shown, `0`-`1`, driving its length, opacity and gap
|
|
43
50
|
* together. Entries are never added or removed: "is this node a child" is not
|
|
44
51
|
* a function of time, while collapsed-but-present is.
|
|
45
52
|
*/
|
|
@@ -50,33 +57,36 @@ export const ChartLegend = component2d({
|
|
|
50
57
|
flow: "horizontal",
|
|
51
58
|
width: "hug",
|
|
52
59
|
height: "hug",
|
|
53
|
-
gap: (state) => state.legend.itemGap,
|
|
60
|
+
gap: (state) => (state.flow === "vertical" ? Math.round(state.legend.itemGap * 0.4) : state.legend.itemGap),
|
|
54
61
|
padding: (state) => state.legend.padding,
|
|
62
|
+
align: (state) => (state.flow === "vertical" ? "centerLeft" : "center"),
|
|
55
63
|
reveal: (state) => state.series.map((s) => ((s.enabled ?? true) ? 1 : 0)),
|
|
56
64
|
},
|
|
57
65
|
// Every entry stays a child, so one always comes back where it belongs.
|
|
58
66
|
children: (state) => {
|
|
59
|
-
const marker = state.legend.markerStyle;
|
|
67
|
+
const marker = () => state.legend.markerStyle;
|
|
68
|
+
const along = state.flow === "vertical" ? "vertical" : "horizontal";
|
|
60
69
|
return state.series.map((series, index) => LegendEntry({
|
|
61
70
|
flow: "horizontal",
|
|
62
|
-
gap:
|
|
71
|
+
gap: () => Math.round((state.legend.textStyle.fontSize ?? 24) * 0.45),
|
|
63
72
|
align: "center",
|
|
64
73
|
width: "hug",
|
|
65
74
|
height: "hug",
|
|
66
|
-
|
|
75
|
+
along,
|
|
76
|
+
// The length follows the reveal in `measure`, and the flanking gap closes with the entry.
|
|
67
77
|
opacity: () => state.reveal[index] ?? 0,
|
|
68
78
|
gapScale: () => state.reveal[index] ?? 0,
|
|
69
79
|
shown: () => state.reveal[index] ?? 0,
|
|
70
80
|
children: [
|
|
71
|
-
Text({ ...textOps.styleProps(state.legend.textStyle), text: series.label }),
|
|
72
81
|
Rect({
|
|
73
|
-
width: marker.width,
|
|
74
|
-
height: marker.height,
|
|
75
|
-
cornerRadius: marker.borderRadius,
|
|
76
|
-
fill: state.swatches[index] ?? "white",
|
|
77
|
-
stroke: marker.stroke,
|
|
78
|
-
shadow: marker.shadow,
|
|
82
|
+
width: () => marker().width,
|
|
83
|
+
height: () => marker().height,
|
|
84
|
+
cornerRadius: () => marker().borderRadius,
|
|
85
|
+
fill: () => state.swatches[index] ?? "white",
|
|
86
|
+
stroke: () => marker().stroke,
|
|
87
|
+
shadow: () => marker().shadow,
|
|
79
88
|
}),
|
|
89
|
+
Text({ ...boundText(() => state.legend.textStyle), text: series.label || series.field }),
|
|
80
90
|
],
|
|
81
91
|
}));
|
|
82
92
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chart-legend.js","sourceRoot":"","sources":["../../src/kit/chart-legend.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n Flow,\n Paint,\n Rect,\n Shapes,\n Text,\n Types,\n component2d,\n textOps,\n type Fill,\n type NodeOf,\n // Named so the row's emitted type reaches the Rect surface it spreads through the sdk, not core.\n type Alignment as _Alignment,\n type CornerRadiusResolved as _CornerRadiusResolved,\n type CornerStyleResolved as _CornerStyleResolved,\n type FillResolved as _FillResolved,\n type FlowMode as _FlowMode,\n type FlowResolved as _FlowResolved,\n type GapSize as _GapSize,\n type Node2D as _Node2D,\n type Node2DProps as _Node2DProps,\n type RectCornerRadius as _RectCornerRadius,\n type RectCornerStyle as _RectCornerStyle,\n type Shadow as _Shadow,\n type ShadowResolved as _ShadowResolved,\n type Stroke as _Stroke,\n type StrokeResolved as _StrokeResolved,\n type Vector2 as _Vector2,\n} from \"@motionscript/sdk\"\n\nimport { fresh } from \"./entries\"\nimport { frameEase } from \"./motion\"\nimport {\n DEFAULT_LEGEND,\n SPOTLIGHT_DIM,\n type ChartSeries,\n type LegendConfig,\n} from \"./shared\"\n\nconst row = { ...Paint.state, ...Flow.state, ...Shapes.corners }\n\n/**\n * One legend entry, hugging its caption and swatch; `shown` scales that width\n * from nothing. The width is measured from the content at any reveal, so a frame\n * never depends on the entry once having been fully shown (`\"hug\"` is not a\n * number to scale until something measures it).\n */\nconst LegendEntry = component2d({\n key: \"legendEntry\",\n state: { ...row, shown: Types.number(1) },\n commands: { ...Paint.commands },\n measure: (measurer, state, children) => {\n const size = Flow.measure(measurer, state, children, Paint.inset(state))\n return state.shown >= 1 ? size : { ...size, width: state.shown * size.width }\n },\n layout: (box, state, children) => Flow.layout(box, state, children, Paint.inset(state)),\n render: (ctx, state) => Paint.draw(ctx, state, Shapes.rect(ctx.size, state)),\n})\n\n/** Written whole, or one entry at a time as `{ [index]: reveal }`, which leaves the others as the frame left them so two series can move at once. */\nfunction revealOf(value: readonly number[] | Readonly<Record<number, number>>, previous?: number[]): number[] {\n if (Array.isArray(value)) return value as number[]\n const next = [...(previous ?? [])]\n for (const [index, reveal] of Object.entries(value)) next[Number(index)] = reveal\n return next\n}\n\n/** A chart's legend: a horizontal row with one entry per series, each a caption and a colour swatch. This node is the row, so the parent places it. */\nexport const ChartLegend = component2d({\n key: \"chartLegend\",\n state: {\n ...row,\n series: fresh<ChartSeries[]>(() => []),\n /** Swatch colour by series index, resolved by the chart; a missing entry is white. */\n swatches: fresh<Fill[]>(() => []),\n legend: Types.custom<LegendConfig>(DEFAULT_LEGEND),\n /**\n * How far each entry is shown, `0`-`1`, driving its width, opacity and gap\n * together. Entries are never added or removed: \"is this node a child\" is not\n * a function of time, while collapsed-but-present is.\n */\n reveal: fresh<number[], number[] | Readonly<Record<number, number>>>(() => [], { resolve: revealOf }),\n },\n // The flow must be stated: a `Rect` with none lays children out `freeform`, stacking every entry on one spot.\n defaults: {\n flow: \"horizontal\",\n width: \"hug\",\n height: \"hug\",\n gap: (state) => state.legend.itemGap,\n padding: (state) => state.legend.padding,\n reveal: (state) => state.series.map((s) => ((s.enabled ?? true) ? 1 : 0)),\n },\n // Every entry stays a child, so one always comes back where it belongs.\n children: (state) => {\n const marker = state.legend.markerStyle\n return state.series.map((series, index) =>\n LegendEntry({\n flow: \"horizontal\",\n gap: 12,\n align: \"center\",\n width: \"hug\",\n height: \"hug\",\n // The width follows the reveal in `measure`, and the flanking gap closes with the entry.\n opacity: () => state.reveal[index] ?? 0,\n gapScale: () => state.reveal[index] ?? 0,\n shown: () => state.reveal[index] ?? 0,\n children: [\n Text({ ...textOps.styleProps(state.legend.textStyle), text: series.label }),\n Rect({\n width: marker.width,\n height: marker.height,\n cornerRadius: marker.borderRadius,\n fill: state.swatches[index] ?? \"white\",\n stroke: marker.stroke,\n shadow: marker.shadow,\n }),\n ],\n })\n )\n },\n commands: {\n ...Paint.commands,\n /** Grow series `index`'s entry back in at its position, the siblings sliding over. */\n showSeries: {\n args: { index: Types.number(0, { min: 0, step: 1 }) },\n // An index that is not a series takes its slot and moves nothing.\n run: (timeline, state) => (timeline.args.index in state.series\n ? timeline.animate(revealFrame(state, timeline.args.index, 1, frameEase(timeline)))\n : timeline.wait(timeline.duration)),\n },\n /** The mirror of `showSeries`. */\n hideSeries: {\n args: { index: Types.number(0, { min: 0, step: 1 }) },\n run: (timeline, state) => (timeline.args.index in state.series\n ? timeline.animate(revealFrame(state, timeline.args.index, 0, frameEase(timeline)))\n : timeline.wait(timeline.duration)),\n },\n /** Dim every entry but `index` to {@link SPOTLIGHT_DIM}, in place. A hidden series' entry is left as `hideSeries` left it. */\n spotlightSeries: {\n args: { index: Types.number(0, { min: 0, step: 1 }) },\n run: (timeline, state, children) =>\n timeline.together(\n children.flatMap((entry, i) =>\n (state.reveal[i] ?? 0) > 0 ? [entry.to({ opacity: i === timeline.args.index ? 1 : SPOTLIGHT_DIM })] : []\n )\n ),\n },\n },\n measure: (measurer, state, children) => Flow.measure(measurer, state, children, Paint.inset(state)),\n layout: (box, state, children) => Flow.layout(box, state, children, Paint.inset(state)),\n render: (ctx, state) => Paint.draw(ctx, state, Shapes.rect(ctx.size, state)),\n})\n\n/** One entry's reveal ramping to `target` from where the command finds it, so a hide after a show starts where the show left it. */\nfunction revealFrame(state: { readonly reveal: readonly number[] }, index: number, target: number, ease: (t: number) => number) {\n const from = state.reveal[index] ?? 0\n return (t: number) => ({ reveal: { [index]: from + (target - from) * ease(t) } })\n}\n\nexport type ChartLegend = NodeOf<typeof ChartLegend>\n"]}
|
|
1
|
+
{"version":3,"file":"chart-legend.js","sourceRoot":"","sources":["../../src/kit/chart-legend.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n Flow,\n Paint,\n Rect,\n Shapes,\n Text,\n Types,\n component2d,\n type Fill,\n type NodeOf,\n // Named so the row's emitted type reaches the Rect surface it spreads through the sdk, not core.\n type Alignment as _Alignment,\n type CornerRadiusResolved as _CornerRadiusResolved,\n type CornerStyleResolved as _CornerStyleResolved,\n type FillResolved as _FillResolved,\n type FlowMode as _FlowMode,\n type FlowResolved as _FlowResolved,\n type GapSize as _GapSize,\n type Node2D as _Node2D,\n type Node2DProps as _Node2DProps,\n type RectCornerRadius as _RectCornerRadius,\n type RectCornerStyle as _RectCornerStyle,\n type Shadow as _Shadow,\n type ShadowResolved as _ShadowResolved,\n type Stroke as _Stroke,\n type StrokeResolved as _StrokeResolved,\n type Vector2 as _Vector2,\n} from \"@motionscript/sdk\"\n\nimport { boundText } from \"./cartesian\"\nimport { fresh } from \"./entries\"\nimport { frameEase } from \"./motion\"\nimport {\n DEFAULT_LEGEND,\n SPOTLIGHT_DIM,\n type ChartSeries,\n type LegendConfig,\n} from \"./shared\"\n\nconst row = { ...Paint.state, ...Flow.state, ...Shapes.corners }\n\n/**\n * One legend entry, hugging its swatch and caption; `shown` scales its length\n * along the legend (`along`) from nothing. The length is measured from the\n * content at any reveal, so a frame never depends on the entry once having been\n * fully shown.\n */\nconst LegendEntry = component2d({\n key: \"legendEntry\",\n state: { ...row, shown: Types.number(1), along: Types.oneOf([\"horizontal\", \"vertical\"] as const) },\n commands: { ...Paint.commands },\n measure: (measurer, state, children) => {\n const size = Flow.measure(measurer, state, children, Paint.inset(state))\n if (state.shown >= 1) return size\n return state.along === \"vertical\" ? { ...size, height: state.shown * size.height } : { ...size, width: state.shown * size.width }\n },\n layout: (box, state, children) => Flow.layout(box, state, children, Paint.inset(state)),\n render: (ctx, state) => Paint.draw(ctx, state, Shapes.rect(ctx.size, state)),\n})\n\n/** Written whole, or one entry at a time as `{ [index]: reveal }`, which leaves the others as the frame left them so two series can move at once. */\nfunction revealOf(value: readonly number[] | Readonly<Record<number, number>>, previous?: number[]): number[] {\n if (Array.isArray(value)) return value as number[]\n const next = [...(previous ?? [])]\n for (const [index, reveal] of Object.entries(value)) next[Number(index)] = reveal\n return next\n}\n\n/**\n * A chart's legend: one entry per series, a colour swatch then its caption, in\n * a row (`flow: \"horizontal\"`) or a column (`\"vertical\"`, for a legend beside\n * the plot). This node is the row, so the parent places it.\n */\nexport const ChartLegend = component2d({\n key: \"chartLegend\",\n state: {\n ...row,\n series: fresh<ChartSeries[]>(() => []),\n /** Swatch colour by series index, resolved by the chart; a missing entry is white. */\n swatches: fresh<Fill[]>(() => []),\n legend: Types.custom<LegendConfig>(DEFAULT_LEGEND),\n /**\n * How far each entry is shown, `0`-`1`, driving its length, opacity and gap\n * together. Entries are never added or removed: \"is this node a child\" is not\n * a function of time, while collapsed-but-present is.\n */\n reveal: fresh<number[], number[] | Readonly<Record<number, number>>>(() => [], { resolve: revealOf }),\n },\n // The flow must be stated: a `Rect` with none lays children out `freeform`, stacking every entry on one spot.\n defaults: {\n flow: \"horizontal\",\n width: \"hug\",\n height: \"hug\",\n gap: (state) => (state.flow === \"vertical\" ? Math.round(state.legend.itemGap * 0.4) : state.legend.itemGap),\n padding: (state) => state.legend.padding,\n align: (state) => (state.flow === \"vertical\" ? \"centerLeft\" : \"center\"),\n reveal: (state) => state.series.map((s) => ((s.enabled ?? true) ? 1 : 0)),\n },\n // Every entry stays a child, so one always comes back where it belongs.\n children: (state) => {\n const marker = () => state.legend.markerStyle\n const along = state.flow === \"vertical\" ? \"vertical\" : \"horizontal\"\n return state.series.map((series, index) =>\n LegendEntry({\n flow: \"horizontal\",\n gap: () => Math.round(((state.legend.textStyle.fontSize as number | undefined) ?? 24) * 0.45),\n align: \"center\",\n width: \"hug\",\n height: \"hug\",\n along,\n // The length follows the reveal in `measure`, and the flanking gap closes with the entry.\n opacity: () => state.reveal[index] ?? 0,\n gapScale: () => state.reveal[index] ?? 0,\n shown: () => state.reveal[index] ?? 0,\n children: [\n Rect({\n width: () => marker().width,\n height: () => marker().height,\n cornerRadius: () => marker().borderRadius,\n fill: () => state.swatches[index] ?? \"white\",\n stroke: () => marker().stroke,\n shadow: () => marker().shadow,\n }),\n Text({ ...boundText(() => state.legend.textStyle), text: series.label || series.field }),\n ],\n })\n )\n },\n commands: {\n ...Paint.commands,\n /** Grow series `index`'s entry back in at its position, the siblings sliding over. */\n showSeries: {\n args: { index: Types.number(0, { min: 0, step: 1 }) },\n // An index that is not a series takes its slot and moves nothing.\n run: (timeline, state) => (timeline.args.index in state.series\n ? timeline.animate(revealFrame(state, timeline.args.index, 1, frameEase(timeline)))\n : timeline.wait(timeline.duration)),\n },\n /** The mirror of `showSeries`. */\n hideSeries: {\n args: { index: Types.number(0, { min: 0, step: 1 }) },\n run: (timeline, state) => (timeline.args.index in state.series\n ? timeline.animate(revealFrame(state, timeline.args.index, 0, frameEase(timeline)))\n : timeline.wait(timeline.duration)),\n },\n /** Dim every entry but `index` to {@link SPOTLIGHT_DIM}, in place. A hidden series' entry is left as `hideSeries` left it. */\n spotlightSeries: {\n args: { index: Types.number(0, { min: 0, step: 1 }) },\n run: (timeline, state, children) =>\n timeline.together(\n children.flatMap((entry, i) =>\n (state.reveal[i] ?? 0) > 0 ? [entry.to({ opacity: i === timeline.args.index ? 1 : SPOTLIGHT_DIM })] : []\n )\n ),\n },\n },\n measure: (measurer, state, children) => Flow.measure(measurer, state, children, Paint.inset(state)),\n layout: (box, state, children) => Flow.layout(box, state, children, Paint.inset(state)),\n render: (ctx, state) => Paint.draw(ctx, state, Shapes.rect(ctx.size, state)),\n})\n\n/** One entry's reveal ramping to `target` from where the command finds it, so a hide after a show starts where the show left it. */\nfunction revealFrame(state: { readonly reveal: readonly number[] }, index: number, target: number, ease: (t: number) => number) {\n const from = state.reveal[index] ?? 0\n return (t: number) => ({ reveal: { [index]: from + (target - from) * ease(t) } })\n}\n\nexport type ChartLegend = NodeOf<typeof ChartLegend>\n"]}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { type NodeOf, type Node2D, type Node2DProps as _Node2DProps } from "@motionscript/sdk";
|
|
2
|
-
import { type Arrival } from "
|
|
3
|
-
import { type AxisConfig, type Range } from "
|
|
2
|
+
import { type Arrival } from "./motion.js";
|
|
3
|
+
import { type AxisConfig, type Range } from "./shared.js";
|
|
4
4
|
/**
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
5
|
+
* A row of {@link Text} markers under the plot, the mirror of `VerticalAxis`
|
|
6
|
+
* (bound text and positions, landed resting state). Markers are placed by value
|
|
7
|
+
* across the range, whatever they say: `2026-03` sits three months along, not
|
|
8
|
+
* three slots along, unlike a bar chart's category axis. An end marker may hang
|
|
9
|
+
* past the row by `overhang` px on either side, then is held inside it.
|
|
9
10
|
*/
|
|
10
11
|
export declare const HorizontalAxis: import("@motionscript/sdk").Component<"horizontalAxis", import("@motionscript/sdk").Merge<import("@motionscript/sdk").Box2DState, {
|
|
11
12
|
readonly range: import("@motionscript/sdk").Type<Range, Range, false>;
|
|
@@ -16,6 +17,14 @@ export declare const HorizontalAxis: import("@motionscript/sdk").Component<"hori
|
|
|
16
17
|
readonly axis: import("@motionscript/sdk").Type<AxisConfig, AxisConfig, false>;
|
|
17
18
|
/** Caption centred beneath the markers; empty hides it. */
|
|
18
19
|
readonly label: "";
|
|
20
|
+
/** How far past the row's left and right ends a marker may reach, in px. */
|
|
21
|
+
readonly overhang: import("@motionscript/sdk").Type<{
|
|
22
|
+
left: number;
|
|
23
|
+
right: number;
|
|
24
|
+
}, {
|
|
25
|
+
left: number;
|
|
26
|
+
right: number;
|
|
27
|
+
}, false>;
|
|
19
28
|
readonly arrivals: import("@motionscript/sdk").Type<Readonly<Record<string, Arrival>>, Readonly<Record<string, Arrival>>, false>;
|
|
20
29
|
}>, {
|
|
21
30
|
readonly enter: {
|
|
@@ -31,6 +40,14 @@ export declare const HorizontalAxis: import("@motionscript/sdk").Component<"hori
|
|
|
31
40
|
readonly axis: import("@motionscript/sdk").Type<AxisConfig, AxisConfig, false>;
|
|
32
41
|
/** Caption centred beneath the markers; empty hides it. */
|
|
33
42
|
readonly label: "";
|
|
43
|
+
/** How far past the row's left and right ends a marker may reach, in px. */
|
|
44
|
+
readonly overhang: import("@motionscript/sdk").Type<{
|
|
45
|
+
left: number;
|
|
46
|
+
right: number;
|
|
47
|
+
}, {
|
|
48
|
+
left: number;
|
|
49
|
+
right: number;
|
|
50
|
+
}, false>;
|
|
34
51
|
readonly arrivals: import("@motionscript/sdk").Type<Readonly<Record<string, Arrival>>, Readonly<Record<string, Arrival>>, false>;
|
|
35
52
|
}>, null, import("@motionscript/sdk").BuiltNode<import("@motionscript/sdk").Merge<import("@motionscript/sdk").Box2DState, {
|
|
36
53
|
readonly range: import("@motionscript/sdk").Type<Range, Range, false>;
|
|
@@ -41,6 +58,14 @@ export declare const HorizontalAxis: import("@motionscript/sdk").Component<"hori
|
|
|
41
58
|
readonly axis: import("@motionscript/sdk").Type<AxisConfig, AxisConfig, false>;
|
|
42
59
|
/** Caption centred beneath the markers; empty hides it. */
|
|
43
60
|
readonly label: "";
|
|
61
|
+
/** How far past the row's left and right ends a marker may reach, in px. */
|
|
62
|
+
readonly overhang: import("@motionscript/sdk").Type<{
|
|
63
|
+
left: number;
|
|
64
|
+
right: number;
|
|
65
|
+
}, {
|
|
66
|
+
left: number;
|
|
67
|
+
right: number;
|
|
68
|
+
}, false>;
|
|
44
69
|
readonly arrivals: import("@motionscript/sdk").Type<Readonly<Record<string, Arrival>>, Readonly<Record<string, Arrival>>, false>;
|
|
45
70
|
}>, {
|
|
46
71
|
readonly enter: {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"horizontal-axis.d.ts","sourceRoot":"","sources":["../../src/kit/horizontal-axis.ts"],"names":[],"mappings":"AAAA,OAAO,EAKL,KAAK,MAAM,EAEX,KAAK,MAAM,EACX,KAAK,WAAW,IAAI,YAAY,EACjC,MAAM,mBAAmB,CAAA;AAK1B,OAAO,EAA8D,KAAK,OAAO,EAAE,MAAM,UAAU,CAAA;AACnG,OAAO,EAAkB,KAAK,UAAU,EAAE,KAAK,KAAK,EAAE,MAAM,UAAU,CAAA;AAKtE;;;;;;GAMG;AACH,eAAO,MAAM,cAAc;;IAIvB,iCAAiC;;IAEjC,0FAA0F;;;IAG1F,2DAA2D;;IAE3D,4EAA4E;;cAC7C,MAAM;eAAS,MAAM;;cAArB,MAAM;eAAS,MAAM;;;;;;;;;;IARpD,iCAAiC;;IAEjC,0FAA0F;;;IAG1F,2DAA2D;;IAE3D,4EAA4E;;cAC7C,MAAM;eAAS,MAAM;;cAArB,MAAM;eAAS,MAAM;;;;;IARpD,iCAAiC;;IAEjC,0FAA0F;;;IAG1F,2DAA2D;;IAE3D,4EAA4E;;cAC7C,MAAM;eAAS,MAAM;;cAArB,MAAM;eAAS,MAAM;;;;;;;;0BAwEtD,CAAA;AAEF,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC,OAAO,cAAc,CAAC,CAAA"}
|
|
@@ -1,15 +1,17 @@
|
|
|
1
|
-
import { Rect, Text, Types, component2d,
|
|
1
|
+
import { Rect, Text, Types, component2d, } from "@motionscript/sdk";
|
|
2
2
|
import { enterBudget } from "@motionscript/sdk/component";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
3
|
+
import { boundText } from "./cartesian.js";
|
|
4
|
+
import { asParts, fresh } from "./entries.js";
|
|
5
|
+
import { armed, arrival, arrivalOf, arrivalsEntry, beats, frameEase } from "./motion.js";
|
|
6
|
+
import { DEFAULT_X_AXIS } from "./shared.js";
|
|
7
|
+
import { axisPads, markerCaption } from "./vertical-axis.js";
|
|
7
8
|
const SLIDE = 24;
|
|
8
9
|
/**
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
10
|
+
* A row of {@link Text} markers under the plot, the mirror of `VerticalAxis`
|
|
11
|
+
* (bound text and positions, landed resting state). Markers are placed by value
|
|
12
|
+
* across the range, whatever they say: `2026-03` sits three months along, not
|
|
13
|
+
* three slots along, unlike a bar chart's category axis. An end marker may hang
|
|
14
|
+
* past the row by `overhang` px on either side, then is held inside it.
|
|
13
15
|
*/
|
|
14
16
|
export const HorizontalAxis = component2d({
|
|
15
17
|
key: "horizontalAxis",
|
|
@@ -22,16 +24,14 @@ export const HorizontalAxis = component2d({
|
|
|
22
24
|
axis: Types.custom(DEFAULT_X_AXIS),
|
|
23
25
|
/** Caption centred beneath the markers; empty hides it. */
|
|
24
26
|
label: "",
|
|
27
|
+
/** How far past the row's left and right ends a marker may reach, in px. */
|
|
28
|
+
overhang: Types.custom({ left: 0, right: 0 }),
|
|
25
29
|
arrivals: arrivalsEntry(),
|
|
26
30
|
},
|
|
27
31
|
// A node made of markers would otherwise hug them.
|
|
28
32
|
defaults: { width: "fill", height: "fill" },
|
|
29
33
|
children: (state) => {
|
|
30
|
-
const
|
|
31
|
-
const titlePad = insetsOps.resolve(state.axis.titlePadding).top;
|
|
32
|
-
const column = [];
|
|
33
|
-
// The column's parent is the axis, whose box the markers are placed in.
|
|
34
|
-
const box = () => column[0]?.parent?.layoutBounds ?? { width: 0, height: 0 };
|
|
34
|
+
const pads = () => axisPads(state.axis, "top");
|
|
35
35
|
const sorted = () => [...state.markers].sort((a, b) => a - b);
|
|
36
36
|
const fracAt = (value) => {
|
|
37
37
|
if (value === undefined)
|
|
@@ -40,18 +40,18 @@ export const HorizontalAxis = component2d({
|
|
|
40
40
|
return max <= min ? 0 : (value - min) / (max - min);
|
|
41
41
|
};
|
|
42
42
|
const markers = state.markers.map((_, i) => {
|
|
43
|
+
const width = () => marker.parent?.layoutBounds.width ?? 0;
|
|
43
44
|
const marker = new Text({
|
|
44
|
-
...
|
|
45
|
+
...boundText(() => state.axis.labelStyle),
|
|
45
46
|
text: () => {
|
|
46
47
|
const value = sorted()[i];
|
|
47
48
|
return value === undefined ? "" : markerCaption(state, value);
|
|
48
49
|
},
|
|
49
50
|
x: () => {
|
|
50
|
-
const
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
return Math.min(centred, limit);
|
|
51
|
+
const w = width();
|
|
52
|
+
const half = marker.layoutBounds.width / 2;
|
|
53
|
+
const centred = (fracAt(sorted()[i]) - 0.5) * w;
|
|
54
|
+
return Math.max(-w / 2 - state.overhang.left + half, Math.min(w / 2 + state.overhang.right - half, centred));
|
|
55
55
|
},
|
|
56
56
|
opacity: () => arrivalOf(state.arrivals, i).opacity,
|
|
57
57
|
y: () => arrivalOf(state.arrivals, i).shift,
|
|
@@ -59,18 +59,17 @@ export const HorizontalAxis = component2d({
|
|
|
59
59
|
return marker;
|
|
60
60
|
});
|
|
61
61
|
const children = [
|
|
62
|
-
new Rect({ width: "fill", height: "hug", padding: { top:
|
|
62
|
+
new Rect({ width: "fill", height: "hug", padding: () => ({ top: pads().tick }), children: markers }),
|
|
63
63
|
];
|
|
64
64
|
if (state.label !== "") {
|
|
65
65
|
children.push(new Text({
|
|
66
|
-
...
|
|
66
|
+
...boundText(() => state.axis.titleStyle),
|
|
67
67
|
text: state.label,
|
|
68
68
|
opacity: () => arrivalOf(state.arrivals, "label").opacity,
|
|
69
69
|
y: () => arrivalOf(state.arrivals, "label").shift,
|
|
70
70
|
}));
|
|
71
71
|
}
|
|
72
|
-
|
|
73
|
-
return asParts(column);
|
|
72
|
+
return asParts([new Rect({ flow: "vertical", gap: () => pads().title, height: "hug", width: "fill", children })]);
|
|
74
73
|
},
|
|
75
74
|
commands: {
|
|
76
75
|
/** Stagger markers in left to right, then the caption. The duration is the whole entrance ({@link enterBudget}). */
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"horizontal-axis.js","sourceRoot":"","sources":["../../src/kit/horizontal-axis.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n Rect,\n Text,\n Types,\n component2d,\n type NodeOf,\n // Named so this component's emitted type reaches `Node2D` and its props through the sdk, not core.\n type Node2D,\n type Node2DProps as _Node2DProps,\n} from \"@motionscript/sdk\"\nimport { enterBudget } from \"@motionscript/sdk/component\"\n\nimport { boundText } from \"./cartesian\"\nimport { asParts, fresh } from \"./entries\"\nimport { armed, arrival, arrivalOf, arrivalsEntry, beats, frameEase, type Arrival } from \"./motion\"\nimport { DEFAULT_X_AXIS, type AxisConfig, type Range } from \"./shared\"\nimport { axisPads, markerCaption } from \"./vertical-axis\"\n\nconst SLIDE = 24\n\n/**\n * A row of {@link Text} markers under the plot, the mirror of `VerticalAxis`\n * (bound text and positions, landed resting state). Markers are placed by value\n * across the range, whatever they say: `2026-03` sits three months along, not\n * three slots along, unlike a bar chart's category axis. An end marker may hang\n * past the row by `overhang` px on either side, then is held inside it.\n */\nexport const HorizontalAxis = component2d({\n key: \"horizontalAxis\",\n state: {\n range: fresh<Range>(() => [0, 1]),\n /** Tick values in data units. */\n markers: fresh<number[]>(() => []),\n /** One caption per marker in its order; a missing one reads as the bare numeric value. */\n captions: fresh<string[]>(() => []),\n axis: Types.custom<AxisConfig>(DEFAULT_X_AXIS),\n /** Caption centred beneath the markers; empty hides it. */\n label: \"\",\n /** How far past the row's left and right ends a marker may reach, in px. */\n overhang: Types.custom<{ left: number; right: number }>({ left: 0, right: 0 }),\n arrivals: arrivalsEntry(),\n },\n // A node made of markers would otherwise hug them.\n defaults: { width: \"fill\", height: \"fill\" },\n children: (state) => {\n const pads = () => axisPads(state.axis, \"top\")\n const sorted = () => [...state.markers].sort((a, b) => a - b)\n const fracAt = (value: number | undefined) => {\n if (value === undefined) return 0\n const [min, max] = state.range\n return max <= min ? 0 : (value - min) / (max - min)\n }\n\n const markers = state.markers.map((_, i) => {\n const width = () => (marker.parent as Node2D | null)?.layoutBounds.width ?? 0\n const marker: Node2D = new Text({\n ...boundText(() => state.axis.labelStyle),\n text: () => {\n const value = sorted()[i]\n return value === undefined ? \"\" : markerCaption(state, value)\n },\n x: () => {\n const w = width()\n const half = marker.layoutBounds.width / 2\n const centred = (fracAt(sorted()[i]) - 0.5) * w\n return Math.max(-w / 2 - state.overhang.left + half, Math.min(w / 2 + state.overhang.right - half, centred))\n },\n opacity: () => arrivalOf(state.arrivals, i).opacity,\n y: () => arrivalOf(state.arrivals, i).shift,\n })\n return marker\n })\n\n const children: Node2D[] = [\n new Rect({ width: \"fill\", height: \"hug\", padding: () => ({ top: pads().tick }), children: markers }) as unknown as Node2D,\n ]\n if (state.label !== \"\") {\n children.push(\n new Text({\n ...boundText(() => state.axis.titleStyle),\n text: state.label,\n opacity: () => arrivalOf(state.arrivals, \"label\").opacity,\n y: () => arrivalOf(state.arrivals, \"label\").shift,\n }) as unknown as Node2D\n )\n }\n return asParts([new Rect({ flow: \"vertical\", gap: () => pads().title, height: \"hug\", width: \"fill\", children }) as unknown as Node2D])\n },\n commands: {\n /** Stagger markers in left to right, then the caption. The duration is the whole entrance ({@link enterBudget}). */\n enter: {\n args: {\n stagger: Types.custom<number | undefined>(undefined),\n slide: Types.number(SLIDE),\n },\n run: (timeline, state) => {\n const { stagger, slide } = timeline.args\n const count = state.markers.length\n const captioned = state.label !== \"\"\n const from: Arrival = { opacity: 0, shift: slide }\n const keys = [...state.markers.keys(), ...(captioned ? [\"label\"] : [])]\n const arm = timeline.animate(() => ({ arrivals: armed(keys, from) }))\n if (count === 0) return arm\n const { step, per, caption } = enterBudget(timeline.duration, count, captioned, stagger)\n const ease = frameEase(timeline)\n const markers = state.markers.map((_, i) => ({ at: i * step, duration: per, piece: arrival(timeline, i, from, ease) }))\n const label = captioned ? [{ at: (count - 1) * step + per, duration: caption, piece: arrival(timeline, \"label\", from, ease) }] : []\n return timeline.together([arm, beats(timeline, [...markers, ...label])])\n },\n },\n },\n})\n\nexport type HorizontalAxis = NodeOf<typeof HorizontalAxis>\n"]}
|
package/dist/kit/motion.d.ts
CHANGED
|
@@ -3,6 +3,11 @@ import { type EasingFunction, type Piece, type Timeline } from "@motionscript/sd
|
|
|
3
3
|
export type AnyTimeline = Timeline<any, any>;
|
|
4
4
|
/** How far a legend starts below its slot when `enter` brings it in, in px. */
|
|
5
5
|
export declare const LEGEND_SLIDE = 20;
|
|
6
|
+
/** Where a legend waits before it comes up: below its place, above it, or to its right. */
|
|
7
|
+
export declare function legendAway(at: string): {
|
|
8
|
+
x?: number;
|
|
9
|
+
y?: number;
|
|
10
|
+
};
|
|
6
11
|
/** Marker count when an axis states no ticks. */
|
|
7
12
|
export declare const DEFAULT_MARKERS = 5;
|
|
8
13
|
/** How a cartesian `enter` splits its duration: axes arriving, marks drawing, legend coming up. Sums to 1. */
|
package/dist/kit/motion.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"motion.d.ts","sourceRoot":"","sources":["../../src/kit/motion.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,KAAK,cAAc,EAAE,KAAK,KAAK,EAAE,KAAK,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAIlG,oGAAoG;AACpG,MAAM,MAAM,WAAW,GAAG,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAC,CAAA;AAE5C,+EAA+E;AAC/E,eAAO,MAAM,YAAY,KAAK,CAAA;AAE9B,iDAAiD;AACjD,eAAO,MAAM,eAAe,IAAI,CAAA;AAEhC,8GAA8G;AAC9G,eAAO,MAAM,WAAW;;;;CAAoD,CAAA;AAE5E;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,QAAQ,EAAE;IAAE,QAAQ,CAAC,MAAM,EAAE,cAAc,GAAG,SAAS,CAAA;CAAE,GAAG,cAAc,CAEnG;AAED,8FAA8F;AAC9F,MAAM,WAAW,IAAI;IACnB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAA;CACtB;AAED;;;;;GAKG;AACH,wBAAgB,KAAK,CAAC,QAAQ,EAAE,WAAW,EAAE,KAAK,EAAE,SAAS,IAAI,EAAE,GAAG,KAAK,CAW1E;AAED,gHAAgH;AAChH,MAAM,WAAW,OAAO;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CACvB;AAED,kEAAkE;AAClE,MAAM,MAAM,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAA;AAIxD;;;;GAIG;AACH,wBAAgB,aAAa,kHAE5B;AAED,wBAAgB,SAAS,CAAC,QAAQ,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAE3E;AAED,gFAAgF;AAChF,wBAAgB,KAAK,CAAC,IAAI,EAAE,SAAS,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,EAAE,IAAI,EAAE,OAAO,GAAG,QAAQ,CAIjF;AAED;;;GAGG;AACH,wBAAgB,OAAO,CAAC,QAAQ,EAAE,WAAW,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,cAAc,GAAG,KAAK,CAY/G"}
|
|
1
|
+
{"version":3,"file":"motion.d.ts","sourceRoot":"","sources":["../../src/kit/motion.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,KAAK,cAAc,EAAE,KAAK,KAAK,EAAE,KAAK,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAIlG,oGAAoG;AACpG,MAAM,MAAM,WAAW,GAAG,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAC,CAAA;AAE5C,+EAA+E;AAC/E,eAAO,MAAM,YAAY,KAAK,CAAA;AAE9B,2FAA2F;AAC3F,wBAAgB,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG;IAAE,CAAC,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,CAAC,EAAE,MAAM,CAAA;CAAE,CAIjE;AAED,iDAAiD;AACjD,eAAO,MAAM,eAAe,IAAI,CAAA;AAEhC,8GAA8G;AAC9G,eAAO,MAAM,WAAW;;;;CAAoD,CAAA;AAE5E;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,QAAQ,EAAE;IAAE,QAAQ,CAAC,MAAM,EAAE,cAAc,GAAG,SAAS,CAAA;CAAE,GAAG,cAAc,CAEnG;AAED,8FAA8F;AAC9F,MAAM,WAAW,IAAI;IACnB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAA;CACtB;AAED;;;;;GAKG;AACH,wBAAgB,KAAK,CAAC,QAAQ,EAAE,WAAW,EAAE,KAAK,EAAE,SAAS,IAAI,EAAE,GAAG,KAAK,CAW1E;AAED,gHAAgH;AAChH,MAAM,WAAW,OAAO;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CACvB;AAED,kEAAkE;AAClE,MAAM,MAAM,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAA;AAIxD;;;;GAIG;AACH,wBAAgB,aAAa,kHAE5B;AAED,wBAAgB,SAAS,CAAC,QAAQ,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAE3E;AAED,gFAAgF;AAChF,wBAAgB,KAAK,CAAC,IAAI,EAAE,SAAS,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,EAAE,IAAI,EAAE,OAAO,GAAG,QAAQ,CAIjF;AAED;;;GAGG;AACH,wBAAgB,OAAO,CAAC,QAAQ,EAAE,WAAW,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,cAAc,GAAG,KAAK,CAY/G"}
|
package/dist/kit/motion.js
CHANGED
|
@@ -2,6 +2,14 @@ import { Types, easeOut } from "@motionscript/sdk";
|
|
|
2
2
|
const identity = (t) => t;
|
|
3
3
|
/** How far a legend starts below its slot when `enter` brings it in, in px. */
|
|
4
4
|
export const LEGEND_SLIDE = 20;
|
|
5
|
+
/** Where a legend waits before it comes up: below its place, above it, or to its right. */
|
|
6
|
+
export function legendAway(at) {
|
|
7
|
+
if (at === "top")
|
|
8
|
+
return { y: LEGEND_SLIDE };
|
|
9
|
+
if (at === "right")
|
|
10
|
+
return { x: LEGEND_SLIDE };
|
|
11
|
+
return { y: -LEGEND_SLIDE };
|
|
12
|
+
}
|
|
5
13
|
/** Marker count when an axis states no ticks. */
|
|
6
14
|
export const DEFAULT_MARKERS = 5;
|
|
7
15
|
/** How a cartesian `enter` splits its duration: axes arriving, marks drawing, legend coming up. Sums to 1. */
|
package/dist/kit/motion.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"motion.js","sourceRoot":"","sources":["../../src/kit/motion.ts"],"names":[],"mappings":"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","sourcesContent":["import { Types, easeOut, type EasingFunction, type Piece, type Timeline } from \"@motionscript/sdk\"\n\nconst identity: EasingFunction = (t) => t\n\n/** Any component's timeline: these helpers only build pieces, which every timeline builds alike. */\nexport type AnyTimeline = Timeline<any, any>\n\n/** How far a legend starts below its slot when `enter` brings it in, in px. */\nexport const LEGEND_SLIDE = 20\n\n/** Marker count when an axis states no ticks. */\nexport const DEFAULT_MARKERS = 5\n\n/** How a cartesian `enter` splits its duration: axes arriving, marks drawing, legend coming up. Sums to 1. */\nexport const ENTER_SHARE = { axes: 0.35, marks: 0.5, legend: 0.15 } as const\n\n/**\n * The ease a part's own frames apply to `t`: none when its command was given\n * one, which already eases every frame the command builds, and otherwise the\n * ease-out every chart command defaults to.\n */\nexport function frameEase(timeline: { readonly easing: EasingFunction | undefined }): EasingFunction {\n return timeline.easing ? identity : easeOut()\n}\n\n/** A piece of a command placed at its own time: from `at` seconds, for `duration` seconds. */\nexport interface Beat {\n readonly at: number\n readonly duration: number\n readonly piece: Piece\n}\n\n/**\n * `beats` at their own offsets over the command, each eased on its own and held\n * at its last frame once it is done. A beat ahead of the playhead writes nothing,\n * so whatever stands before it is written by a piece ahead of these. Beats that\n * run past the command are played faster to end with it.\n */\nexport function beats(timeline: AnyTimeline, parts: readonly Beat[]): Piece {\n const total = timeline.duration\n const natural = parts.reduce((end, part) => Math.max(end, part.at + part.duration), 0)\n const k = natural > total && natural > 0 ? total / natural : 1\n return timeline.together(\n parts.map(({ at, duration, piece }) => {\n const start = at * k\n const length = duration * k\n return timeline.sequence([timeline.wait(start), piece, timeline.wait(Math.max(0, total - start - length))])\n })\n )\n}\n\n/** How far one piece of a staggered entrance has come: its opacity, and how far it still sits off its place. */\nexport interface Arrival {\n readonly opacity: number\n readonly shift: number\n}\n\n/** Each piece's arrival, by key. An unlisted piece has landed. */\nexport type Arrivals = Readonly<Record<string, Arrival>>\n\nconst LANDED: Arrival = { opacity: 1, shift: 0 }\n\n/**\n * A part's private record of its pieces' arrivals. A write merges into it, so\n * beats placed apart each write their own piece and leave the others as the\n * frame left them.\n */\nexport function arrivalsEntry() {\n return Types.custom<Arrivals>({}, { private: true, resolve: (next: Arrivals, previous?: Arrivals) => ({ ...previous, ...next }) })\n}\n\nexport function arrivalOf(arrivals: Arrivals, key: string | number): Arrival {\n return arrivals[key] ?? LANDED\n}\n\n/** Every piece in `keys` armed at `from`: the first frame of their entrance. */\nexport function armed(keys: readonly (string | number)[], from: Arrival): Arrivals {\n const record: Record<string, Arrival> = {}\n for (const key of keys) record[key] = from\n return record\n}\n\n/**\n * A piece arriving from `from` over its beat: a part armed at `from` tweened to\n * `{ opacity: 1, [axis]: 0 }`, eased by `ease`.\n */\nexport function arrival(timeline: AnyTimeline, key: string | number, from: Arrival, ease: EasingFunction): Piece {\n return timeline.animate((t) => {\n const e = ease(t)\n return {\n arrivals: {\n [key]: {\n opacity: from.opacity + (LANDED.opacity - from.opacity) * e,\n shift: from.shift + (LANDED.shift - from.shift) * e,\n },\n },\n }\n })\n}\n"]}
|
|
1
|
+
{"version":3,"file":"motion.js","sourceRoot":"","sources":["../../src/kit/motion.ts"],"names":[],"mappings":"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","sourcesContent":["import { Types, easeOut, type EasingFunction, type Piece, type Timeline } from \"@motionscript/sdk\"\n\nconst identity: EasingFunction = (t) => t\n\n/** Any component's timeline: these helpers only build pieces, which every timeline builds alike. */\nexport type AnyTimeline = Timeline<any, any>\n\n/** How far a legend starts below its slot when `enter` brings it in, in px. */\nexport const LEGEND_SLIDE = 20\n\n/** Where a legend waits before it comes up: below its place, above it, or to its right. */\nexport function legendAway(at: string): { x?: number; y?: number } {\n if (at === \"top\") return { y: LEGEND_SLIDE }\n if (at === \"right\") return { x: LEGEND_SLIDE }\n return { y: -LEGEND_SLIDE }\n}\n\n/** Marker count when an axis states no ticks. */\nexport const DEFAULT_MARKERS = 5\n\n/** How a cartesian `enter` splits its duration: axes arriving, marks drawing, legend coming up. Sums to 1. */\nexport const ENTER_SHARE = { axes: 0.35, marks: 0.5, legend: 0.15 } as const\n\n/**\n * The ease a part's own frames apply to `t`: none when its command was given\n * one, which already eases every frame the command builds, and otherwise the\n * ease-out every chart command defaults to.\n */\nexport function frameEase(timeline: { readonly easing: EasingFunction | undefined }): EasingFunction {\n return timeline.easing ? identity : easeOut()\n}\n\n/** A piece of a command placed at its own time: from `at` seconds, for `duration` seconds. */\nexport interface Beat {\n readonly at: number\n readonly duration: number\n readonly piece: Piece\n}\n\n/**\n * `beats` at their own offsets over the command, each eased on its own and held\n * at its last frame once it is done. A beat ahead of the playhead writes nothing,\n * so whatever stands before it is written by a piece ahead of these. Beats that\n * run past the command are played faster to end with it.\n */\nexport function beats(timeline: AnyTimeline, parts: readonly Beat[]): Piece {\n const total = timeline.duration\n const natural = parts.reduce((end, part) => Math.max(end, part.at + part.duration), 0)\n const k = natural > total && natural > 0 ? total / natural : 1\n return timeline.together(\n parts.map(({ at, duration, piece }) => {\n const start = at * k\n const length = duration * k\n return timeline.sequence([timeline.wait(start), piece, timeline.wait(Math.max(0, total - start - length))])\n })\n )\n}\n\n/** How far one piece of a staggered entrance has come: its opacity, and how far it still sits off its place. */\nexport interface Arrival {\n readonly opacity: number\n readonly shift: number\n}\n\n/** Each piece's arrival, by key. An unlisted piece has landed. */\nexport type Arrivals = Readonly<Record<string, Arrival>>\n\nconst LANDED: Arrival = { opacity: 1, shift: 0 }\n\n/**\n * A part's private record of its pieces' arrivals. A write merges into it, so\n * beats placed apart each write their own piece and leave the others as the\n * frame left them.\n */\nexport function arrivalsEntry() {\n return Types.custom<Arrivals>({}, { private: true, resolve: (next: Arrivals, previous?: Arrivals) => ({ ...previous, ...next }) })\n}\n\nexport function arrivalOf(arrivals: Arrivals, key: string | number): Arrival {\n return arrivals[key] ?? LANDED\n}\n\n/** Every piece in `keys` armed at `from`: the first frame of their entrance. */\nexport function armed(keys: readonly (string | number)[], from: Arrival): Arrivals {\n const record: Record<string, Arrival> = {}\n for (const key of keys) record[key] = from\n return record\n}\n\n/**\n * A piece arriving from `from` over its beat: a part armed at `from` tweened to\n * `{ opacity: 1, [axis]: 0 }`, eased by `ease`.\n */\nexport function arrival(timeline: AnyTimeline, key: string | number, from: Arrival, ease: EasingFunction): Piece {\n return timeline.animate((t) => {\n const e = ease(t)\n return {\n arrivals: {\n [key]: {\n opacity: from.opacity + (LANDED.opacity - from.opacity) * e,\n shift: from.shift + (LANDED.shift - from.shift) * e,\n },\n },\n }\n })\n}\n"]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type NodeOf, type Alignment as _Alignment, type CornerRadiusResolved as _CornerRadiusResolved, type CornerStyleResolved as _CornerStyleResolved, type Fill as _Fill, type FillResolved as _FillResolved, type FlowMode as _FlowMode, type FlowResolved as _FlowResolved, type GapSize as _GapSize, type Node2D as _Node2D, type Node2DProps as _Node2DProps, type RectCornerRadius as _RectCornerRadius, type RectCornerStyle as _RectCornerStyle, type Shadow as _Shadow, type ShadowResolved as _ShadowResolved, type Stroke as _Stroke, type StrokeResolved as _StrokeResolved, type Vector2 as _Vector2 } from "@motionscript/sdk";
|
|
2
|
-
import { type Arrival } from "
|
|
3
|
-
import { type LegendConfig } from "
|
|
4
|
-
import type { PieSlice } from "./
|
|
2
|
+
import { type Arrival } from "./motion.js";
|
|
3
|
+
import { type LegendConfig } from "./shared.js";
|
|
4
|
+
import type { PieSlice } from "./polar.js";
|
|
5
5
|
/**
|
|
6
6
|
* The legend of a {@link PieChart}: a column (it sits beside the ring, in the
|
|
7
7
|
* vertical strip it leaves) of caption-and-swatch entries, one per slice. No
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pie-legend.d.ts","sourceRoot":"","sources":["../../src/kit/pie-legend.ts"],"names":[],"mappings":"AAAA,OAAO,EAUL,KAAK,MAAM,EAEX,KAAK,SAAS,IAAI,UAAU,EAC5B,KAAK,oBAAoB,IAAI,qBAAqB,EAClD,KAAK,mBAAmB,IAAI,oBAAoB,EAChD,KAAK,IAAI,IAAI,KAAK,EAClB,KAAK,YAAY,IAAI,aAAa,EAClC,KAAK,QAAQ,IAAI,SAAS,EAC1B,KAAK,YAAY,IAAI,aAAa,EAClC,KAAK,OAAO,IAAI,QAAQ,EACxB,KAAK,MAAM,IAAI,OAAO,EACtB,KAAK,WAAW,IAAI,YAAY,EAChC,KAAK,gBAAgB,IAAI,iBAAiB,EAC1C,KAAK,eAAe,IAAI,gBAAgB,EACxC,KAAK,MAAM,IAAI,OAAO,EACtB,KAAK,cAAc,IAAI,eAAe,EACtC,KAAK,MAAM,IAAI,OAAO,EACtB,KAAK,cAAc,IAAI,eAAe,EACtC,KAAK,OAAO,IAAI,QAAQ,EACzB,MAAM,mBAAmB,CAAA;AAG1B,OAAO,EAA8D,KAAK,OAAO,EAAE,MAAM,UAAU,CAAA;AACnG,OAAO,EAAkB,KAAK,YAAY,EAAE,MAAM,UAAU,CAAA;AAC5D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAA;AAIvC;;;;;GAKG;AACH,eAAO,MAAM,SAAS;IAMlB,0CAA0C;;;IAG1C,iIAAiI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAHjI,0CAA0C;;;IAG1C,iIAAiI;;;;;;;;;;;;;;;;;;IAHjI,0CAA0C;;;IAG1C,iIAAiI;;;;;;;;;;;;;;;;;;;;;;;;;;;;2BAyEnI,CAAA;AAEF,MAAM,MAAM,SAAS,GAAG,MAAM,CAAC,OAAO,SAAS,CAAC,CAAA"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Flow, Paint, Rect, Shapes, Text, Types, clamp, component2d, textOps, } from "@motionscript/sdk";
|
|
2
|
-
import { fresh } from "
|
|
3
|
-
import { armed, arrival, arrivalOf, arrivalsEntry, beats, frameEase } from "
|
|
4
|
-
import { DEFAULT_LEGEND } from "
|
|
2
|
+
import { fresh } from "./entries.js";
|
|
3
|
+
import { armed, arrival, arrivalOf, arrivalsEntry, beats, frameEase } from "./motion.js";
|
|
4
|
+
import { DEFAULT_LEGEND } from "./shared.js";
|
|
5
5
|
const SLIDE = 16;
|
|
6
6
|
/**
|
|
7
7
|
* The legend of a {@link PieChart}: a column (it sits beside the ring, in the
|
|
@@ -33,7 +33,7 @@ export const PieLegend = component2d({
|
|
|
33
33
|
},
|
|
34
34
|
// The selection dim rides a wrapper, so the entrance animates the entry's own opacity without the two fighting over one value.
|
|
35
35
|
children: (state) => {
|
|
36
|
-
const marker = state.legend.markerStyle;
|
|
36
|
+
const marker = () => state.legend.markerStyle;
|
|
37
37
|
return state.slices.map((_, index) => Rect({
|
|
38
38
|
width: "hug",
|
|
39
39
|
height: "hug",
|
|
@@ -42,7 +42,7 @@ export const PieLegend = component2d({
|
|
|
42
42
|
children: [
|
|
43
43
|
Rect({
|
|
44
44
|
flow: "horizontal",
|
|
45
|
-
gap: 12,
|
|
45
|
+
gap: () => Math.round(state.legend.textStyle.fontSize === undefined ? 12 : Number(state.legend.textStyle.fontSize) * 0.4),
|
|
46
46
|
align: "center",
|
|
47
47
|
width: "hug",
|
|
48
48
|
height: "hug",
|
|
@@ -50,15 +50,16 @@ export const PieLegend = component2d({
|
|
|
50
50
|
x: () => arrivalOf(state.arrivals, index).shift,
|
|
51
51
|
children: [
|
|
52
52
|
Rect({
|
|
53
|
-
width: marker.
|
|
54
|
-
height: marker.height,
|
|
55
|
-
cornerRadius: marker.borderRadius,
|
|
53
|
+
width: () => marker().width,
|
|
54
|
+
height: () => marker().height,
|
|
55
|
+
cornerRadius: () => marker().borderRadius,
|
|
56
56
|
fill: () => state.slices[index]?.fill ?? "white",
|
|
57
|
-
stroke: marker.stroke,
|
|
58
|
-
shadow: marker.shadow,
|
|
59
57
|
}),
|
|
60
58
|
Text({
|
|
61
59
|
...textOps.styleProps(state.legend.textStyle),
|
|
60
|
+
fill: () => state.legend.textStyle.fill ?? "white",
|
|
61
|
+
fontSize: () => state.legend.textStyle.fontSize ?? 28,
|
|
62
|
+
fontWeight: () => state.legend.textStyle.fontWeight ?? 500,
|
|
62
63
|
text: () => state.slices[index]?.category ?? "",
|
|
63
64
|
}),
|
|
64
65
|
],
|