@motionscript/charts 0.1.0-alpha.3 → 0.1.0-alpha.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (154) hide show
  1. package/CHANGELOG.md +63 -0
  2. package/LICENSE +201 -201
  3. package/NOTICE +48 -0
  4. package/README.md +99 -0
  5. package/dist/bar-chart/bar-chart.d.ts +93 -231
  6. package/dist/bar-chart/bar-chart.d.ts.map +1 -1
  7. package/dist/bar-chart/bar-chart.js +378 -565
  8. package/dist/bar-chart/bar-chart.js.map +1 -1
  9. package/dist/bar-chart/category-axis.d.ts +24 -41
  10. package/dist/bar-chart/category-axis.d.ts.map +1 -1
  11. package/dist/bar-chart/category-axis.js +93 -115
  12. package/dist/bar-chart/category-axis.js.map +1 -1
  13. package/dist/bar-chart/chart-bars.d.ts +36 -70
  14. package/dist/bar-chart/chart-bars.d.ts.map +1 -1
  15. package/dist/bar-chart/chart-bars.js +156 -210
  16. package/dist/bar-chart/chart-bars.js.map +1 -1
  17. package/dist/bar-chart/index.d.ts +2 -2
  18. package/dist/bar-chart/index.d.ts.map +1 -1
  19. package/dist/bar-chart/index.js +1 -1
  20. package/dist/bar-chart/index.js.map +1 -1
  21. package/dist/bar-chart/shared.d.ts +6 -6
  22. package/dist/bar-chart/shared.d.ts.map +1 -1
  23. package/dist/bar-chart/shared.js +6 -6
  24. package/dist/bar-chart/shared.js.map +1 -1
  25. package/dist/browser/chunks/chunk-XROBIRQK.js +2 -0
  26. package/dist/browser/chunks/chunk-XROBIRQK.js.map +7 -0
  27. package/dist/browser/index.js +1 -1
  28. package/dist/browser/index.js.map +3 -3
  29. package/dist/browser/kit.js +1 -1
  30. package/dist/browser/manifest.json +3 -2
  31. package/dist/engine.d.ts +8 -6
  32. package/dist/engine.d.ts.map +1 -1
  33. package/dist/engine.js +8 -6
  34. package/dist/engine.js.map +1 -1
  35. package/dist/index.js.map +1 -1
  36. package/dist/kit/cartesian.d.ts +44 -0
  37. package/dist/kit/cartesian.d.ts.map +1 -0
  38. package/dist/kit/cartesian.js +59 -0
  39. package/dist/kit/cartesian.js.map +1 -0
  40. package/dist/kit/chart-border.d.ts +8 -11
  41. package/dist/kit/chart-border.d.ts.map +1 -1
  42. package/dist/kit/chart-border.js +15 -32
  43. package/dist/kit/chart-border.js.map +1 -1
  44. package/dist/kit/chart-canvas.d.ts +23 -21
  45. package/dist/kit/chart-canvas.d.ts.map +1 -1
  46. package/dist/kit/chart-canvas.js +33 -90
  47. package/dist/kit/chart-canvas.js.map +1 -1
  48. package/dist/kit/chart-legend.d.ts +79 -88
  49. package/dist/kit/chart-legend.d.ts.map +1 -1
  50. package/dist/kit/chart-legend.js +137 -186
  51. package/dist/kit/chart-legend.js.map +1 -1
  52. package/dist/kit/entries.d.ts +17 -0
  53. package/dist/kit/entries.d.ts.map +1 -0
  54. package/dist/kit/entries.js +19 -0
  55. package/dist/kit/entries.js.map +1 -0
  56. package/dist/kit/motion.d.ts +48 -0
  57. package/dist/kit/motion.d.ts.map +1 -0
  58. package/dist/kit/motion.js +63 -0
  59. package/dist/kit/motion.js.map +1 -0
  60. package/dist/kit/paints.d.ts +10 -0
  61. package/dist/kit/paints.d.ts.map +1 -0
  62. package/dist/kit/paints.js +12 -0
  63. package/dist/kit/paints.js.map +1 -0
  64. package/dist/kit/shared.d.ts +59 -8
  65. package/dist/kit/shared.d.ts.map +1 -1
  66. package/dist/kit/shared.js +105 -10
  67. package/dist/kit/shared.js.map +1 -1
  68. package/dist/kit/vertical-axis.d.ts +36 -61
  69. package/dist/kit/vertical-axis.d.ts.map +1 -1
  70. package/dist/kit/vertical-axis.js +97 -132
  71. package/dist/kit/vertical-axis.js.map +1 -1
  72. package/dist/line-chart/chart-line.d.ts +27 -53
  73. package/dist/line-chart/chart-line.d.ts.map +1 -1
  74. package/dist/line-chart/chart-line.js +89 -120
  75. package/dist/line-chart/chart-line.js.map +1 -1
  76. package/dist/line-chart/chart-region.d.ts +14 -14
  77. package/dist/line-chart/chart-region.d.ts.map +1 -1
  78. package/dist/line-chart/chart-region.js +26 -64
  79. package/dist/line-chart/chart-region.js.map +1 -1
  80. package/dist/line-chart/horizontal-axis.d.ts +32 -56
  81. package/dist/line-chart/horizontal-axis.d.ts.map +1 -1
  82. package/dist/line-chart/horizontal-axis.js +85 -123
  83. package/dist/line-chart/horizontal-axis.js.map +1 -1
  84. package/dist/line-chart/index.d.ts +2 -2
  85. package/dist/line-chart/index.d.ts.map +1 -1
  86. package/dist/line-chart/index.js +1 -1
  87. package/dist/line-chart/index.js.map +1 -1
  88. package/dist/line-chart/line-chart.d.ts +111 -311
  89. package/dist/line-chart/line-chart.d.ts.map +1 -1
  90. package/dist/line-chart/line-chart.js +403 -639
  91. package/dist/line-chart/line-chart.js.map +1 -1
  92. package/dist/line-chart/shared.d.ts +6 -6
  93. package/dist/line-chart/shared.d.ts.map +1 -1
  94. package/dist/line-chart/shared.js +22 -7
  95. package/dist/line-chart/shared.js.map +1 -1
  96. package/dist/line-chart/x-scale.d.ts +1 -1
  97. package/dist/line-chart/x-scale.js +1 -1
  98. package/dist/line-chart/x-scale.js.map +1 -1
  99. package/dist/nodes.d.ts +6 -9
  100. package/dist/nodes.d.ts.map +1 -1
  101. package/dist/nodes.js +7 -9
  102. package/dist/nodes.js.map +1 -1
  103. package/dist/pie-chart/index.d.ts +2 -2
  104. package/dist/pie-chart/index.d.ts.map +1 -1
  105. package/dist/pie-chart/index.js +1 -1
  106. package/dist/pie-chart/index.js.map +1 -1
  107. package/dist/pie-chart/pie-chart.d.ts +77 -134
  108. package/dist/pie-chart/pie-chart.d.ts.map +1 -1
  109. package/dist/pie-chart/pie-chart.js +199 -268
  110. package/dist/pie-chart/pie-chart.js.map +1 -1
  111. package/dist/pie-chart/pie-legend.d.ts +54 -31
  112. package/dist/pie-chart/pie-legend.d.ts.map +1 -1
  113. package/dist/pie-chart/pie-legend.js +93 -107
  114. package/dist/pie-chart/pie-legend.js.map +1 -1
  115. package/dist/pie-chart/pie-ring.d.ts +142 -122
  116. package/dist/pie-chart/pie-ring.d.ts.map +1 -1
  117. package/dist/pie-chart/pie-ring.js +333 -361
  118. package/dist/pie-chart/pie-ring.js.map +1 -1
  119. package/dist/pie-chart/shared.d.ts +3 -3
  120. package/dist/pie-chart/shared.js +3 -3
  121. package/dist/pie-chart/shared.js.map +1 -1
  122. package/package.json +6 -5
  123. package/registry.json +23 -23
  124. package/src/bar-chart/bar-chart.ts +534 -814
  125. package/src/bar-chart/category-axis.ts +162 -177
  126. package/src/bar-chart/chart-bars.ts +288 -310
  127. package/src/bar-chart/index.ts +31 -31
  128. package/src/bar-chart/shared.ts +354 -354
  129. package/src/engine.ts +28 -26
  130. package/src/index.ts +5 -5
  131. package/src/kit/cartesian.ts +81 -0
  132. package/src/kit/chart-border.ts +50 -61
  133. package/src/kit/chart-canvas.ts +122 -157
  134. package/src/kit/chart-legend.ts +229 -250
  135. package/src/kit/entries.ts +20 -0
  136. package/src/kit/motion.ts +90 -0
  137. package/src/kit/paints.ts +15 -0
  138. package/src/kit/shared.ts +782 -675
  139. package/src/kit/vertical-axis.ts +194 -224
  140. package/src/line-chart/chart-line.ts +181 -208
  141. package/src/line-chart/chart-region.ts +106 -135
  142. package/src/line-chart/horizontal-axis.ts +166 -202
  143. package/src/line-chart/index.ts +39 -39
  144. package/src/line-chart/line-chart.ts +585 -929
  145. package/src/line-chart/shared.ts +473 -459
  146. package/src/line-chart/x-scale.ts +367 -367
  147. package/src/nodes.ts +18 -20
  148. package/src/pie-chart/index.ts +37 -37
  149. package/src/pie-chart/pie-chart.ts +293 -381
  150. package/src/pie-chart/pie-legend.ts +169 -159
  151. package/src/pie-chart/pie-ring.ts +848 -903
  152. package/src/pie-chart/shared.ts +490 -490
  153. package/dist/browser/chunks/chunk-RMHQ6GYU.js +0 -2
  154. package/dist/browser/chunks/chunk-RMHQ6GYU.js.map +0 -7
@@ -1,6 +1,6 @@
1
- import { Rect, type CommandArgs, type NodeConfig, type RectProps } from "@motionscript/sdk";
1
+ import { type NodeOf, type RectProps, 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 "../kit/motion.js";
2
3
  import { type LegendConfig } from "../kit/shared.js";
3
- import { type Seekable } from "@motionscript/sdk/component";
4
4
  import type { PieSlice } from "./shared.js";
5
5
  export interface PieLegendProps extends RectProps {
6
6
  /** One entry per slice, in ring order. */
@@ -27,34 +27,57 @@ export interface PieLegendProps extends RectProps {
27
27
  * shouldn't be in the chart shouldn't be in the table — removing one would
28
28
  * silently re-cut every other wedge's share, which is a different chart rather
29
29
  * than the same chart with something hidden. Selection is what a pie has
30
- * instead, and it arrives through {@link dims}.
30
+ * instead, and it arrives through {@link PieLegendProps.dims}.
31
31
  */
32
- export declare class PieLegend extends Rect {
33
- slices: PieSlice[];
34
- legend: LegendConfig;
35
- dims: number[];
36
- /** One entry per slice, ordered top → bottom, for the staggered entrance. */
37
- private items;
38
- constructor(props?: NodeConfig<PieLegend, PieLegendProps>);
39
- /** One entry: the slice's colour swatch beside its caption. */
40
- private buildItem;
41
- /**
42
- * Prime every entry at its pre-entrance state: shifted right and transparent.
43
- *
44
- * Idempotent, and separate from {@link enter} so the chart can arm its whole
45
- * composition before the first frame is drawn — the resting state is the
46
- * finished legend, so there is nothing hidden to reveal unless a scene asks.
47
- */
48
- arm(slide?: number): void;
49
- /**
50
- * Slide + fade every entry in from the right, staggered top-to-bottom.
51
- *
52
- * `duration` is the **whole** entrance: the stagger is carved out of it rather
53
- * than added on top, so the command takes exactly the time the timeline laid
54
- * out for it.
55
- */
56
- enter(args: CommandArgs<Record<string, never>> & {
57
- duration: number;
58
- }): Seekable;
59
- }
32
+ export declare const PieLegend: import("@motionscript/sdk").Component<"pieLegend", import("@motionscript/sdk").Merge<import("@motionscript/sdk").Box2DState, {
33
+ readonly slices: import("@motionscript/sdk").Type<PieSlice[], PieSlice[], false>;
34
+ readonly legend: import("@motionscript/sdk").Type<LegendConfig, LegendConfig, false>;
35
+ readonly dims: import("@motionscript/sdk").Type<number[], number[], false>;
36
+ readonly arrivals: import("@motionscript/sdk").Type<Readonly<Record<string, Arrival>>, Readonly<Record<string, Arrival>>, false>;
37
+ readonly cornerRadius: import("@motionscript/sdk").Attribute<_RectCornerRadius, _CornerRadiusResolved>;
38
+ readonly cornerStyle: import("@motionscript/sdk").Attribute<_RectCornerStyle, _CornerStyleResolved>;
39
+ readonly flow: import("@motionscript/sdk").Type<_FlowMode, _FlowResolved, false>;
40
+ readonly gap: import("@motionscript/sdk").Type<_GapSize, _GapSize, false>;
41
+ readonly wrap: boolean;
42
+ readonly crossGap: import("@motionscript/sdk").Type<number | undefined, number | undefined, false>;
43
+ readonly columns: import("@motionscript/sdk").Type<number, number, false>;
44
+ readonly align: import("@motionscript/sdk").Attribute<_Alignment, _Vector2>;
45
+ readonly fill: import("@motionscript/sdk").Attribute<_Fill, _FillResolved[]>;
46
+ readonly stroke: import("@motionscript/sdk").Attribute<_Stroke, _StrokeResolved[]>;
47
+ readonly shadow: import("@motionscript/sdk").Attribute<_Shadow, _ShadowResolved[]>;
48
+ readonly overlay: import("@motionscript/sdk").Attribute<_Fill, _FillResolved[]>;
49
+ readonly start: import("@motionscript/sdk").Type<number, number, false>;
50
+ readonly end: import("@motionscript/sdk").Type<number, number, false>;
51
+ }>, {
52
+ readonly arm: unknown;
53
+ readonly enter: unknown;
54
+ readonly fillTo: readonly ["fill"];
55
+ readonly strokeTo: readonly ["stroke"];
56
+ readonly shadowTo: readonly ["shadow"];
57
+ readonly overlayTo: readonly ["overlay"];
58
+ readonly progressTo: readonly ["start", "end"];
59
+ readonly flash: {
60
+ readonly portion: import("@motionscript/sdk").Type<number, number, false>;
61
+ };
62
+ }, null, _Node2D<_Node2DProps>, import("@motionscript/sdk").CallProps<import("@motionscript/sdk").Merge<import("@motionscript/sdk").Box2DState, {
63
+ readonly slices: import("@motionscript/sdk").Type<PieSlice[], PieSlice[], false>;
64
+ readonly legend: import("@motionscript/sdk").Type<LegendConfig, LegendConfig, false>;
65
+ readonly dims: import("@motionscript/sdk").Type<number[], number[], false>;
66
+ readonly arrivals: import("@motionscript/sdk").Type<Readonly<Record<string, Arrival>>, Readonly<Record<string, Arrival>>, false>;
67
+ readonly cornerRadius: import("@motionscript/sdk").Attribute<_RectCornerRadius, _CornerRadiusResolved>;
68
+ readonly cornerStyle: import("@motionscript/sdk").Attribute<_RectCornerStyle, _CornerStyleResolved>;
69
+ readonly flow: import("@motionscript/sdk").Type<_FlowMode, _FlowResolved, false>;
70
+ readonly gap: import("@motionscript/sdk").Type<_GapSize, _GapSize, false>;
71
+ readonly wrap: boolean;
72
+ readonly crossGap: import("@motionscript/sdk").Type<number | undefined, number | undefined, false>;
73
+ readonly columns: import("@motionscript/sdk").Type<number, number, false>;
74
+ readonly align: import("@motionscript/sdk").Attribute<_Alignment, _Vector2>;
75
+ readonly fill: import("@motionscript/sdk").Attribute<_Fill, _FillResolved[]>;
76
+ readonly stroke: import("@motionscript/sdk").Attribute<_Stroke, _StrokeResolved[]>;
77
+ readonly shadow: import("@motionscript/sdk").Attribute<_Shadow, _ShadowResolved[]>;
78
+ readonly overlay: import("@motionscript/sdk").Attribute<_Fill, _FillResolved[]>;
79
+ readonly start: import("@motionscript/sdk").Type<number, number, false>;
80
+ readonly end: import("@motionscript/sdk").Type<number, number, false>;
81
+ }>, null>>;
82
+ export type PieLegend = NodeOf<typeof PieLegend>;
60
83
  //# sourceMappingURL=pie-legend.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"pie-legend.d.ts","sourceRoot":"","sources":["../../src/pie-chart/pie-legend.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,IAAI,EAKJ,KAAK,WAAW,EAChB,KAAK,UAAU,EACf,KAAK,SAAS,EACf,MAAM,mBAAmB,CAAA;AAE1B,OAAO,EAGL,KAAK,YAAY,EAClB,MAAM,eAAe,CAAA;AACtB,OAAO,EAAqB,KAAK,QAAQ,EAAE,MAAM,6BAA6B,CAAA;AAC9E,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAA;AAExC,MAAM,WAAW,cAAe,SAAQ,SAAS;IAC/C,0CAA0C;IAC1C,MAAM,EAAE,QAAQ,EAAE,CAAA;IAClB,oFAAoF;IACpF,MAAM,EAAE,YAAY,CAAA;IACpB;;;OAGG;IACH,IAAI,EAAE,MAAM,EAAE,CAAA;CACf;AAKD;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,SAAU,SAAQ,IAAI;IACsB,MAAM,EAAE,QAAQ,EAAE,CAAA;IAC1B,MAAM,EAAE,YAAY,CAAA;IACd,IAAI,EAAE,MAAM,EAAE,CAAA;IAEnE,6EAA6E;IAC7E,OAAO,CAAC,KAAK,CAAa;gBAEd,KAAK,CAAC,EAAE,UAAU,CAAC,SAAS,EAAE,cAAc,CAAC;IAmCzD,+DAA+D;IAC/D,OAAO,CAAC,SAAS;IAwBjB;;;;;;OAMG;IACH,GAAG,CAAC,KAAK,SAAQ,GAAG,IAAI;IAIxB;;;;;;OAMG;IAEH,KAAK,CACH,IAAI,EAAE,WAAW,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,GAAG;QAAE,QAAQ,EAAE,MAAM,CAAA;KAAE,GAC9D,QAAQ;CAkBZ"}
1
+ {"version":3,"file":"pie-legend.d.ts","sourceRoot":"","sources":["../../src/pie-chart/pie-legend.ts"],"names":[],"mappings":"AAAA,OAAO,EASL,KAAK,MAAM,EACX,KAAK,SAAS,EAEd,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,eAAe,CAAA;AACxG,OAAO,EAGL,KAAK,YAAY,EAClB,MAAM,eAAe,CAAA;AACtB,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAA;AAExC,MAAM,WAAW,cAAe,SAAQ,SAAS;IAC/C,0CAA0C;IAC1C,MAAM,EAAE,QAAQ,EAAE,CAAA;IAClB,oFAAoF;IACpF,MAAM,EAAE,YAAY,CAAA;IACpB;;;OAGG;IACH,IAAI,EAAE,MAAM,EAAE,CAAA;CACf;AAKD;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UA+FpB,CAAA;AAEF,MAAM,MAAM,SAAS,GAAG,MAAM,CAAC,OAAO,SAAS,CAAC,CAAA"}
@@ -1,12 +1,7 @@
1
- var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
- else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
- return c > 3 && r && Object.defineProperty(target, key, r), r;
6
- };
7
- import { command, Rect, Text, easeOut, property, textOps, } from "@motionscript/sdk";
1
+ import { Flow, Paint, Rect, Shapes, Text, Types, component2d, textOps, } from "@motionscript/sdk";
2
+ import { fresh } from "../kit/entries.js";
3
+ import { armed, arrival, arrivalOf, arrivalsEntry, beats, frameEase } from "../kit/motion.js";
8
4
  import { DEFAULT_LEGEND, clampUnit, } from "../kit/shared.js";
9
- import { at, compose, hold } from "@motionscript/sdk/component";
10
5
  /** How far an entry starts to the right of its slot when it enters, in px. */
11
6
  const SLIDE = 16;
12
7
  /**
@@ -23,109 +18,100 @@ const SLIDE = 16;
23
18
  * shouldn't be in the chart shouldn't be in the table — removing one would
24
19
  * silently re-cut every other wedge's share, which is a different chart rather
25
20
  * than the same chart with something hidden. Selection is what a pie has
26
- * instead, and it arrives through {@link dims}.
21
+ * instead, and it arrives through {@link PieLegendProps.dims}.
27
22
  */
28
- export class PieLegend extends Rect {
29
- /** One entry per slice, ordered top → bottom, for the staggered entrance. */
30
- items = [];
31
- constructor(props) {
32
- // `flow` with the rest of the fixed geometry, and for the reason
33
- // {@link ChartLegend} spells out: a `Rect` given none lays its children out
34
- // `freeform`, so an unstated column is every caption drawn on top of the
35
- // last one.
36
- super({
37
- ...props,
38
- flow: "vertical",
39
- align: "centerLeft",
40
- width: "hug",
41
- height: "hug",
42
- });
43
- // Fixed column geometry last, so it wins over what super() applied.
44
- this.set({ gap: this.legend.itemGap / 3, padding: this.legend.padding });
45
- for (let i = 0; i < this.slices.length; i++) {
46
- const item = this.buildItem(this.slices[i]);
47
- this.items.push(item);
48
- // The selection dim rides a wrapper rather than the entry itself, so the
49
- // entrance can animate the entry's own opacity without the two fighting
50
- // over one value — opacity multiplies down the tree, which is exactly the
51
- // composition wanted here.
52
- this.add(new Rect({
53
- width: "hug",
54
- height: "hug",
55
- flow: "freeform",
56
- opacity: () => clampUnit(this.dims[i] ?? 1),
57
- children: [item],
58
- }));
59
- }
60
- }
61
- /** One entry: the slice's colour swatch beside its caption. */
62
- buildItem(slice) {
63
- const marker = this.legend.markerStyle;
64
- return new Rect({ flow: "horizontal",
65
- gap: 12,
66
- align: "center",
23
+ export const PieLegend = component2d({
24
+ key: "pieLegend",
25
+ state: {
26
+ ...Paint.state,
27
+ ...Flow.state,
28
+ ...Shapes.corners,
29
+ slices: fresh(() => []),
30
+ legend: Types.custom(DEFAULT_LEGEND),
31
+ dims: fresh(() => []),
32
+ arrivals: arrivalsEntry(),
33
+ },
34
+ // A column, for the reason `ChartLegend` gives for its row: a `Rect` given no
35
+ // flow lays its children out `freeform`, every caption on top of the last.
36
+ defaults: {
37
+ flow: "vertical",
38
+ align: "centerLeft",
39
+ width: "hug",
40
+ height: "hug",
41
+ gap: (state) => state.legend.itemGap / 3,
42
+ padding: (state) => state.legend.padding,
43
+ },
44
+ // One entry per slice, ordered top → bottom. The selection dim rides a wrapper
45
+ // rather than the entry itself, so the entrance can animate the entry's own
46
+ // opacity without the two fighting over one value — opacity multiplies down
47
+ // the tree, which is exactly the composition wanted here.
48
+ children: (state) => {
49
+ const marker = state.legend.markerStyle;
50
+ return state.slices.map((_, index) => Rect({
67
51
  width: "hug",
68
52
  height: "hug",
53
+ flow: "freeform",
54
+ opacity: () => clampUnit(state.dims[index] ?? 1),
69
55
  children: [
70
- new Rect({
71
- width: marker.height,
72
- height: marker.height,
73
- cornerRadius: marker.borderRadius,
74
- fill: slice.fill,
75
- stroke: marker.stroke,
76
- shadow: marker.shadow,
77
- }),
78
- new Text({
79
- ...textOps.styleProps(this.legend.textStyle),
80
- text: slice.category,
56
+ Rect({
57
+ flow: "horizontal",
58
+ gap: 12,
59
+ align: "center",
60
+ width: "hug",
61
+ height: "hug",
62
+ opacity: () => arrivalOf(state.arrivals, index).opacity,
63
+ x: () => arrivalOf(state.arrivals, index).shift,
64
+ children: [
65
+ Rect({
66
+ width: marker.height,
67
+ height: marker.height,
68
+ cornerRadius: marker.borderRadius,
69
+ fill: () => state.slices[index]?.fill ?? "white",
70
+ stroke: marker.stroke,
71
+ shadow: marker.shadow,
72
+ }),
73
+ Text({
74
+ ...textOps.styleProps(state.legend.textStyle),
75
+ text: () => state.slices[index]?.category ?? "",
76
+ }),
77
+ ],
81
78
  }),
82
79
  ],
83
- });
84
- }
85
- /**
86
- * Prime every entry at its pre-entrance state: shifted right and transparent.
87
- *
88
- * Idempotent, and separate from {@link enter} so the chart can arm its whole
89
- * composition before the first frame is drawn — the resting state is the
90
- * finished legend, so there is nothing hidden to reveal unless a scene asks.
91
- */
92
- arm(slide = SLIDE) {
93
- for (const item of this.items)
94
- item.set({ opacity: 0, x: slide });
95
- }
96
- /**
97
- * Slide + fade every entry in from the right, staggered top-to-bottom.
98
- *
99
- * `duration` is the **whole** entrance: the stagger is carved out of it rather
100
- * than added on top, so the command takes exactly the time the timeline laid
101
- * out for it.
102
- */
103
- enter(args) {
104
- const duration = args.duration;
105
- const easing = args.easing ?? easeOut();
106
- const items = this.items;
107
- if (items.length === 0)
108
- return hold(duration);
109
- this.arm();
110
- // Each gap is a fifth of an entry's own move, the rhythm the axes use;
111
- // solved for from the budget rather than added to it. The offsets were
112
- // always `i * step` — written as `wait` inside a generator they merely only
113
- // existed while it ran.
114
- const per = duration / (1 + Math.max(0, items.length - 1) / 5);
115
- const step = per / 5;
116
- return compose(items.map((item, i) => at(i * step, item.to({ data: { opacity: 1, x: 0 }, duration: per, easing }))));
117
- }
118
- }
119
- __decorate([
120
- property({ default: () => [] })
121
- ], PieLegend.prototype, "slices", void 0);
122
- __decorate([
123
- property({ default: DEFAULT_LEGEND })
124
- ], PieLegend.prototype, "legend", void 0);
125
- __decorate([
126
- property({ default: () => [] })
127
- ], PieLegend.prototype, "dims", void 0);
128
- __decorate([
129
- command()
130
- ], PieLegend.prototype, "enter", null);
80
+ }));
81
+ },
82
+ commands: {
83
+ ...Paint.commands,
84
+ /**
85
+ * Every entry at its pre-entrance state, shifted right and transparent: what
86
+ * a chart shows ahead of this legend's own beat in its entrance, since
87
+ * `enter` arms the entries only on its first frame.
88
+ */
89
+ arm: (timeline, state) => timeline.animate(() => ({ arrivals: armed([...state.slices.keys()], { opacity: 0, shift: SLIDE }) })),
90
+ /**
91
+ * Slide + fade every entry in from the right, staggered top-to-bottom. Its
92
+ * first frame arms them all: shifted right and transparent.
93
+ *
94
+ * The timeline's duration is the **whole** entrance: the stagger is carved
95
+ * out of it rather than added on top, so the command takes exactly the time
96
+ * the timeline laid out for it.
97
+ */
98
+ enter: (timeline, state) => {
99
+ const count = state.slices.length;
100
+ if (count === 0)
101
+ return timeline.wait(timeline.duration);
102
+ const from = { opacity: 0, shift: SLIDE };
103
+ const arm = timeline.animate(() => ({ arrivals: armed([...state.slices.keys()], from) }));
104
+ // Each gap is a fifth of an entry's own move, the rhythm the axes use;
105
+ // solved for from the budget rather than added to it.
106
+ const per = timeline.duration / (1 + Math.max(0, count - 1) / 5);
107
+ const step = per / 5;
108
+ const ease = frameEase(timeline);
109
+ const entries = state.slices.map((_, i) => ({ at: i * step, duration: per, piece: arrival(timeline, i, from, ease) }));
110
+ return timeline.together([arm, beats(timeline, entries)]);
111
+ },
112
+ },
113
+ measure: (measurer, state, children) => Flow.measure(measurer, state, children, Paint.inset(state)),
114
+ layout: (box, state, children) => Flow.layout(box, state, children, Paint.inset(state)),
115
+ render: (ctx, state) => Paint.draw(ctx, state, Shapes.rect(ctx.size, state)),
116
+ });
131
117
  //# sourceMappingURL=pie-legend.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"pie-legend.js","sourceRoot":"","sources":["../../src/pie-chart/pie-legend.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n command,\n Rect,\n Text,\n easeOut,\n property,\n textOps,\n type CommandArgs,\n type NodeConfig,\n type RectProps,\n} from \"@motionscript/sdk\"\n\nimport {\n DEFAULT_LEGEND,\n clampUnit,\n type LegendConfig,\n} from \"../kit/shared\"\nimport { at, compose, hold, type Seekable } from \"@motionscript/sdk/component\"\nimport type { PieSlice } from \"./shared\"\n\nexport interface PieLegendProps extends RectProps {\n /** One entry per slice, in ring order. */\n slices: PieSlice[]\n /** Padding, caption style, gaps, and swatch geometry — see {@link LegendConfig}. */\n legend: LegendConfig\n /**\n * Per-slice opacity multiplier, by index — the same signal that dims the ring,\n * so an entry fades in step with the wedge it names. Missing entries read as 1.\n */\n dims: number[]\n}\n\n/** How far an entry starts to the right of its slot when it enters, in px. */\nconst SLIDE = 16\n\n/**\n * The legend of a {@link PieChart}: a **vertical-flow column** of entries, one per\n * slice, each pairing the slice's caption with its colour swatch.\n *\n * A column rather than the cartesian charts' row, because it sits *beside* the\n * ring rather than beneath the plot — a pie is as tall as it is wide, so the\n * space it leaves over is a vertical strip. It is otherwise the same entry: the\n * swatch carries the colour, the caption reads in the legend's neutral ink, and\n * both take the shared {@link LegendConfig}.\n *\n * There is no show/hide here. A pie's marks are its *rows*, and a row that\n * shouldn't be in the chart shouldn't be in the table — removing one would\n * silently re-cut every other wedge's share, which is a different chart rather\n * than the same chart with something hidden. Selection is what a pie has\n * instead, and it arrives through {@link dims}.\n */\nexport class PieLegend extends Rect {\n @property({ default: () => [] as PieSlice[] }) declare slices: PieSlice[]\n @property({ default: DEFAULT_LEGEND }) declare legend: LegendConfig\n @property({ default: () => [] as number[] }) declare dims: number[]\n\n /** One entry per slice, ordered top → bottom, for the staggered entrance. */\n private items: Rect[] = []\n\n constructor(props?: NodeConfig<PieLegend, PieLegendProps>) {\n // `flow` with the rest of the fixed geometry, and for the reason\n // {@link ChartLegend} spells out: a `Rect` given none lays its children out\n // `freeform`, so an unstated column is every caption drawn on top of the\n // last one.\n super({\n ...(props as RectProps),\n flow: \"vertical\",\n align: \"centerLeft\",\n width: \"hug\",\n height: \"hug\",\n })\n\n // Fixed column geometry last, so it wins over what super() applied.\n this.set({ gap: this.legend.itemGap / 3, padding: this.legend.padding })\n\n for (let i = 0; i < this.slices.length; i++) {\n const item = this.buildItem(this.slices[i])\n this.items.push(item)\n // The selection dim rides a wrapper rather than the entry itself, so the\n // entrance can animate the entry's own opacity without the two fighting\n // over one value — opacity multiplies down the tree, which is exactly the\n // composition wanted here.\n this.add(\n new Rect({\n width: \"hug\",\n height: \"hug\",\n flow: \"freeform\",\n opacity: () => clampUnit(this.dims[i] ?? 1),\n children: [item],\n })\n )\n }\n }\n\n /** One entry: the slice's colour swatch beside its caption. */\n private buildItem(slice: PieSlice): Rect {\n const marker = this.legend.markerStyle\n return new Rect({ flow: \"horizontal\",\n gap: 12,\n align: \"center\",\n width: \"hug\",\n height: \"hug\",\n children: [\n new Rect({\n width: marker.height,\n height: marker.height,\n cornerRadius: marker.borderRadius,\n fill: slice.fill,\n stroke: marker.stroke,\n shadow: marker.shadow,\n }),\n new Text({\n ...textOps.styleProps(this.legend.textStyle),\n text: slice.category,\n }),\n ],\n })\n }\n\n /**\n * Prime every entry at its pre-entrance state: shifted right and transparent.\n *\n * Idempotent, and separate from {@link enter} so the chart can arm its whole\n * composition before the first frame is drawn — the resting state is the\n * finished legend, so there is nothing hidden to reveal unless a scene asks.\n */\n arm(slide = SLIDE): void {\n for (const item of this.items) item.set({ opacity: 0, x: slide })\n }\n\n /**\n * Slide + fade every entry in from the right, staggered top-to-bottom.\n *\n * `duration` is the **whole** entrance: the stagger is carved out of it rather\n * than added on top, so the command takes exactly the time the timeline laid\n * out for it.\n */\n @command()\n enter(\n args: CommandArgs<Record<string, never>> & { duration: number }\n ): Seekable {\n const duration = args.duration\n const easing = args.easing ?? easeOut()\n const items = this.items\n if (items.length === 0) return hold(duration)\n this.arm()\n\n // Each gap is a fifth of an entry's own move, the rhythm the axes use;\n // solved for from the budget rather than added to it. The offsets were\n // always `i * step` — written as `wait` inside a generator they merely only\n // existed while it ran.\n const per = duration / (1 + Math.max(0, items.length - 1) / 5)\n const step = per / 5\n\n return compose(\n items.map((item, i) => at(i * step, item.to({ data: { opacity: 1, x: 0 }, duration: per, easing })))\n )\n }\n}\n"]}
1
+ {"version":3,"file":"pie-legend.js","sourceRoot":"","sources":["../../src/pie-chart/pie-legend.ts"],"names":[],"mappings":"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","sourcesContent":["import {\r\n Flow,\r\n Paint,\r\n Rect,\r\n Shapes,\r\n Text,\r\n Types,\r\n component2d,\r\n textOps,\r\n type NodeOf,\r\n type RectProps,\r\n // Named so the column's emitted type reaches the Rect surface it spreads through the sdk, not core.\r\n type Alignment as _Alignment,\r\n type CornerRadiusResolved as _CornerRadiusResolved,\r\n type CornerStyleResolved as _CornerStyleResolved,\r\n type Fill as _Fill,\r\n type FillResolved as _FillResolved,\r\n type FlowMode as _FlowMode,\r\n type FlowResolved as _FlowResolved,\r\n type GapSize as _GapSize,\r\n type Node2D as _Node2D,\r\n type Node2DProps as _Node2DProps,\r\n type RectCornerRadius as _RectCornerRadius,\r\n type RectCornerStyle as _RectCornerStyle,\r\n type Shadow as _Shadow,\r\n type ShadowResolved as _ShadowResolved,\r\n type Stroke as _Stroke,\r\n type StrokeResolved as _StrokeResolved,\r\n type Vector2 as _Vector2,\r\n} from \"@motionscript/sdk\"\r\n\r\nimport { fresh } from \"../kit/entries\"\r\nimport { armed, arrival, arrivalOf, arrivalsEntry, beats, frameEase, type Arrival } from \"../kit/motion\"\r\nimport {\r\n DEFAULT_LEGEND,\r\n clampUnit,\r\n type LegendConfig,\r\n} from \"../kit/shared\"\r\nimport type { PieSlice } from \"./shared\"\r\n\r\nexport interface PieLegendProps extends RectProps {\r\n /** One entry per slice, in ring order. */\r\n slices: PieSlice[]\r\n /** Padding, caption style, gaps, and swatch geometry — see {@link LegendConfig}. */\r\n legend: LegendConfig\r\n /**\r\n * Per-slice opacity multiplier, by index — the same signal that dims the ring,\r\n * so an entry fades in step with the wedge it names. Missing entries read as 1.\r\n */\r\n dims: number[]\r\n}\r\n\r\n/** How far an entry starts to the right of its slot when it enters, in px. */\r\nconst SLIDE = 16\r\n\r\n/**\r\n * The legend of a {@link PieChart}: a **vertical-flow column** of entries, one per\r\n * slice, each pairing the slice's caption with its colour swatch.\r\n *\r\n * A column rather than the cartesian charts' row, because it sits *beside* the\r\n * ring rather than beneath the plot — a pie is as tall as it is wide, so the\r\n * space it leaves over is a vertical strip. It is otherwise the same entry: the\r\n * swatch carries the colour, the caption reads in the legend's neutral ink, and\r\n * both take the shared {@link LegendConfig}.\r\n *\r\n * There is no show/hide here. A pie's marks are its *rows*, and a row that\r\n * shouldn't be in the chart shouldn't be in the table — removing one would\r\n * silently re-cut every other wedge's share, which is a different chart rather\r\n * than the same chart with something hidden. Selection is what a pie has\r\n * instead, and it arrives through {@link PieLegendProps.dims}.\r\n */\r\nexport const PieLegend = component2d({\r\n key: \"pieLegend\",\r\n state: {\r\n ...Paint.state,\r\n ...Flow.state,\r\n ...Shapes.corners,\r\n slices: fresh<PieSlice[]>(() => []),\r\n legend: Types.custom<LegendConfig>(DEFAULT_LEGEND),\r\n dims: fresh<number[]>(() => []),\r\n arrivals: arrivalsEntry(),\r\n },\r\n // A column, for the reason `ChartLegend` gives for its row: a `Rect` given no\r\n // flow lays its children out `freeform`, every caption on top of the last.\r\n defaults: {\r\n flow: \"vertical\",\r\n align: \"centerLeft\",\r\n width: \"hug\",\r\n height: \"hug\",\r\n gap: (state) => state.legend.itemGap / 3,\r\n padding: (state) => state.legend.padding,\r\n },\r\n // One entry per slice, ordered top → bottom. The selection dim rides a wrapper\r\n // rather than the entry itself, so the entrance can animate the entry's own\r\n // opacity without the two fighting over one value — opacity multiplies down\r\n // the tree, which is exactly the composition wanted here.\r\n children: (state) => {\r\n const marker = state.legend.markerStyle\r\n return state.slices.map((_, index) =>\r\n Rect({\r\n width: \"hug\",\r\n height: \"hug\",\r\n flow: \"freeform\",\r\n opacity: () => clampUnit(state.dims[index] ?? 1),\r\n children: [\r\n Rect({\r\n flow: \"horizontal\",\r\n gap: 12,\r\n align: \"center\",\r\n width: \"hug\",\r\n height: \"hug\",\r\n opacity: () => arrivalOf(state.arrivals, index).opacity,\r\n x: () => arrivalOf(state.arrivals, index).shift,\r\n children: [\r\n Rect({\r\n width: marker.height,\r\n height: marker.height,\r\n cornerRadius: marker.borderRadius,\r\n fill: () => state.slices[index]?.fill ?? \"white\",\r\n stroke: marker.stroke,\r\n shadow: marker.shadow,\r\n }),\r\n Text({\r\n ...textOps.styleProps(state.legend.textStyle),\r\n text: () => state.slices[index]?.category ?? \"\",\r\n }),\r\n ],\r\n }),\r\n ],\r\n })\r\n )\r\n },\r\n commands: {\r\n ...Paint.commands,\r\n /**\r\n * Every entry at its pre-entrance state, shifted right and transparent: what\r\n * a chart shows ahead of this legend's own beat in its entrance, since\r\n * `enter` arms the entries only on its first frame.\r\n */\r\n arm: (timeline, state) =>\r\n timeline.animate(() => ({ arrivals: armed([...state.slices.keys()], { opacity: 0, shift: SLIDE }) })),\r\n /**\r\n * Slide + fade every entry in from the right, staggered top-to-bottom. Its\r\n * first frame arms them all: shifted right and transparent.\r\n *\r\n * The timeline's duration is the **whole** entrance: the stagger is carved\r\n * out of it rather than added on top, so the command takes exactly the time\r\n * the timeline laid out for it.\r\n */\r\n enter: (timeline, state) => {\r\n const count = state.slices.length\r\n if (count === 0) return timeline.wait(timeline.duration)\r\n const from: Arrival = { opacity: 0, shift: SLIDE }\r\n const arm = timeline.animate(() => ({ arrivals: armed([...state.slices.keys()], from) }))\r\n // Each gap is a fifth of an entry's own move, the rhythm the axes use;\r\n // solved for from the budget rather than added to it.\r\n const per = timeline.duration / (1 + Math.max(0, count - 1) / 5)\r\n const step = per / 5\r\n const ease = frameEase(timeline)\r\n const entries = state.slices.map((_, i) => ({ at: i * step, duration: per, piece: arrival(timeline, i, from, ease) }))\r\n return timeline.together([arm, beats(timeline, entries)])\r\n },\r\n },\r\n measure: (measurer, state, children) => Flow.measure(measurer, state, children, Paint.inset(state)),\r\n layout: (box, state, children) => Flow.layout(box, state, children, Paint.inset(state)),\r\n render: (ctx, state) => Paint.draw(ctx, state, Shapes.rect(ctx.size, state)),\r\n})\r\n\r\nexport type PieLegend = NodeOf<typeof PieLegend>\r\n"]}