Brain force layout runs in a worker: 300 ticks took ~75 ms cold, ~30 ms warm on the Demo's render thread
This commit is contained in:
@@ -0,0 +1,54 @@
|
||||
/**
|
||||
* The brain's force layout, off the render thread.
|
||||
*
|
||||
* Run to rest in one go, it took several frames on the main thread: about
|
||||
* 75 ms on a page's first layout and 30 ms after for the Demo's 29 neurons,
|
||||
* and 250 ms at five times that. Answers with where each neuron settled, in
|
||||
* the order they came.
|
||||
*
|
||||
* `forceX`/`forceY` rather than `forceCenter`: centering only translates the
|
||||
* whole thing, so unconnected flows — which is most of them — would push each
|
||||
* other apart forever with nothing pulling back.
|
||||
*/
|
||||
import {
|
||||
forceCollide,
|
||||
forceLink,
|
||||
forceManyBody,
|
||||
forceSimulation,
|
||||
forceX,
|
||||
forceY,
|
||||
type SimulationNodeDatum,
|
||||
} from "d3-force"
|
||||
|
||||
export type Seed = SimulationNodeDatum & { id: string; room: number }
|
||||
|
||||
export type LayoutRequest = {
|
||||
placed: Seed[]
|
||||
links: { source: string; target: string }[]
|
||||
}
|
||||
|
||||
self.onmessage = ({ data }: MessageEvent<LayoutRequest>) => {
|
||||
const { placed, links } = data
|
||||
forceSimulation(placed)
|
||||
.force(
|
||||
"link",
|
||||
forceLink(links)
|
||||
.id((node) => (node as Seed).id)
|
||||
.distance(130),
|
||||
)
|
||||
.force("charge", forceManyBody().strength(-320).distanceMax(500))
|
||||
.force(
|
||||
"collide",
|
||||
forceCollide<Seed>((node) => node.room),
|
||||
)
|
||||
// Centring pulls nearly three times as hard vertically as horizontally, so
|
||||
// the graph compresses into a band roughly twice as wide as it is tall
|
||||
// instead of the square an even pull settles into. Coming out of the
|
||||
// simulation rather than out of a transform keeps the circles round and the
|
||||
// edges the length the link force asked for.
|
||||
.force("x", forceX(0).strength(0.05))
|
||||
.force("y", forceY(0).strength(0.14))
|
||||
.stop()
|
||||
.tick(300)
|
||||
self.postMessage(placed.map((node) => [node.x ?? 0, node.y ?? 0]))
|
||||
}
|
||||
Reference in New Issue
Block a user