fixed zoom to fit

This commit is contained in:
Ladd 2025-12-27 11:51:42 -06:00
parent 103fd7f694
commit 1e3efe5150
3 changed files with 15 additions and 16 deletions

View File

@ -86,7 +86,8 @@ export class Pointer {
// Monitor wheel events // Monitor wheel events
el.addEventListener('wheel', e => { el.addEventListener('wheel', e => {
const factor = e.deltaY > 0 ? ZOOM_IN_FACTOR : ZOOM_OUT_FACTOR; const factor = e.deltaY > 0 ? ZOOM_IN_FACTOR : ZOOM_OUT_FACTOR;
this.sim.scheduleZoom({x: e.clientX, y: e.clientY}, factor); const {x, y} = this.sim.screenToSim(e.clientX, e.clientY);
this.sim.scheduleZoom({x, y}, factor);
}); });
} }

View File

@ -56,12 +56,13 @@ export class Sim {
this.nextZoom = {x, y, factor}; this.nextZoom = {x, y, factor};
} }
zoom({x: screenX, y: screenY, factor}) { // x, y should be in Sim coordinates
const {x, y} = this.screenToSim(screenX, screenY); zoom({x, y, factor}) {
// x, y are the mouse coordinates, which should be the center of the new view frame // x, y are the mouse coordinates, which should be the center of the new view frame
// the new view origin should be x, y minus half the new view width and height // the new view origin should be x, y minus half the new view width and height
// compute new scale // compute new scale
this.display.scalePower += factor; this.display.scalePower += factor;
// TODO: Lossy rescaling to expand zoom range
if (this.display.scalePower > SCALE_POWER_MAX) this.display.scalePower = SCALE_POWER_MAX; if (this.display.scalePower > SCALE_POWER_MAX) this.display.scalePower = SCALE_POWER_MAX;
if (this.display.scalePower < SCALE_POWER_MIN) this.display.scalePower = SCALE_POWER_MIN; if (this.display.scalePower < SCALE_POWER_MIN) this.display.scalePower = SCALE_POWER_MIN;
// compute coordinates of new view frame // compute coordinates of new view frame
@ -71,7 +72,7 @@ export class Sim {
this.pointer.clearPointerHistory(); this.pointer.clearPointerHistory();
if (this.pointer.panning) { if (this.pointer.panning) {
this.pointer.panning = undefined; this.pointer.panning = undefined;
// TODO: Maybe rescale velocity // TODO: Maybe show velocity vectors relative to view velocity
} }
} }

View File

@ -24,21 +24,21 @@ export class Zoom extends Tool {
zoomIn.innerHTML = '<h2>Zoom<br>In</h2>'; zoomIn.innerHTML = '<h2>Zoom<br>In</h2>';
zoomAll.innerHTML = '<h2>Zoom to Fit</h2>'; zoomAll.innerHTML = '<h2>Zoom to Fit</h2>';
zoomOut.addEventListener('click', (e) => { zoomOut.addEventListener('click', () => {
// Aim at center of view // Aim at center of view
const x = this.sim.display.width * this.sim.display.scale / 2; const x = this.sim.display.width * this.sim.display.scale / 2;
const y = this.sim.display.height * this.sim.display.scale / 2; const y = this.sim.display.height * this.sim.display.scale / 2;
this.sim.scheduleZoom({x, y}, ZOOM_OUT_FACTOR); this.sim.scheduleZoom(this.sim.screenToSim(x, y), ZOOM_OUT_FACTOR);
}); });
zoomIn.addEventListener('click', (e) => { zoomIn.addEventListener('click', () => {
// Aim at center of view // Aim at center of view
const x = this.sim.display.width * this.sim.display.scale / 2; const x = this.sim.display.width * this.sim.display.scale / 2;
const y = this.sim.display.height * this.sim.display.scale / 2; const y = this.sim.display.height * this.sim.display.scale / 2;
this.sim.scheduleZoom({x, y}, ZOOM_IN_FACTOR); this.sim.scheduleZoom(this.sim.screenToSim(x, y), ZOOM_IN_FACTOR);
}); });
zoomAll.addEventListener('click', (e) => { zoomAll.addEventListener('click', () => {
// Determine bounding box // Determine bounding box
const box = this.sim.objects.boundingBox; const box = this.sim.objects.boundingBox;
const x = (box.start.x + box.end.x) / 2; const x = (box.start.x + box.end.x) / 2;
@ -47,13 +47,10 @@ export class Zoom extends Tool {
const widthRatio = Math.abs(box.start.x - box.end.x) / this.sim.display.width; 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 heightRatio = Math.abs(box.start.y - box.end.y) / this.sim.display.height;
const biggerRatio = Math.max(widthRatio, heightRatio); const biggerRatio = Math.max(widthRatio, heightRatio);
if (biggerRatio <= 1) { const base2factor = Math.log(1/biggerRatio) / Math.log(2);
const base2Ratio = Math.log(1/biggerRatio) / Math.log(2); const factor = Math.floor(base2factor) - 1;
this.sim.scheduleZoom({x, y}, Math.floor(base2Ratio)); console.log({biggerRatio, base2factor, factor});
} else { this.sim.scheduleZoom({x, y}, factor);
const base2Ratio = Math.log(1/biggerRatio) / Math.log(2);
this.sim.scheduleZoom({x, y}, Math.ceil(base2Ratio));
}
} }
}); });
} }