Compare commits
No commits in common. "3b2122d2e6fd73533136356de1a9dbef8d9c1595" and "4bb91d664d71a10c6df626d3383ba5d7160b77fe" have entirely different histories.
3b2122d2e6
...
4bb91d664d
15
config.js
15
config.js
@ -4,26 +4,16 @@ export const DISPLAY_CANVAS_SIZE = false;
|
|||||||
export const DISPLAY_CURRENT_SCALE = true;
|
export const DISPLAY_CURRENT_SCALE = true;
|
||||||
export const DISPLAY_CURRENT_MODE = false;
|
export const DISPLAY_CURRENT_MODE = false;
|
||||||
export const DISPLAY_VELOCITY_VECTORS = true;
|
export const DISPLAY_VELOCITY_VECTORS = true;
|
||||||
export const DISPLAY_ACCELERATION_VECTORS = true;
|
|
||||||
|
|
||||||
export const MASS_CREATION_RATE = 0.001;
|
export const MASS_CREATION_RATE = 0.001;
|
||||||
export const POINTER_HISTORY_SIZE = 15;
|
export const POINTER_HISTORY_SIZE = 15;
|
||||||
|
|
||||||
export const VELOCITY_VECTOR_SCALE = 0.1;
|
export const VELOCITY_VECTOR_SCALE = 0.1;
|
||||||
export const VELOCITY_VECTOR_COLOR = 'rgb(150, 150, 150)'; // optionally set to 'object color'
|
export const VELOCITY_VECTOR_COLOR = 'rgb(150, 150, 150)'; // optionally set to 'object color'
|
||||||
export const VELOCITY_VECTOR_WIDTH = 1.5;
|
export const VELOCITY_VECTOR_WIDTH = 1.5;
|
||||||
export const VELOCITY_VECTOR_ARROWHEAD = true;
|
export const VELOCITY_VECTOR_ARROWHEAD = true;
|
||||||
|
|
||||||
export const ACCELERATION_VECTOR_SCALE = 1E-1;
|
|
||||||
export const ACCELERATION_VECTOR_COLOR = 'rgb(0, 255, 0)'; // optionally set to 'object color'
|
|
||||||
export const ACCELERATION_VECTOR_WIDTH = 1.5;
|
|
||||||
export const ACCELERATION_VECTOR_ARROWHEAD = true;
|
|
||||||
|
|
||||||
export const MOTION_TIME_SCALE = 5E-5;
|
|
||||||
export const PAN_VELOCITY_SCALE_FACTOR = 1E-3;
|
|
||||||
|
|
||||||
export const ARROWHEAD_LENGTH = 7;
|
export const ARROWHEAD_LENGTH = 7;
|
||||||
export const ARROWHEAD_WIDTH = 5;
|
export const ARROWHEAD_WIDTH = 5;
|
||||||
|
export const MOTION_TIME_SCALE = 0.001;
|
||||||
export const OFFSCREEN_OBJECT_LINE_SCALE = 7;
|
export const OFFSCREEN_OBJECT_LINE_SCALE = 7;
|
||||||
export const OFFSCREEN_OBJECT_LINE_WIDTH = 2;
|
export const OFFSCREEN_OBJECT_LINE_WIDTH = 2;
|
||||||
export const OFFSCREEN_OBJECT_ARROWHEAD_LENGTH = 15;
|
export const OFFSCREEN_OBJECT_ARROWHEAD_LENGTH = 15;
|
||||||
@ -31,7 +21,8 @@ export const ZOOM_IN_FACTOR = 1;
|
|||||||
export const ZOOM_OUT_FACTOR = -1;
|
export const ZOOM_OUT_FACTOR = -1;
|
||||||
export const SCALE_POWER_MAX = 8;
|
export const SCALE_POWER_MAX = 8;
|
||||||
export const SCALE_POWER_MIN = -8;
|
export const SCALE_POWER_MIN = -8;
|
||||||
export const GRAVITATIONAL_CONSTANT = 1E5;
|
export const PAN_VELOCITY_SCALE_FACTOR = 1E-3;
|
||||||
|
export const PAN_DRAG = 1;
|
||||||
|
|
||||||
export const DRAGGABLE_ELEMENT_CLASSNAME = 'lhg-draggable-element';
|
export const DRAGGABLE_ELEMENT_CLASSNAME = 'lhg-draggable-element';
|
||||||
|
|
||||||
|
|||||||
45
display.js
45
display.js
@ -3,18 +3,12 @@ import {
|
|||||||
VELOCITY_VECTOR_COLOR,
|
VELOCITY_VECTOR_COLOR,
|
||||||
VELOCITY_VECTOR_WIDTH,
|
VELOCITY_VECTOR_WIDTH,
|
||||||
VELOCITY_VECTOR_ARROWHEAD,
|
VELOCITY_VECTOR_ARROWHEAD,
|
||||||
ACCELERATION_VECTOR_SCALE,
|
|
||||||
ACCELERATION_VECTOR_COLOR,
|
|
||||||
ACCELERATION_VECTOR_WIDTH,
|
|
||||||
ACCELERATION_VECTOR_ARROWHEAD,
|
|
||||||
ARROWHEAD_LENGTH,
|
ARROWHEAD_LENGTH,
|
||||||
ARROWHEAD_WIDTH,
|
ARROWHEAD_WIDTH,
|
||||||
OFFSCREEN_OBJECT_LINE_SCALE,
|
OFFSCREEN_OBJECT_LINE_SCALE,
|
||||||
OFFSCREEN_OBJECT_LINE_WIDTH,
|
OFFSCREEN_OBJECT_LINE_WIDTH,
|
||||||
OFFSCREEN_OBJECT_ARROWHEAD_LENGTH,
|
OFFSCREEN_OBJECT_ARROWHEAD_LENGTH,
|
||||||
DISPLAY_CANVAS_SIZE,
|
DISPLAY_CANVAS_SIZE,
|
||||||
DISPLAY_VELOCITY_VECTORS,
|
|
||||||
DISPLAY_ACCELERATION_VECTORS,
|
|
||||||
} from './config.js';
|
} from './config.js';
|
||||||
|
|
||||||
export class Display {
|
export class Display {
|
||||||
@ -83,7 +77,6 @@ export class Display {
|
|||||||
const {r, g, b} = obj.color;
|
const {r, g, b} = obj.color;
|
||||||
const {x, y} = obj.position;
|
const {x, y} = obj.position;
|
||||||
const {x: vx, y: vy} = obj.velocity;
|
const {x: vx, y: vy} = obj.velocity;
|
||||||
const acceleration = obj.acceleration;
|
|
||||||
const radius = obj.radius;
|
const radius = obj.radius;
|
||||||
const {height: H, width: W} = this;
|
const {height: H, width: W} = this;
|
||||||
const ox = this.viewOrigin.x;
|
const ox = this.viewOrigin.x;
|
||||||
@ -146,34 +139,18 @@ export class Display {
|
|||||||
ctx.fill();
|
ctx.fill();
|
||||||
|
|
||||||
// Draw arrow for the velocity
|
// Draw arrow for the velocity
|
||||||
if (DISPLAY_VELOCITY_VECTORS) {
|
const endVx = x + VELOCITY_VECTOR_SCALE * vx;
|
||||||
const endVx = x + VELOCITY_VECTOR_SCALE * vx;
|
const endVy = y + VELOCITY_VECTOR_SCALE * vy;
|
||||||
const endVy = y + VELOCITY_VECTOR_SCALE * vy;
|
const style = VELOCITY_VECTOR_COLOR === 'object color' ? ctx.fillStyle : VELOCITY_VECTOR_COLOR;
|
||||||
const style = VELOCITY_VECTOR_COLOR === 'object color' ?
|
this.drawArrow(x, y, endVx, endVy, {
|
||||||
ctx.fillStyle : VELOCITY_VECTOR_COLOR;
|
style,
|
||||||
this.drawArrow(x, y, endVx, endVy, {
|
width: VELOCITY_VECTOR_WIDTH,
|
||||||
style,
|
arrowhead: VELOCITY_VECTOR_ARROWHEAD,
|
||||||
width: VELOCITY_VECTOR_WIDTH,
|
fill: false,
|
||||||
arrowhead: VELOCITY_VECTOR_ARROWHEAD,
|
ifShort: 'head'
|
||||||
fill: false,
|
});
|
||||||
ifShort: 'head'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Draw arrow for acceleration
|
// TODO: Draw arrow for acceleration
|
||||||
if (DISPLAY_ACCELERATION_VECTORS) {
|
|
||||||
const endAx = x + ACCELERATION_VECTOR_SCALE * acceleration.x;
|
|
||||||
const endAy = y + ACCELERATION_VECTOR_SCALE * acceleration.y;
|
|
||||||
const style = ACCELERATION_VECTOR_COLOR === 'object color' ?
|
|
||||||
ctx.fillStyle : ACCELERATION_VECTOR_COLOR;
|
|
||||||
this.drawArrow(x, y, endAx, endAy, {
|
|
||||||
style,
|
|
||||||
width: ACCELERATION_VECTOR_WIDTH,
|
|
||||||
arrowhead: ACCELERATION_VECTOR_ARROWHEAD,
|
|
||||||
fill: false,
|
|
||||||
ifShort: 'tail'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
drawObjects() {
|
drawObjects() {
|
||||||
|
|||||||
15
object.js
15
object.js
@ -6,8 +6,6 @@ export class MassObject {
|
|||||||
velocity = {x: 0, y: 0};
|
velocity = {x: 0, y: 0};
|
||||||
color = {r: undefined, g: undefined, b: undefined};
|
color = {r: undefined, g: undefined, b: undefined};
|
||||||
created = undefined;
|
created = undefined;
|
||||||
forces = []; // [{x, y}]
|
|
||||||
active = false;
|
|
||||||
|
|
||||||
constructor(x, y, index) {
|
constructor(x, y, index) {
|
||||||
this.index = index;
|
this.index = index;
|
||||||
@ -27,18 +25,5 @@ export class MassObject {
|
|||||||
// radius should be proportional to cube root of mass
|
// radius should be proportional to cube root of mass
|
||||||
return Math.pow(this.mass / this.density, 1/3);
|
return Math.pow(this.mass / this.density, 1/3);
|
||||||
}
|
}
|
||||||
|
|
||||||
get acceleration() {
|
|
||||||
let ax = 0;
|
|
||||||
let ay = 0;
|
|
||||||
for (let {x, y} of this.forces) {
|
|
||||||
ax += x;
|
|
||||||
ay += y;
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
x: ax / this.mass,
|
|
||||||
y: ay / this.mass,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
87
objects.js
87
objects.js
@ -3,7 +3,6 @@ import {
|
|||||||
MASS_CREATION_RATE,
|
MASS_CREATION_RATE,
|
||||||
DISPLAY_OBJECTS_INFO,
|
DISPLAY_OBJECTS_INFO,
|
||||||
MOTION_TIME_SCALE,
|
MOTION_TIME_SCALE,
|
||||||
GRAVITATIONAL_CONSTANT,
|
|
||||||
} from './config.js';
|
} from './config.js';
|
||||||
|
|
||||||
export class Objects {
|
export class Objects {
|
||||||
@ -24,11 +23,7 @@ export class Objects {
|
|||||||
}
|
}
|
||||||
|
|
||||||
doneCreatingObject() {
|
doneCreatingObject() {
|
||||||
if (this.creatingObject !== undefined) {
|
this.creatingObject = undefined;
|
||||||
const obj = this.objects[this.creatingObject];
|
|
||||||
obj.active = true;
|
|
||||||
this.creatingObject = undefined;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
object(i) {
|
object(i) {
|
||||||
@ -54,26 +49,6 @@ export class Objects {
|
|||||||
return this.objects.length;
|
return this.objects.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
get boundingBox() {
|
|
||||||
const box = {
|
|
||||||
start: {x: undefined, y: undefined},
|
|
||||||
end: {x: undefined, y: undefined},
|
|
||||||
};
|
|
||||||
for (let i = 0; i < this.objects.length; i++) {
|
|
||||||
const obj = this.objects[i];
|
|
||||||
if (box.start.x === undefined) {
|
|
||||||
box.start = {...obj.position};
|
|
||||||
box.end = {...obj.position};
|
|
||||||
} else {
|
|
||||||
if (obj.position.x < box.start.x) box.start.x = obj.position.x;
|
|
||||||
if (obj.position.x > box.end.x) box.end.x = obj.position.x;
|
|
||||||
if (obj.position.y < box.start.y) box.start.y = obj.position.y;
|
|
||||||
if (obj.position.y > box.end.y) box.end.y = obj.position.y;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return box;
|
|
||||||
}
|
|
||||||
|
|
||||||
objectAtLocation(x, y) {
|
objectAtLocation(x, y) {
|
||||||
for (let i = 0; i < this.objects.length; i++) {
|
for (let i = 0; i < this.objects.length; i++) {
|
||||||
const obj = this.objects[i];
|
const obj = this.objects[i];
|
||||||
@ -105,7 +80,7 @@ export class Objects {
|
|||||||
handlePointerMove({x, y, vx, vy}) {
|
handlePointerMove({x, y, vx, vy}) {
|
||||||
// If the cursor moves while creating an object, or while an object is selected,
|
// If the cursor moves while creating an object, or while an object is selected,
|
||||||
// update the position and velocity of the object
|
// update the position and velocity of the object
|
||||||
const obj = this.getSelectedOrCreating();
|
const obj = this.sim.objects.getSelectedOrCreating();
|
||||||
if (obj !== undefined) {
|
if (obj !== undefined) {
|
||||||
obj.position.x = x;
|
obj.position.x = x;
|
||||||
obj.position.y = y;
|
obj.position.y = y;
|
||||||
@ -114,29 +89,6 @@ export class Objects {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
computeForces(elapsedTime) {
|
|
||||||
if (this.objects.length < 2) return;
|
|
||||||
for (let i = 0; i < this.objects.length; i++) {
|
|
||||||
this.objects[i].forces = [];
|
|
||||||
}
|
|
||||||
for (let i = 0; i < this.objects.length; i++) {
|
|
||||||
const A = this.objects[i];
|
|
||||||
for (let j = i + 1; j < this.objects.length; j++) {
|
|
||||||
const B = this.objects[j];
|
|
||||||
if (!A.active || !B.active) continue;
|
|
||||||
const dx = (B.position.x - A.position.x);
|
|
||||||
const dy = (B.position.y - A.position.y);
|
|
||||||
const dSquared = dx ** 2 + dy ** 2;
|
|
||||||
const d = Math.sqrt(dSquared);
|
|
||||||
const F = GRAVITATIONAL_CONSTANT * A.mass * B.mass / dSquared;
|
|
||||||
const Fx = F * dx / d;
|
|
||||||
const Fy = F * dy / d;
|
|
||||||
A.forces.push({ x: Fx, y: Fy });
|
|
||||||
B.forces.push({ x: -Fx, y: -Fy });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
computeFrame(elapsedTime) {
|
computeFrame(elapsedTime) {
|
||||||
// If we're creating an object, increment its mass
|
// If we're creating an object, increment its mass
|
||||||
// with the mass creation rate accelerating over time
|
// with the mass creation rate accelerating over time
|
||||||
@ -147,41 +99,12 @@ export class Objects {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (this.sim.playing) {
|
if (this.sim.playing) {
|
||||||
// Calculate forces due to gravity.
|
// Update positions. Simple Euler method for now.
|
||||||
this.computeForces(elapsedTime);
|
|
||||||
|
|
||||||
// Generate predicted positions (Velocity verlet method)
|
|
||||||
for (let i = 0; i < this.objects.length; i++) {
|
for (let i = 0; i < this.objects.length; i++) {
|
||||||
const obj = this.objects[i];
|
const obj = this.objects[i];
|
||||||
obj.currentAcceleration = {...obj.acceleration};
|
obj.position.x += obj.velocity.x * MOTION_TIME_SCALE;
|
||||||
obj.projectedPosition = {
|
obj.position.y += obj.velocity.y * MOTION_TIME_SCALE;
|
||||||
x: obj.position.x + MOTION_TIME_SCALE * elapsedTime *
|
|
||||||
(obj.velocity.x + 1/2 * obj.currentAcceleration.x * elapsedTime),
|
|
||||||
y: obj.position.y + MOTION_TIME_SCALE * elapsedTime *
|
|
||||||
(obj.velocity.y + 1/2 * obj.currentAcceleration.y * elapsedTime),
|
|
||||||
};
|
|
||||||
obj.currentPosition = {...obj.position};
|
|
||||||
obj.position = obj.projectedPosition;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Recompute forces
|
|
||||||
this.computeForces();
|
|
||||||
|
|
||||||
// Average first and second predicted accelerations
|
|
||||||
for (let i = 0; i < this.objects.length; i++) {
|
|
||||||
const obj = this.objects[i];
|
|
||||||
const acceleration = {...obj.acceleration};
|
|
||||||
const meanAcceleration = {
|
|
||||||
x: (obj.currentAcceleration.x + acceleration.x) / 2,
|
|
||||||
y: (obj.currentAcceleration.y + acceleration.y) / 2,
|
|
||||||
};
|
|
||||||
obj.velocity.x += meanAcceleration.x * MOTION_TIME_SCALE * elapsedTime;
|
|
||||||
obj.velocity.y += meanAcceleration.y * MOTION_TIME_SCALE * elapsedTime;
|
|
||||||
|
|
||||||
obj.position.x = obj.currentPosition.x + obj.velocity.x * MOTION_TIME_SCALE * elapsedTime;
|
|
||||||
obj.position.y = obj.currentPosition.y + obj.velocity.y * MOTION_TIME_SCALE * elapsedTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Display objects info
|
// Display objects info
|
||||||
|
|||||||
17
pointer.js
17
pointer.js
@ -68,7 +68,7 @@ export class Pointer {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
this.handlePointerDown({x: e.clientX, y: e.clientY});
|
this.handlePointerDown(this.sim.screenToSim(e.clientX, e.clientY));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -79,7 +79,7 @@ export class Pointer {
|
|||||||
this.draggingElement = undefined;
|
this.draggingElement = undefined;
|
||||||
this.lastPosition = {x: undefined, y: undefined};
|
this.lastPosition = {x: undefined, y: undefined};
|
||||||
} else {
|
} else {
|
||||||
this.handlePointerUp({x: e.clientX, y: e.clientY});
|
this.handlePointerUp(this.sim.screenToSim(e.clientX, e.clientY));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -118,29 +118,24 @@ export class Pointer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handlePointerDown({x: clientX, y: clientY}) {
|
handlePointerDown({x, y}) {
|
||||||
if (this.sim.isCurrentMode(MODE_MASS_GENERATION)) {
|
if (this.sim.isCurrentMode(MODE_MASS_GENERATION)) {
|
||||||
const {x, y} = this.sim.screenToSim(clientX, clientY)
|
|
||||||
this.sim.objects.handlePointerDown({x, y});
|
this.sim.objects.handlePointerDown({x, y});
|
||||||
|
|
||||||
} else if (this.sim.isCurrentMode(MODE_PAN_VIEW)) {
|
} else if (this.sim.isCurrentMode(MODE_PAN_VIEW)) {
|
||||||
this.panning = {
|
this.panning = {
|
||||||
gathering: true,
|
gathering: true,
|
||||||
viewOriginStart: this.sim.display.viewOrigin,
|
viewOriginStart: this.sim.display.viewOrigin,
|
||||||
pointerStart: {x: clientX, y: clientY},
|
pointerStart: {x, y},
|
||||||
pointerCurrent: {x: clientX, y: clientY},
|
pointerCurrent: {x, y},
|
||||||
velocity: this.getPointerVelocity(),
|
velocity: this.getPointerVelocity(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handlePointerUp({x: clientX, y: clientY}) {
|
handlePointerUp({x, y}) {
|
||||||
this.clearPointerHistory();
|
this.clearPointerHistory();
|
||||||
|
|
||||||
if (this.sim.isCurrentMode(MODE_MASS_GENERATION)) {
|
if (this.sim.isCurrentMode(MODE_MASS_GENERATION)) {
|
||||||
const {x, y} = this.sim.screenToSim(clientX, clientY);
|
|
||||||
this.sim.objects.handlePointerUp({x, y});
|
this.sim.objects.handlePointerUp({x, y});
|
||||||
|
|
||||||
} else if (this.sim.isCurrentMode(MODE_PAN_VIEW)) {
|
} else if (this.sim.isCurrentMode(MODE_PAN_VIEW)) {
|
||||||
if (this.panning?.gathering) {
|
if (this.panning?.gathering) {
|
||||||
this.panning.gathering = false;
|
this.panning.gathering = false;
|
||||||
|
|||||||
@ -58,7 +58,7 @@ export class Sim {
|
|||||||
// 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 > 0 ? 1 : -1;
|
||||||
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
|
||||||
|
|||||||
36
tool/zoom.js
36
tool/zoom.js
@ -10,18 +10,19 @@ export class Zoom extends Tool {
|
|||||||
|
|
||||||
const zoomOut = document.createElement('button');
|
const zoomOut = document.createElement('button');
|
||||||
const zoomIn = document.createElement('button');
|
const zoomIn = document.createElement('button');
|
||||||
const zoomAll = document.createElement('button');
|
|
||||||
|
for (let b of [zoomIn, zoomOut]) {
|
||||||
|
// b.style.width = '100px';
|
||||||
|
// b.style.height = '50px';
|
||||||
|
// b.style['padding-left'] = '25px';
|
||||||
|
// b.style['padding-right'] = '25px';
|
||||||
|
}
|
||||||
|
|
||||||
this.div.appendChild(zoomOut);
|
this.div.appendChild(zoomOut);
|
||||||
this.div.appendChild(zoomIn);
|
this.div.appendChild(zoomIn);
|
||||||
this.div.appendChild(document.createElement('br'));
|
|
||||||
this.div.appendChild(zoomAll);
|
|
||||||
|
|
||||||
zoomAll.classList.add('wide');
|
zoomOut.innerHTML = '<h2>Zoom<br>-<br>Out</h2>';
|
||||||
|
zoomIn.innerHTML = '<h2>Zoom<br>+<br>In</h2>';
|
||||||
zoomOut.innerHTML = '<h2>Zoom<br>Out</h2>';
|
|
||||||
zoomIn.innerHTML = '<h2>Zoom<br>In</h2>';
|
|
||||||
zoomAll.innerHTML = '<h2>Zoom to Fit</h2>';
|
|
||||||
|
|
||||||
zoomOut.addEventListener('click', (e) => {
|
zoomOut.addEventListener('click', (e) => {
|
||||||
// Aim at center of view
|
// Aim at center of view
|
||||||
@ -36,24 +37,5 @@ export class Zoom extends Tool {
|
|||||||
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({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));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user