mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-04 18:34:02 +00:00
92 lines
2.8 KiB
JavaScript
92 lines
2.8 KiB
JavaScript
import * as Cesium from 'cesium';
|
|
import { holdContinuousRender, releaseContinuousRender } from './renderGovernor.js';
|
|
|
|
/**
|
|
* OrbitController — smooth orbit around a target point.
|
|
* Uses scene.preRender for frame-rate-independent 60fps updates.
|
|
* Toggle with O key; auto-stops on POI/city change.
|
|
*/
|
|
export class OrbitController {
|
|
constructor(viewer) {
|
|
this.viewer = viewer;
|
|
this.active = false;
|
|
this.target = null;
|
|
this.radius = 500;
|
|
this.pitch = -30;
|
|
this.speed = Cesium.Math.toRadians(6); // ~6°/sec → full rotation in ~60s
|
|
this.angle = 0;
|
|
this._removeListener = null;
|
|
}
|
|
|
|
/**
|
|
* Start orbiting around a target position.
|
|
* @param {Cesium.Cartesian3} targetCartesian - The point to orbit around
|
|
* @param {object} options
|
|
* @param {number} options.radius - Distance from target in meters
|
|
* @param {number} options.pitch - Tilt angle in degrees (negative = looking down)
|
|
* @param {number} options.speed - Degrees per second (default 6)
|
|
*/
|
|
start(targetCartesian, options = {}) {
|
|
if (!targetCartesian) return;
|
|
|
|
this.target = targetCartesian;
|
|
this.radius = options.radius || this.radius;
|
|
this.pitch = options.pitch || this.pitch;
|
|
this.speed = Cesium.Math.toRadians(options.speed || 6);
|
|
this.active = true;
|
|
// Orbit mutates the camera from preRender — without a hold the loop
|
|
// starves after its first idle frame. (perf wave 2)
|
|
holdContinuousRender('camera-orbit');
|
|
|
|
// Start from the camera's current heading for seamless transition
|
|
this.angle = this.viewer.camera.heading;
|
|
|
|
let lastTime = Date.now();
|
|
this._removeListener = this.viewer.scene.preRender.addEventListener(() => {
|
|
if (!this.active) return;
|
|
|
|
const now = Date.now();
|
|
const dt = (now - lastTime) / 1000;
|
|
lastTime = now;
|
|
|
|
this.angle += this.speed * dt;
|
|
|
|
const hpr = new Cesium.HeadingPitchRange(
|
|
this.angle,
|
|
Cesium.Math.toRadians(this.pitch),
|
|
this.radius
|
|
);
|
|
this.viewer.camera.lookAt(this.target, hpr);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Stop orbiting. Camera freezes at current position and user regains control.
|
|
*/
|
|
stop() {
|
|
this.active = false;
|
|
releaseContinuousRender('camera-orbit');
|
|
if (this._removeListener) {
|
|
this._removeListener();
|
|
this._removeListener = null;
|
|
}
|
|
// Unlock camera for free interaction
|
|
this.viewer.camera.lookAtTransform(Cesium.Matrix4.IDENTITY);
|
|
}
|
|
|
|
/**
|
|
* Toggle orbit on/off.
|
|
* @param {Cesium.Cartesian3} targetCartesian - Required when starting
|
|
* @param {object} options - Passed to start()
|
|
* @returns {boolean} Whether orbit is now active
|
|
*/
|
|
toggle(targetCartesian, options) {
|
|
if (this.active) {
|
|
this.stop();
|
|
} else {
|
|
this.start(targetCartesian, options);
|
|
}
|
|
return this.active;
|
|
}
|
|
}
|