[TypeScript] 제스처로 대화하기. #8 - 팬(with. 드래그) 편
![[TypeScript] 제스처로 대화하기. #8 - 팬(with. 드래그) 편](/_next/image?url=https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fstock%2Funsplash%2FJe6p3FF4jh0%2Fupload%2F1043002fa96fda078514eafbea299e21.jpeg&w=3840&q=75)
이번 편은 이전 편으로부터 이어집니다.
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에서 이를 활용하여 실제로 움직일 요소를 파악할 수 있습니다. 감지는 더 넓은 범위에서 이루어지므로 이 범위에서 벗어나지 않는 한 포인터는 대상을 놓치지 않습니다.
내용은 다음 편에서 이어집니다. 읽어주셔서 감사합니다!
묻고 답하기
개인적인 판단에 의해 적절하다고 여겨지는 경우, 모두가 볼 수 있도록 이곳에 문답이 추가됩니다. 그렇지 않더라도 질문에 대한 답변은 별도로 이루어집니다.
![[TypeScript] 자료 구조로 담아내기. #14 - 연결 리스트(with. 이중 연결)](/_next/image?url=https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fstock%2Funsplash%2FJZ8AHFr2aEg%2Fupload%2F64ada685c81df630bc522030ccb249a6.jpeg&w=3840&q=75)
![[TypeScript] 자료 구조로 담아내기. #13 - 연결 리스트(with. 탐색)](/_next/image?url=https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fstock%2Funsplash%2F11KDtiUWRq4%2Fupload%2F9d73119b329ff023d19fc6162630671c.jpeg&w=3840&q=75)
![[TypeScript] 자료 구조로 담아내기. #12 - 연결 리스트(with. null 노드)](/_next/image?url=https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fstock%2Funsplash%2F5v235ueAU58%2Fupload%2F265377fe2e8da28d69701f873c907dc4.jpeg&w=3840&q=75)
![[TypeScript] 자료 구조로 담아내기. #11 - 연결 리스트(with. 헤드 노드)](/_next/image?url=https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fstock%2Funsplash%2Fv8pL84kvTTc%2Fupload%2Fd70e9fdf03dc1e678f9026bee97e822d.jpeg&w=3840&q=75)
![[TypeScript] 자료 구조로 담아내기. #10 - 연결 리스트(with. 연결)](/_next/image?url=https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fstock%2Funsplash%2FXe7za0JtTeM%2Fupload%2F1b7999ae5b4dd213025f4034465ddb80.jpeg&w=3840&q=75)