118 lines
3.1 KiB
JavaScript
118 lines
3.1 KiB
JavaScript
import {PANNING_ZERO_TOUCH_THRESHOLD} from "./config.js";
|
|
import {add, copy, div, mult, zero} from "./vector.js";
|
|
|
|
export class Panning {
|
|
sim = undefined;
|
|
touchStart = undefined;
|
|
touchLatest = undefined;
|
|
paused = false;
|
|
velocity = zero;
|
|
|
|
constructor(sim) {
|
|
this.sim = sim;
|
|
}
|
|
|
|
initializeTouch({x, y}) {
|
|
this.touchStart = {
|
|
x,
|
|
y,
|
|
t: this.sim.rawTime,
|
|
viewOrigin: copy(this.sim.display.viewOrigin),
|
|
};
|
|
this.touchLatest = {
|
|
...this.touchStart,
|
|
dx: 0,
|
|
dy: 0,
|
|
dt: 0,
|
|
};
|
|
}
|
|
|
|
toJSON() {
|
|
return {
|
|
velocity: this.velocity,
|
|
};
|
|
}
|
|
|
|
fromJSON({velocity}) {
|
|
this.velocity = copy(velocity);
|
|
this.paused = true;
|
|
}
|
|
|
|
handlePointerDown({x, y}) {
|
|
this.initializeTouch({x, y});
|
|
if (this.paused) {
|
|
this.paused = false;
|
|
}
|
|
}
|
|
|
|
// With fast panning, panning velocity calculation happens every move;
|
|
// With normal panning, calculation only happens at pointer up.
|
|
handlePointerMove({x, y}) {
|
|
if (this.touchStart) {
|
|
this.touchLatest = {
|
|
x,
|
|
y,
|
|
t: this.sim.rawTime,
|
|
dx: x - this.touchStart.x,
|
|
dy: x - this.touchStart.y,
|
|
dt: this.sim.rawTime - this.touchStart.t,
|
|
};
|
|
|
|
// Convert pointer velocity to simulation scale
|
|
let velocity = div(this.sim.pointer.latestVelocity, this.sim.display.scale);
|
|
|
|
// Optional time scale compensation
|
|
if (this.sim.getOption('compensate.timeScale')) {
|
|
velocity = div(velocity, this.sim.timeScale);
|
|
}
|
|
|
|
// Additional scaling factor
|
|
velocity = mult(velocity, this.sim.getOption('display.panningSpeed'));
|
|
|
|
// TODO: Make it easier to slow down the camera
|
|
|
|
// Add pointer velocity to current panning velocity
|
|
this.velocity = add(this.velocity, velocity);
|
|
}
|
|
}
|
|
|
|
handlePointerUp() {
|
|
if (this.touchStart && this.touchLatest) {
|
|
if (this.touchLatest.dt < PANNING_ZERO_TOUCH_THRESHOLD) {
|
|
this.velocity = zero;
|
|
}
|
|
this.touchStart = undefined;
|
|
|
|
if (this.sim.getOption('compensate.fastPanning')) {
|
|
this.velocity = zero;
|
|
}
|
|
}
|
|
}
|
|
|
|
frame(elapsedTime) {
|
|
const {display} = this.sim;
|
|
|
|
// Apply update to viewOrigin based on panning
|
|
if (!this.paused) {
|
|
// elapsedTime is scaled by time scale, is that what we want?
|
|
// Yes because if panning.velocity == obj.velocity, object should stay in view
|
|
display.viewOrigin = add(display.viewOrigin, mult(this.velocity, elapsedTime));
|
|
}
|
|
|
|
if (this.sim.getOption('debug.panningInfo')) {
|
|
const {x, y} = this.sim.panning?.velocity ?? {};
|
|
this.sim.info['Panning Velocity'] = [`${x?.toPrecision(6)}, `, y?.toPrecision(6)];
|
|
const {centerOfMass} = this.sim.system.computeSystemCenter();
|
|
this.sim.info['Center of Mass'] = [`${centerOfMass.x.toPrecision(6)}, `, centerOfMass.y.toPrecision(6)];
|
|
this.sim.info['Net Angular Momentum'] = this.sim.system.computeSystemAngularMomentum().toPrecision(6);
|
|
}
|
|
}
|
|
|
|
setVelocity(velocity) {
|
|
this.velocity = velocity;
|
|
if (!this.sim.playing) {
|
|
this.paused = true;
|
|
}
|
|
}
|
|
}
|