Skip to content

Instantly share code, notes, and snippets.

@steveruizok
Last active June 8, 2022 01:59
Show Gist options
  • Save steveruizok/99c7d3f99d94bb9aed10a9b4a70366cb to your computer and use it in GitHub Desktop.
Save steveruizok/99c7d3f99d94bb9aed10a9b4a70366cb to your computer and use it in GitHub Desktop.
A second iteration on finding snap points. Includes lines for rendering snap points.
interface BBox {
minX: number
midX: number
maxX: number
minY: number
midY: number
maxY: number
width: number
height: number
}
function findSnapPoints(
bounds: BBox,
others: BBox[],
isCareful: boolean
) {
const A = { ...bounds } // We'll mutate this
const offset = [0, 0]
const snapLines: TLSnapLine[] = []
// 1.
// Find the snap points for the x and y axes
const fxs = isCareful ? [A.midX, A.minX, A.maxX] : [A.midX]
const fys = isCareful ? [A.midY, A.minY, A.maxY] : [A.midY]
let xs = null as { B: BoundsWithCenter; i: number } | null
let ys = null as { B: BoundsWithCenter; i: number } | null
for (const B of others) {
if (!xs) {
const txs = isCareful ? [B.midX, B.minX, B.maxX] : [B.midX]
fxs.forEach((f, i) =>
txs.forEach((t) => {
if (xs) return
if (Math.abs(t - f) < SNAP_DISTANCE) {
xs = { B, i }
offset[0] = [
// How far to offset the delta on the x axis in
// order to "snap" the selection to the right place
A.midX - t,
A.midX - (t + A.width / 2),
A.midX - (t - A.width / 2),
][i]
// Also apply the offset to bounds A, so that our snap lines are correct
A.minX -= offset[0]
A.midX -= offset[0]
A.maxX -= offset[0]
}
})
)
}
if (!ys) {
const tys = isCareful ? [B.midY, B.minY, B.maxY] : [B.midY]
fys.forEach((f, i) =>
tys.forEach((t) => {
if (ys) return
if (Math.abs(t - f) < SNAP_DISTANCE) {
ys = { B, i }
offset[1] = [
//
A.midY - t,
A.midY - (t + A.height / 2),
A.midY - (t - A.height / 2),
][i]
A.minY -= offset[1]
A.midY -= offset[1]
A.maxY -= offset[1]
}
})
)
}
if (xs && ys) break
}
// 2.
// Calculcate snap lines based on adjusted bounds A. This has
// to happen after we've adjusted both dimensions x and y of
// the bounds A!
if (xs) {
const { i, B } = xs
const x = [A.midX, A.minX, A.maxX][i % 3]
// If A is snapped at its center, show include only the midY;
// otherwise, include both its minY and maxY.
snapLines.push({
points:
i === 0
? [
[x, A.midY],
[x, B.minY],
[x, B.maxY],
]
: [
[x, A.minY],
[x, A.maxY],
[x, B.minY],
[x, B.maxY],
],
})
}
if (ys) {
const { i, B } = ys
const y = [A.midY, A.minY, A.maxY][i % 3]
snapLines.push({
points:
i === 0
? [
[A.midX, y],
[B.minX, y],
[B.maxX, y],
]
: [
[A.minX, y],
[A.maxX, y],
[B.minX, y],
[B.maxX, y],
],
})
}
return { offset, snapLines }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment