improved scaling representation and mode selection
This commit is contained in:
parent
2dc55377d3
commit
b76adc6941
14
config.js
14
config.js
@ -1,8 +1,9 @@
|
|||||||
export const DISPLAY_OBJECTS_INFO = false;
|
export const DISPLAY_OBJECTS_INFO = false;
|
||||||
export const DISPLAY_CURSOR_INFO = false;
|
export const DISPLAY_CURSOR_INFO = false;
|
||||||
export const DISPLAY_CANVAS_SIZE = true;
|
export const DISPLAY_CANVAS_SIZE = false;
|
||||||
|
export const DISPLAY_CURRENT_SCALE = true;
|
||||||
export const DISPLAY_VELOCITY_VECTORS = true;
|
export const DISPLAY_VELOCITY_VECTORS = true;
|
||||||
|
|
||||||
export const MASS_CREATION_RATE = 0.001;
|
export const MASS_CREATION_RATE = 0.001;
|
||||||
export const POINTER_HISTORY_SIZE = 10;
|
export const POINTER_HISTORY_SIZE = 10;
|
||||||
export const VELOCITY_VECTOR_SCALE = 0.2;
|
export const VELOCITY_VECTOR_SCALE = 0.2;
|
||||||
@ -15,10 +16,11 @@ 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;
|
||||||
export const ZOOM_IN_FACTOR = 2;
|
export const ZOOM_IN_FACTOR = 1;
|
||||||
export const ZOOM_OUT_FACTOR = 0.5;
|
export const ZOOM_OUT_FACTOR = -1;
|
||||||
export const SCALE_MAX = 256;
|
export const SCALE_POWER_MAX = 8;
|
||||||
export const SCALE_MIN = 1/256;
|
export const SCALE_POWER_MIN = -8;
|
||||||
|
|
||||||
export const DRAGGABLE_ELEMENT_CLASSNAME = 'lhg-draggable-element';
|
export const DRAGGABLE_ELEMENT_CLASSNAME = 'lhg-draggable-element';
|
||||||
|
|
||||||
export const MODE_MASS_GENERATION = 'mass-gen';
|
export const MODE_MASS_GENERATION = 'mass-gen';
|
||||||
|
|||||||
@ -13,7 +13,7 @@ import {
|
|||||||
|
|
||||||
export class Display {
|
export class Display {
|
||||||
sim = undefined;
|
sim = undefined;
|
||||||
scale = 1;
|
scalePower = 0;
|
||||||
viewOrigin = {x: 0, y: 0};
|
viewOrigin = {x: 0, y: 0};
|
||||||
|
|
||||||
constructor(sim) {
|
constructor(sim) {
|
||||||
@ -30,6 +30,10 @@ export class Display {
|
|||||||
window.addEventListener('resize', () => this.fullscreen());
|
window.addEventListener('resize', () => this.fullscreen());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get scale() {
|
||||||
|
return 2 ** this.scalePower;
|
||||||
|
}
|
||||||
|
|
||||||
get ctx() {
|
get ctx() {
|
||||||
const ctx = this.canvas.getContext("2d");
|
const ctx = this.canvas.getContext("2d");
|
||||||
ctx.resetTransform();
|
ctx.resetTransform();
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import {
|
|||||||
DISPLAY_CURSOR_INFO,
|
DISPLAY_CURSOR_INFO,
|
||||||
DRAGGABLE_ELEMENT_CLASSNAME,
|
DRAGGABLE_ELEMENT_CLASSNAME,
|
||||||
MODE_MASS_GENERATION,
|
MODE_MASS_GENERATION,
|
||||||
|
MODE_PAN_VIEW,
|
||||||
} from './config.js';
|
} from './config.js';
|
||||||
|
|
||||||
function dispatchEvent(target, eventType, data) {
|
function dispatchEvent(target, eventType, data) {
|
||||||
@ -17,6 +18,7 @@ export class Pointer {
|
|||||||
|
|
||||||
pointerHistory = [];
|
pointerHistory = [];
|
||||||
draggingElement = undefined;
|
draggingElement = undefined;
|
||||||
|
panning = undefined;
|
||||||
|
|
||||||
constructor(sim) {
|
constructor(sim) {
|
||||||
this.sim = sim;
|
this.sim = sim;
|
||||||
@ -127,10 +129,16 @@ export class Pointer {
|
|||||||
|
|
||||||
if (this.sim.isCurrentMode(MODE_MASS_GENERATION)) {
|
if (this.sim.isCurrentMode(MODE_MASS_GENERATION)) {
|
||||||
this.sim.objects.handlePointerDown({x, y});
|
this.sim.objects.handlePointerDown({x, y});
|
||||||
|
} else if (this.sim.isCurrentMode(MODE_PAN_VIEW)) {
|
||||||
|
this.panning = {
|
||||||
|
pointerStart: {x, y},
|
||||||
|
pointerCurrent: {x, y},
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handlePointerUp({x, y}) {
|
handlePointerUp({x, y}) {
|
||||||
|
this.panning = undefined;
|
||||||
if (this.sim.isCurrentMode(MODE_MASS_GENERATION)) {
|
if (this.sim.isCurrentMode(MODE_MASS_GENERATION)) {
|
||||||
this.sim.objects.handlePointerUp({x, y});
|
this.sim.objects.handlePointerUp({x, y});
|
||||||
}
|
}
|
||||||
|
|||||||
29
simulator.js
29
simulator.js
@ -6,7 +6,11 @@ import { Toolbar } from './toolbar.js';
|
|||||||
import { PlayPause } from './tool/play-pause.js';
|
import { PlayPause } from './tool/play-pause.js';
|
||||||
import { Zoom } from './tool/zoom.js';
|
import { Zoom } from './tool/zoom.js';
|
||||||
import { ModeSwitch } from './tool/modes.js';
|
import { ModeSwitch } from './tool/modes.js';
|
||||||
import { SCALE_MAX, SCALE_MIN} from './config.js';
|
import {
|
||||||
|
SCALE_POWER_MAX,
|
||||||
|
SCALE_POWER_MIN,
|
||||||
|
DISPLAY_CURRENT_SCALE,
|
||||||
|
} from './config.js';
|
||||||
|
|
||||||
export class Sim {
|
export class Sim {
|
||||||
info = {};
|
info = {};
|
||||||
@ -53,9 +57,9 @@ 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.scale = this.display.scale * factor;
|
this.display.scalePower += factor > 0 ? 1 : -1;
|
||||||
if (this.display.scale > SCALE_MAX) this.display.scale = SCALE_MAX;
|
if (this.display.scalePower > SCALE_POWER_MAX) this.display.scalePower = SCALE_POWER_MAX;
|
||||||
if (this.display.scale < SCALE_MIN) this.display.scale = SCALE_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
|
||||||
this.display.viewOrigin.x = x - this.display.width / 2;
|
this.display.viewOrigin.x = x - this.display.width / 2;
|
||||||
this.display.viewOrigin.y = y - this.display.height / 2;
|
this.display.viewOrigin.y = y - this.display.height / 2;
|
||||||
@ -78,16 +82,27 @@ export class Sim {
|
|||||||
loop(currentTime) {
|
loop(currentTime) {
|
||||||
const elapsedTime = currentTime - this.time;
|
const elapsedTime = currentTime - this.time;
|
||||||
this.time = currentTime;
|
this.time = currentTime;
|
||||||
|
|
||||||
|
this.info['Mode'] = this.getCurrentMode();
|
||||||
|
|
||||||
if (this.nextZoom) {
|
if (this.nextZoom) {
|
||||||
this.zoom(this.nextZoom);
|
this.zoom(this.nextZoom);
|
||||||
this.nextZoom = undefined;
|
this.nextZoom = undefined;
|
||||||
}
|
}
|
||||||
this.info['scale'] = this.display.scale;
|
|
||||||
|
if (DISPLAY_CURRENT_SCALE) {
|
||||||
|
const scale = 2 ** Math.abs(this.display.scalePower);
|
||||||
|
this.info['Scale'] = this.display.scalePower >= 0 ? `${scale}` : `1/${scale}`;
|
||||||
|
}
|
||||||
|
|
||||||
this.objects.computeFrame(elapsedTime);
|
this.objects.computeFrame(elapsedTime);
|
||||||
this.display.fillCanvas();
|
|
||||||
this.display.drawObjects();
|
|
||||||
this.overlay.updateDraggable();
|
this.overlay.updateDraggable();
|
||||||
this.overlay.renderInfo();
|
this.overlay.renderInfo();
|
||||||
|
|
||||||
|
this.display.fillCanvas();
|
||||||
|
this.display.drawObjects();
|
||||||
|
|
||||||
requestAnimationFrame(t => this.loop(t));
|
requestAnimationFrame(t => this.loop(t));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,6 +11,7 @@ export class ModeSwitch extends Tool {
|
|||||||
[MODE_MASS_GENERATION, 'Generate Mass'],
|
[MODE_MASS_GENERATION, 'Generate Mass'],
|
||||||
[MODE_PAN_VIEW, 'Pan View'],
|
[MODE_PAN_VIEW, 'Pan View'],
|
||||||
];
|
];
|
||||||
|
buttons = [];
|
||||||
|
|
||||||
constructor(toolbar) {
|
constructor(toolbar) {
|
||||||
super(toolbar);
|
super(toolbar);
|
||||||
@ -34,21 +35,31 @@ export class ModeSwitch extends Tool {
|
|||||||
|
|
||||||
for (let [modeID, modeTitle] of this.modes) {
|
for (let [modeID, modeTitle] of this.modes) {
|
||||||
const button = document.createElement('button');
|
const button = document.createElement('button');
|
||||||
|
this.buttons.push(button);
|
||||||
|
button.modeID = modeID;
|
||||||
modesDiv.appendChild(button);
|
modesDiv.appendChild(button);
|
||||||
button.innerHTML = `<h3>${modeTitle}</h3>`;
|
button.innerHTML = `<h3>${modeTitle}</h3>`;
|
||||||
button.classList.add('wide');
|
button.classList.add('wide');
|
||||||
button.style.opacity = modeID === currentModeID ? '50%' : '100%';
|
|
||||||
|
|
||||||
button.addEventListener('click', (e) => {
|
button.addEventListener('click', (e) => {
|
||||||
if (this.currentMode !== modeID) {
|
if (this.currentMode !== modeID) {
|
||||||
this.currentMode = modeID;
|
this.currentMode = modeID;
|
||||||
|
this.setModesOpacity();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
this.setModesOpacity();
|
||||||
|
|
||||||
// Add global method to get current mode / check mode
|
// Add global method to get current mode / check mode
|
||||||
this.sim.getCurrentMode = () => this.currentMode;
|
this.sim.getCurrentMode = () => this.currentMode;
|
||||||
this.sim.isCurrentMode = (modeID) => modeID === this.currentMode;
|
this.sim.isCurrentMode = (modeID) => modeID === this.currentMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setModesOpacity() {
|
||||||
|
for (let button of this.buttons) {
|
||||||
|
button.style.opacity = button.modeID === this.currentMode ? '50%' : '100%';
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user