之前曾以iPad為對象寫過為網頁加入多點觸控功能範例,如今支援觸控的Windows 8筆電在手,不改寫成IE10版怎能止癢?

經過簡單研究,大致整理IE10與Safari/Chrome觸控事件差異如下:

  1. 事件名稱不同,IE使用的不是touchstart、touchmove、touchend等名稱,而是MSPointerDown, MSPointerMove, MSPointerUp, MSPointerOver, MSPointerOut, MSPointerHover... 等。另外,還有高階的手勢事件: MSGestureTap, MSGestureHold, MSGestureStart, MSGestureChange, MSGestureEnd, MSInertiaStart,讓開發者不用自己費心追蹤各指座標變化,就能判定使用者正在縮放、旋轉動作,真是佛心來著,將來肯定要抽空玩一下才不會暴殄天物。
  2. MSPointerDown等事件概念與touchstart也有所差異。在touchstart中會得到touches陣列,包含多個觸控點的資料;MSPointerDown則是個每個觸控點活動都會觸發一次。
  3. 滑鼠也會觸發MSPointer*事件! 如只想對觸控產生反應,可用if (e.pointerType == e.MSPOINTER_TYPE_TOUCH)過濾。
  4. 因為事件觸發基礎不同,原先在touchmove中可以透過changedTouches取得移動中的觸控點,使用IE10則要自行比對座標值該點是否在移動。
  5. 要攔截觸控事件的元素需加上CSS設定: -ms-touch-action: none; 防止跟IE10預設的縮放、移動瀏覽等觸控操作打架。
  6. 檢查navigator.msMaxTouchPoints屬性存在與否可偵測IE是否支援觸控,由navigator.msMaxTouchPoints亦可得到裝置所支援的觸控點數。

把握以上重點,經過簡單修改,支援IE10的多點觸控展示網頁就完成囉~ 線上展示

<!DOCTYPE html>
 
<html>
<head>
    <title>Mutli-Touch Test</title>
    <script src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.6.4.js" 
            type="text/javascript"> </script>   
    <meta name="viewport" 
     content="width=device-width, initial-scale=1.0, user-scalable=no">
    <style>
        html,body {
            /* 停用預設的縮放、移動瀏覽(Panning)等觸控功能, 由自訂程式接管 */
            -ms-touch-action: none;
        }
    </style>
    <script>
        //http://msdn.microsoft.com/en-us/library/ie/hh673557(v=vs.85).aspx
        $.extend($.support, { ieTouch: "msMaxTouchPoints" in window.navigator });
        $(function () {
            //檢查是否為支援觸控功能的IE瀏覽器
            if (!$.support.ieTouch) {
                $("body").html("<span>IE on touchable device only!</span>");
                return;
            }
            //使用canvas繪製回應
            var canvas = document.getElementById("sketchpad");
            var ctx = canvas.getContext("2d");
            //宣告變數儲存活動中觸控點的資訊
            var touches = {}, changedTouches = {};
            //傳回仿touchStart事件的touch物件
            function createTouchObject(e) {
                return { identifier: e.pointerId, pageX: e.clientX, pageY: e.clientY };
            }
            canvas.addEventListener("MSPointerDown", function (e) {
                //由於滑鼠也會觸發,先檢查pointerType,只針對觸控做反應
                if (e.pointerType != e.MSPOINTER_TYPE_TOUCH) return;
                var t = createTouchObject(e);
                touches[t.identifier] = t;
            });
            canvas.addEventListener("MSPointerMove", function (e) {
                if (e.pointerType != e.MSPOINTER_TYPE_TOUCH) return;
                var t = createTouchObject(e);
                var origT = touches[t.identifier];
                touches[t.identifier] = t;
                //與前次保存資料比較,偵測點觸控點是否移動
                if (origT &&
                    Math.abs(t.pageX - origT.pageX) + Math.abs(t.pageY - origT.pageY) > 1)
                    changedTouches[t.identifier] = t;
                else
                    delete changedTouches[t.identifier];
            });
            canvas.addEventListener("MSPointerUp", function (e) {
                if (e.pointerType != e.MSPOINTER_TYPE_TOUCH) return;
                var t = createTouchObject(e);
                //停止活動,將觸控點自touches及changedTouches移除
                delete touches[t.identifier];
                delete changedTouches[t.identifier];
            });
            //定義不同顏色用來追蹤多點
            var colors =
                ("red,orange,yellow,green,blue,indigo,purple," +
                "aqua,khaki,darkred,lawngreen,salmon,navy," +
                "deeppink,brown,olive,violet,tomato,gray").split(',');
            //在canvas繪製追蹤點
            ctx.lineWidth = 3;
            ctx.font = "10pt Arial";
            var r = 40;
            function drawPoint(i, x, y, c, id, chg) {
                ctx.beginPath();
                ctx.fillStyle = c;
                //若屬changedTouches則顯示黑框
                ctx.strokeStyle = chg ? "#000" : c;
                ctx.arc(x, y, r, 0, 2 * Math.PI, true);
                ctx.fill();
                ctx.stroke();
                //顯示touch的identifier及其在陣列中的序號
                //touches在上排藍字,chagedTouches在下排紅字
                ctx.fillStyle = chg ? "red" : "blue";
                ctx.fillText(id,
                    x - r, y - r - 25 + (chg ? 15 : 0));
            }
            //清除canvas
            function clearCanvas() {
                ctx.clearRect(0, 0, canvas.width, canvas.height);
            }
            //利用identifier識別,相同時要保持同一個顏色
            var touchHash = {}, colorIdx = 0;
            function getColor(id) {
                if (touchHash[id] == undefined)
                    touchHash[id] = ++colorIdx % colors.length;
                return colors[touchHash[id]];
            }
            //每秒更新20次,顯示目前的多點觸控資訊
            setInterval(function () {
                clearCanvas();
                //console.log(JSON.stringify(touches));
                for (var i in touches) {
                    var t = touches[i];
                    drawPoint(i, t.pageX, t.pageY, getColor(t.identifier),
                              t.identifier);
                }
                for (var i in changedTouches) {
                    var t = changedTouches[i];
                    drawPoint(i, t.pageX, t.pageY, getColor(t.identifier),
                              t.identifier, true);
                }
            }, 50);
        });
    </script>
</head>
<body style="padding: 0px; margin: 0px;">
<canvas id="sketchpad" width="1366" height="760" style="border: 1px solid gray">
</canvas>
</body>
</html>

實測結果如下: (幸好最多只有10點,不然連腳都要舉起來"觸控"才能完成測試,肯定抽筋)


Comments

Be the first to post a comment

Post a comment