การพัฒนาเว็บแบบมัลติทัช

เกริ่นนำ

อุปกรณ์เคลื่อนที่ เช่น สมาร์ทโฟนและแท็บเล็ตมักจะมีหน้าจอที่ไวต่อการสัมผัสแบบคาปาซิทีฟเพื่อจับภาพการโต้ตอบที่เกิดจากนิ้วของผู้ใช้ เมื่อเว็บบนอุปกรณ์เคลื่อนที่พัฒนาเพื่อรองรับแอปพลิเคชันที่ซับซ้อนขึ้นเรื่อยๆ นักพัฒนาซอฟต์แวร์เว็บก็ต้องการวิธีจัดการกับเหตุการณ์เหล่านี้ ตัวอย่างเช่น เกมที่เล่นเร็วเกือบทุกเกม ผู้เล่นจะต้องกดปุ่มหลายปุ่มพร้อมกัน ซึ่งจะหมายถึงมัลติทัชในบริบทของหน้าจอสัมผัส

Apple ได้เปิดตัว API กิจกรรมการแตะใน iOS 2.0 Android ได้ทำตามมาตรฐาน ข้อเท็จจริงนี้ และปิดช่องโหว่นี้ เมื่อเร็วๆ นี้ กลุ่มทำงาน W3C ได้ร่วมกันทำงานเพื่อ ปรับปรุงข้อกำหนดเหตุการณ์การสัมผัสนี้

ในบทความนี้ ฉันจะเจาะลึกเกี่ยวกับ API กิจกรรมการแตะที่ให้บริการโดยอุปกรณ์ iOS และ Android รวมถึง Chrome บนเดสก์ท็อปในฮาร์ดแวร์ที่รองรับการแตะ และสำรวจประเภทแอปพลิเคชันที่คุณสร้างได้ นำเสนอแนวทางปฏิบัติที่ดีที่สุด และเทคนิคที่เป็นประโยชน์ซึ่งช่วยให้พัฒนาแอปพลิเคชันที่เปิดใช้ระบบสัมผัสได้ง่ายขึ้น

เหตุการณ์เกี่ยวกับการสัมผัส

เหตุการณ์การแตะพื้นฐาน 3 รายการแสดงอยู่ในข้อกำหนดเฉพาะและนำไปใช้ในอุปกรณ์เคลื่อนที่อย่างทั่วถึง ดังนี้

  • touchstart: วางนิ้วไว้บนองค์ประกอบ DOM
  • touchmove: มีการลากนิ้วไปตามองค์ประกอบ DOM
  • touchend: มีการถอดนิ้วออกจากองค์ประกอบ DOM

กิจกรรมการแตะแต่ละกิจกรรมจะมีการแตะ 3 รายการ ดังนี้

  • แตะ: รายการนิ้วทั้งหมดที่อยู่บนหน้าจอในขณะนี้
  • targetTouches: รายการนิ้วบนองค์ประกอบ DOM ปัจจุบัน
  • changedTouches: รายการนิ้วที่เกี่ยวข้องในเหตุการณ์ปัจจุบัน เช่น ในเหตุการณ์การแตะจะเป็นนิ้วที่ถูกนำออก

รายการเหล่านี้ประกอบด้วยวัตถุที่มีข้อมูลการสัมผัสดังนี้

  • identifier: หมายเลขที่ระบุนิ้วปัจจุบันอย่างไม่ซ้ำกันในเซสชันการสัมผัส
  • target: องค์ประกอบ DOM ที่เป็นเป้าหมายของการกระทำดังกล่าว
  • พิกัดไคลเอ็นต์/หน้า/หน้าจอ: ตำแหน่งที่เกิดการกระทำบนหน้าจอ
  • รัศมีและมุมการหมุน: อธิบายวงรีที่ประมาณรูปร่างนิ้ว

แอปที่รองรับระบบสัมผัส

เหตุการณ์ 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);

เดโม

เรามีการสาธิตแบบมัลติทัชที่น่าสนใจมากมายให้ใช้งานอยู่แล้ว เช่น การสาธิตการวาดด้วยผืนผ้าใบนี้โดย Paul Ireland และคนอื่นๆ

ภาพหน้าจอภาพวาด

และ Browser Ninja ซึ่งเป็น เดโมเทคโนโลยีที่โคลนของ Fruit Ninja โดยใช้ CSS3 เปลี่ยนรูปแบบและการเปลี่ยนภาพ รวมถึงแคนวาส

เบราว์เซอร์นินจา

แนวทางปฏิบัติแนะนำ

ป้องกันการซูม

การตั้งค่าเริ่มต้นทำงานได้ไม่ดีนักสำหรับมัลติทัช เนื่องจากการปัดและท่าทางสัมผัสมักเกี่ยวข้องกับลักษณะการทำงานของเบราว์เซอร์ เช่น การเลื่อนและการซูม

หากต้องการปิดการซูม ให้ตั้งค่าวิวพอร์ตไม่ให้ผู้ใช้ปรับขนาดได้ด้วยเมตาแท็กต่อไปนี้

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

ดูข้อมูลเพิ่มเติมเกี่ยวกับการตั้งค่าวิวพอร์ตได้ในบทความ HTML5 บนอุปกรณ์เคลื่อนที่นี้

ป้องกันการเลื่อน

อุปกรณ์เคลื่อนที่บางรุ่นมีลักษณะการทำงานเริ่มต้นสำหรับการแตะ เช่น เอฟเฟกต์การเลื่อนเกินของ 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 และ ChangeTouch

โปรดทราบว่า event.touches เป็นอาร์เรย์ของนิ้วทั้งหมดที่สัมผัสกับหน้าจอ ไม่ใช่แค่ในเป้าหมายขององค์ประกอบ DOM คุณอาจพบว่าการใช้ event.targetTouches หรือ event.changedTouches แทนนั้นมีประโยชน์มากกว่า

สุดท้ายนี้ เนื่องจากคุณกำลังพัฒนาสำหรับอุปกรณ์เคลื่อนที่ คุณจึงควรคำนึงถึงแนวทางปฏิบัติแนะนำสำหรับอุปกรณ์เคลื่อนที่โดยทั่วไป ซึ่งมีอยู่ในบทความของ Eric Bidelman และเอกสาร W3C นี้

การรองรับอุปกรณ์

อย่างไรก็ตาม การใช้งานกิจกรรมการแตะจะแตกต่างกันในเรื่องความสมบูรณ์และคุณภาพ ผมได้เขียนสคริปต์การวินิจฉัยที่แสดงข้อมูลพื้นฐานเกี่ยวกับการใช้งาน Touch API รวมถึงเหตุการณ์ที่รองรับและการแก้ปัญหาการเริ่มทำงานแบบ Touchmove ผมได้ทดสอบ Android 2.3.3 บน Nexus One และฮาร์ดแวร์ Nexus S, Android 3.0.1 บน Xoom และ iOS 4.2 บน iPad และ iPhone

โดยสรุปแล้ว เบราว์เซอร์ที่ทดสอบทั้งหมดรองรับเหตุการณ์ touchstart, touchend และ touchmove

ข้อกำหนดนี้มีเหตุการณ์การสัมผัสเพิ่มเติม 3 รายการ แต่ไม่มีเบราว์เซอร์ที่ทดสอบรองรับเหตุการณ์ดังกล่าว ดังนี้

  • touchenter: การเคลื่อนไหวนิ้วจะเข้าสู่องค์ประกอบ DOM
  • touchleave: นิ้วเลื่อนจะออกจากองค์ประกอบ DOM
  • touchcancel: การแตะถูกขัดจังหวะ (เฉพาะสำหรับการใช้งาน)

ในรายการสัมผัสแต่ละรายการ เบราว์เซอร์ที่ทดสอบยังมี การแตะ, targetTouches และ changedTouches ในรายการ อย่างไรก็ตาม ไม่มีเบราว์เซอร์ที่ทดสอบใดๆ ที่สนับสนุน รัศมี X, รัศมี Y หรือ มุมหมุน ซึ่งระบุรูปร่างของนิ้วที่แตะหน้าจอ

ระหว่างการเปลี่ยนผ่านการสัมผัส เหตุการณ์จะเริ่มทำงานประมาณ 60 ครั้งต่อวินาทีในอุปกรณ์ที่ทดสอบทั้งหมด

แอนดรอยด์ 2.3.3 (Nexus)

ส่วนในเบราว์เซอร์ Android Gingerbread (ผ่านการทดสอบบน Nexus One และ Nexus S) จะไม่รองรับมัลติทัช ซึ่งกรณีนี้เป็นปัญหาที่ทราบ

แอนดรอยด์ 3.0.1 (Xoom)

ในเบราว์เซอร์ของ Xoom จะมีการสนับสนุนมัลติทัชพื้นฐาน แต่จะทำงานกับ องค์ประกอบ DOM เดียวเท่านั้น เบราว์เซอร์ตอบสนองต่อการแตะ 2 แบบพร้อมกันไม่ถูกต้องในเอลิเมนต์ DOM ต่างๆ กล่าวอีกนัยหนึ่งคือ รายการต่อไปนี้จะตอบสนองต่อการแตะ 2 แบบพร้อมกัน

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 รองรับมัลติทัชอย่างสมบูรณ์ สามารถติดตามได้หลายนิ้ว และมอบประสบการณ์การแตะที่ตอบสนองตามอุปกรณ์ในเบราว์เซอร์

เครื่องมือสำหรับนักพัฒนาซอฟต์แวร์

ในการพัฒนาอุปกรณ์เคลื่อนที่ การสร้างต้นแบบบนเดสก์ท็อปก่อน แล้วจัดการกับชิ้นส่วนสำหรับอุปกรณ์เคลื่อนที่โดยเฉพาะในอุปกรณ์ที่คุณต้องการจะสนับสนุนนั้นมักจะทำได้ง่าย มัลติทัชเป็นหนึ่งในฟีเจอร์เหล่านั้นที่ทดสอบบนพีซีได้ยาก เพราะพีซีส่วนใหญ่ไม่มีการป้อนข้อมูลด้วยการสัมผัส

การทดสอบในอุปกรณ์เคลื่อนที่อาจทำให้วงจรการพัฒนานานขึ้น เนื่องจากทุกการเปลี่ยนแปลงที่คุณทำจะต้องพุชไปยังเซิร์ฟเวอร์แล้วโหลดลงในอุปกรณ์ จากนั้นเมื่อเรียกใช้แล้ว คุณจะแก้ไขข้อบกพร่องของแอปพลิเคชันได้ไม่มากนัก เนื่องจากแท็บเล็ตและสมาร์ทโฟนไม่มีเครื่องมือสำหรับนักพัฒนาซอฟต์แวร์เว็บ

วิธีแก้ปัญหานี้คือการจำลองเหตุการณ์การแตะบนเครื่องการพัฒนาของคุณ สำหรับการแตะเพียงครั้งเดียว เหตุการณ์การแตะสามารถจำลองได้จากเหตุการณ์ของเมาส์ คุณสามารถจำลองเหตุการณ์แบบมัลติทัชได้หากคุณมีอุปกรณ์ที่ใช้ การป้อนข้อมูลด้วยการแตะ เช่น Apple MacBook รุ่นใหม่

เหตุการณ์ด้วยการแตะเพียงครั้งเดียว

หากคุณต้องการจำลองเหตุการณ์ด้วยการแตะเพียงครั้งเดียวบนเดสก์ท็อป Chrome มีการจำลองเหตุการณ์แบบสัมผัสจากเครื่องมือสำหรับนักพัฒนาซอฟต์แวร์ เปิดเครื่องมือสำหรับนักพัฒนาซอฟต์แวร์ จากนั้นเลือกเฟืองการตั้งค่า ตามด้วย "ลบล้าง" หรือ "การเลียนแบบ" จากนั้นเปิด "จำลองเหตุการณ์การแตะ"

สำหรับเบราว์เซอร์อื่นๆ คุณอาจต้องการทดลองใช้ Phantom Limb ซึ่งจะจำลองเหตุการณ์การแตะบนหน้าและยังเป็นมือยักษ์ในการเปิดเครื่อง

นอกจากนี้ยังมีปลั๊กอิน jQuery แตะได้ ที่จะรวมเหตุการณ์การแตะและเมาส์ในทุกแพลตฟอร์ม

เหตุการณ์แบบมัลติทัช

เพื่อให้เว็บแอปพลิเคชันแบบมัลติทัชทำงานในเบราว์เซอร์บนแทร็กแพดแบบมัลติทัช (เช่น Apple MacBook หรือ MagicPad) ฉันได้สร้าง polyfill MagicTouch.js แล้ว โดยจะบันทึกเหตุการณ์การแตะจากแทร็กแพด แล้วเปลี่ยนให้เป็นเหตุการณ์การแตะที่เข้ากันได้แบบมาตรฐาน

  1. ดาวน์โหลดและติดตั้งปลั๊กอิน npTuioClient NPAPI ใน ~/Library/Internet Plug-Ins/
  2. ดาวน์โหลดแอป ToongSeng TUIO สำหรับ MagicPad ของ Mac และเริ่ม เซิร์ฟเวอร์
  3. ดาวน์โหลด MagicTouch.js ซึ่งเป็นไลบรารี JavaScript เพื่อจำลองเหตุการณ์การแตะที่เข้ากันได้กับข้อมูลจำเพาะโดยอิงตามการเรียกกลับของ npTuioClient
  4. ใส่สคริปต์ maMagictouch.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>

คุณอาจต้องเปิดใช้ปลั๊กอิน

การสาธิตแบบสดด้วย magictouch.js มีอยู่ที่ paulirish.com/demo/multi

ผมทดสอบวิธีนี้กับ Chrome 10 เท่านั้น แต่น่าจะใช้งานได้ กับเบราว์เซอร์สมัยใหม่อื่นๆ ที่มีการปรับแต่งเพียงเล็กน้อย

หากคอมพิวเตอร์ของคุณไม่มีการป้อนข้อมูลแบบมัลติทัช คุณสามารถจำลองเหตุการณ์การแตะโดยใช้ตัวติดตาม TUIO อื่นๆ ได้ เช่น reacTIVision ดูข้อมูลเพิ่มเติมได้ที่หน้าโปรเจ็กต์ TuUIO

โปรดทราบว่าท่าทางสัมผัสของคุณอาจเหมือนกับท่าทางสัมผัสแบบมัลติทัชระดับระบบปฏิบัติการ ใน OS X คุณกำหนดค่าเหตุการณ์ทั้งระบบได้โดยไปที่แผงค่ากำหนดแทร็กแพดในค่ากำหนดของระบบ

เนื่องจากคุณลักษณะแบบมัลติทัชได้รับการรองรับอย่างกว้างขวางในเบราว์เซอร์บนอุปกรณ์เคลื่อนที่มากขึ้น ผมจึงตื่นเต้นมากที่ได้เห็นเว็บแอปพลิเคชันใหม่ๆ ใช้ประโยชน์จาก API ที่สมบูรณ์นี้ได้อย่างเต็มที่