playcanvas
Version:
Open-source WebGL/WebGPU 3D engine for the web
121 lines (120 loc) • 3.67 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 {
_movementState = movementState();
_pointerEvents = /* @__PURE__ */ new Map();
_pointerPos = new Vec2();
_pinchDist = -1;
constructor() {
super({
touch: [0, 0],
count: [0],
pinch: [0]
});
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
};