대부분의 사용자가 모바일 환경이 아닌 일반적인 PC web 인터페이스로 웹서비스에 접속하던 시절에는 방문자의 브라우저와 운영체제만 감지를 하면 대부분의 문제를 해결할 수 있었지만, 태블릿과 스맛폰이 많이 보급되면서 크로스브라우징 뿐만 아니라 어떤 기기로 접속했느냐에 따라 각각 처리와 대응을 따로 해줄 필요가 생겼습니다. 이러한 문제를 해결하기 위해 구글링을 하면서 알아낸 것들을 바탕으로 터치 이벤트 환경 및 접속 기기를 감지해주는 자바스크립트 함수를 짜봤습니다.
함수의 대략적인 흐름은 다음과 같습니다:
createTouch 생성이 가능한지 확인하여 터치 이벤트 가용 환경인지 확인.
navigator.userAgent 속성을 이용해 접속기기가 아이폰인지 안드로이드폰인지 확인.
1, 2의 결과에 따라 "iPhone", "Android", "true", "false" 리턴.
터치를 기반으로 한 양질의 서비스를 제공하기 위해, Touch Events(터치이벤트)는 터치로 인한 움직임을 감지할 능력을 제공합니다.
터치 이벤트 인터페이스는 상대적으로 low-lever API이며 multi-touch interaction등의 다양한 동작을 특정해 트리거 할 수 있습니다. multi-touch interaction은 한 손가락이 터치패드에 처음 닫는 순간 시작합니다. 이후 다른 손가락들이 터치패드에 닿고 선택적으로 터치패드를 가로지를 수도 있습니다. interaction은 손가락들이 터치패드에서 떨어지면 끝납니다. interaction동안에 어플리케이션은 touch start, move, end 이벤트들을 받습니다.
Touch events는 동시에 여러 손가락으로 동시에 혹은 여러 지점에 터치 할 수 있다는 것만 제외하면 마우스 이벤트와 유사합니다. 터치이벤트 인터페이스는 현재 액션과 터치 지점을 캡슐화 합니다. single touch로 대표되는 interface는 터치된 정보등을 포함합니다.
This example tracks multiple touch points at a time, allowing the user to draw in a <canvas> with more than one finger at a time. It will only work on a browser that supports touch events.
Note: The text below uses the term "finger" when describing the contact with the surface, but it could, of course, also be a stylus or other contact method.
Create a canvas
<canvas id="canvas" width="600" height="600" style="border:solid black 1px;"> Your browser does not support canvas element. </canvas> <br> <button onclick="startup()">Initialize</button> <br> Log: <pre id="log" style="border: 1px solid #ccc;"></pre>
Setting up the event handlers
When the page loads, the startup() function shown below should be called by our <body> element's onload attribute (but in the example we use a button to trigger it, due to limitations of the MDN live example system).
function startup() { var el = document.getElementsByTagName("canvas")[0]; el.addEventListener("touchstart", handleStart, false); el.addEventListener("touchend", handleEnd, false); el.addEventListener("touchcancel", handleCancel, false); el.addEventListener("touchmove", handleMove, false); log("initialized."); }
This simply sets up all the event listeners for our <canvas> element so we can handle the touch events as they occur.
Tracking new touches
We'll keep track of the touches in-progress.
var ongoingTouches = [];
When a touchstart event occurs, indicating that a new touch on the surface has occurred, the handleStart() function below is called.
function handleStart(evt) { evt.preventDefault(); log("touchstart."); var el = document.getElementsByTagName("canvas")[0]; var ctx = el.getContext("2d"); var touches = evt.changedTouches; for (var i = 0; i < touches.length; i++) { log("touchstart:" + i + "..."); ongoingTouches.push(copyTouch(touches[i])); var color = colorForTouch(touches[i]); ctx.beginPath(); ctx.arc(touches[i].pageX, touches[i].pageY, 4, 0, 2 * Math.PI, false); // a circle at the start ctx.fillStyle = color; ctx.fill(); log("touchstart:" + i + "."); } }
This calls event.preventDefault() to keep the browser from continuing to process the touch event (this also prevents a mouse event from also being delivered). Then we get the context and pull the list of changed touch points out of the event's TouchEvent.changedTouches property.
After that, we iterate over all the Touch objects in the list, pushing them onto an array of active touch points and drawing the start point for the draw as a small circle; we're using a 4-pixel wide line, so a 4 pixel radius circle will show up neatly.
Drawing as the touches move
Each time one or more fingers moves, a touchmove event is delivered, resulting in our handleMove() function being called. Its responsibility in this example is to update the cached touch information and to draw a line from the previous position to the current position of each touch.
function handleMove(evt) { evt.preventDefault(); var el = document.getElementsByTagName("canvas")[0]; var ctx = el.getContext("2d"); var touches = evt.changedTouches; for (var i = 0; i < touches.length; i++) { var color = colorForTouch(touches[i]); var idx = ongoingTouchIndexById(touches[i].identifier); if (idx >= 0) { log("continuing touch "+idx); ctx.beginPath(); log("ctx.moveTo(" + ongoingTouches[idx].pageX + ", " + ongoingTouches[idx].pageY + ");"); ctx.moveTo(ongoingTouches[idx].pageX, ongoingTouches[idx].pageY); log("ctx.lineTo(" + touches[i].pageX + ", " + touches[i].pageY + ");"); ctx.lineTo(touches[i].pageX, touches[i].pageY); ctx.lineWidth = 4; ctx.strokeStyle = color; ctx.stroke(); ongoingTouches.splice(idx, 1, copyTouch(touches[i])); // swap in the new touch record log("."); } else { log("can't figure out which touch to continue"); } } }
This iterates over the changed touches as well, but it looks in our cached touch information array for the previous information about each touch in order to determine the starting point for each touch's new line segment to be drawn. This is done by looking at each touch's Touch.identifier property. This property is a unique integer for each touch, and remains consistent for each event during the duration of each finger's contact with the surface.
This lets us get the coordinates of the previous position of each touch and use the appropriate context methods to draw a line segment joining the two positions together.
After drawing the line, we call Array.splice() to replace the previous information about the touch point with the current information in the ongoingTouches array.
Handling the end of a touch
When the user lifts a finger off the surface, a touchend event is sent. We handle both of these the same way: by calling the handleEnd()function below. Its job is to draw the last line segment for each touch that ended and remove the touch point from the ongoing touch list.
function handleEnd(evt) { evt.preventDefault(); log("touchend"); var el = document.getElementsByTagName("canvas")[0]; var ctx = el.getContext("2d"); var touches = evt.changedTouches; for (var i = 0; i < touches.length; i++) { var color = colorForTouch(touches[i]); var idx = ongoingTouchIndexById(touches[i].identifier); if (idx >= 0) { ctx.lineWidth = 4; ctx.fillStyle = color; ctx.beginPath(); ctx.moveTo(ongoingTouches[idx].pageX, ongoingTouches[idx].pageY); ctx.lineTo(touches[i].pageX, touches[i].pageY); ctx.fillRect(touches[i].pageX - 4, touches[i].pageY - 4, 8, 8); // and a square at the end ongoingTouches.splice(idx, 1); // remove it; we're done } else { log("can't figure out which touch to end"); } } }
This is very similar to the previous function; the only real differences are that we draw a small square to mark the end and that when we call Array.splice(), we simply remove the old entry from the ongoing touch list, without adding in the updated information. The result is that we stop tracking that touch point.
Handling canceled touches
If the user's finger wanders into browser UI, or the touch otherwise needs to be canceled, the touchcancel event is sent, and we call the handleCancel() function below.
function handleCancel(evt) { evt.preventDefault(); log("touchcancel."); var touches = evt.changedTouches; for (var i = 0; i < touches.length; i++) { var idx = ongoingTouchIndexById(touches[i].identifier); ongoingTouches.splice(idx, 1); // remove it; we're done } }
Since the idea is to immediately abort the touch, we simply remove it from the ongoing touch list without drawing a final line segment.
Convenience functions
This example uses two convenience functions that should be looked at briefly to help make the rest of the code more clear.
Selecting a color for each touch
In order to make each touch's drawing look different, the colorForTouch() function is used to pick a color based on the touch's unique identifier. This identifier is an opaque number, but we can at least rely on it differing between the currently-active touches.
function colorForTouch(touch) { var r = touch.identifier % 16; var g = Math.floor(touch.identifier / 3) % 16; var b = Math.floor(touch.identifier / 7) % 16; r = r.toString(16); // make it a hex digit g = g.toString(16); // make it a hex digit b = b.toString(16); // make it a hex digit var color = "#" + r + g + b; log("color for touch with identifier " + touch.identifier + " = " + color); return color; }
The result from this function is a string that can be used when calling <canvas> functions to set drawing colors. For example, for a Touch.identifier value of 10, the resulting string is "#aaa".
Copying a touch object
Some browsers (mobile Safari, for one) re-use touch objects between events, so it's best to copy the bits you care about, rather than referencing the entire object.
The ongoingTouchIndexById() function below scans through the ongoingTouches array to find the touch matching the given identifier, then returns that touch's index into the array.
function ongoingTouchIndexById(idToFind) { for (var i = 0; i < ongoingTouches.length; i++) { var id = ongoingTouches[i].identifier; if (id == idToFind) { return i; } } return -1; // not found }
Showing what's going on
function log(msg) { var p = document.getElementById('log'); p.innerHTML = msg + "\n" + p.innerHTML; }
This section provides additional tips on how to handle touch events in your web application.
Handling clicks
Since calling preventDefault() on a touchstart or the first touchmove event of a series prevents the corresponding mouse events from firing, it's common to call preventDefault() on touchmove rather than touchstart. That way, mouse events can still fire and things like links will continue to work. Alternatively, some frameworks have taken to refiring touch events as mouse events for this same purpose. (This example is oversimplified and may result in strange behavior. It is only intended as a guide.)
function onTouch(evt) { evt.preventDefault(); if (evt.touches.length > 1 || (evt.type == "touchend" && evt.touches.length > 0)) return; var newEvt = document.createEvent("MouseEvents"); var type = null; var touch = null; switch (evt.type) { case "touchstart": type = "mousedown"; touch = evt.changedTouches[0]; break; case "touchmove": type = "mousemove"; touch = evt.changedTouches[0]; break; case "touchend": type = "mouseup"; touch = evt.changedTouches[0]; break; } newEvt.initMouseEvent(type, true, true, evt.originalTarget.ownerDocument.defaultView, 0, touch.screenX, touch.screenY, touch.clientX, touch.clientY, evt.ctrlKey, evt.altKey, evt.shiftKey, evt.metaKey, 0, null); evt.originalTarget.dispatchEvent(newEvt); }
Calling preventDefault() only on a second touch
One technique for preventing things like pinchZoom on a page is to call preventDefault() on the second touch in a series. This behavior is not well defined in the touch events spec, and results in different behavior for different browsers (i.e., iOS will prevent zooming but still allow panning with both fingers; Android will allow zooming but not panning; Opera and Firefox currently prevent all panning and zooming.) Currently, it's not recommended to depend on any particular behavior in this case, but rather to depend on meta viewport to prevent zooming.
=======================
=======================
=======================
현재 자신의 터치 위치 알아내기
다른 터치이벤트 "touchstart", "touchend", "touchcancel" 등등에도 아래와 비슷하게 적용하면 된다.
//캔버스나 다른 변수가 있을떄에는 domelement 대신 캔버스 변수나 다른변수로 넣어주면 된다.
let x = touch1.pageX - domElement.offsetLeft;
let y = touch1.pageY - domElement.offsetTop;
//code
//....
//....
}, false);
=======================
=======================
=======================
출처: http://www.freeimage.kr/iphone/64
Android 또는 iOS을 사용하면 Javascript의 mousedown, mouseup, mousemove같은 이벤트를 그대로 사용할 수 없다. 터치스크린은 마우스가 아니기때문이다. Android와 iOS는 새로운 Javascript touch events API를 지원함으로서 Javascript가 터치스크린을 원할하게 사용 할 수 있도록 하고 있다.
Touche events
touchstart: 손이 터치스크린의 닫는 순간 발생
touchend: 손이 터치스크린에서 떨어지는 순간 발생 (iOS의 경우 touchcancel이벤트 발생)
touchmove: 손을 터치한상태로 터치스크린을 이동하면 발생
touchcancel: iOS에서 touchend의 또다른 이름 인것 같다.
터치스크린은 단순한 터치 뿐만 아니라 멀티터치라는 또다른 제스쳐를 사용 할 수 있다. 이를 위해 Javascript는 Gesture events API또한 제공하고 있다. 하지만 안타깝게도 Android에서는 Gesture events API를 지원하지 않는다고 한다.
Gesture events
gesturestart: 멀티 터치 시작
gesturechange: 멀티 터치상태로 이동
gestureend: 멀티 터치 종료
Example :
function touch(event){ alert(event.touches.length); } document.addEventListener('touchstart', touch, false);
기본은 터치이벤트라 불리는 이벤트의 종류입니다. 현재 대부분의 모바일 기기에서 지원되는 이벤트는 3가지로 그 외에는 벤더의 의존성이 너무 심해서 범용으로 쓰기는 무리가 있습니다.
touchstart : 손가락을 화면에 닿는 순간 발생
touchmove : touchstart 한 상태에서 떼지 않고 화면을 움직여 다닐 때 주기적으로 발생
touchend : 손가락을 화면에서 떼면 발생
느낌으로 보자면 mousedown, mousemove, mouseup 과 같은 분위기 입니다…만!
터치이벤트는 중요한 차이점이 있습니다. 멀티터치를 지원한다는 거죠.
예를 들어 검지가 화면에 닿는 순간 이미 touchstart 가 발생했습니다.
하지만 그 상태에서 중지가 화면에 닿으면 touchend가 발생한 적도 없이 또 touchstart가 발생합니다.
마찬가지로 검지를 움직이면서 중지를 떼면 touchmove가 발생하면서 동시에 touchend도 발생합니다.
이 점이 바로 지옥입니다.
손가락이 여러 개다 보니 하면서 ~ 한다는 거죠. 이런 관점으로 마우스 이벤트를 새삼 바라보면 손가락을 한 개만 지원하는 프로요같은 싱글 터치기반의 이벤트와 비슷한 것입니다.
단순히 dom 에 터치이벤트를 거는 것 만으로는 복잡한 처리를 할 수 없습니다. touchstart 가 수신 되어도 모든 손가락이 touchstart 가 아니고 어떤 손가락은 touchmove 중이고, 어떤 손가락은 이미 touchstart 가 발생된 상태이기 때문입니다.
이를 테스트하기 위한 간단한 js를 제작해 봅시다.
div 를 하나 설정하고 id 를 test 로 준다.
touchstart, touchend 를 걸어 결과를 test.innerHTML 을 통해 보여준다.
별도의 로그함수를 작성하여 간단히 사용한다.
로그함수를 작성해봅시다. div는 공간이 유한하므로 10개 정도 보이다가 다시 클리어하고 보여주는 식으로 가겠습니다.
다음은 이벤트 리스너에서의 작동인데 배열에 필요한 내용을 차곡히 넣은 뒤 join( ” ) 을 통해 log 로 쏴주면 될 것입니다. 터치된 객체 자체는 touches 에 들어있지만 touchend 의 경우는 changedTouches 를 조사해야 하니 두 개 다 정리해서 보여주도록 하겠습니다.
모바일에선 일반적으로 (안드로이드, ios 등) mouseDown, mouseMove, mouseUp 대신 touchstart, touchmove, touchend를 사용하면 된다. 단, 마소 IE의 경우 따로 MSPointerDown, MSPointerMove, MSPointerUP을 사용한다..
document.addEventListener('touchmove', function(event) { var touch1 = event.touches[0]; var touch2 = event.touches[1]; if(touch1 && touch2){ //멀티터치 } else { //싱글터치 } }, false); IE의 경우는 event.getPointerList(event.pointerID).length == 2 뭐 이런식으로 해야하는 듯.. 통일 좀 했으면 좋겟다.....
Click Delay
모바일 웹에서 클릭 이벤트를 구현해보면 클릭하고 약간의 지연시간(300ms)이 있다. 브라우저에서 다른 제스처들 (스와이프, 더블탭 등)을 확인하기 위해서인데 이게 의외로 답답하다. 이를 없애기 위해서 jquery mobile에서 tap 이벤트를 사용하거나 이와 관련해서 플러그인도 많으니 찾아 쓰면 된다. 직접 해결하려면 touchstart와 touchend를 사용해서 구현하면 된다.
preventDefault & stopPropagation
모바일에서 성능에 문제가 있을 때.. event.preventDefault()와 event.stopPropagation()을 적절히 사용하면 도움이 될 수 있다..
=======================
=======================
=======================
출처: https://ncube.net/10453
JavaScript를 이용해 좌우 swipe 방향 알아내기
JavaScript를 이용하여 터치기기에서 좌우 swipe 방향을 체크하는 개념적인 방법이다. 기본적인 아이디어 수준의 코드이기 때문에 실제 사용하는 것은 무리가 있을 것이라 생각한다. 사용자가 기기에 터치를 하면 touchstart 이벤트를 이용해 터치가 시작된 좌표를 기록해둔다. 그런 다음 touchend 이벤트를 이용해 터치가 끝났을 때 시작점의 좌표와 종료점의 좌표를 비교해서 swipe 방향을 체크하는 것이다. iOS 기기의 Safari 브라우저에서는 터치가 끝난 후 touchend 이벤트가 만료되지 않아 touches.length == 0 이라는 조건을 추가해서 체크하도록 했다. Android 기기에서는 바로 이벤트가 만료되는 듯 했다. 좌우로 swipe 하면서 완전히 일직선으로 움직이는 것은 불가능하기 때문에 약간의 허용오차를 둬서 오차범위일 때만 alert 함수가 실행된다.
얼핏보면 괜찮은 방법인 것 같은데 scroll 이벤트가 함께 발생하기 때문에 좌우 swipe 임에도 문서가 오르락내리락 할 수 있다. 이런 경우에도 대비를 해야하겠지만 당장은 방법이 떠오르지 않아 이정도에서 마무리를 한다. 이전에 포스팅했던 jQuery swipe 플러그인을 사용하면 scroll 이벤트까지 제어하면서 swipe 이벤트를 제대로 활용할 수 있다. 플러그인이 있는데 굳이 이런 걸 해본 것은 삽질을 좋아하기 때문이다. ㅋㅋ
=======================
=======================
=======================
출처: http://blog.iolo.kr/490
터치기반 모바일 웹킷에서 버튼 반응 속도 개선하기
아이폰/아이패드/아이팟의 모바일 사파리와 안드로이드의 모바일 크롬 등은 모두 터치기반 모바일 웹킷을 사용하는 브라우져들이다. 이 브라우져들은 버튼 등을 눌렀다(touchstart) 떼도(touchup) 즉시 반응(click)하지 않는데, 그 이유는 연속되는 터치 동작(touchstart-touchmove-touchend)들이 제스쳐(swipe, long click, …)인지 여부를 확인하기 위해 최대 300ms의 지연시간이 생기기 때문이다. 모바일 웹 사이트를 만드는 경우라면 이 정도의 지연시간은 크게 문제가 되지않지만, 상대적으로 신속한 반응을 요구하는 “웹앱"이라면 얘기가 달라진다.
해결책은 간단하다: 1. 손가락으로 무언가를 누르면(touchstart) 2. 웹킷의 기본 동작(300ms 지연)을 못하게 막고(preventDefault) 3. 움직임(touchmove) 없이 4. 손가락을 떼면(touchend) 5. 클릭(click)으로 간주한다.
touchstart/touchend을 mousedown/mouseup으로 바꿔놓고 보면 HTML5 이전에 drag & drop을 처리하기 위해서 사용하는 방식과 유사하다.
다시 말하지만, 위의 페이지는 터치기반의 모바일 웹킷, 즉 모바일 사파리나 모바일 크롬으로 봐야 효과가 있다.
일단 눈에 보이는 Slow Button과 Fast Button 각각을 평소대로 눌러보자. 클릭을 감지하는데 걸린 시간이 표시되는데, Fast 쪽이 조금 빠르긴 하지만 큰 차이는 없어 보인다. 이번에는 평소보다 좀 더 손끝에 감각을 모아서 “톡톡 두드린다는 느낌”으로 각 버튼을 눌러보자. Slow Button의 경우엔 아예 반응을 하지 않거나 확대(아이폰등에서는 더블탭이 자동 확대/축소)기능이 동작된다. Fast Button은 그런 동작을 하지 않는다.
이 글에서는 touchstart-touchmove-touchend 이벤트를 활용하여 버튼의 반응속도를 개선하는 방법을 알아보았다. 이 세가지 이벤트의 활용법을 잘 익혀두면 다양한 유형의 터치 입력을 처리하는데 많은 도움이 될 것이다.
첫째, jquery animate로 구현할 것인지 혹은 css3의 animate기능을 구현할 것인지 선택해야 한다. jquery animate로 결정하면, css3의 animate기능을 지원하지 않는 브라우저에서도 동일한 효과를 구현할 수 있다. 하지만 속도는 css3의 animate에 비해서 느리다. 반면에 css3의 animate로 결정하면, 속도가 빠르다. 만약 제작시에 클라이언트나 상사의 요구가 없다면 css의 animate로 구현할것을 권한다. 이 기능은 대부분의 모바일 브라우저에 사용할 것이고, 글을 쓰는 시점에서 브라우저중 css3의 animate를 지원하지 않는 것은 없었다.
두번쨰로 고려할것은, jquery를 사용할 경우이다. 만약 사용하는 jquery의 버젼이 1.9.1 이하이면 jquery의 버젼을 업그레이드 하거나 혹은 직접 css3 관련 함수를 구현하거나 cssHock기능을 사용해야 한다. 왜냐하면 jquery 1.9.1 이하버젼에서는 elemenet.css() 함수안에 css3 속성을 지원하지 않기 때문이다.
들어가기… 앞에서 두 가지를 결정하였다면, 이제 코드를 작성해야 한다.기본적으로는 롤링 배너에 터치 기능이 추가되기 때문에 관련 스크립트 소스가 있으면 더욱 좋을것 같다. 먼저 터치 관련 이벤트 함수를 알아야 한다. 모바일에 터치 기능이 추가되면서, 자연스럽게 javascript에도 이를 지원해주는 함수가 추가되었다. touchstart, touchmove, touchend이다. 이 세 이벤트는 이름 그대로이다. 다만 이들은 click함수와 이벤트 발생 순서만 차이 있을 뿐, 비슷하기 때문에 이를 구별해 주어야 한다. 각 이벤트별로 설명을 약간의 설명을 더하면, 먼저 터치 시작시 이벤트에는 시작 위치와 시작 이전의 원래위치를 기억해야만 한다. 터치중 이벤트에서는 기억된 시작위치에서 현재위치를 뺸 값을 css3 transition값에 대입하여 슬라이드 DOM이 따라오도록 해야 한다. 마지막으로 터치가 끝났을때는 사용자의 터치한 길이가 어느정도 이상이면 다음 슬라이드 혹은 이전 슬라이드로 이동하도록 하면 된다. 만약, 터치한 길이가 매우 짧으면 터치 시작시 기억한 시작 이전의 원래위치로 돌아가면 된다. 아래는 참고 소스이다.
var touch_start_y = 0; var touch_start_x = 0; var save_x = 0; var save_y = 0; var move_dx = 0; element.addEventListener( 'touchstart', function( e ) { if ( e.type === 'touchstart' && e.touches.length === 1 ) { touch_start_x = e.touches[ 0 ].pageX; touch_start_y = e.touches[ 0 ].pageY; } }, false ); element.addEventListener( 'touchmove', function( e ) { var drag_dist = 0; var scroll_dist = 0; if ( e.type === 'touchmove' && e.touches.length === 1 ) { drag_dist = e.touches[ 0 ].pageX - touch_start_x; scroll_dist = e.touches[ 0 ].pageY - touch_start_y; move_dx = ( drag_dist / list_Width ) * 100; if ( Math.abs( drag_dist ) > Math.abs( scroll_dist ) ) { // ... move slide element e.preventDefault( ); } } }, false ); element.addEventListener( 'touchend', function( e ) { if ( e.type === 'touchend' && e.touches.length === 0 ) { if ( Math.abs( move_dx ) > 40 ) { // ... move slide element to Next or Prev slide } else { // ... move slide element to save_x or save_y position } touch_start_y = 0; touch_start_x = 0; move_x = 0; move_y = 0; move_dx = 0; e.preventDefault( ); } }, false );
추가 팁이 있다면, css3의 transition를 사용하게 될때 일부 디바이스에서는 번쩍거리는 현상이 있었다. 이런 현상이 있다면, 부모 DOM에 transform-style를 preserve-3d로 설정하여야 한다. 또한 일부 개발자중에 이벤트 전달 인자가 없거나 ie 브라우저를 생각하고 e = e || window.event 이런 코드를 삽입하는 경우가 있다. 이 코드를 삽입하게 되면 사용자가 터치 하지 않은 공간에서도 이벤트가 발생하니 유념하기 바란다.
정리하며… 앞에서도 언급했다시피, 롤링 배너위에 단순히 터치 기능만 추가된다고 생각하고 금방 하겠지 하고 들어갔지만 생각보다 고려할 상황이 많았다. 덕분에 모바일에 특성에 대해서 많이 배운 기회였던 것 같다.