layerchart 2.0.0-next.15 → 2.0.0-next.17

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 (33) hide show
  1. package/dist/components/Arc.svelte +2 -2
  2. package/dist/components/Blur.svelte +5 -3
  3. package/dist/components/Blur.svelte.d.ts +2 -5
  4. package/dist/components/Connector.svelte +2 -2
  5. package/dist/components/Connector.svelte.d.ts +1 -1
  6. package/dist/components/Ellipse.svelte +187 -0
  7. package/dist/components/Ellipse.svelte.d.ts +64 -0
  8. package/dist/components/ForceSimulation.svelte +122 -38
  9. package/dist/components/ForceSimulation.svelte.d.ts +58 -23
  10. package/dist/components/GeoPath.svelte +5 -4
  11. package/dist/components/GeoPoint.svelte +1 -2
  12. package/dist/components/GeoSpline.svelte +4 -4
  13. package/dist/components/GeoSpline.svelte.d.ts +1 -1
  14. package/dist/components/MonthPath.svelte +11 -8
  15. package/dist/components/MonthPath.svelte.d.ts +4 -3
  16. package/dist/components/Polygon.svelte +285 -0
  17. package/dist/components/Polygon.svelte.d.ts +115 -0
  18. package/dist/components/Spline.svelte +29 -17
  19. package/dist/components/Spline.svelte.d.ts +12 -4
  20. package/dist/components/Treemap.svelte +63 -26
  21. package/dist/components/Treemap.svelte.d.ts +11 -11
  22. package/dist/components/index.d.ts +4 -0
  23. package/dist/components/index.js +4 -0
  24. package/dist/components/layout/Layer.svelte +6 -4
  25. package/dist/components/layout/Layer.svelte.d.ts +6 -4
  26. package/dist/components/tooltip/TooltipList.svelte +1 -1
  27. package/dist/utils/canvas.js +15 -0
  28. package/dist/utils/path.d.ts +10 -0
  29. package/dist/utils/path.js +30 -0
  30. package/dist/utils/shape.d.ts +43 -0
  31. package/dist/utils/shape.js +59 -0
  32. package/dist/utils/treemap.d.ts +1 -1
  33. package/package.json +1 -1
@@ -401,13 +401,13 @@
401
401
  <Spline
402
402
  pathData={trackArc()}
403
403
  stroke="none"
404
- bind:splineRef={trackRef}
404
+ bind:pathRef={trackRef}
405
405
  {...extractLayerProps(track, 'arc-track')}
406
406
  />
407
407
  {/if}
408
408
 
409
409
  <Spline
410
- bind:splineRef={ref}
410
+ bind:pathRef={ref}
411
411
  pathData={arc()}
412
412
  transform="translate({xOffset}, {yOffset})"
413
413
  {fill}
@@ -14,9 +14,9 @@
14
14
 
15
15
  /**
16
16
  * The default children snippet which provides
17
- * the id and url for the filter.
17
+ * the id for the filter.
18
18
  */
19
- children?: Snippet<[{ id: string; url: string }]>;
19
+ children?: Snippet;
20
20
  };
21
21
  </script>
22
22
 
@@ -42,7 +42,9 @@
42
42
 
43
43
  {#if children}
44
44
  <g filter="url(#{id})" class={layerClass('blur-g')}>
45
- {@render children({ id, url: `url(#${id})` })}
45
+ {@render children()}
46
46
  </g>
47
47
  {/if}
48
+ {:else if children}
49
+ {@render children()}
48
50
  {/if}
@@ -11,12 +11,9 @@ export type BlurProps = {
11
11
  stdDeviation?: number;
12
12
  /**
13
13
  * The default children snippet which provides
14
- * the id and url for the filter.
14
+ * the id for the filter.
15
15
  */
16
- children?: Snippet<[{
17
- id: string;
18
- url: string;
19
- }]>;
16
+ children?: Snippet;
20
17
  };
21
18
  import type { Snippet } from 'svelte';
22
19
  declare const Blur: import("svelte").Component<BlurProps, {}, "">;
@@ -82,7 +82,7 @@
82
82
  type = 'rounded',
83
83
  radius = 20,
84
84
  curve = curveLinear,
85
- splineRef = $bindable(),
85
+ pathRef = $bindable(),
86
86
  pathData: pathDataProp,
87
87
  marker,
88
88
  markerStart,
@@ -137,7 +137,7 @@
137
137
 
138
138
  <Spline
139
139
  pathData={motionPath.current}
140
- bind:splineRef
140
+ bind:pathRef
141
141
  marker-start={markerStartId ? `url(#${markerStartId})` : undefined}
142
142
  marker-mid={markerMidId ? `url(#${markerMidId})` : undefined}
143
143
  marker-end={markerEndId ? `url(#${markerEndId})` : undefined}
@@ -46,6 +46,6 @@ import { type CurveFactory } from 'd3-shape';
46
46
  import { type ConnectorCoords, type ConnectorSweep, type ConnectorType } from '../utils/connectorUtils.js';
47
47
  import { type SplineProps, type SplinePropsWithoutHTML } from './Spline.svelte';
48
48
  import type { Without } from '../utils/types.js';
49
- declare const Connector: import("svelte").Component<ConnectorProps, {}, "splineRef">;
49
+ declare const Connector: import("svelte").Component<ConnectorProps, {}, "pathRef">;
50
50
  type Connector = ReturnType<typeof Connector>;
51
51
  export default Connector;
@@ -0,0 +1,187 @@
1
+ <script lang="ts" module>
2
+ import type { CommonStyleProps, Without } from '../utils/types.js';
3
+
4
+ export type EllipsePropsWithoutHTML = {
5
+ /**
6
+ * The center x position of the ellipse.
7
+ *
8
+ * @default 0
9
+ */
10
+ cx?: number;
11
+
12
+ /**
13
+ * The initial center x position of the ellipse.
14
+ *
15
+ * @default cx
16
+ */
17
+ initialCx?: number;
18
+
19
+ /**
20
+ * The center y position of the ellipse.
21
+ *
22
+ * @default 0
23
+ */
24
+ cy?: number;
25
+
26
+ /**
27
+ * The initial center y position of the ellipse.
28
+ *
29
+ * @default cy
30
+ */
31
+ initialCy?: number;
32
+
33
+ /**
34
+ * The radius of the ellipse on the x-axis.
35
+ *
36
+ * @default 1
37
+ */
38
+ rx?: number;
39
+
40
+ /**
41
+ * The initial radius of the ellipse on the x-axis.
42
+ *
43
+ * @default rx
44
+ */
45
+ initialRx?: number;
46
+
47
+ /**
48
+ * The radius of the ellipse on the y-axis.
49
+ *
50
+ * @default 1
51
+ */
52
+ ry?: number;
53
+
54
+ /**
55
+ * The initial radius of the ellipse on the y-axis.
56
+ *
57
+ * @default ry
58
+ */
59
+ initialRy?: number;
60
+
61
+ /**
62
+ * A bindable reference to the `<ellipse>` element
63
+ *
64
+ * @bindable
65
+ */
66
+ ref?: SVGEllipseElement;
67
+
68
+ motion?: MotionProp;
69
+ } & CommonStyleProps;
70
+
71
+ export type EllipseProps = EllipsePropsWithoutHTML &
72
+ Without<SVGAttributes<Element>, EllipsePropsWithoutHTML>;
73
+ </script>
74
+
75
+ <script lang="ts">
76
+ import { cls } from '@layerstack/tailwind';
77
+ import { merge } from 'lodash-es';
78
+
79
+ import { getRenderContext } from './Chart.svelte';
80
+ import { createMotion, type MotionProp } from '../utils/motion.svelte.js';
81
+ import { registerCanvasComponent } from './layout/Canvas.svelte';
82
+ import { renderEllipse, type ComputedStylesOptions } from '../utils/canvas.js';
83
+ import type { SVGAttributes } from 'svelte/elements';
84
+ import { createKey } from '../utils/key.svelte.js';
85
+ import { layerClass } from '../utils/attributes.js';
86
+
87
+ let {
88
+ cx = 0,
89
+ initialCx: initialCxProp,
90
+ cy = 0,
91
+ initialCy: initialCyProp,
92
+ rx = 1,
93
+ initialRx: initialRxProp,
94
+ ry = 1,
95
+ initialRy: initialRyProp,
96
+ motion,
97
+ fill,
98
+ fillOpacity,
99
+ stroke,
100
+ strokeWidth,
101
+ opacity,
102
+ class: className,
103
+ ref: refProp = $bindable(),
104
+ ...restProps
105
+ }: EllipseProps = $props();
106
+
107
+ let ref = $state<SVGEllipseElement>();
108
+
109
+ $effect.pre(() => {
110
+ refProp = ref;
111
+ });
112
+
113
+ const initialCx = initialCxProp ?? cx;
114
+ const initialCy = initialCyProp ?? cy;
115
+ const initialRx = initialRxProp ?? rx;
116
+ const initialRy = initialRyProp ?? ry;
117
+
118
+ const renderCtx = getRenderContext();
119
+
120
+ const motionCx = createMotion(initialCx, () => cx, motion);
121
+ const motionCy = createMotion(initialCy, () => cy, motion);
122
+ const motionRx = createMotion(initialRx, () => rx, motion);
123
+ const motionRy = createMotion(initialRy, () => ry, motion);
124
+
125
+ function render(
126
+ ctx: CanvasRenderingContext2D,
127
+ styleOverrides: ComputedStylesOptions | undefined
128
+ ) {
129
+ renderEllipse(
130
+ ctx,
131
+ { cx: motionCx.current, cy: motionCy.current, rx: motionRx.current, ry: motionRy.current },
132
+ styleOverrides
133
+ ? merge({ styles: { strokeWidth } }, styleOverrides)
134
+ : {
135
+ styles: { fill, fillOpacity, stroke, strokeWidth, opacity },
136
+ classes: className,
137
+ }
138
+ );
139
+ }
140
+
141
+ // TODO: Use objectId to work around Svelte 4 reactivity issue (even when memoizing gradients)
142
+ const fillKey = createKey(() => fill);
143
+ const strokeKey = createKey(() => stroke);
144
+
145
+ if (renderCtx === 'canvas') {
146
+ registerCanvasComponent({
147
+ name: 'Ellipse',
148
+ render,
149
+ events: {
150
+ click: restProps.onclick,
151
+ pointerdown: restProps.onpointerdown,
152
+ pointerenter: restProps.onpointerenter,
153
+ pointermove: restProps.onpointermove,
154
+ pointerleave: restProps.onpointerleave,
155
+ },
156
+ deps: () => [
157
+ motionCx.current,
158
+ motionCy.current,
159
+ motionRx.current,
160
+ motionRy.current,
161
+ fillKey.current,
162
+ fillOpacity,
163
+ strokeKey.current,
164
+ strokeWidth,
165
+ opacity,
166
+ className,
167
+ ],
168
+ });
169
+ }
170
+ </script>
171
+
172
+ {#if renderCtx === 'svg'}
173
+ <ellipse
174
+ bind:this={ref}
175
+ cx={motionCx.current}
176
+ cy={motionCy.current}
177
+ rx={motionRx.current}
178
+ ry={motionRy.current}
179
+ {fill}
180
+ fill-opacity={fillOpacity}
181
+ {stroke}
182
+ stroke-width={strokeWidth}
183
+ {opacity}
184
+ class={cls(layerClass('ellipse'), fill == null && 'fill-surface-content', className)}
185
+ {...restProps}
186
+ />
187
+ {/if}
@@ -0,0 +1,64 @@
1
+ import type { CommonStyleProps, Without } from '../utils/types.js';
2
+ export type EllipsePropsWithoutHTML = {
3
+ /**
4
+ * The center x position of the ellipse.
5
+ *
6
+ * @default 0
7
+ */
8
+ cx?: number;
9
+ /**
10
+ * The initial center x position of the ellipse.
11
+ *
12
+ * @default cx
13
+ */
14
+ initialCx?: number;
15
+ /**
16
+ * The center y position of the ellipse.
17
+ *
18
+ * @default 0
19
+ */
20
+ cy?: number;
21
+ /**
22
+ * The initial center y position of the ellipse.
23
+ *
24
+ * @default cy
25
+ */
26
+ initialCy?: number;
27
+ /**
28
+ * The radius of the ellipse on the x-axis.
29
+ *
30
+ * @default 1
31
+ */
32
+ rx?: number;
33
+ /**
34
+ * The initial radius of the ellipse on the x-axis.
35
+ *
36
+ * @default rx
37
+ */
38
+ initialRx?: number;
39
+ /**
40
+ * The radius of the ellipse on the y-axis.
41
+ *
42
+ * @default 1
43
+ */
44
+ ry?: number;
45
+ /**
46
+ * The initial radius of the ellipse on the y-axis.
47
+ *
48
+ * @default ry
49
+ */
50
+ initialRy?: number;
51
+ /**
52
+ * A bindable reference to the `<ellipse>` element
53
+ *
54
+ * @bindable
55
+ */
56
+ ref?: SVGEllipseElement;
57
+ motion?: MotionProp;
58
+ } & CommonStyleProps;
59
+ export type EllipseProps = EllipsePropsWithoutHTML & Without<SVGAttributes<Element>, EllipsePropsWithoutHTML>;
60
+ import { type MotionProp } from '../utils/motion.svelte.js';
61
+ import type { SVGAttributes } from 'svelte/elements';
62
+ declare const Ellipse: import("svelte").Component<EllipseProps, {}, "ref">;
63
+ type Ellipse = ReturnType<typeof Ellipse>;
64
+ export default Ellipse;
@@ -8,35 +8,97 @@
8
8
  } from 'd3-force';
9
9
  import type { Snippet } from 'svelte';
10
10
 
11
- type Forces = Record<string, Force<any, any>>;
11
+ export type Forces<
12
+ NodeDatum extends SimulationNodeDatum,
13
+ LinkDatum extends SimulationLinkDatum<NodeDatum> | undefined,
14
+ > = Record<string, Force<NodeDatum, LinkDatum>>;
12
15
 
13
16
  export type Data<TNode = any, TLink = any> = {
14
17
  nodes: TNode[];
15
18
  links?: TLink[];
16
19
  };
17
20
 
18
- export type LinkPosition = Prettify<{
21
+ export type LinkPosition = {
19
22
  x1: number;
20
23
  y1: number;
21
24
  x2: number;
22
25
  y2: number;
23
- }>;
26
+ };
24
27
 
25
- type NodeDatumFor<NodeDatum> = Prettify<NodeDatum & SimulationNodeDatum>;
26
- type LinkDatumFor<NodeDatum, LinkDatum> = Prettify<
27
- LinkDatum & SimulationLinkDatum<NodeDatumFor<NodeDatum>>
28
- >;
28
+ export type OnStartEvent<
29
+ NodeDatum extends SimulationNodeDatum,
30
+ LinkDatum extends SimulationLinkDatum<NodeDatum> | undefined,
31
+ > = {
32
+ alpha: number;
33
+ alphaTarget: number;
34
+ simulation: SimulationFor<NodeDatum, LinkDatum>;
35
+ };
36
+
37
+ export type OnTickEvent<
38
+ NodeDatum extends SimulationNodeDatum,
39
+ LinkDatum extends SimulationLinkDatum<NodeDatum> | undefined,
40
+ > = {
41
+ alpha: number;
42
+ alphaTarget: number;
43
+ nodes: NodeDatumFor<NodeDatum>[];
44
+ links: LinkDatumFor<NodeDatum, LinkDatum>[];
45
+ simulation: SimulationFor<NodeDatum, LinkDatum>;
46
+ };
47
+
48
+ export type OnEndEvent<
49
+ NodeDatum extends SimulationNodeDatum,
50
+ LinkDatum extends SimulationLinkDatum<NodeDatum> | undefined,
51
+ > = {
52
+ alpha: number;
53
+ alphaTarget: number;
54
+ simulation: SimulationFor<NodeDatum, LinkDatum>;
55
+ };
56
+
57
+ /**
58
+ * Default initial alpha value of the simulation.
59
+ */
60
+ export const DEFAULT_ALPHA: number = 1;
61
+
62
+ /**
63
+ * Default target alpha value for the simulation.
64
+ */
65
+ export const DEFAULT_ALPHA_TARGET: number = 0;
66
+
67
+ /**
68
+ * Default alpha decay rate per tick.
69
+ *
70
+ * Formula: `1 - Math.pow(0.001, 1 / 300)`.
71
+ */
72
+ export const DEFAULT_ALPHA_DECAY: number = 1 - Math.pow(0.001, 1 / 300);
73
+
74
+ /**
75
+ * Default minimum alpha value at which simulation stops.
76
+ */
77
+ export const DEFAULT_ALPHA_MIN: number = 0.01;
78
+
79
+ /**
80
+ * Default velocity decay factor applied to nodes each tick.
81
+ */
82
+ export const DEFAULT_VELOCITY_DECAY: number = 0.4;
83
+
84
+ type NodeDatumFor<NodeDatum> = NodeDatum & SimulationNodeDatum;
85
+
86
+ type LinkDatumFor<NodeDatum, LinkDatum> = LinkDatum &
87
+ SimulationLinkDatum<NodeDatumFor<NodeDatum>>;
29
88
 
30
89
  type SimulationFor<NodeDatum, LinkDatum> = Simulation<
31
90
  NodeDatumFor<NodeDatum>,
32
91
  LinkDatumFor<NodeDatum, LinkDatum>
33
92
  >;
34
93
 
35
- export type ForceSimulationProps<NodeDatum, LinkDatum> = {
94
+ export type ForceSimulationProps<
95
+ NodeDatum extends SimulationNodeDatum,
96
+ LinkDatum extends SimulationLinkDatum<NodeDatum> | undefined,
97
+ > = {
36
98
  /**
37
99
  * Force simulation parameters
38
100
  */
39
- forces: Forces;
101
+ forces: Forces<NodeDatum, LinkDatum>;
40
102
 
41
103
  /**
42
104
  * An object with arrays of nodes and links,
@@ -46,31 +108,31 @@
46
108
 
47
109
  /**
48
110
  * Current alpha value of the simulation
49
- * @default 1
111
+ * @default DEFAULT_ALPHA
50
112
  */
51
113
  alpha?: number;
52
114
 
53
115
  /**
54
116
  * Target alpha value for the simulation
55
- * @default 0
117
+ * @default DEFAULT_ALPHA_TARGET
56
118
  */
57
119
  alphaTarget?: number;
58
120
 
59
121
  /**
60
122
  * Alpha decay rate per tick
61
- * @default 1 - Math.pow(0.001, 1 / 300)
123
+ * @default DEFAULT_ALPHA_DECAY
62
124
  */
63
125
  alphaDecay?: number;
64
126
 
65
127
  /**
66
128
  * Minimum alpha value at which simulation stops
67
- * @default 0.01
129
+ * @default DEFAULT_ALPHA_MIN
68
130
  */
69
131
  alphaMin?: number;
70
132
 
71
133
  /**
72
134
  * Velocity decay factor applied to nodes each tick
73
- * @default 0.4
135
+ * @default DEFAULT_VELOCITY_DECAY
74
136
  */
75
137
  velocityDecay?: number;
76
138
 
@@ -95,17 +157,17 @@
95
157
  /**
96
158
  * Callback function triggered when simulation starts
97
159
  */
98
- onStart?: () => void;
160
+ onStart?: (e: OnStartEvent<NodeDatum, LinkDatum | undefined>) => void;
99
161
 
100
162
  /**
101
163
  * Callback function triggered on each simulation tick
102
164
  */
103
- onTick?: (e: { alpha: number; alphaTarget: number }) => void;
165
+ onTick?: (e: OnTickEvent<NodeDatum, LinkDatum | undefined>) => void;
104
166
 
105
167
  /**
106
168
  * Callback function triggered when simulation ends
107
169
  */
108
- onEnd?: () => void;
170
+ onEnd?: (e: OnEndEvent<NodeDatum, LinkDatum | undefined>) => void;
109
171
 
110
172
  children?: Snippet<
111
173
  [
@@ -120,23 +182,26 @@
120
182
  };
121
183
  </script>
122
184
 
123
- <script lang="ts" generics="NodeDatum, LinkDatum = undefined">
185
+ <script
186
+ lang="ts"
187
+ generics="NodeDatum extends SimulationNodeDatum,
188
+ LinkDatum extends SimulationLinkDatum<NodeDatum> | undefined,"
189
+ >
124
190
  import { watch } from 'runed';
125
- import type { Prettify } from '@layerstack/utils';
126
191
 
127
192
  let {
128
193
  forces,
129
194
  data,
130
- alpha = $bindable(1),
131
- alphaTarget = 0,
132
- alphaDecay = 1 - Math.pow(0.001, 1 / 300),
133
- alphaMin = 0.001,
134
- velocityDecay = 0.4,
195
+ alpha = $bindable(DEFAULT_ALPHA),
196
+ alphaTarget = DEFAULT_ALPHA_TARGET,
197
+ alphaDecay = DEFAULT_ALPHA_DECAY,
198
+ alphaMin = DEFAULT_ALPHA_MIN,
199
+ velocityDecay = DEFAULT_VELOCITY_DECAY,
135
200
  stopped = false,
136
201
  static: staticProp,
137
- onStart: onStartProp = () => {},
138
- onTick: onTickProp = () => {},
139
- onEnd: onEndProp = () => {},
202
+ onStart: onStartProp,
203
+ onTick: onTickProp,
204
+ onEnd: onEndProp,
140
205
  children,
141
206
  cloneNodes = false,
142
207
  }: ForceSimulationProps<NodeDatum, LinkDatum> = $props();
@@ -159,7 +224,7 @@
159
224
 
160
225
  // d3.Simulation does not provide a `.forces()` getter, so we need to
161
226
  // keep track of previous forces ourselves, for diffing against `forces`.
162
- let previousForces: Forces = {};
227
+ let previousForces: Forces<NodeDatum, LinkDatum> = {};
163
228
 
164
229
  let paused: boolean = true;
165
230
 
@@ -220,12 +285,8 @@
220
285
  // pass it to the internal d3 simulation object:
221
286
  pushAlphaToSimulation(alpha);
222
287
 
223
- // Only resume the simulation as long as `alpha`
224
- // is above the cut-off threshold of `alphaMin`,
225
- // otherwise our simulation will never terminate:
226
- if (simulation.alpha() >= simulation.alphaMin()) {
227
- runOrResumeSimulation();
228
- }
288
+ // Then we attempt to resume the simulation:
289
+ runOrResumeSimulation();
229
290
  }
230
291
  );
231
292
 
@@ -263,7 +324,7 @@
263
324
  simulation.nodes(nodes);
264
325
  }
265
326
 
266
- function pushForcesToSimulation(forces: Forces) {
327
+ function pushForcesToSimulation(forces: Forces<NodeDatum, LinkDatum>) {
267
328
  // Evict obsolete forces:
268
329
  const names = Object.keys(previousForces);
269
330
  for (const name of names) {
@@ -366,6 +427,13 @@
366
427
  return;
367
428
  }
368
429
 
430
+ if (simulation.alpha() < simulation.alphaMin()) {
431
+ // Only resume the simulation as long as `alpha`
432
+ // is above the cut-off threshold of `alphaMin`,
433
+ // otherwise our simulation will never terminate:
434
+ return;
435
+ }
436
+
369
437
  onStart();
370
438
  simulation.restart();
371
439
 
@@ -393,7 +461,12 @@
393
461
  }
394
462
 
395
463
  paused = false;
396
- onStartProp();
464
+
465
+ onStartProp?.({
466
+ alpha,
467
+ alphaTarget,
468
+ simulation,
469
+ });
397
470
  }
398
471
 
399
472
  function onTick() {
@@ -401,7 +474,13 @@
401
474
  pullAlphaFromSimulation();
402
475
  updateLinkPositions();
403
476
 
404
- onTickProp({ alpha, alphaTarget });
477
+ onTickProp?.({
478
+ alpha,
479
+ alphaTarget,
480
+ nodes: simulatedNodes,
481
+ links: simulatedLinks,
482
+ simulation,
483
+ });
405
484
  }
406
485
 
407
486
  function onEnd() {
@@ -411,7 +490,12 @@
411
490
  }
412
491
 
413
492
  paused = true;
414
- onEndProp();
493
+
494
+ onEndProp?.({
495
+ alpha,
496
+ alphaTarget,
497
+ simulation,
498
+ });
415
499
  }
416
500
 
417
501
  $effect(() => {