멀티터치 웹 브라우저에서의 개발

번역 : bellamy.chang([email protected]http://izect.kr)

들어가며


스마트폰이나 타블렛 같은 모바일 장치들은 보통 유저의 손가락을 통한 전기적 터치를 스크린을 통해 감지합니다. 모바일 웹이 더욱더 애플리케이션에 점점 가까워 질수록 웹 개발자들은 이러한 터치 이벤트를 다루는 것이 필요합니다. 에를 들어, 가까운 어떤 빠른 페이스의 게임이 플레이어에게 여러 버튼을 한번에 누르게 요구되면 터치 스크린은 멀티 터치가 가능한 환경이 되어야 합니다.

애플은 그들의 터치 이벤트 API를 iOS2.0 에서 소개하였습니다. 안드로이드도 이러한 표준을 발표하고 iOS와의 차이를 좁히기 위해 노력하고 있습니다. 최근에는 W3C 워킹 그룹과 함께 터치 이벤트 스펙을 작업중입니다.

이 강의에서 저는 iOS와 안드로이드에서 공급하는 터치 이벤트 API에 대해 어떤 종류의 어플리케이션을 만들 수 있고, 몇가지 예를 보여주고 터치 기반의 애플리케이션 개발을 편리하게 해주는 유용한 기술을 함께 알아보도록 하겠습니다.

터치 이벤트들


모바일 장치들의 스펙과 도구에는 3가지 가장 기본적인 터치 이벤트가 있습니다.

  • touchstart : 손가락이 DOM 객체에 위치.

  • touchmove : 손가락이 DOM 객체들 사이를 드래그함.

  • touchend : 손가락이 DOM 객체에서 떼어짐

각각의 터치 이벤트는 아래 3개의 터치중 하나의 이벤트로 보입니다.

  • touches : 현재 스크린에 있는 모든 손가락

  • targetTouches : 현재 DOM 객체에 있는 손가락

  • changedTouches : 현재 이벤트를 포함하고 있는 손가락. 예를 들어 touchend 이벤트는 분명 손가락이 스크린에서 떼진 상태일 것입니다.

아래 리스트는 터치에 대한 각종 정보를 담고 있습니다.

  • identifier : 현재의 터치를 세션에 담고 있는 숫자형태의 독립적ㅇ니 구분자 입니다.

  • target : 타겟된 행동에 대한 DOM 요소입니다.

  • client/page/screen coordinates : 손가락이 터치된 부분을 타원형으로 표현하여 담고 있습니다.

터치가 가능한 앱들


touchstarttouchmove, 그리고 touchend 이벤트는 시각적이고 두손가락으로 확대, 회전 같은 유용한 멀티 터치 제스처같은 터치기반의 상호작용을 충분히 제공해 줍니다. 

아래 코드조각은 손가락 하나를 이용해 DOM객체를 드래그 합니다.

var obj = document.getElementById('id');
obj
.addEventListener('touchmove', function(event) {
 
// If there's exactly one finger inside this element
 
if (event.targetTouches.length == 1) {
   
var touch = event.targetTouches[0];
   
// Place element where the finger is
    obj
.style.left = touch.pageX + 'px';
    obj
.style.top = touch.pageY + 'px';
 
}
}, false);

아래는 스크린에서 모든 터치에 대한 샘플입니다. 이는 장비의 터치 민감도에 따라 유용하게 느껴질 수도 있습니다.

 

// Setup canvas and expose context via ctx variable
canvas
.addEventListener('touchmove', function(event) {
 
for (var i = 0; i < event.touches.length; i++) {
   
var touch = event.touches[i];
    ctx
.beginPath();
    ctx
.arc(touch.pageX, touch.pageY, 20, 0, 2*Math.PI, true);
    ctx
.fill();
    ctx
.stroke();
 
}
}, false);


예제 

캔버스 기반 드로잉(폴 아이리시 제작) 같은 몇가지의 흥미로운 멀티 터치 예제가 이미 여러군데에 존재합니다.

draw.png 

그리고 닌자 브라우저 같은 CSS3 형태 변환(transform)과 투명도(transition)을 사용해 캔버스로 만든 예제도 있습니다.

browser-ninja.png 

모범 사례

확대 못하게 하기


기본적으로 멀티 터치는 잘 작동하지 않습니다. 스크롤링이나 확대같은 동작이 스와이핑이나 제스처를 할 때 중복되게 됩니다.

줌을 비활성화 하려면 뷰포트에 아래 메타 테그처럼 scalable을 사용 못하게 하면 됩니다.

<meta name="viewport"
 
content="width=device-width, initial-scale=1.0, user-scalable=no">


뷰포트 세팅에 대해서는 본 모바일 html5 기사를 참조해주세요.

스크롤링 못하게 하기


몇몇의 모바일 장비들은 touchmove가 예전의 iOS 오버스크롤 효과같이 기본 행동으로 정해져 있습니다. 이는 스크롤링이 컨텐츠의 영역을 벗어날때 보이게 됩니다. 이는 많은 멀티터치 어플리케이션에서 혼동을 일으킬 수 있는데 아래와 같이 쉽게 비활성화 할 수 있습니다.

document.body.addEventListener('touchmove', function(event) {
 
event.preventDefault();
}, false);

조심스럽게 랜더(render, 화면에 그리기)하기


만약 다양한 손가락을 활용한 제스처를 사용한 멀티 터치 기반의 어플리케이션을 제작한다면, 한번에 터치되는 양을 잘 조절해서 터치 이벤트가 조심스레 발생되어야 합니다. 아래 샘플은 스크린에 터치되는 모든 영역을 그려줍니다.

canvas.addEventListener('touchmove', function(event) {
  renderTouches
(event.touches);
}, false);

허나 위의 예제는 스크린에 터치되는 수를 제한하지 않았습니다. 대신에 아래처럼 작성하면 모든 손가락을 추적할 수 있고 이를 그려주는데(render)더 나은 성능을 보여줄 것입니다.


var touches = []
canvas
.addEventListener('touchmove', function(event) {
  touches
= event.touches;
}, false);

// Setup a 60fps timer
timer
= setInterval(function() {
  renderTouches
(touches);
}, 15);


팁 : setInterval 은 애니메이션에 별로 안좋습니다. 이를 사용하면 일반적인 브라우저에서 랜더링 해주는 루프에 들어가지 않습니다. 최신 데스크탑 브라우저들은 requestAnimationFrame을 제공하는데 이게 더 나은 옵션과 성능, 그리고 배터리 성능을 보여줍니다. 향후 모바일 브라우저에서 서포트 되면 이게 더 나은 방법이 될 것입니다.

targetTouches와 changedTouches를 사용하자.


event.touches는 단지 하나의 터치된 DOM뿐만 아니라 모든 스크린에 접촉되는 손가락의 정보를 배열로 담는다는 것을 기억해야 합니다. 아마 event.targetTouches나 event.changedTouches에서 더 유용한 것을 찾을수도 있습니다.

마지막으로 일반적인 베스트 모바일에 의거하여 모바일을 개발할 때 Eric Bidelman의 글이나 W3C의 문서를 보면 더욱 좋습니다.


장비의 지원


안타깝게도 터치 이벤트는 퀄리티와 완성도를 위해 매우 자주 바뀝니다. 제가 이 진단 스크립트를 터치 API 의 기본적인 정보에 의해 작성할 떄 이 이벤트들은 모두 지원되었고 touchmove는 재결의 되었습니다. 저는 넥서스 원과 넥서스 S 에 설치된 안드로이드 2.3.3과 Xoom의 Android 3.0.1 그리고 아이패드와 아이폰의 iOS 4.2에서 테스트 해 보았습니다.

분명한 것은 touchstart, touchend 그리고 touchmove 이벤트는 위의 모든 브라우저에서 테스트 되었습니다.

아래는 터치 스펙에서는 3개의 터치 이벤트가 더 있는데, 브라우저에서는 지원안되는 이벤트 들입니다.

  • touchenter : 손가락을 움직여 DOM 객체에 들어옴.

  • touchleave : 돔 객체를 손가락을 움직여 떠남.

  • touchcancel : 터치가 중단됨(실행 계획)

위의 것들은 테스트 되면 touches, targetTouches, changedTouches 의 터치 리스트에서 제공될 것입니다. 그러나 스크린 터치시에 radiusX, radiusY 혹은 rotationAngle 같은 것이 테스트된 브라우저는 없습니다.

touchmove 를 하는 중에 대강 60초 후에는 모든 테스트 장비에서는 이 이벤트가 사라졌습니다.

안드로이드 2.3.3(넥서스)


넥서스 원과 넥서스 S에서 테스트한 안드로이드 진저브래드의 브라우저는 멀티터치를 지원하지 않습니다.이 이슈를 참조하세요.

안드로이드 3.0.1(Xoom)


Xoom의 브라우저는 기본적인 멀티 터치를 지원합니다. 그러나 이는 단일 DOM객체에서만 작동합니다. 동시에 두개의 다른 DOM 객체를 터치하는 것에 대한 응답은 없습니다. 아래 예제는 동시에 두개를 터치할 때에 실행될 것입니다.


obj1.addEventListener('touchmove', function(event) {
 
for (var i = 0; i < event.targetTouches; i++) {
   
var touch = event.targetTouches[i];
    console
.log('touched ' + touch.identifier);
 
}
}, false);

허나 아래 예제는 제공되지 않습니다.

var objs = [obj1, obj2];
for (var i = 0; i < objs.length; i++) {
 
var obj = objs[i];
  obj
.addEventListener('touchmove', function(event) {
   
if (event.targetTouches.length == 1) {
      console
.log('touched ' + event.targetTouches[0].identifier);
   
}
 
}, false);
}


iOS 4.x (아이패드, 아이폰)


iOS 장비는 어떤 브라우저보다도 더 터치에 관해 많은 정보를 제공해주며, 모든 멀티 터치를 제공합니다.


개발자 툴


모바일 개발에 있어서 데스크탑에서 프로토 타입을 개발하기란 쉽지 않습니다. 그래서 개발하고자 하는 부분이 장비에서 지원되어야 합니다. 멀티터치는 특히나 PC에서 테스트 하기 힘듭니다. 대부분의 PC들은 터치 입력이 없습니다.

개발하는 동안에는 매번 서버와 장비에서 로딩된 모습을 보며 테스트 해야 합니다. 한번 실행하면 계속해서 작은 디버깅 거리가 생기기 때문에 타블렛이나 스마트폰은 웹 개발툴로는 부적합합니다.

이 문제를 해결하기 위해서는 당신의 개발 장비에 터치 이벤트가 시뮬레이션 되어야 합니다. 단일 터치, 터치 이벤트 등은 마우스로 입력됩니다. 멀티터치 이벤트는 애플의 최신 맥북이 있다면 시물레이션 할 수 있을 껍니다.

단일 터치 이벤트


만약 데스크탑에서 단일 터치를 시물레이션 하고 싶다면 Phantom Limb 라는 큰 손을 통해 페이지에 터치 이벤트를 주는 것을 사용해 보세요.

또한 Touchable 이라는 jQuery로된 터치와 마우스 이벤트가 통합된 플렛폼도 있습니다.

멀티터치 이벤트


애플의 맥북이나 매직패드처럼 멀티터치가 가능한 장비로 브라우저에서 웹 어플리케이션을 멀티터치가 가능하도록 하기 위해서 저는  MagicTouch.js polyfill을 만들었습니다. 이는 당신의 트랙패드의 터치 이벤트를 캐치해서 호환 가능한 기본 터치 이벤트로 넘겨줄 것입니다.

  1. npTuioClient NPAPI 플러그인을 받고 ~/Library/Internet Plug-Ins/ 에 설치합니다.

  2. 맥의 매직패드를 위한 TongSeng TUIO 앱을 다운받고 서버를 시작합니다.

  3. MagicTouch.js를 다운받습니다.(이는 npTuioClient 콜백 기반의 터치 이벤트를 시뮬레이션 해주는 자바스크립트 라이브러리 입니다.)

  4. magictouch.js스크립트와 npTuioClient 플러그인을 아래처럼 추가합니다.

<head>
  ...
 
<script src="/path/to/magictouch.js"></script>
</head>

<body>
  ...
 
<object id="tuio" type="application/x-tuio" style="width: 0px; height: 0px;">
    Touch input plugin failed to load!
 
</object>
</body>

저는 이를 크롬 10에서만 테스트 해봤는데, 아마 다른 최신 브라우저에서도 동작할 것입니다. 

컴퓨터에 멀티터치 입력장치가 없으면 다른 TUIO 트랙커(reacTIVision 가 있습니다. TUIO project page를 참조하시길..) 를 사용할 수 있습니다.

주의할 것은 터치 제스처는 아마도 OS레벨에서의 멀티 터치 제스터일 껍니다. OS X에서는 시스템 환결설정의 트랙패드 에서 시스템 이벤트의 범위를 지정할 수 있습니다.

멀티터치의 특징은 더 많은 브라우저들에서 동작할 것입니다. 전 정말 이러한 훌륭한 API가 어떤 새로운 웹 앱을 만들어 낼지 기대가 매우매우매우매우 큽니다.

(이 글은 한국 HTML5 사용자 모임 에 기고된 글입니다.)