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 = '

Zoom
Out

'; zoomIn.innerHTML = '

Zoom
In

'; zoomAll.innerHTML = '

Zoom to Fit

'; zeroNetMomentum.innerHTML = '

Zero Net Momentum

'; 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; } }); } }