개발 · 컴퓨터공학 / / 2022. 10. 12. 16:02

three.js Raycaster 마우스 클릭 감지와 드래그

728x90
반응형

마우스 이벤트를 위해서 canvas 상에서 돌아가는 event listener를 알아보자.

canvas.addEventListener('click', e=>{
    console.log(e.clientX, e.clientY);
});

mouse 클릭 이벤트를 통해 클릭 포인터를 알 수 있다.

 

window.addEventListener('resize', setSize);
canvas.addEventListener('click', e=>{
    mouse.x = e.clientX / canvas.clientWidth * 2 - 1;
    mouse.y = -(e.clientY / canvas.clientHeight * 2 - 1);
    console.log(mouse);
});

현재 canvas화면 비율에 맞춰 중심을 0,0으로 하고 2차원 좌표계로 표현할 수 있다. 

y의 경우 위가 (-)이고, 아래가 (+)로 처리되어있어, (-)로 부호를 바꿔주어야한다.

 

function checkIntersects(){
    raycaster.setFromCamera(mouse, camera);

    const intersects = raycaster.intersectObjects(meshes);
    for(const item of intersects) {
        console.log(item.object.name);
        break;
    }
    // other method
    // if(intersects[0]){
    //     console.log(intersects[0].object.name);
    // }
}

...

// event
window.addEventListener('resize', setSize);
canvas.addEventListener('click', e=>{
    mouse.x = e.clientX / canvas.clientWidth * 2 - 1;
    mouse.y = -(e.clientY / canvas.clientHeight * 2 - 1);
    checkIntersects();
});

checkIntersects라는 함수를 통해서 클릭한 방향으로 raycast를 쏘고, 감지할 수 있다.

raycaster는 쏘는 시작 origin이 중요한데, setFromCamera를 통해 camera에서 raycaster를 쏠 수 있다.

 

raycaster가 감지하는 오브젝트는 여러개 일 수 있어서, 만약 처음 감지한 하나만 뽑고 싶다면 intersectObjects 중에서 가장 먼저 감지된 것만을 보는 방법을 사용한다.

 

 

클릭 이벤트는 드래그를 한 후에 마우스를 떼는 것도 클릭 이벤트로 감지된다. 이는 별도로 처리해주어야한다.

canvas.addEventListener('click', e=>{
    mouse.x = e.clientX / canvas.clientWidth * 2 - 1;
    mouse.y = -(e.clientY / canvas.clientHeight * 2 - 1);
    checkIntersects();
});
let mouseMoved;
let clickStartX;
let clickStartY;
let clickStartTime;
canvas.addEventListener('mousedown', e=>{
    clickStartX = e.clientX;
    clickStartY = e.clientY;
    clickStartTime = Date.now();
})
canvas.addEventListener('mouseup', e => {
    const xGap = Math.abs(e.clientX - clickStartX);
    const yGap = Math.abs(e.clientY - clickStartY);
    const timeGap = Date.now() - clickStartTime;

    if (xGap > 5 || yGap > 5 || timeGap > 500){
        mouseMoved = true;
    }
    else{
        mouseMoved = false;
    }
})

마우스를 누를 때와 떼었을 때 좌표 변화가 얼마나 생겼는지를 이용해서, moseMoved라는 변수로 click과 drag를 구분할 수 있도록 한다.

또 마우스를 너무 오래 눌렀다 떼는 경우도 제외하기 위해서 clickStartTime을 체크하려 timeGap을 0.5초(500ms)로 설정한다.

 

// PreventDragClick.js

export class PreventDragClick{
    constructor(elem) {
        this.mouseMoved;
        let clickStartX;
        let clickStartY;
        let clickStartTime;
        elem.addEventListener('mousedown', e=>{
            clickStartX = e.clientX;
            clickStartY = e.clientY;
            clickStartTime = Date.now();
        })
        elem.addEventListener('mouseup', e => {
            const xGap = Math.abs(e.clientX - clickStartX);
            const yGap = Math.abs(e.clientY - clickStartY);
            const timeGap = Date.now() - clickStartTime;
            
            if (xGap > 5 || yGap > 5 || timeGap > 500){
                this.mouseMoved = true;
            }
            else{
                this.mouseMoved = false;
            }
        })
    }
}

click와 drag를 구분하는 코드를 위와 같이 모듈화한 다음

PreventDragClick(canvas)로 객체를 생성해서 사용할 수 있다.

728x90
반응형
  • 네이버 블로그 공유
  • 네이버 밴드 공유
  • 페이스북 공유
  • 카카오스토리 공유