You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
157 lines
4.4 KiB
157 lines
4.4 KiB
class Pointer {
|
|
constructor(nativePointer) {
|
|
this.id = self.Touch && nativePointer instanceof Touch ? nativePointer.identifier : -1;
|
|
|
|
this.pageX = nativePointer.pageX;
|
|
this.pageY = nativePointer.pageY;
|
|
|
|
this.clientX = nativePointer.clientX;
|
|
this.clientY = nativePointer.clientY;
|
|
}
|
|
}
|
|
|
|
const getDistance = (a, b) => {
|
|
if (!b) {
|
|
return 0;
|
|
}
|
|
|
|
return Math.sqrt((b.clientX - a.clientX) ** 2 + (b.clientY - a.clientY) ** 2);
|
|
};
|
|
|
|
const getMidpoint = (a, b) => {
|
|
if (!b) {
|
|
return a;
|
|
}
|
|
|
|
return {
|
|
clientX: (a.clientX + b.clientX) / 2,
|
|
clientY: (a.clientY + b.clientY) / 2,
|
|
};
|
|
};
|
|
|
|
const isTouchEvent = (event) => "changedTouches" in event;
|
|
|
|
class PointerTracker {
|
|
constructor(_element, { start = () => true, move = () => {}, end = () => {} } = {}) {
|
|
this._element = _element;
|
|
|
|
this.startPointers = [];
|
|
this.currentPointers = [];
|
|
|
|
this._pointerStart = (event) => {
|
|
if (event.buttons > 0 && event.button !== 0) {
|
|
return;
|
|
}
|
|
|
|
const pointer = new Pointer(event);
|
|
|
|
if (this.currentPointers.some((p) => p.id === pointer.id)) {
|
|
return;
|
|
}
|
|
|
|
if (!this._triggerPointerStart(pointer, event)) {
|
|
return;
|
|
}
|
|
|
|
window.addEventListener("mousemove", this._move);
|
|
window.addEventListener("mouseup", this._pointerEnd);
|
|
};
|
|
|
|
this._touchStart = (event) => {
|
|
for (const touch of Array.from(event.changedTouches || [])) {
|
|
this._triggerPointerStart(new Pointer(touch), event);
|
|
}
|
|
};
|
|
|
|
this._move = (event) => {
|
|
const previousPointers = this.currentPointers.slice();
|
|
const changedPointers = isTouchEvent(event)
|
|
? Array.from(event.changedTouches).map((t) => new Pointer(t))
|
|
: [new Pointer(event)];
|
|
|
|
const trackedChangedPointers = [];
|
|
|
|
for (const pointer of changedPointers) {
|
|
const index = this.currentPointers.findIndex((p) => p.id === pointer.id);
|
|
|
|
if (index < 0) {
|
|
continue;
|
|
}
|
|
|
|
trackedChangedPointers.push(pointer);
|
|
|
|
this.currentPointers[index] = pointer;
|
|
}
|
|
|
|
this._moveCallback(previousPointers, this.currentPointers.slice(), event);
|
|
};
|
|
|
|
this._triggerPointerEnd = (pointer, event) => {
|
|
const index = this.currentPointers.findIndex((p) => p.id === pointer.id);
|
|
|
|
if (index < 0) {
|
|
return false;
|
|
}
|
|
|
|
this.currentPointers.splice(index, 1);
|
|
this.startPointers.splice(index, 1);
|
|
|
|
this._endCallback(pointer, event);
|
|
|
|
return true;
|
|
};
|
|
|
|
this._pointerEnd = (event) => {
|
|
if (event.buttons > 0 && event.button !== 0) {
|
|
return;
|
|
}
|
|
|
|
if (!this._triggerPointerEnd(new Pointer(event), event)) {
|
|
return;
|
|
}
|
|
|
|
window.removeEventListener("mousemove", this._move, { passive: false });
|
|
window.removeEventListener("mouseup", this._pointerEnd, { passive: false });
|
|
};
|
|
|
|
this._touchEnd = (event) => {
|
|
for (const touch of Array.from(event.changedTouches || [])) {
|
|
this._triggerPointerEnd(new Pointer(touch), event);
|
|
}
|
|
};
|
|
|
|
this._startCallback = start;
|
|
this._moveCallback = move;
|
|
this._endCallback = end;
|
|
|
|
this._element.addEventListener("mousedown", this._pointerStart, { passive: false });
|
|
this._element.addEventListener("touchstart", this._touchStart, { passive: false });
|
|
this._element.addEventListener("touchmove", this._move, { passive: false });
|
|
this._element.addEventListener("touchend", this._touchEnd);
|
|
this._element.addEventListener("touchcancel", this._touchEnd);
|
|
}
|
|
|
|
stop() {
|
|
this._element.removeEventListener("mousedown", this._pointerStart, { passive: false });
|
|
this._element.removeEventListener("touchstart", this._touchStart, { passive: false });
|
|
this._element.removeEventListener("touchmove", this._move, { passive: false });
|
|
this._element.removeEventListener("touchend", this._touchEnd);
|
|
this._element.removeEventListener("touchcancel", this._touchEnd);
|
|
|
|
window.removeEventListener("mousemove", this._move);
|
|
window.removeEventListener("mouseup", this._pointerEnd);
|
|
}
|
|
|
|
_triggerPointerStart(pointer, event) {
|
|
if (!this._startCallback(pointer, event)) {
|
|
return false;
|
|
}
|
|
|
|
this.currentPointers.push(pointer);
|
|
this.startPointers.push(pointer);
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
export { PointerTracker, getDistance, getMidpoint };
|
|
|