Sandcorp샌드코프 · 웹·AI 제품 개발

새 프로젝트 받는 중 · 갱신 2026.11sandcorp.co.krGitHub

← 팁

프론트·UI

드래그·그리기 계산은 화면 좌표가 아니라 대상 좌표계에서 한다

드래그 중에도 스크롤과 확대가 일어난다. 포인터를 대상 좌표로 바꾼 뒤 차이를 구하고, 스크롤 때 다시 계산한다.

요소를 끌다가 휠로 스크롤하면 끌던 요소가 포인터를 따라오지 않고 엉뚱한 곳에 남는다. 확대한 화면에서는 포인터보다 빠르거나 느리게 움직인다.

드래그 이동량을 clientX·clientY의 차이로 구하면 화면 좌표 기준이 된다. 그런데 드래그 중에도 대상은 스크롤되고 확대된다. 포인터는 화면에서 가만히 있어도 대상 위에서의 위치는 바뀌고, 확대 배율이 있으면 화면 1px이 대상 1px이 아니다.

포인터를 먼저 대상 좌표계로 바꾼 다음 시작점과의 차이를 구한다. 스크롤 이벤트가 오면 마지막 포인터 위치로 다시 계산한다. 최종 위치는 렌더된 상태에서 읽지 말고 pointerup 시점에 직접 계산한다.

function toTarget(e: { clientX: number; clientY: number }, el: HTMLElement, scale: number) {
  const r = el.getBoundingClientRect();
  return { x: (e.clientX - r.left) / scale, y: (e.clientY - r.top) / scale };
}

let start = { x: 0, y: 0 };
let last: PointerEvent | null = null;

board.addEventListener('pointerdown', (e) => {
  start = toTarget(e, board, zoom);
  last = e;
});
board.addEventListener('pointermove', (e) => {
  last = e;
  move(toTarget(e, board, zoom));
});
scroller.addEventListener('scroll', () => {
  if (last) move(toTarget(last, board, zoom)); // 포인터는 그대로여도 대상 위 위치가 바뀐다
});

function move(p: { x: number; y: number }) {
  setOffset({ dx: p.x - start.x, dy: p.y - start.y });
}

문의 →