Skip to content

Commit 816c348

Browse files
authored
Add onNodesChange callback to ForceSimulation (#607)
* chore(ForceSimulation): Simplify unnecessarily complex internal types of `ForceSimulation` * feat(ForceSimulation): Add `onNodesChange` callback to `ForceSimulation`
1 parent 94813dd commit 816c348

2 files changed

Lines changed: 45 additions & 24 deletions

File tree

.changeset/lemon-bats-change.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'layerchart': minor
3+
---
4+
5+
feat(ForceSimulation): Added `onNodesChange` callback to `ForceSimulation`

packages/layerchart/src/lib/components/ForceSimulation.svelte

Lines changed: 40 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
> = {
3232
alpha: number;
3333
alphaTarget: number;
34-
simulation: SimulationFor<NodeDatum, LinkDatum>;
34+
simulation: Simulation<NodeDatum, LinkDatum>;
3535
};
3636
3737
export type OnTickEvent<
@@ -40,9 +40,9 @@
4040
> = {
4141
alpha: number;
4242
alphaTarget: number;
43-
nodes: NodeDatumFor<NodeDatum>[];
44-
links: LinkDatumFor<NodeDatum, LinkDatum>[];
45-
simulation: SimulationFor<NodeDatum, LinkDatum>;
43+
nodes: NodeDatum[];
44+
links: LinkDatum[];
45+
simulation: Simulation<NodeDatum, LinkDatum>;
4646
};
4747
4848
export type OnEndEvent<
@@ -51,7 +51,18 @@
5151
> = {
5252
alpha: number;
5353
alphaTarget: number;
54-
simulation: SimulationFor<NodeDatum, LinkDatum>;
54+
simulation: Simulation<NodeDatum, LinkDatum>;
55+
};
56+
57+
export type OnNodesChangeEvent<
58+
NodeDatum extends SimulationNodeDatum,
59+
LinkDatum extends SimulationLinkDatum<NodeDatum> | undefined,
60+
> = {
61+
alpha: number;
62+
alphaTarget: number;
63+
nodes: NodeDatum[];
64+
links: LinkDatum[];
65+
simulation: Simulation<NodeDatum, LinkDatum>;
5566
};
5667
5768
/**
@@ -81,16 +92,6 @@
8192
*/
8293
export const DEFAULT_VELOCITY_DECAY: number = 0.4;
8394
84-
type NodeDatumFor<NodeDatum> = NodeDatum & SimulationNodeDatum;
85-
86-
type LinkDatumFor<NodeDatum, LinkDatum> = LinkDatum &
87-
SimulationLinkDatum<NodeDatumFor<NodeDatum>>;
88-
89-
type SimulationFor<NodeDatum, LinkDatum> = Simulation<
90-
NodeDatumFor<NodeDatum>,
91-
LinkDatumFor<NodeDatum, LinkDatum>
92-
>;
93-
9495
export type ForceSimulationProps<
9596
NodeDatum extends SimulationNodeDatum,
9697
LinkDatum extends SimulationLinkDatum<NodeDatum> | undefined,
@@ -159,6 +160,11 @@
159160
*/
160161
onStart?: (e: OnStartEvent<NodeDatum, LinkDatum | undefined>) => void;
161162
163+
/**
164+
* Callback function triggered right before nodes get passed to the simulation
165+
*/
166+
onNodesChange?: (e: OnNodesChangeEvent<NodeDatum, LinkDatum | undefined>) => void;
167+
162168
/**
163169
* Callback function triggered on each simulation tick
164170
*/
@@ -172,10 +178,10 @@
172178
children?: Snippet<
173179
[
174180
{
175-
nodes: NodeDatumFor<NodeDatum>[];
176-
links: LinkDatumFor<NodeDatum, LinkDatum>[];
181+
nodes: NodeDatum[];
182+
links: LinkDatum[];
177183
linkPositions: LinkPosition[];
178-
simulation: SimulationFor<NodeDatum, LinkDatum>;
184+
simulation: Simulation<NodeDatum, LinkDatum>;
179185
},
180186
]
181187
>;
@@ -200,6 +206,7 @@
200206
stopped = false,
201207
static: staticProp,
202208
onStart: onStartProp,
209+
onNodesChange: onNodesChangeProp,
203210
onTick: onTickProp,
204211
onEnd: onEndProp,
205212
children,
@@ -211,15 +218,13 @@
211218
// MARK: Private Props
212219
213220
let linkPositions: LinkPosition[] = $state([]);
214-
let simulatedNodes: NodeDatumFor<NodeDatum>[] = $state([]);
215-
let simulatedLinks: LinkDatumFor<NodeDatum, LinkDatum>[] = $derived(
216-
(data.links ?? []) as LinkDatumFor<NodeDatum, LinkDatum>[]
217-
);
221+
let simulatedNodes: NodeDatum[] = $state([]);
222+
let simulatedLinks: LinkDatum[] = $derived(data.links ?? []);
218223
219224
// This casting is unfortunately necessary, due to unfortunate
220225
// overloading choices made, over at `@typed/d3-force`:
221-
const simulation: SimulationFor<NodeDatum, LinkDatum> = (
222-
forceSimulation() as SimulationFor<NodeDatum, LinkDatum>
226+
const simulation: Simulation<NodeDatum, LinkDatum> = (
227+
forceSimulation<NodeDatum>() as Simulation<NodeDatum, LinkDatum>
223228
).stop();
224229
225230
// d3.Simulation does not provide a `.forces()` getter, so we need to
@@ -263,6 +268,7 @@
263268
() => {
264269
// Any time the `nodes` prop, or the `data` store gets changed
265270
// we pass them to the internal d3 simulation object:
271+
onNodesChange();
266272
pushNodesToSimulation(data.nodes);
267273
runOrResumeSimulation();
268274
}
@@ -498,6 +504,16 @@
498504
});
499505
}
500506
507+
function onNodesChange() {
508+
onNodesChangeProp?.({
509+
alpha,
510+
alphaTarget,
511+
nodes: data.nodes,
512+
links: data.links ?? [],
513+
simulation,
514+
});
515+
}
516+
501517
$effect(() => {
502518
return () => {
503519
simulation.stop();

0 commit comments

Comments
 (0)