使用 Pointer Events

Baseline 廣泛可用 *

此特性已經十分成熟,可在許多裝置和瀏覽器版本上使用。自 2020 年 7 月以來,它已在各大瀏覽器中可用。

* 此特性的某些部分可能存在不同級別的支援。

本指南演示如何使用 pointer events 和 HTML <canvas> 元素構建支援多點觸控的繪圖應用程式。此示例基於 touch events overview 中的示例,但它使用了 pointer events 輸入事件模型。另一個不同之處在於,由於 pointer events 是裝置無關的,因此該應用程式使用相同的程式碼接受來自滑鼠、筆或指尖的基於座標的輸入。

此應用程式僅在支援 pointer events 的瀏覽器中執行。

定義

Surface

一個支援觸控的表面。這可能是一個觸控板、觸控式螢幕,甚至是使用者桌面表面(或滑鼠墊)與物理螢幕的虛擬對映。

Touch point

與表面的接觸點。這可能是一個手指(或肘部、耳朵、鼻子,任何東西,但通常是手指)、手寫筆、滑鼠,或任何其他用於在表面上指定單個點的方法。

示例

注意: 下面的文字在描述與表面的接觸時使用了“手指”一詞,但當然也可以是手寫筆、滑鼠或其他指向某個位置的方法。

Drawing application

HTML

HTML 由一個單獨的 <canvas> 元素組成。曲線將根據使用者的觸控手勢繪製。還包含一個用於清除畫布的按鈕。

html
<canvas id="canvas" width="600" height="600">
  Your browser does not support the canvas element.
</canvas>
<button id="clear">Clear canvas</button>

CSS

設定了 touch-action 屬性為 none,以防止瀏覽器對應用程式應用其預設的觸控行為。

css
#canvas {
  border: solid black 1px;
  touch-action: none;
  display: block;
}

JavaScript

我們將跟蹤所有正在進行的觸控,併為每個觸控繪製線條。colors 用於區分不同的手指。

js
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");

// Mapping from the pointerId to the current finger position
const ongoingTouches = new Map();
const colors = ["red", "green", "blue"];

handleStart 函式監聽 pointerdown 事件,並在觸控開始時繪製一個圓圈。

js
function handleStart(event) {
  const touch = {
    pageX: event.pageX,
    pageY: event.pageY,
    color: colors[ongoingTouches.size % colors.length],
  };
  ongoingTouches.set(event.pointerId, touch);

  ctx.beginPath();
  ctx.arc(touch.pageX, touch.pageY, 4, 0, 2 * Math.PI, false);
  ctx.fillStyle = touch.color;
  ctx.fill();
}

canvas.addEventListener("pointerdown", handleStart);

handleEnd 函式監聽 pointerup 事件,並在觸控結束時繪製一個正方形。

js
function handleEnd(event) {
  const touch = ongoingTouches.get(event.pointerId);

  if (!touch) {
    console.error(`End: Could not find touch ${event.pointerId}`);
    return;
  }

  ctx.lineWidth = 4;
  ctx.fillStyle = touch.color;
  ctx.beginPath();
  ctx.moveTo(touch.pageX, touch.pageY);
  ctx.lineTo(event.pageX, event.pageY);
  ctx.fillRect(event.pageX - 4, event.pageY - 4, 8, 8);
  ongoingTouches.delete(event.pointerId);
}

canvas.addEventListener("pointerup", handleEnd);

handleCancel 函式監聽 pointercancel 事件,並停止跟蹤觸控。

js
function handleCancel(event) {
  const touch = ongoingTouches.get(event.pointerId);

  if (!touch) {
    console.error(`Cancel: Could not find touch ${event.pointerId}`);
    return;
  }

  ongoingTouches.delete(event.pointerId);
}

canvas.addEventListener("pointercancel", handleCancel);

handleMove 函式監聽 pointermove 事件,並在觸控的開始和結束之間繪製一條線。

js
function handleMove(event) {
  const touch = ongoingTouches.get(event.pointerId);

  // Event was not started
  if (!touch) {
    return;
  }

  ctx.beginPath();
  ctx.moveTo(touch.pageX, touch.pageY);
  ctx.lineTo(event.pageX, event.pageY);
  ctx.lineWidth = 4;
  ctx.strokeStyle = touch.color;
  ctx.stroke();

  const newTouch = {
    pageX: event.pageX,
    pageY: event.pageY,
    color: touch.color,
  };

  ongoingTouches.set(event.pointerId, newTouch);
}

canvas.addEventListener("pointermove", handleMove);

最後,新增清除功能。

js
document.getElementById("clear").addEventListener("click", () => {
  ctx.clearRect(0, 0, canvas.width, canvas.height);
});

規範

規範
指標事件
# pointerevent-interface

瀏覽器相容性

另見