[TypeScript] 제스처로 대화하기. #8 - 팬(with. 드래그) 편
Table of contents
이번 편은 이전 편으로부터 이어집니다.
pointermove
를 드래그 대상에 설정하면 포인터를 빠르게 이동할 경우, 대상을 놓치는 것을 느끼셨을 겁니다. 왜 이런 일이 벌어질까요? 상상해 보세요. 포인터가 이동했습니다. 충분히 이동했다면 요소 바깥으로 넘어갔을 겁니다. 이후 핸들러가 호출되고, 대상을 이동하면 포인터를 따라잡을 겁니다. 하지만 핸들러가 호출되기 전에 포인터가 한 번 더 이동하면 어떻게 될까요? 이번에도 충분히 이동했다면 대상이 이동한 자리에는 이미 포인터가 없을 수도 있습니다.
어떻게 문제를 해결할 수 있을까요? 두 가지 방법을 생각할 수 있습니다. 포인터를 캡처하거나 상자보다 더 넓은 범위의 대상에서 팬을 감지하는 것입니다. 또한 두 방법은 반대가 아니며 함께 사용할 수 있습니다. 포인터 캡처는 pointerdown
에서 setPointerCapture
를 사용하여 간단하게 수행할 수 있습니다. 따라서 본 포스트에서는 후자에 대해서만 다루도록 하겠습니다.
interface PanEvent {
type: "panstart" | "pan" | "panend";
pointerId: number;
x: number;
y: number;
// ...
}
parentElement.addEventListener("pointerdown", e => {
const event: PanEvent = {
type: "panstart",
pointerId: e.pointerId,
x: e.clientX,
y: e.clientY
};
// ...
});
팬 이벤트의 유형을 panstart
, pan
, panend
로 구분하여 각각 초기화, 드래그, 정리의 용도로 활용할 수 있습니다. 위 코드에서는 pointerdown
에 대해서만 나타내지만, 그 외에도 pointermove
, pointerup
에서도 각각의 유형을 동일하게 적용할 수 있습니다.
const holdMap = new Map<number, Element>();
onPan(e => {
switch(e.type) {
case "panstart":
holdMap.set(e.pointerId, document.elementFromPoint(e.x, e.y)!);
break;
case "pan":
// ...
break;
case "panend":
holdMap.delete(e.pointerId);
break;
}
});
holdMap
은 포인터가 현재 잡고 있는 요소를 저장합니다. panstart
시 저장하고, panend
시 제거합니다. pan
에서 이를 활용하여 실제로 움직일 요소를 파악할 수 있습니다. 감지는 더 넓은 범위에서 이루어지므로 이 범위에서 벗어나지 않는 한 포인터는 대상을 놓치지 않습니다.
내용은 다음 편에서 이어집니다. 읽어주셔서 감사합니다!
묻고 답하기
개인적인 판단에 의해 적절하다고 여겨지는 경우, 모두가 볼 수 있도록 이곳에 문답이 추가됩니다. 그렇지 않더라도 질문에 대한 답변은 별도로 이루어집니다.
Subscribe to my newsletter
Read articles from 고라니드로 directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by