move tool
move tool은 가장 기본적인 편집 도구입니다. 사용자가 선택된 도형을 드래그하면 node의 world 위치가 바뀝니다.
단순해 보이지만 여기에도 중요한 경계가 있습니다.
drag 시작 상태를 저장한다
pointerdown에서 시작 world 좌표와 선택된 node들의 초기 transform을 저장합니다.
function beginMove(snapshot, input) {
const selectedNodes = snapshot.selection.ids.map((id) => snapshot.scene.nodesById.get(id));
return {
type: "move",
startWorld: input.world,
initial: selectedNodes.map((node) => ({
id: node.id,
x: node.x,
y: node.y
}))
};
}
pointermove에서는 현재 world 좌표와 시작 world 좌표의 차이를 구합니다.
delta = currentWorld - startWorld
delta를 초기 transform에 더한다
매 pointermove마다 이전 frame의 위치에 delta를 더하면 오차가 쌓이거나 snapping과 충돌하기 쉽습니다. 시작 상태를 기준으로 새 위치를 계산합니다.
function updateMove(document, drag, currentWorld, snap = { x: 0, y: 0 }) {
const delta = {
x: currentWorld.x - drag.startWorld.x + snap.x,
y: currentWorld.y - drag.startWorld.y + snap.y
};
return drag.initial.reduce((nextDocument, item) => {
return updateNode(nextDocument, item.id, {
x: item.x + delta.x,
y: item.y + delta.y
});
}, document);
}
이 방식은 undo/redo에도 좋습니다. command는 최종 before/after transform을 기록하면 됩니다.
move는 문서 편집이다
hover와 달리 move는 scene model을 바꿉니다. 하지만 모든 pointermove를 undo history에 넣으면 안 됩니다.
보통 drag 중에는 live state를 갱신하고, pointerup에서 하나의 command로 확정합니다.
function commitMove(drag, beforeDocument, afterDocument) {
return {
type: "moveNodes",
nodeIds: drag.initial.map((item) => item.id),
before: pickNodePositions(beforeDocument, drag.initial),
after: pickNodePositions(afterDocument, drag.initial)
};
}
오늘의 핵심
move tool은 pointer delta를 node transform에 적용하는 도구입니다.
startWorld
currentWorld
delta
initial transform + delta