@pmndrs/handle
Version:
framework agnostic expandable handle implementation for threejs
70 lines (69 loc) • 2.16 kB
JavaScript
import { getVoidObject } from '@pmndrs/pointer-events';
import { Vector2 } from 'three';
export class ScreenHandleStore {
apply;
getInitial;
map = new Map();
initial;
constructor(apply, getInitial) {
this.apply = apply;
this.getInitial = getInitial;
this.initial = getInitial();
}
bind(scene) {
const down = this.onPointerDown.bind(this);
const up = this.onPointerUp.bind(this);
const move = this.onPointerMove.bind(this);
const voidObject = getVoidObject(scene);
voidObject.addEventListener('pointermove', move);
voidObject.addEventListener('pointerdown', down);
voidObject.addEventListener('pointerup', up);
return () => {
voidObject.removeEventListener('pointermove', move);
voidObject.removeEventListener('pointerdown', down);
voidObject.removeEventListener('pointerup', up);
};
}
onPointerDown(e) {
if (e.intersection.details.type != 'screen-ray') {
return;
}
e.target.setPointerCapture(e.pointerId);
this.map.set(e.pointerId, {
initialScreenPosition: new Vector2(),
currentScreenPosition: e.intersection.details.screenPoint.clone(),
initialEvent: e,
latestEvent: e,
});
this.save();
}
onPointerUp(e) {
if (!this.map.delete(e.pointerId)) {
return;
}
this.save();
}
onPointerMove(e) {
if (e.intersection.details.type != 'screen-ray') {
return;
}
const entry = this.map.get(e.pointerId);
if (entry == null) {
return;
}
entry.latestEvent = e;
entry.currentScreenPosition.copy(e.intersection.details.screenPoint);
}
save() {
for (const entry of this.map.values()) {
entry.initialScreenPosition.copy(entry.currentScreenPosition);
}
this.initial = this.getInitial();
}
update() {
if (this.map.size === 0) {
return;
}
this.apply(this.initial, this.map);
}
}