-
-
Notifications
You must be signed in to change notification settings - Fork 12
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Refactor ForceSimulation
to allow for more dynamism
#205
Conversation
|
The latest updates on your projects. Learn more about Vercel for Git ↗︎
|
FYI: I added "collide easing" (as described in #198) to the "Force Graph" example for illustration purposes. I don't expect/intend it to remain there. This goes for most of the example changes in this PR, honestly. |
@regexident Wow, this looks great, thanks! Will take me a bit to read through fully (definitely more complicated implementation from before), but makes sense at first pass. I did notice a regression with the Force Group example no longer clumping. My guess is related to "does not re-initialize forces on unrelated prop-changes". CleanShot.2024-06-23.at.10.02.08.mp4Also, what do you say we keep the changes you made to Force Graph as a new "Force Debug" or "Force Playground" example? |
$: { | ||
// Any time the `stopped` prop gets toggled we | ||
// update the running state of the simulation: | ||
updateStateOnChangeOf({ | ||
stopped, | ||
_static, | ||
}); | ||
} | ||
|
||
$: { | ||
// Any time the `static` prop gets toggled we | ||
// either attach or detach our internal event listeners: | ||
updateEventListenersOnChangeOf({ _static }); | ||
} | ||
|
||
$: { | ||
// Any time the `$data` store gets changed we | ||
// pass them to the internal d3 simulation object: | ||
updateNodesOnChangeOf({ data: $data }); | ||
} | ||
|
||
$: { | ||
// Any time the `forces` prop gets changed we | ||
// pass them to the internal d3 simulation object: | ||
updateForcesOnChangeOf({ forces }); | ||
} | ||
|
||
$: { | ||
// Any time the `alpha` prop gets changed we | ||
// pass it to the internal d3 simulation object: | ||
updateAlphaOnChangeOf({ alpha }); | ||
} | ||
|
||
$: { | ||
// Any time any of the the alpha props get changed we | ||
// pass them all to the internal d3 simulation object | ||
// (they are cheap, so passing them as a batch is fine!): | ||
updateSettingsOnChangeOf({ | ||
alphaTarget, | ||
alphaMin, | ||
alphaDecay, | ||
velocityDecay, | ||
_static, | ||
}); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any reason we couldn't move each of these function implementations inline to the related $: { ... }
statements. I don't think they are needed to hide reactivity from Svelte (sometimes a trick I use, especially for circular references). I think this would help readability. I spot checked most of them and they looked to be called once.
We could also add a runStaticOrResumeDynamicSimulation()
to simplify them as well.
function runStaticOrResumeDynamicSimulation() {
if (_static) {
runStaticSimulation();
} else {
resumeDynamicSimulation(alpha);
}
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[…] I don't think they are needed to hide reactivity from Svelte (sometimes a trick I use, especially for circular references). […]
That's actually exactly why I added them at some point in the refactor. 😄
But on second glance it looks like in the state they ended up in no (major) hiding is necessary anymore, so I'll try to inline them where possible. 👍🏻
|
||
let nodes: any[] = []; | ||
|
||
const simulation = forceSimulation().stop(); //.nodes(nodesFromData()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove //.nodes(nodesFromData());
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, good catch!
Yeah, it is indeed quite a bit more complex. 😅 But at the benefit of being much, much more efficient and also more versatile.
Oh, I missed that button, good catch, I'll look into it!
Either that or I would just add them to the "Force Graph" example directly. Minus some of the bells and whistles that were only meant as a demonstration of things this refactor enables, such as the controls for "State", "Status", "Charge Distance Min", "Charge Distance Max", and "Collide Strength Target" (which I would just replace with a simple "Collide Strength" control). |
…alpha reheating where necessary
af27cf4
to
5e911f7
Compare
@techniq One significant (but intentional) change of this refactor is that I think that this behavior is a net-positive, as it …
It's also important to note that with today's So in a way things are more consistent now. |
@techniq I've adapted all other examples under "Force", resolving any regressions (like the one you mentioned above) and making use of more efficient force caching. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks great, thanks!
This admittedly major refactor of
ForceSimulation
resolves #198, #202, #203 and #204, while adding support for highly dynamic, yet efficient simulations.Changes
cloneData
asconst
(rather thanlet
)(resolves
ForceSimulation
'scloneData
should probably beexport const
#203)alpha
prop based on internal d3 simulation (important: dynamic sims now need reheating!)(resolves
ForceSimulation
does not update itsalpha
prop based on the internal d3 simulation #202)Improvements
(resolves
ForceSimulation
keeps redundantly re-initializing all forces any time any other (non-force) props change #204)(resolves
ForceSimulation
keeps redundantly re-initializing all forces any time any of their parameters change #201)d3.Simulation
forstatic=true
on every frameBug Fixes
(resolves
ForceSimulation
never evicts obsolete forces #206)New features
start
,tick
andend
events(resolves Expose
on:tick
fromForceSimulation
to allow for dynamic simulation tuning #198)stopped
prop for pausing simulationExample changes