모바일 터치 이벤트를 따라다니는 요소 만들기 mobile touchmove event의 offset 값을 따라다니는 element 만들기

 

이번 포스팅에서는 모바일에서 touchmove 이벤트가 일어날 때 그 터치하는 영역의 좌표값을 따라다니는 요소를 만들어보도록 하겠습니다. 이러한 기술은 복권을 긁는 UI, 그림을 그리는 기능 등을 만들 때 유용하게 사용할 수 있습니다.

 

1. Preview

오늘 만들어볼 화면을 미리 살펴보겠습니다.

 

마리오가 그려진 박스 안에서 사용자가 터치 이벤트를 발생시킬 경우, 즉 모바일 환경에서 마리오를 스와이프 하거나 문지를 경우 코인이 나타나서 손가락이 터치하는대로 따라다닙니다. 그리고 사용자가 손을 떼면 동전이 사라집니다. 마리오 바깥 영역에서 터치를 시작하면 이벤트가 발생하지 않습니다. 오늘은 이런 결과물을 만들어 보겠습니다.

 

그럼 먼저 해결 방법을 알아보기에 앞서 해결 방법에 사용되는 개념을 간략히 정리해보겠습니다.

 

2. clientX, clientY 와 pageX, pageY

이 두 메서드는 화면 상에서 마우스 이벤트가 일어날 때 좌표 값을 불러오는 기능을 합니다. 마우스 이벤트에는 click, mouseUp, mouseDown 등의 마우스 이벤트 뿐만 아니라 touchmove, touchstart, touchend 등의 모바일 상의 터치 이벤트도 포함됩니다.

2.1. clientX, clientY

위 메서드는 마우스 이벤트가 일어날 때 뷰포트, 즉 window 창을 기준으로 좌표 값을 제공합니다. 스크롤의 여부와 관계 없이 좌측 가장 상단을 찍으면 (0,0)이 구해진다는 의미입니다. 브라우저 창을 기준으로 좌표 값을 구해주는 기능을 하는 것이니 CSS의 position: fixed와 궁합이 좋겠죠.

2.2. pageX, pageY

위 메서드는 마우스 이벤트가 일어날 때 문서 즉 document 를 기준으로 좌표 값을 제공합니다. 스크롤의 양에 따라 좌표값이 계속 달라집니다. position: fixed 보다는 body를 offsetParent로 삼는 position: absolute 요소와 함께 사용하기에 적합합니다.

 

 

3. 문제 해결하기

3.1. 마크업 & CSS

터치 이벤트 즉 손가락을 따라다닐 요소와 그 요소가 움직일 박스 영역 하나를 만들어 줍니다.

<style>
    body {
      margin: 100px;
    }

    img {
      max-width: 100%;
    }

    .mario-box {
      width: 900px;
      height: 500px;
      background: url(https://github.com/likeanewstar/snake/assets/33821863/bacff81a-18f1-4f42-819f-9bf1fde388af) no-repeat bottom center/cover;
    }

    .coin {
      display: none;
      position: fixed;
      width: 100px;
      transform: translate(-50%,-50%);
    }

    .coin.show {
      display: block;
    }
</style>

<div class="mario-box"></div>
<div class="coin">
  <img src="https://github.com/likeanewstar/snake/assets/33821863/5d009456-43ae-4311-9b13-fe7708dfb701" alt="">
</div>

 

3.2. 터치 이벤트 추가하기

let isDrag = false;

$('.mario-box').on('touchmove', function(e) {
  e.preventDefault();

  if(isDrag === false) {
    $('.coin').addClass('show');  
  }

  isDrag = true;

  const touch = e.touches[0];

  let clientY = touch.clientY;
  let clientX = touch.clientX;

  $('.coin').css({'top': clientY});
  $('.coin').css({'left': clientX});
})


$(document).on('touchend', function(e) {
  $('.coin').removeClass('show');
  isDrag = false;
});
  1. isDrag라는 변수를 이용해 touchmove가 처음 발생한 최초 1번만 .coin에게 .show 클래스를 주어 coin이 화면상에 보이도록 합니다.
  2. 손으로 터치를 했을 때 요소가 따라다니게 할 영역인 .mario-box에 touchmove 이벤트를 걸어줍니다.
  3. 사용자가 터치한 지점의 좌표값을 clientX, clientY 메서드를 이용해 구해줍니다. (coin을 position: fixed로 자리잡아줄 것이기 때문)
  4. 구한 좌표 값을 각각 .coin의 top, left 값으로 설정합니다.
  5. document에게 touchend 이벤트를 걸어 사용자가 터치이벤트를 끝냈을 경우, .coin에 .show 클래스를 제거하고 isDrag 변수를 초기화해줍니다.
    (선택자를 document로 잡는 이유 : .mario-box를 선택자로 잡게 되면 사용자가 터치를 하다가 .mario-box 밖 영역에서 터치를 뗄 경우에 대한 대응이 되지 않기 때문입니다.)

 

4. 결과 확인하기

본 작업물은 모바일 환경에서만 동작하는 touch 이벤트를 이용해 제작하였으니 크롬의 개발자 도구 등으로 가상의 모바일 환경을 만들거나 실제 모바일 환경에서 테스트하셔야 정상적으로 확인이 가능합니다.

 

See the Pen Tracking Element Movement with Touch Event Offsets by newstar (@newstar_) on CodePen.

 

 

5. 주의사항

모바일 터치 이벤트를 다룰 때의 주의사항은 아이폰과 안드로이드의 터치 이벤트에 다른 부분들이 있으니 이 점을 고려하여 작업해야 한다는 점입니다. 이점에 대해서는 다음에 자세히 다루도록 하겠습니다. 크로스 브라우징을 통해 두 환경에서 모두 잘 동작하는지 잘 파악하는 작업이 꼭 필요합니다.

 

이번 포스팅에서는 JavaScript를 이용해 사용자의 모바일 터치 좌표를 따라다니는 요소를 만들어보았습니다.

도움이 되셨길 바랍니다.

 

감사합니다.