92 lines
3.1 KiB
JavaScript
92 lines
3.1 KiB
JavaScript
import { Tool } from '../tool.js';
|
|
import {
|
|
ZOOM_IN_FACTOR,
|
|
ZOOM_OUT_FACTOR,
|
|
} from '../config.js';
|
|
|
|
export class Zoom extends Tool {
|
|
constructor(toolbar) {
|
|
super(toolbar);
|
|
|
|
const zoomOut = document.createElement('button');
|
|
const zoomIn = document.createElement('button');
|
|
const zoomAll = document.createElement('button');
|
|
const zeroNetMomentum = document.createElement('button');
|
|
|
|
this.div.appendChild(zoomOut);
|
|
this.div.appendChild(zoomIn);
|
|
this.div.appendChild(document.createElement('br'));
|
|
this.div.appendChild(zoomAll);
|
|
this.div.appendChild(document.createElement('br'));
|
|
this.div.appendChild(zeroNetMomentum);
|
|
|
|
zoomAll.classList.add('wide');
|
|
zeroNetMomentum.classList.add('wide');
|
|
|
|
zoomOut.innerHTML = '<h2>Zoom<br>Out</h2>';
|
|
zoomIn.innerHTML = '<h2>Zoom<br>In</h2>';
|
|
zoomAll.innerHTML = '<h2>Zoom to Fit</h2>';
|
|
zeroNetMomentum.innerHTML = '<h2>Zero Net Momentum</h2>';
|
|
|
|
zoomOut.addEventListener('click', (e) => {
|
|
// Aim at center of view
|
|
const x = this.sim.display.width * this.sim.display.scale / 2;
|
|
const y = this.sim.display.height * this.sim.display.scale / 2;
|
|
this.sim.scheduleZoom({x, y}, ZOOM_OUT_FACTOR);
|
|
});
|
|
|
|
zoomIn.addEventListener('click', (e) => {
|
|
// Aim at center of view
|
|
const x = this.sim.display.width * this.sim.display.scale / 2;
|
|
const y = this.sim.display.height * this.sim.display.scale / 2;
|
|
this.sim.scheduleZoom({x, y}, ZOOM_IN_FACTOR);
|
|
});
|
|
|
|
zoomAll.addEventListener('click', (e) => {
|
|
// Determine bounding box
|
|
const box = this.sim.objects.boundingBox;
|
|
const x = (box.start.x + box.end.x) / 2;
|
|
const y = (box.start.y + box.end.y) / 2;
|
|
if (box.start.x !== box.end.x && box.start.y !== box.end.y) {
|
|
const widthRatio = Math.abs(box.start.x - box.end.x) / this.sim.display.width;
|
|
const heightRatio = Math.abs(box.start.y - box.end.y) / this.sim.display.height;
|
|
const biggerRatio = Math.max(widthRatio, heightRatio);
|
|
if (biggerRatio <= 1) {
|
|
const base2Ratio = Math.log(1/biggerRatio) / Math.log(2);
|
|
this.sim.scheduleZoom({x, y}, Math.floor(base2Ratio));
|
|
} else {
|
|
const base2Ratio = Math.log(1/biggerRatio) / Math.log(2);
|
|
this.sim.scheduleZoom({x, y}, Math.ceil(base2Ratio));
|
|
}
|
|
}
|
|
});
|
|
|
|
zeroNetMomentum.addEventListener('click', (e) => {
|
|
const { objects } = this.sim.objects;
|
|
|
|
// Find total momentum
|
|
let totalMomentum = objects.reduce((total, obj) => {
|
|
const px = obj.mass * obj.velocity.x;
|
|
const py = obj.mass * obj.velocity.y;
|
|
return {
|
|
x: total.x + px,
|
|
y: total.y + py,
|
|
};
|
|
}, {x: 0, y: 0});
|
|
|
|
// Find average momentum
|
|
let averageMomentum = {
|
|
x: totalMomentum.x / objects.length,
|
|
y: totalMomentum.y / objects.length,
|
|
};
|
|
|
|
// Subtract average from each
|
|
for (let i = 0; i < objects.length; i++) {
|
|
const obj = objects[i];
|
|
obj.velocity.x -= averageMomentum.x / obj.mass;
|
|
obj.velocity.y -= averageMomentum.y / obj.mass;
|
|
}
|
|
});
|
|
}
|
|
}
|