@polygonjs/polygonjs
Version:
node-based WebGL 3D engine https://polygonjs.com
102 lines (94 loc) • 3 kB
text/typescript
import {BaseEvent, Camera, Vector3, EventDispatcher} from 'three';
import {CameraControls} from '../../nodes/event/_BaseCameraControls';
import type {OrbitControls} from '../../nodes/event/CameraOrbitControls';
import {TypedViewer} from '../_Base';
type UpdateControlsFunc = (delta: number) => void;
export enum CameraControlsEvent {
start = 'start',
end = 'end',
}
export const CAMERA_CONTROLS_EVENTS: CameraControlsEvent[] = [CameraControlsEvent.start, CameraControlsEvent.end];
const START_EVENT: BaseEvent<'start'> = {type: CameraControlsEvent.start};
const END_EVENT: BaseEvent<'end'> = {type: CameraControlsEvent.end};
export class ViewerControlsController<C extends Camera> extends EventDispatcher<{change: any}> {
protected _active: boolean = false;
private _updateControlsFunc: UpdateControlsFunc | undefined;
protected _controls: CameraControls | undefined;
private _mounted = false;
constructor(private viewer: TypedViewer<C>) {
super();
}
controls() {
return this._controls;
}
mount() {
if (this._mounted) {
return;
}
this._mounted = true;
const controlsNode = this.viewer.controlsNode();
const camera = this.viewer.camera();
if (!(controlsNode && camera)) {
return;
}
controlsNode.applyControls(camera, this.viewer).then((controls) => {
this._controls = controls;
// make sure that the function is (delta) => controls.update(delta)
// and not just "controls.update", as this would prevent the controls from binding "this" properly.
// This messes up with the FirstPersoControls for instance.
this._updateControlsFunc = controls ? (delta) => controls.update(delta) : undefined;
for (const eventName of CAMERA_CONTROLS_EVENTS) {
controls.addEventListener(eventName, this._boundEventHandler[eventName]);
}
if (!this._mounted) {
this._disposeControls();
}
});
}
unmount() {
if (!this._mounted) {
return;
}
this._mounted = false;
this._disposeControls();
// dispose controls
// this._controlsNode = undefined;
}
private _disposeControls() {
if (this._controls) {
for (const eventName of CAMERA_CONTROLS_EVENTS) {
this._controls.removeEventListener(eventName, this._boundEventHandler[eventName]);
}
this._controls.dispose();
// this._controls = undefined;
// this._updateControlsFunc = undefined;
}
this._updateControlsFunc = undefined;
}
update(delta: number) {
if (this._updateControlsFunc) {
this._updateControlsFunc(delta);
}
}
setActive(active: boolean) {
if (active) {
this.mount();
} else {
this.unmount();
}
}
setTarget(target: Vector3) {
if (!this._controls) {
return;
}
const orbitControls = this._controls as OrbitControls;
if (!orbitControls.target) {
return;
}
orbitControls.target.copy(target);
}
private _boundEventHandler: Record<CameraControlsEvent, () => void> = {
[CameraControlsEvent.start]: () => this.dispatchEvent(START_EVENT),
[CameraControlsEvent.end]: () => this.dispatchEvent(END_EVENT),
};
}