UNPKG

@pmndrs/pointer-events

Version:

framework agnostic pointer-events implementation for threejs

134 lines (133 loc) 5.31 kB
import { intersectPointerEventTargets } from './intersections/utils.js'; export class CombinedPointer { enableMultiplePointers; pointers = []; isDefaults = []; enabled = true; activePointer; nonCapturedPointers = []; constructor(enableMultiplePointers) { this.enableMultiplePointers = enableMultiplePointers; } register(pointer, isDefault = false) { this.pointers.push(pointer); this.isDefaults.push(isDefault); return this.unregister.bind(this, pointer); } unregister(pointer) { const index = this.pointers.indexOf(pointer); if (index === -1) { return; } this.isDefaults.splice(index, 1); this.pointers.splice(index, 1); } /** * @returns true if any pointer is captured */ startIntersection(nonCapturedPointers, nativeEvent) { const length = this.pointers.length; let anyPointerIsCaptured = false; for (let i = 0; i < length; i++) { const pointer = this.pointers[i]; if (pointer instanceof CombinedPointer) { pointer.startIntersection(nonCapturedPointers, nativeEvent); continue; } const pointerCapture = pointer.getPointerCapture(); if (pointerCapture != null) { anyPointerIsCaptured = true; pointer.setIntersection(pointer.intersector.intersectPointerCapture(pointerCapture, nativeEvent)); continue; } nonCapturedPointers.push(pointer); pointer.intersector.startIntersection(nativeEvent); } return anyPointerIsCaptured; } /** * only for internal use */ getIntersection() { return this.activePointer?.getIntersection(); } /** * only for internal use */ getPointerCapture() { return this.activePointer?.getPointerCapture(); } computeActivePointer() { let smallestDistance; this.activePointer = undefined; const length = this.pointers.length; for (let i = 0; i < length; i++) { const pointer = this.pointers[i]; if (pointer instanceof CombinedPointer) { pointer.computeActivePointer(); } const intersection = pointer.getIntersection(); const distance = pointer.getPointerCapture() != null ? -Infinity : intersection?.object.isVoidObject ? Infinity : (intersection?.distance ?? Infinity); const isDefault = this.isDefaults[i]; if (smallestDistance == null || (isDefault && distance === smallestDistance) || distance < smallestDistance) { this.activePointer = pointer; smallestDistance = distance; } } } /** * only for internal use */ commit(nativeEvent, emitMove, computeActivePointer = true) { if (this.enableMultiplePointers) { const length = this.pointers.length; for (let i = 0; i < length; i++) { this.pointers[i].commit(nativeEvent, emitMove); } return; } if (computeActivePointer) { this.computeActivePointer(); } //commit all pointers, enable the active pointer, and disable all other pointers const length = this.pointers.length; for (let i = 0; i < length; i++) { const pointer = this.pointers[i]; pointer.setEnabled(pointer === this.activePointer, nativeEvent, false); pointer.commit(nativeEvent, emitMove, false); } } move(scene, nativeEvent) { if (!this.enabled) { return; } //start intersection, build nonCapturedPointers list, and compute the intersection for all captured pointers this.nonCapturedPointers.length = 0; const anyPointerIsCaptured = this.startIntersection(this.nonCapturedPointers, nativeEvent); //we only need to intersect the scene if no pointer is captured or (in case one or more pointers are captured) if mulitple pointers can be enabled if (!anyPointerIsCaptured || this.enableMultiplePointers) { //intersect scene using the non captured pointers intersectPointerEventTargets('pointer', scene, this.nonCapturedPointers); //finalize the intersection for the non captured pointers const nonCapturedPointerLength = this.nonCapturedPointers.length; for (let i = 0; i < nonCapturedPointerLength; i++) { const pointer = this.nonCapturedPointers[i]; pointer.setIntersection(pointer.intersector.finalizeIntersection(scene)); } } //commit the intersection, compute active pointers, and enabling/disabling pointers this.commit(nativeEvent, true); } setEnabled(enabled, nativeEvent) { this.enabled = enabled; const length = this.pointers.length; for (let i = 0; i < length; i++) { const pointer = this.pointers[i]; pointer.setEnabled(enabled && (this.enableMultiplePointers || pointer == this.activePointer), nativeEvent); } } }