Skip to main content

Command Palette

Search for a command to run...

[TypeScript] 제스처로 대화하기. #8 - 팬(with. 드래그) 편

Updated
2 min read
[TypeScript] 제스처로 대화하기. #8 - 팬(with. 드래그) 편

이번 편은 이전 편으로부터 이어집니다.

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에서 이를 활용하여 실제로 움직일 요소를 파악할 수 있습니다. 감지는 더 넓은 범위에서 이루어지므로 이 범위에서 벗어나지 않는 한 포인터는 대상을 놓치지 않습니다.

내용은 다음 편에서 이어집니다. 읽어주셔서 감사합니다!

묻고 답하기

개인적인 판단에 의해 적절하다고 여겨지는 경우, 모두가 볼 수 있도록 이곳에 문답이 추가됩니다. 그렇지 않더라도 질문에 대한 답변은 별도로 이루어집니다.

More from this blog

[TypeScript] 자료 구조로 담아내기. #14 - 연결 리스트(with. 이중 연결)

이번 편은 이전 편으로부터 이어집니다. 연결 리스트의 또 다른 형태는 이중 연결 리스트입니다. 후임자의 참조만 저장하는 단일 연결 리스트와 달리 이중 연결 리스트는 선임자의 참조도 함께 저장합니다. interface DoublyLinkedListNode<T> extends DoublyLinkedList<T> { linkBefore(succ: DoublyLinkedListNode<T>): void; linkAfter(pred: D...

May 3, 20253 min read9
[TypeScript] 자료 구조로 담아내기. #14 - 연결 리스트(with. 이중 연결)

[TypeScript] 자료 구조로 담아내기. #12 - 연결 리스트(with. null 노드)

이번 편은 이전 편으로부터 이어집니다. 조금 예리하신 분들은 이전 편에서 다룬 헤드 노드만으로는 충분치 않다는 것을 느끼셨을 것입니다. 최소한 첫 노드에 예외를 부여하는 상황은 피했으나 후임자가 null임을 확인하는 구현 또한 만족스럽지는 않습니다. 카이로의 코끼리 카이로의 코끼리에 대해 알고 계십니까? 링크를 통해 확인하실 수 있습니다. 꽤 재밌으므로 한번 읽어 보시길 추천합니다. 여기서 중요한 아이디어는 끝 위치에 미리 코끼리를 둔다는 것...

Apr 19, 20252 min read12
[TypeScript] 자료 구조로 담아내기. #12 - 연결 리스트(with. null 노드)

[TypeScript] 자료 구조로 담아내기. #11 - 연결 리스트(with. 헤드 노드)

이번 편은 이전 편으로부터 이어집니다. 이전 편에서는 연결 리스트의 접근자는 첫 노드의 선임자가 적절하다는 것을 알았습니다. 얼핏 보기엔 문제없어 보이는데 어떤가요? 최상위 연결 리스트 즉, 가장 처음에 위치한 노드로 시작하는 경우를 생각해 봅시다. 가장 처음에 위치한 노드의 선임자는 무엇인가요? 맞습니다. 선임자가 존재하지 않겠지요. 그럼 어떻게 해야 할까요? 선임자를 가지지 않는 첫 노드를 갖는 연결 리스트에 대해 예외를 적용해야 할까요?...

Apr 12, 20252 min read13
[TypeScript] 자료 구조로 담아내기. #11 - 연결 리스트(with. 헤드 노드)

고라니드로의 블로그

47 posts