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

บทนำ

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

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

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

การโต้ตอบแบบสัมผัส

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

  • touchstart: นิ้ววางอยู่บนองค์ประกอบ DOM
  • touchmove: มีการใช้นิ้วลากไปตามองค์ประกอบ DOM
  • touchend: นิ้วถูกนำออกจากองค์ประกอบ DOM

เหตุการณ์การสัมผัสแต่ละรายการประกอบด้วยรายการการสัมผัส 3 รายการ ได้แก่

  • touches: รายการนิ้วทั้งหมดที่อยู่บนหน้าจอในขณะนี้
  • 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 รวมถึง Canvas

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

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

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

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

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

<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 และ changedTouches

โปรดทราบว่า 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 รายการที่แตะได้อีกด้วย อย่างไรก็ตาม ไม่มีเบราว์เซอร์ที่ทดสอบรองรับ radiusX, radiusY หรือ rotationAngle ซึ่งระบุรูปร่างของนิ้วที่สัมผัสหน้าจอ

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

Android 2.3.3 (Nexus)

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

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

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

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

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

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

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

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

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

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

เหตุการณ์การสัมผัสหลายจุด

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

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

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

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

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

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

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

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