פיתוח אינטרנט לכמה נקודות מגע

בוריס סמוס
בוריס סמוס

מבוא

במכשירים ניידים כמו סמארטפונים וטאבלטים יש בדרך כלל מסך קיבולי רגיש למגע, כדי שאפשר יהיה לתעד אינטראקציות שמבוצעות עם האצבעות של המשתמשים. האינטרנט לנייד מתפתח כל הזמן כדי לאפשר אפליקציות מתוחכמות יותר ויותר, ולכן מפתחי האינטרנט צריכים דרך לטפל באירועים האלה. לדוגמה, כמעט בכל משחק שבקצב מהיר נדרש לשחקן ללחוץ על כמה לחצנים בו-זמנית, ובהקשר של מסך מגע כולל שימוש במספר נקודות מגע.

Apple הוסיפה את touch events API ל-iOS 2.0. מערכת Android מתעדכנת בסטנדרט בפועל ומצמצמת את הפער. לאחרונה התכנסה קבוצת עבודה של W3C כדי לעבוד על המפרט של אירועי מגע.

במאמר הזה אפרט על ה-API של אירועי המגע שמסופק על ידי מכשירי iOS ו-Android, וגם על Chrome למחשב בחומרה שתומכת במגע, ואציג את סוגי האפליקציות שאפשר ליצור, אציג כמה שיטות מומלצות ונדון בשיטות שימושיות שמקלות על פיתוח אפליקציות עם מגע.

אירועי מגע

שלושה אירועי מגע בסיסיים מתוארים במפרט ומיושמים באופן נרחב במכשירים ניידים:

  • touchstart: אצבע ממוקמת על רכיב DOM.
  • touchmove: גוררים אצבע לאורך רכיב DOM.
  • מגע: מתבצעת הסרה של אצבע מרכיב DOM.

כל אירוע מגע כולל שלוש רשימות של נגיעות:

  • נגיעות: רשימה של כל האצבעות שמופיעות כרגע במסך.
  • targetTouches: רשימה של אצבעות ברכיב ה-DOM הנוכחי.
  • changedTouches: רשימה של אצבעות שמעורבות באירוע הנוכחי. למשל, באירוע של קצה מגע, זו תהיה האצבע שהוסרה.

הרשימות האלה מורכבות מאובייקטים שמכילים פרטי מגע:

  • identifier: מספר שמזהה באופן ייחודי את האצבע הנוכחית בסשן המגע.
  • target: רכיב ה-DOM שהיה היעד של הפעולה.
  • קואורדינטות של לקוח/דף/מסך: המקום במסך שבו התרחשה הפעולה.
  • קואורדינטות של רדיוס ו-rotAngle: מתאר את האליפסה בהתאם לצורת האצבע.

אפליקציות שמופעלות במגע

האירועים touchstart, touchmove ו-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);

הדגמות

יש כמה הדגמות מעניינות עם נקודות מגע רבות, כמו הדגמה זו של ציור מבוסס-בד מאת פול איריש ואחרים.

צילום מסך של שרטוט

ו-Browser Ninja, הדגמה טכנית שהוא שכפול של Fruit Ninja באמצעות מעברים ומעברים של CSS3, וכן לוח הציור:

נינג&#39;ה של הדפדפן

שיטות מומלצות

מניעת שינוי מרחק התצוגה

הגדרות ברירת המחדל לא פועלות כשמשתמשים בריבוי נקודות מגע, כי הרבה פעמים תנועות והחלקה קשורות להתנהגות הדפדפן, כמו גלילה ושינוי מרחק התצוגה.

כדי להשבית את שינוי מרחק התצוגה, מגדירים את אזור התצוגה כך שלא ניתן יהיה להתאים את המשתמש באמצעות המטא תג הבא:

<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); 

עיבוד בקפידה

אם אתם כותבים אפליקציה עם כמה נקודות מגע שכוללת תנועות מורכבות עם כמה אצבעות, כדאי להיזהר בדרך שבה אתם מגיבים לאירועי מגע, כי תטפלו בכל כך הרבה בבת אחת. חשבו על הדוגמה שבקטע הקודם שמתייחסת לכל הנגיעות במסך. אתם יכולים לצייר ברגע שיש קלט מגע:

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

אבל השיטה הזו לא משתנה באמצעות מספר אצבעות על המסך. במקום זאת, ניתן לעקוב אחרי כל האצבעות ולעבד אותן בלופ כדי להשיג ביצועים הרבה יותר טובים:

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

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

שימוש ב- targetTouches ובנגיעות שהשתנו

חשוב לזכור שהאירוע event.touches הוא מערך של ALL אצבעות שמגעות במסך, ולא רק אלה שביעד של רכיב ה-DOM. במקום זאת, השימוש ב-event.targetTouches או ב-event.changedTouches עשוי להיות הרבה יותר מועיל.

לבסוף, מאחר שאתם מפתחים לנייד, חשוב שתכירו את השיטות המומלצות הכלליות לשימוש בנייד, שמפורטות במאמר של אריק בידלמן ובמסמך של W3C.

תמיכה במכשיר

לצערנו, הטמעות של אירועי מגע שונות מאוד זו מזו מבחינת השלמות והאיכות. כתבתי סקריפט אבחון שמציג מידע בסיסי על הטמעת ה-API במגע, כולל האירועים הנתמכים ורזולוציית ההפעלה של touchmove. בדקתי את Android 2.3.3 ב-Nexus One ובחומרה של Nexus S, את Android 3.0.1 ב-Xoom ואת iOS 4.2 ב-iPad וב-iPhone.

בקצרה, כל הדפדפנים שנבדקים תומכים באירועי touchstart, touchend ו-touchmove.

במפרט מופיע שלושה אירועי מגע נוספים, אבל אף דפדפן שנבדק לא תומך בהם:

  • touchenter: אצבע זזה נכנסת לרכיב DOM.
  • touchleave: אצבע זזה יוצאת מרכיב DOM.
  • touchcancel: נגיעה הופסקה (ספציפי להטמעה).

בכל רשימת מגע, הדפדפנים הנבדקים מספקים גם את רשימות המגע TouchTouch, targetTouches ו-changedTouches. עם זאת, אף דפדפן שנבדק לא תומך ב-radiusX, ב-radiusY או ב-rotAngle, שבהם מצוין צורת האצבע הנגיעה במסך.

במהלך העברת מגע, אירועים מופעלים בערך 60 פעמים בשנייה בכל המכשירים שנבדקים.

Android 2.3.3 (Nexus)

בדפדפן Gingerbread של Android (שנבדק ב-Nexus One וב-Nexus S), אין תמיכה במגע בריבוי נקודות מגע. זוהי בעיה ידועה.

Android 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 (iPad, iPhone)

מכשירי iOS תומכים באופן מלא בריבוי מגע, יכולים לעקוב אחרי לא מעט אצבעות ולספק חוויית מגע רספונסיבית מאוד בדפדפן.

כלים למפתחים

בפיתוח של מכשירים ניידים, בדרך כלל קל יותר להתחיל ליצור אבטיפוס במחשב ולאחר מכן להתמודד עם החלקים הספציפיים לנייד במכשירים שבהם אתם מתכוונים לתמוך. התכונה Multi-touch היא אחת מהתכונות שקשה לבדוק במחשב PC, כי ברוב המחשבים אין קלט מגע.

בדיקה בנייד יכולה להאריך את מחזור הפיתוח, כי כל שינוי שמבצעים צריך להתבצע בדחיפה לשרת ואז לטעון אותו במכשיר. לאחר ההפעלה, לא תוכלו לבצע מעט ניפוי באגים באפליקציה שלכם, כי בטאבלטים ובסמארטפונים אין כלים למפתחי אתרים.

הפתרון לבעיה הזו הוא ליצור סימולציות של אירועי מגע במכונת הפיתוח שלכם. בנגיעות בודדות, ניתן לדמות אירועי מגע על סמך אירועי עכבר. אפשר לדמות אירועים שכוללים מגע במספר נקודות אם יש לכם מכשיר עם קלט מגע, כמו Apple MacBook מודרני.

אירועים בנגיעה יחידה

כדי לדמות אירועים בנגיעה יחידה במחשב, Chrome מספק אמולציה של אירועי מגע מהכלים למפתחים. פותחים את הכלים למפתחים, בוחרים בסמל ההגדרות, בוחרים ב'שינויי הגדרות' או ב'אמולציה' ומפעילים את האפשרות 'אמולציה של אירועי מגע'.

בדפדפנים אחרים, מומלץ לנסות את Phantom Limb, שמדמה אירועי מגע בדפים וגם נותן יד לאתחול.

יש גם את הפלאגין Touchable של jQuery, שמאחד אירועי מגע ועכבר בפלטפורמות שונות.

אירועי ריבוי מגע

כדי לאפשר ליישום האינטרנט מרובה המגע לפעול בדפדפן שלך במשטח המגע מרובה המגע (כמו Apple MacBook או MagicPad), יצרתי את MagicTouch.js polyfill. הוא מתעד את אירועי המגע ממשטח המגע והופך אותם לאירועי מגע שתואמים לסטנדרטים הרגילים.

  1. מורידים את הפלאגין npTuioClient NPAPI אל ~/Library/Internet Plug-Ins/.
  2. הורידו את האפליקציה TongSeng TUIO ל-MagicPad של Mac והפעילו את השרת.
  3. מורידים את MagicTouch.js, ספריית JavaScript כדי לדמות אירועי מגע שתואמים למפרטים על סמך קריאות חוזרות של npTuioClient.
  4. עליכם לכלול באפליקציה את הסקריפט Magtouch.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>

ייתכן שתצטרכו להפעיל את הפלאגין.

הדגמה בזמן אמת עם Magtouch.js זמינה בכתובת paulirish.com/demo/multi:

בדקתי את הגישה הזו רק עם Chrome 10, אבל היא אמורה לפעול בדפדפנים מודרניים אחרים עם שינויים קלים בלבד.

אם המחשב לא תומך בקלט מולטי מגע, אפשר לדמות אירועי מגע באמצעות כלי מעקב אחרים של TUIO, כמו reacTIVision. למידע נוסף, היכנסו לדף הפרויקט של TUIO.

חשוב לזכור: יכול להיות שהתנועות יהיו זהות לתנועות עם כמה נקודות מגע ברמת מערכת ההפעלה. ב-OS X, אפשר להגדיר אירועים ברמת המערכת באמצעות מעבר לחלונית ההעדפה של משטח המגע ב'העדפות המערכת'.

ככל שתכונות ריבוי המגע נתמכות בדפדפנים לנייד יותר ויותר, אני מצפה לראות שיישומי אינטרנט חדשים מנצלים את מלוא היתרונות של ממשק ה-API העשיר.