playcanvas
Version:
Open-source WebGL/WebGPU 3D engine for the web
162 lines (161 loc) • 5.05 kB
JavaScript
var __defProp = Object.defineProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
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]
});
/**
* @type {ReturnType<typeof movementState>}
* @private
*/
__publicField(this, "_movementState", movementState());
/**
* @type {Map<number, PointerEvent>}
* @private
*/
__publicField(this, "_pointerEvents", /* @__PURE__ */ new Map());
/** @private */
__publicField(this, "_pointerPos", new Vec2());
/** @private */
__publicField(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);
}
/**
* @param {PointerEvent} event - The pointer event.
* @private
*/
_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();
}
}
/**
* @param {PointerEvent} event - The pointer event.
* @private
*/
_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]);
}
}
/**
* @param {PointerEvent} event - The pointer event.
* @private
*/
_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);
}
/**
* @param {MouseEvent} event - The mouse event.
* @private
*/
_onContextMenu(event) {
event.preventDefault();
}
/**
* @param {Vec2} out - The output vector.
* @returns {Vec2} The mid point.
* @private
*/
_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);
}
/**
* @returns {number} The pinch distance.
* @private
*/
_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);
}
/**
* @param {HTMLElement} element - The element.
*/
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
};