layerchart 2.0.0-next.14 → 2.0.0-next.16

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.
@@ -1,54 +1,110 @@
1
1
  <script lang="ts" module>
2
- import { forceSimulation, type Force, type Simulation, type SimulationNodeDatum } from 'd3-force';
2
+ import {
3
+ forceSimulation,
4
+ type Force,
5
+ type Simulation,
6
+ type SimulationLinkDatum,
7
+ type SimulationNodeDatum,
8
+ } from 'd3-force';
3
9
  import type { Snippet } from 'svelte';
4
10
 
5
- 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>>;
6
15
 
7
- export type LinkPosition = {
16
+ export type Data<TNode = any, TLink = any> = {
17
+ nodes: TNode[];
18
+ links?: TLink[];
19
+ };
20
+
21
+ export type LinkPosition = Prettify<{
8
22
  x1: number;
9
23
  y1: number;
10
24
  x2: number;
11
25
  y2: number;
12
- };
13
-
14
- export type ForceSimulationProps = {
26
+ }>;
27
+
28
+ /**
29
+ * Default initial alpha value of the simulation.
30
+ */
31
+ export const DEFAULT_ALPHA: number = 1;
32
+
33
+ /**
34
+ * Default target alpha value for the simulation.
35
+ */
36
+ export const DEFAULT_ALPHA_TARGET: number = 0;
37
+
38
+ /**
39
+ * Default alpha decay rate per tick.
40
+ *
41
+ * Formula: `1 - Math.pow(0.001, 1 / 300)`.
42
+ */
43
+ export const DEFAULT_ALPHA_DECAY: number = 1 - Math.pow(0.001, 1 / 300);
44
+
45
+ /**
46
+ * Default minimum alpha value at which simulation stops.
47
+ */
48
+ export const DEFAULT_ALPHA_MIN: number = 0.01;
49
+
50
+ /**
51
+ * Default velocity decay factor applied to nodes each tick.
52
+ */
53
+ export const DEFAULT_VELOCITY_DECAY: number = 0.4;
54
+
55
+ type NodeDatumFor<NodeDatum> = Prettify<NodeDatum & SimulationNodeDatum>;
56
+
57
+ type LinkDatumFor<NodeDatum, LinkDatum> = Prettify<
58
+ LinkDatum & SimulationLinkDatum<NodeDatumFor<NodeDatum>>
59
+ >;
60
+
61
+ type SimulationFor<NodeDatum, LinkDatum> = Simulation<
62
+ NodeDatumFor<NodeDatum>,
63
+ LinkDatumFor<NodeDatum, LinkDatum>
64
+ >;
65
+
66
+ export type ForceSimulationProps<
67
+ NodeDatum extends SimulationNodeDatum,
68
+ LinkDatum extends SimulationLinkDatum<NodeDatum> | undefined,
69
+ > = {
15
70
  /**
16
71
  * Force simulation parameters
17
72
  */
18
- forces: Forces;
73
+ forces: Forces<NodeDatum, LinkDatum>;
19
74
 
20
75
  /**
21
- * An array of links to be used for position calculation.
76
+ * An object with arrays of nodes and links,
77
+ * to be used for position calculation.
22
78
  */
23
- links?: any[];
79
+ data: Data<NodeDatum, LinkDatum>;
24
80
 
25
81
  /**
26
82
  * Current alpha value of the simulation
27
- * @default 1
83
+ * @default DEFAULT_ALPHA
28
84
  */
29
85
  alpha?: number;
30
86
 
31
87
  /**
32
88
  * Target alpha value for the simulation
33
- * @default 0
89
+ * @default DEFAULT_ALPHA_TARGET
34
90
  */
35
91
  alphaTarget?: number;
36
92
 
37
93
  /**
38
94
  * Alpha decay rate per tick
39
- * @default 1 - Math.pow(0.001, 1 / 300)
95
+ * @default DEFAULT_ALPHA_DECAY
40
96
  */
41
97
  alphaDecay?: number;
42
98
 
43
99
  /**
44
100
  * Minimum alpha value at which simulation stops
45
- * @default 0.01
101
+ * @default DEFAULT_ALPHA_MIN
46
102
  */
47
103
  alphaMin?: number;
48
104
 
49
105
  /**
50
106
  * Velocity decay factor applied to nodes each tick
51
- * @default 0.4
107
+ * @default DEFAULT_VELOCITY_DECAY
52
108
  */
53
109
  velocityDecay?: number;
54
110
 
@@ -88,27 +144,32 @@
88
144
  children?: Snippet<
89
145
  [
90
146
  {
91
- nodes: any[];
92
- simulation: Simulation<SimulationNodeDatum, undefined>;
147
+ nodes: NodeDatumFor<NodeDatum>[];
148
+ links: LinkDatumFor<NodeDatum, LinkDatum>[];
93
149
  linkPositions: LinkPosition[];
150
+ simulation: SimulationFor<NodeDatum, LinkDatum>;
94
151
  },
95
152
  ]
96
153
  >;
97
154
  };
98
155
  </script>
99
156
 
100
- <script lang="ts">
101
- import { getChartContext } from './Chart.svelte';
157
+ <script
158
+ lang="ts"
159
+ generics="NodeDatum extends SimulationNodeDatum,
160
+ LinkDatum extends SimulationLinkDatum<NodeDatum> | undefined,"
161
+ >
102
162
  import { watch } from 'runed';
163
+ import type { Prettify } from '@layerstack/utils';
103
164
 
104
165
  let {
105
166
  forces,
106
- links = [],
107
- alpha = $bindable(1),
108
- alphaTarget = 0,
109
- alphaDecay = 1 - Math.pow(0.001, 1 / 300),
110
- alphaMin = 0.001,
111
- velocityDecay = 0.4,
167
+ data,
168
+ alpha = $bindable(DEFAULT_ALPHA),
169
+ alphaTarget = DEFAULT_ALPHA_TARGET,
170
+ alphaDecay = DEFAULT_ALPHA_DECAY,
171
+ alphaMin = DEFAULT_ALPHA_MIN,
172
+ velocityDecay = DEFAULT_VELOCITY_DECAY,
112
173
  stopped = false,
113
174
  static: staticProp,
114
175
  onStart: onStartProp = () => {},
@@ -116,22 +177,27 @@
116
177
  onEnd: onEndProp = () => {},
117
178
  children,
118
179
  cloneNodes = false,
119
- }: ForceSimulationProps = $props();
120
-
121
- const ctx = getChartContext();
180
+ }: ForceSimulationProps<NodeDatum, LinkDatum> = $props();
122
181
 
123
182
  // MARK: Public Props
124
183
 
125
184
  // MARK: Private Props
126
185
 
127
- let nodes: SimulationNodeDatum[] = $state([]);
128
186
  let linkPositions: LinkPosition[] = $state([]);
187
+ let simulatedNodes: NodeDatumFor<NodeDatum>[] = $state([]);
188
+ let simulatedLinks: LinkDatumFor<NodeDatum, LinkDatum>[] = $derived(
189
+ (data.links ?? []) as LinkDatumFor<NodeDatum, LinkDatum>[]
190
+ );
129
191
 
130
- const simulation = forceSimulation().stop();
192
+ // This casting is unfortunately necessary, due to unfortunate
193
+ // overloading choices made, over at `@typed/d3-force`:
194
+ const simulation: SimulationFor<NodeDatum, LinkDatum> = (
195
+ forceSimulation() as SimulationFor<NodeDatum, LinkDatum>
196
+ ).stop();
131
197
 
132
198
  // d3.Simulation does not provide a `.forces()` getter, so we need to
133
199
  // keep track of previous forces ourselves, for diffing against `forces`.
134
- let previousForces: Forces = {};
200
+ let previousForces: Forces<NodeDatum, LinkDatum> = {};
135
201
 
136
202
  let paused: boolean = true;
137
203
 
@@ -166,11 +232,11 @@
166
232
  );
167
233
 
168
234
  watch.pre(
169
- () => ctx.data,
235
+ () => data,
170
236
  () => {
171
- // Any time the `data` store gets changed we
172
- // pass them to the internal d3 simulation object:
173
- pushNodesToSimulation(ctx.data as any[]);
237
+ // Any time the `nodes` prop, or the `data` store gets changed
238
+ // we pass them to the internal d3 simulation object:
239
+ pushNodesToSimulation(data.nodes);
174
240
  runOrResumeSimulation();
175
241
  }
176
242
  );
@@ -235,7 +301,7 @@
235
301
  simulation.nodes(nodes);
236
302
  }
237
303
 
238
- function pushForcesToSimulation(forces: Forces) {
304
+ function pushForcesToSimulation(forces: Forces<NodeDatum, LinkDatum>) {
239
305
  // Evict obsolete forces:
240
306
  const names = Object.keys(previousForces);
241
307
  for (const name of names) {
@@ -259,7 +325,7 @@
259
325
  // Keeping the link positions in sync with the simulation
260
326
  // so we don't need to recalculate _all_ link positions on each tick
261
327
  // which bogs down the simulation
262
- linkPositions = links.map((link: any) => ({
328
+ linkPositions = simulatedLinks.map((link: any) => ({
263
329
  x1: link.source.x ?? 0,
264
330
  y1: link.source.y ?? 0,
265
331
  x2: link.target.x ?? 0,
@@ -270,7 +336,8 @@
270
336
  // MARK: Pull State
271
337
 
272
338
  function pullNodesFromSimulation() {
273
- nodes = cloneNodes ? structuredClone(simulation.nodes()) : simulation.nodes();
339
+ const simulationNodes = simulation.nodes();
340
+ simulatedNodes = cloneNodes ? structuredClone(simulationNodes) : simulationNodes;
274
341
  }
275
342
 
276
343
  function pullAlphaFromSimulation() {
@@ -393,4 +460,9 @@
393
460
  });
394
461
  </script>
395
462
 
396
- {@render children?.({ nodes: nodes, simulation, linkPositions })}
463
+ {@render children?.({
464
+ nodes: simulatedNodes,
465
+ links: simulatedLinks,
466
+ simulation,
467
+ linkPositions,
468
+ })}
@@ -1,44 +1,74 @@
1
- import { type Force, type Simulation, type SimulationNodeDatum } from 'd3-force';
1
+ import { type Force, type Simulation, type SimulationLinkDatum, type SimulationNodeDatum } from 'd3-force';
2
2
  import type { Snippet } from 'svelte';
3
- type Forces = Record<string, Force<any, any>>;
4
- export type LinkPosition = {
3
+ export type Forces<NodeDatum extends SimulationNodeDatum, LinkDatum extends SimulationLinkDatum<NodeDatum> | undefined> = Record<string, Force<NodeDatum, LinkDatum>>;
4
+ export type Data<TNode = any, TLink = any> = {
5
+ nodes: TNode[];
6
+ links?: TLink[];
7
+ };
8
+ export type LinkPosition = Prettify<{
5
9
  x1: number;
6
10
  y1: number;
7
11
  x2: number;
8
12
  y2: number;
9
- };
10
- export type ForceSimulationProps = {
13
+ }>;
14
+ /**
15
+ * Default initial alpha value of the simulation.
16
+ */
17
+ export declare const DEFAULT_ALPHA: number;
18
+ /**
19
+ * Default target alpha value for the simulation.
20
+ */
21
+ export declare const DEFAULT_ALPHA_TARGET: number;
22
+ /**
23
+ * Default alpha decay rate per tick.
24
+ *
25
+ * Formula: `1 - Math.pow(0.001, 1 / 300)`.
26
+ */
27
+ export declare const DEFAULT_ALPHA_DECAY: number;
28
+ /**
29
+ * Default minimum alpha value at which simulation stops.
30
+ */
31
+ export declare const DEFAULT_ALPHA_MIN: number;
32
+ /**
33
+ * Default velocity decay factor applied to nodes each tick.
34
+ */
35
+ export declare const DEFAULT_VELOCITY_DECAY: number;
36
+ type NodeDatumFor<NodeDatum> = Prettify<NodeDatum & SimulationNodeDatum>;
37
+ type LinkDatumFor<NodeDatum, LinkDatum> = Prettify<LinkDatum & SimulationLinkDatum<NodeDatumFor<NodeDatum>>>;
38
+ type SimulationFor<NodeDatum, LinkDatum> = Simulation<NodeDatumFor<NodeDatum>, LinkDatumFor<NodeDatum, LinkDatum>>;
39
+ export type ForceSimulationProps<NodeDatum extends SimulationNodeDatum, LinkDatum extends SimulationLinkDatum<NodeDatum> | undefined> = {
11
40
  /**
12
41
  * Force simulation parameters
13
42
  */
14
- forces: Forces;
43
+ forces: Forces<NodeDatum, LinkDatum>;
15
44
  /**
16
- * An array of links to be used for position calculation.
45
+ * An object with arrays of nodes and links,
46
+ * to be used for position calculation.
17
47
  */
18
- links?: any[];
48
+ data: Data<NodeDatum, LinkDatum>;
19
49
  /**
20
50
  * Current alpha value of the simulation
21
- * @default 1
51
+ * @default DEFAULT_ALPHA
22
52
  */
23
53
  alpha?: number;
24
54
  /**
25
55
  * Target alpha value for the simulation
26
- * @default 0
56
+ * @default DEFAULT_ALPHA_TARGET
27
57
  */
28
58
  alphaTarget?: number;
29
59
  /**
30
60
  * Alpha decay rate per tick
31
- * @default 1 - Math.pow(0.001, 1 / 300)
61
+ * @default DEFAULT_ALPHA_DECAY
32
62
  */
33
63
  alphaDecay?: number;
34
64
  /**
35
65
  * Minimum alpha value at which simulation stops
36
- * @default 0.01
66
+ * @default DEFAULT_ALPHA_MIN
37
67
  */
38
68
  alphaMin?: number;
39
69
  /**
40
70
  * Velocity decay factor applied to nodes each tick
41
- * @default 0.4
71
+ * @default DEFAULT_VELOCITY_DECAY
42
72
  */
43
73
  velocityDecay?: number;
44
74
  /**
@@ -73,12 +103,28 @@ export type ForceSimulationProps = {
73
103
  onEnd?: () => void;
74
104
  children?: Snippet<[
75
105
  {
76
- nodes: any[];
77
- simulation: Simulation<SimulationNodeDatum, undefined>;
106
+ nodes: NodeDatumFor<NodeDatum>[];
107
+ links: LinkDatumFor<NodeDatum, LinkDatum>[];
78
108
  linkPositions: LinkPosition[];
109
+ simulation: SimulationFor<NodeDatum, LinkDatum>;
79
110
  }
80
111
  ]>;
81
112
  };
82
- declare const ForceSimulation: import("svelte").Component<ForceSimulationProps, {}, "alpha">;
83
- type ForceSimulation = ReturnType<typeof ForceSimulation>;
113
+ import type { Prettify } from '@layerstack/utils';
114
+ declare class __sveltets_Render<NodeDatum extends SimulationNodeDatum, LinkDatum extends SimulationLinkDatum<NodeDatum> | undefined> {
115
+ props(): ForceSimulationProps<NodeDatum, LinkDatum>;
116
+ events(): {};
117
+ slots(): {};
118
+ bindings(): "alpha";
119
+ exports(): {};
120
+ }
121
+ interface $$IsomorphicComponent {
122
+ new <NodeDatum extends SimulationNodeDatum, LinkDatum extends SimulationLinkDatum<NodeDatum> | undefined>(options: import('svelte').ComponentConstructorOptions<ReturnType<__sveltets_Render<NodeDatum, LinkDatum>['props']>>): import('svelte').SvelteComponent<ReturnType<__sveltets_Render<NodeDatum, LinkDatum>['props']>, ReturnType<__sveltets_Render<NodeDatum, LinkDatum>['events']>, ReturnType<__sveltets_Render<NodeDatum, LinkDatum>['slots']>> & {
123
+ $$bindings?: ReturnType<__sveltets_Render<NodeDatum, LinkDatum>['bindings']>;
124
+ } & ReturnType<__sveltets_Render<NodeDatum, LinkDatum>['exports']>;
125
+ <NodeDatum extends SimulationNodeDatum, LinkDatum extends SimulationLinkDatum<NodeDatum> | undefined>(internal: unknown, props: ReturnType<__sveltets_Render<NodeDatum, LinkDatum>['props']> & {}): ReturnType<__sveltets_Render<NodeDatum, LinkDatum>['exports']>;
126
+ z_$$bindings?: ReturnType<__sveltets_Render<any, any>['bindings']>;
127
+ }
128
+ declare const ForceSimulation: $$IsomorphicComponent;
129
+ type ForceSimulation<NodeDatum extends SimulationNodeDatum, LinkDatum extends SimulationLinkDatum<NodeDatum> | undefined> = InstanceType<typeof ForceSimulation<NodeDatum, LinkDatum>>;
84
130
  export default ForceSimulation;
@@ -75,3 +75,17 @@ export declare function getSpiral({ angle, radius, count, width, height, }: {
75
75
  x: number;
76
76
  y: number;
77
77
  }[];
78
+ interface SineWaveOptions {
79
+ numPoints: number;
80
+ frequency?: number;
81
+ amplitude?: number;
82
+ noiseLevel?: number;
83
+ phase?: number;
84
+ xMin?: number;
85
+ xMax?: number;
86
+ }
87
+ export declare function generateSineWave(options: SineWaveOptions): {
88
+ x: number;
89
+ y: number;
90
+ }[];
91
+ export {};
@@ -124,3 +124,21 @@ export function getSpiral({ angle, radius, count, width, height, }) {
124
124
  };
125
125
  });
126
126
  }
127
+ export function generateSineWave(options) {
128
+ const { numPoints, frequency = 1, amplitude = 1, noiseLevel = 0, phase = 0, xMin = 0, xMax = 2 * Math.PI, } = options;
129
+ if (numPoints <= 0) {
130
+ throw new Error('Number of points must be greater than 0');
131
+ }
132
+ const points = [];
133
+ const xStep = (xMax - xMin) / (numPoints - 1);
134
+ for (let i = 0; i < numPoints; i++) {
135
+ const x = xMin + i * xStep;
136
+ // Generate base sine wave
137
+ const sineValue = amplitude * Math.sin(frequency * x + phase);
138
+ // Add random noise if specified
139
+ const noise = noiseLevel > 0 ? (Math.random() - 0.5) * 2 * noiseLevel : 0;
140
+ const y = sineValue + noise;
141
+ points.push({ x, y });
142
+ }
143
+ return points;
144
+ }
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "author": "Sean Lynch <techniq35@gmail.com>",
5
5
  "license": "MIT",
6
6
  "repository": "techniq/layerchart",
7
- "version": "2.0.0-next.14",
7
+ "version": "2.0.0-next.16",
8
8
  "devDependencies": {
9
9
  "@changesets/cli": "^2.29.4",
10
10
  "@iconify-json/lucide": "^1.2.44",