Created
April 3, 2023 08:14
-
-
Save fostyfost/251f34c3846f09233a506b1d9f766aab to your computer and use it in GitHub Desktop.
D3 force rectangle
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { quadtree } from 'd3' | |
type Rectangle = { | |
x: number | |
y: number | |
width: number | |
height: number | |
} | |
export const forceRectangle = <T extends Rectangle>(gapX: number, gapY: number) => { | |
let nodes: T[] = [] | |
const getX = (rectangle: T): number => rectangle.x | |
const getY = (rectangle: T): number => rectangle.y | |
const force = () => { | |
const quad = quadtree(nodes, getX, getY) | |
for (const node of nodes) { | |
quad.visit(quadItem => { | |
let updated = false | |
if ('data' in quadItem && quadItem.data && quadItem.data !== node) { | |
let x = getX(node) - getX(quadItem.data) | |
let y = getY(node) - getY(quadItem.data) | |
const xSpacing = gapX + (quadItem.data.width + node.width) / 2 | |
const ySpacing = gapY + (quadItem.data.height + node.height) / 2 | |
const absX = Math.abs(x) | |
const absY = Math.abs(y) | |
if (absX < xSpacing && absY < ySpacing) { | |
const distance = Math.sqrt(x * x + y * y) | |
let distanceX = (absX - xSpacing) / distance | |
let distanceY = (absY - ySpacing) / distance | |
// The one that's barely within the bounds probably triggered the collision | |
if (Math.abs(distanceX) > Math.abs(distanceY)) { | |
distanceX = 0 | |
} else { | |
distanceY = 0 | |
} | |
node.x -= x *= distanceX | |
node.y -= y *= distanceY | |
quadItem.data.x += x | |
quadItem.data.y += y | |
updated = true | |
} | |
} | |
return updated | |
}) | |
} | |
} | |
force.initialize = (_: T[]) => (nodes = _) | |
return force | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment