Как правильно использовать onpointermove для рисования в HTML5 Canvas - PullRequest
1 голос
/ 18 марта 2020

Я использую onpointerdown, onpointerup и onpointermove для обработки HTML5 Рисование холстом от руки, и оно отлично работает с мышью. Однако, когда я использую мобильный телефон, он не работает, я должен добавить ontouchmove, как показано в моем рабочем примере.

Как мне избавиться от ontouchmove и использовать только PointerEvents .

const canvas = document.querySelector('canvas')
const ctx = canvas.getContext('2d')

// Same window dimensions
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;

// We need to track mouse/finger position and down/up
let x, y, down

// Start
canvas.onpointerdown = e => {
  const { pageX, pageY } = e
  down = true
  x = pageX
  y = pageY
}

// End
canvas.onpointerup = () => down = false

// Move
canvas.onpointermove = canvas.ontouchmove = e => {
  // Return if we havent finish yet
  if (!down) return
  const { pageX, pageY } = (e.touches && e.touches[0]) || e
  // Draw line
  ctx.beginPath()
  ctx.moveTo(x, y)
  ctx.lineTo(pageX, pageY)
  ctx.lineWidth = 1
  ctx.stroke()
  // Update
  x = pageX
  y = pageY
}
body {
  margin: 0;
  padding: 0;
  background-color: #bbb;
  width: 100vw;
  height: 100vh;
  overflow: hidden;
}
<canvas></canvas>

Обновлено

Я использую Samsung Galaxy A5 (2017) с Android 8 и Chrome 80.

Проверьте это демо без ontouchmove в мобильном телефоне. Это снимок экрана с моего устройства.

1 Ответ

1 голос
/ 18 марта 2020

Вы не можете: поскольку существуют устаревшие сенсорные устройства, которые не поддерживают этот API (например, iOS 12 и ниже), вам необходимо привязать события для ontouchdown, ontouchmove и ontouchend отдельно. Вы можете проверить поддержку браузером API события указателя здесь .

Вы можете использовать window.PointerEvent, чтобы определить поддержку браузером этого API, а затем вернуть правильное имя события, с которым вы хотите связать :

const hasPointerEvent = !!window.PointerEvent;
const pointerEventNames = {
  start: window.PointerEvent ? 'pointerdown' : 'touchstart',
  move: window.PointerEvent ? 'pointermove' : 'touchmove',
  end: window.PointerEvent ? 'pointerup' : 'touchend',
};

Если вы хотите поддерживать IE10, вам нужно будет добавить дополнительную проверку для window.MSPointerEvent, поскольку IE10 поддерживает только события с префиксом MS (и они также являются PascalCased):

function getPointerEventNames() {
  const o = {
    start: 'pointerdown',
    move: 'pointermove',
    end: 'pointerup'
  };

  if (!window.PointerEvent) {
    o.start = 'touchstart';
    o.move = 'touchmove';
    o.end = 'touchend';
  } else if (!!window.MSPointerEvent) {
    o.start = 'MSPointerDown';
    o.move = 'MSPointerMove';
    o.end = 'MSPointerUp';
  }
}
const pointerEventNames = getPointerEventNames();

Вместо того, чтобы делать canvas.onpointerdown = ... и затем повторять тот же лог c для canvas.ontouchstart, вместо него можно использовать canvas.addEventListener. Преимущество этого состоит в том, что вы можете использовать словарь pointerEventNames выше, который будет возвращать имена поддерживаемых событий для устройства, на котором вы находитесь:

// Define common handler
const onDown = (e) => {
  const { pageX, pageY } = e
  down = true
  x = pageX
  y = pageY
}
canvas.addEventListener(pointerEventNames.start, onDown);

И вы повторите это для двух других событий ... см. подтверждение концепции ниже:

const hasPointerEvent = !!window.PointerEvent;
const pointerEventNames = {
  start: window.PointerEvent ? 'pointerdown' : 'touchstart',
  move: window.PointerEvent ? 'pointermove' : 'touchmove',
  end: window.PointerEvent ? 'pointerup' : 'touchend',
};

const canvas = document.querySelector('canvas')
const ctx = canvas.getContext('2d')

// Same window dimensions
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;

// We need to track mouse/finger position and down/up
let x, y, down

// Start
const onStart = (e) => {
  const {
    pageX,
    pageY
  } = e
  down = true
  x = pageX
  y = pageY
}
canvas.addEventListener(pointerEventName.start, onStart);

// End
const onEnd = () => down = false;
canvas.addEventListener(pointerEventName.end, onEnd);

// Move
const onMove = (e) => {
  // Return if we havent finish yet
  if (!down) return
  const {
    pageX,
    pageY
  } = (e.touches && e.touches[0]) || e
  // Draw line
  ctx.beginPath()
  ctx.moveTo(x, y)
  ctx.lineTo(pageX, pageY)
  ctx.lineWidth = 1
  ctx.stroke()
  // Update
  x = pageX
  y = pageY
}
canvas.addEventListener(pointerEventName.move, onMove);
body {
  margin: 0;
  padding: 0;
  background-color: #bbb;
  width: 100vw;
  height: 100vh;
  overflow: hidden;
}
<canvas></canvas>
...