playcanvas
Version:
PlayCanvas WebGL game engine
136 lines (133 loc) • 4.04 kB
JavaScript
import { Vec2 } from '../../../core/math/vec2.js';
import { InputSource } from '../input.js';
import { movementState } from '../utils.js';
const tmpVa = new Vec2();
class MultiTouchSource extends InputSource {
constructor(){
super({
touch: [
0,
0
],
count: [
0
],
pinch: [
0
]
}), this._movementState = movementState(), this._pointerEvents = new Map(), this._pointerPos = new Vec2(), this._pinchDist = -1;
this._onPointerDown = this._onPointerDown.bind(this);
this._onPointerMove = this._onPointerMove.bind(this);
this._onPointerUp = this._onPointerUp.bind(this);
this._onContextMenu = this._onContextMenu.bind(this);
}
_onPointerDown(event) {
const { pointerId, pointerType } = event;
this._movementState.down(event);
if (pointerType !== 'touch') {
return;
}
this._element?.setPointerCapture(pointerId);
this._pointerEvents.set(pointerId, event);
this.deltas.count.append([
1
]);
if (this._pointerEvents.size > 1) {
this._getMidPoint(this._pointerPos);
this._pinchDist = this._getPinchDist();
}
}
_onPointerMove(event) {
const { pointerType, target, pointerId } = event;
const [movementX, movementY] = this._movementState.move(event);
if (pointerType !== 'touch') {
return;
}
if (target !== this._element) {
return;
}
if (this._pointerEvents.size === 0) {
return;
}
this._pointerEvents.set(pointerId, event);
if (this._pointerEvents.size > 1) {
const mid = this._getMidPoint(tmpVa);
this.deltas.touch.append([
mid.x - this._pointerPos.x,
mid.y - this._pointerPos.y
]);
this._pointerPos.copy(mid);
const pinchDist = this._getPinchDist();
if (this._pinchDist > 0) {
this.deltas.pinch.append([
this._pinchDist - pinchDist
]);
}
this._pinchDist = pinchDist;
} else {
this.deltas.touch.append([
movementX,
movementY
]);
}
}
_onPointerUp(event) {
const { pointerType, pointerId } = event;
this._movementState.up(event);
if (pointerType !== 'touch') {
return;
}
this._element?.releasePointerCapture(pointerId);
this._pointerEvents.delete(pointerId);
this.deltas.count.append([
-1
]);
if (this._pointerEvents.size < 2) {
this._pinchDist = -1;
}
this._pointerPos.set(0, 0);
}
_onContextMenu(event) {
event.preventDefault();
}
_getMidPoint(out) {
if (this._pointerEvents.size < 2) {
return out.set(0, 0);
}
const [a, b] = this._pointerEvents.values();
const dx = a.clientX - b.clientX;
const dy = a.clientY - b.clientY;
return out.set(b.clientX + dx * 0.5, b.clientY + dy * 0.5);
}
_getPinchDist() {
if (this._pointerEvents.size < 2) {
return 0;
}
const [a, b] = this._pointerEvents.values();
const dx = a.clientX - b.clientX;
const dy = a.clientY - b.clientY;
return Math.sqrt(dx * dx + dy * dy);
}
attach(element) {
super.attach(element);
this._element = element;
this._element.addEventListener('pointerdown', this._onPointerDown);
this._element.addEventListener('pointermove', this._onPointerMove);
this._element.addEventListener('pointerup', this._onPointerUp);
this._element.addEventListener('pointercancel', this._onPointerUp);
this._element.addEventListener('contextmenu', this._onContextMenu);
}
detach() {
if (!this._element) {
return;
}
this._element.removeEventListener('pointerdown', this._onPointerDown);
this._element.removeEventListener('pointermove', this._onPointerMove);
this._element.removeEventListener('pointerup', this._onPointerUp);
this._element.removeEventListener('pointercancel', this._onPointerUp);
this._element.removeEventListener('contextmenu', this._onContextMenu);
this._pointerEvents.clear();
super.detach();
}
}
export { MultiTouchSource };