snapping과 smart guides
snapping은 도형을 움직이거나 resize할 때 다른 도형의 edge, center, 간격에 맞춰 붙는 기능입니다. smart guide는 그 이유를 선으로 보여주는 피드백입니다.
snap 후보와 delta를 찾는 코드
먼저 움직이지 않는 node들의 기준선을 모으고, 움직이는 selection의 기준선과 비교합니다.
function guidesForBounds(bounds) {
return {
x: [bounds.x, bounds.x + bounds.width / 2, bounds.x + bounds.width],
y: [bounds.y, bounds.y + bounds.height / 2, bounds.y + bounds.height]
};
}
function findSnapDelta(movingBounds, candidateBoundsList, threshold = 6) {
const moving = guidesForBounds(movingBounds);
const candidates = candidateBoundsList.flatMap((bounds) => {
const guides = guidesForBounds(bounds);
return [
...guides.x.map((value) => ({ axis: "x", value })),
...guides.y.map((value) => ({ axis: "y", value }))
];
});
let best = null;
for (const guide of candidates) {
for (const value of moving[guide.axis]) {
const delta = guide.value - value;
if (Math.abs(delta) <= threshold && (!best || Math.abs(delta) < Math.abs(best.delta))) {
best = { axis: guide.axis, delta, guideValue: guide.value };
}
}
}
return best;
}
결과가 { axis: "x", delta: 3 }이면 이동 delta에 x 보정을 더하고, guideValue를 overlay guide line으로 그립니다.
move delta에 snap을 적용한다
snapping은 node 위치를 직접 고르는 기능이 아니라, 사용자가 만든 raw delta를 보정하는 기능으로 두면 move/resize에 재사용하기 쉽습니다.
function applySnapToDelta(delta, snap) {
if (!snap) return delta;
return {
x: delta.x + (snap.axis === "x" ? snap.delta : 0),
y: delta.y + (snap.axis === "y" ? snap.delta : 0)
};
}
function snapMove(selectionBounds, candidateBoundsList, rawDelta) {
const movingBounds = {
...selectionBounds,
x: selectionBounds.x + rawDelta.x,
y: selectionBounds.y + rawDelta.y
};
const snap = findSnapDelta(movingBounds, candidateBoundsList);
return {
delta: applySnapToDelta(rawDelta, snap),
guide: snap && { axis: snap.axis, value: snap.guideValue }
};
}
guide는 문서 상태가 아니라 overlay가 한 프레임 동안 그릴 피드백입니다.
snap 후보를 만든다
먼저 현재 scene에서 맞출 수 있는 기준선을 모읍니다.
left, centerX, right
top, centerY, bottom
선택된 도형 자신은 후보에서 제외합니다. 다른 도형, frame, grid, ruler tick이 후보가 될 수 있습니다.
움직이는 도형의 기준선과 비교한다
drag 중인 도형의 edge/center와 후보 기준선의 거리를 계산합니다.
distance = candidateGuide - movingGuide
거리가 threshold보다 작으면 snap delta로 사용할 수 있습니다.
guide는 계산 결과를 보여준다
snap이 적용되면 사용자는 왜 도형이 붙었는지 알아야 합니다. 그래서 smart guide line을 overlay에 그립니다.
snap candidate world line
-> screen line
-> overlay guide
오늘의 핵심
snapping은 거리 계산이고, smart guide는 그 계산의 시각적 설명입니다.
candidate guides
moving guides
nearest distance
snap delta
overlay guide