JavaScript UI component library, includes the latest Fancybox
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

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 };