Last active
June 23, 2023 01:50
-
-
Save steveruizok/5f47a58318afddf09379e07bce4e883b to your computer and use it in GitHub Desktop.
Find the snap points between a bounding box and several other bounding boxes.
This file contains 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
interface TLBoundsWithCenter { | |
minX: number | |
midX: number | |
maxX: number | |
minY: number | |
midY: number | |
maxY: number | |
width: number | |
height: number | |
} | |
function findSnapPoints( | |
bounds: TLBoundsWithCenter, | |
others: TLBoundsWithCenter[], | |
isCareful: boolean | |
) { | |
const A = { ...bounds } | |
const offset = [0, 0] | |
const snapLines: number[][][] = [] | |
// 1. | |
// Find the snap points for the x and y axes | |
let xs = null as { B: TLBoundsWithCenter; i: number } | null | |
let ys = null as { B: TLBoundsWithCenter; i: number } | null | |
const fxs = [A.midX, A.minX, A.maxX] | |
const fys = [A.midY, A.minY, A.maxY] | |
for (const B of others) { | |
if (!xs) { | |
const txs = [B.midX, B.minX, B.maxX] | |
fxs.forEach((f, i) => | |
txs.forEach((t, k) => { | |
// If we're not dragging carefully, only snap to center or opposite points | |
if (xs || !(isCareful || i === 0 || i + k === 3)) return | |
if (Math.abs(t - f) < 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 the bounds | |
A.minX -= offset[0] | |
A.midX -= offset[0] | |
A.maxX -= offset[0] | |
} | |
}) | |
) | |
} | |
if (!ys) { | |
const tys = [B.midY, B.minY, B.maxY] | |
fys.forEach((f, i) => | |
tys.forEach((t, k) => { | |
if (ys || !(isCareful || i === k)) return | |
if (Math.abs(t - f) < 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. | |
// Calculate 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( | |
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( | |
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