Ukážeme si na závěr jednoduchý příklad, jak sledovat dotyky více prsty najednou (příklad se hodí i jako jednoduchý test, zda zařízení, například tablet, podporuje multitouch).
Příklad vychází z kódu na adrese http://sebleedelisle.com/2011/04/multi-touch-game-controller-in-javascripthtml5-for-ipad/ od Seba Lee-Delisle)
Zdrojový kód:
<style> … canvas { background-color:#111133; display:block; position:absolute; } #container { width:auto; text-align:center; background-color:#ff0000; } </style> <script> "use strict"; var c, canvas, touches; function touchstart(e){ touches = e.touches; } function touchmove(e){ e.preventDefault(); touches = e.touches; } function touchend(e){ touches = e.touches; } function draw() { if (touches && touches.length>0) { c.clearRect(0,0,canvas.width, canvas.height); for(var i=0; i<touches.length; i++) { var touch = touches[i]; c.fillStyle = "white"; c.fillText("touch id : "+touch.identifier+" x:"+touch.clientX+" y:"+touch.clientY, touch.clientX+30, touch.clientY-30); c.beginPath(); c.strokeStyle = "magenta"; c.lineWidth = "6"; c.arc(touch.clientX, touch.clientY, 40, 0, Math.PI*2, true); c.stroke(); } } else { c.clearRect(0,0,canvas.width, canvas.height); } } function resetCanvas() { canvas.width = window.innerWidth; canvas.height = window.innerHeight; window.scrollTo(0,0); } function onload(){ canvas = document.getElementById( 'c' ); c = canvas.getContext( '2d' ); canvas.width = window.innerWidth; canvas.height = window.innerHeight; canvas.ontouchstart = touchstart; canvas.ontouchmove = touchmove; canvas.ontouchend = touchend; window.onorientationchange = resetCanvas; window.onresize = resetCanvas; setInterval(draw, 1000/35); } </script> </head> <body onload="onload()"> <div id="container"> <canvas id="c"></canvas> </div> </body></html>
Obsluha událostí spočívá pouze v tom, že jsou aktuální souřadnice dotyků (e.touches) uloženy do globální proměnné. U pohybu je ještě zablokováno vykonávání systémové události. Pamatujte: obsluha událostí by měla být co nejrychlejší, což je tu dodrženo.
function touchstart(e){ touches = e.touches; } function touchmove(e){ e.preventDefault(); touches = e.touches; } function touchend(e){ touches = e.touches; }
Na začátku (onload) je získán 2D kontext pro canvas. Canvas je přes celou plochu, proto navěsíme obsluhu touch událostí právě na něj. Důležité je periodické vyvolání funkce draw, která se postará o vizualizaci míst dotyku.
Funkce draw()
vezme souřadnice dotyků (z globální proměnné) a vykreslí do patřičných míst kroužky a k nim připojí text s informacemi o souřadnicích a o ID dotykové události.
Vykreslení je implementováno „naivně“ – funkce se vyvolává pravidelně v daném intervalu, vždy smaže celý canvas a vykreslí vše znovu. Samotná animace je poměrně jednoduchá, takže „problikávání“ není vidět – pokud byste ale implementovali nějaké složitější vykreslování, bylo by samozřejmě na místě použít vyspělejší animační techniky (double / triple buffering atd.)
Poznámka k animaci
V době psaní této kapitoly bohužel ještě iOS nepodporoval animační novinku – JS funkci requestAnimationFrame()
. Tato funkce je velmi podobná funkci setInterval() s tím rozdílem, že interval je daný „systémovou“ animační smyčkou, v níž systém vykonává např. CSS animace. Pokud řešíte animace v JavaScriptu, je výhodné použít právě tuto funkci. Prohlížeč ji pak vyvolává tak často jako ostatní animační rutiny, vykreslování je tedy synchronizované a s optimální rychlostí.
Vlastní kód lze upravit tak, aby byl připravený na okamžik, kdy iOS tuto funkci implementuje:
var requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame || (function(x){setInterval(x,1000/60);}); requestAnimationFrame(draw);
Tento shim definuje funkci requestAnimationFrame. Pokud je systémová, použije ji. Pokud prohlížeč nabízí funkci s vendor prefixem, použije tu. Pokud nemá ani s prefixem, použije náhradní řešení se setInterval.
Pro podobné krátké kódy, které řeší problémy s kompatibilitou mezi prohlížeči, se vžilo označení shim. Kódy, které pomáhají používat nové funkce i v prohlížečích, kde nejsou implementované, se označují jako polyfill.
Ve chvíli, kdy prohlížeč Safari v iOS implementuje requestAnimationFrame, použije kód tuto implementaci, do té doby si vystačí se setInterval.
Autor děkuje společnosti Czech Computer za laskavé zapůjčení tabletu iPad 2.
Přehled komentářů