mode enter/leave callbacks
This commit is contained in:
parent
4f88d404d6
commit
28909a0c82
@ -44,6 +44,10 @@ export const GRAVITATIONAL_CONSTANT = 1E5;
|
|||||||
// CSS CLASS NAMES
|
// CSS CLASS NAMES
|
||||||
export const DRAGGABLE_ELEMENT_CLASSNAME = 'lhg-draggable-element';
|
export const DRAGGABLE_ELEMENT_CLASSNAME = 'lhg-draggable-element';
|
||||||
|
|
||||||
|
// EVENT NAMES
|
||||||
|
export const EVENT_MODE_LEAVE = 'lhg-mode-leave';
|
||||||
|
export const EVENT_MODE_ENTER = 'lhg-mode-enter';
|
||||||
|
|
||||||
// MODES
|
// MODES
|
||||||
export const MODE_MASS_GENERATION = 'mass-gen';
|
export const MODE_MASS_GENERATION = 'mass-gen';
|
||||||
export const MODE_PAN_VIEW = 'pan-view';
|
export const MODE_PAN_VIEW = 'pan-view';
|
||||||
|
|||||||
@ -194,7 +194,6 @@ export class Display {
|
|||||||
|
|
||||||
// Draw arrow for the velocity
|
// Draw arrow for the velocity
|
||||||
if (this.sim.getOption('display.velocity')) {
|
if (this.sim.getOption('display.velocity')) {
|
||||||
console.log('velocity vector');
|
|
||||||
const speed = Math.sqrt(vx ** 2 + vy ** 2);
|
const speed = Math.sqrt(vx ** 2 + vy ** 2);
|
||||||
const endVx = x + VELOCITY_VECTOR_SCALE * vx / speed * Math.log(speed);
|
const endVx = x + VELOCITY_VECTOR_SCALE * vx / speed * Math.log(speed);
|
||||||
const endVy = y + VELOCITY_VECTOR_SCALE * vy / speed * Math.log(speed);
|
const endVy = y + VELOCITY_VECTOR_SCALE * vy / speed * Math.log(speed);
|
||||||
|
|||||||
10
objects.js
10
objects.js
@ -98,11 +98,13 @@ export class Objects {
|
|||||||
}
|
}
|
||||||
|
|
||||||
objectAtLocation(x, y) {
|
objectAtLocation(x, y) {
|
||||||
this.forEachObject(obj => {
|
let idx = undefined;
|
||||||
|
this.forEachObject((obj, i) => {
|
||||||
// If distance to object is less than object's radius, we are touching the object
|
// If distance to object is less than object's radius, we are touching the object
|
||||||
const dist = Math.pow((obj.position.x - x)**2 + (obj.position.y - y)**2, 1/2);
|
const dist = Math.pow((obj.position.x - x)**2 + (obj.position.y - y)**2, 1/2);
|
||||||
if (dist <= obj.radius) {
|
if (dist <= obj.radius) {
|
||||||
return i;
|
idx = i;
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -137,11 +139,13 @@ export class Objects {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// cb: (obj, idx) => {}
|
// cb: (obj, idx) => {}
|
||||||
|
// TODO: Reducer
|
||||||
forEachObject(cb, alive = true, startWith = 0) {
|
forEachObject(cb, alive = true, startWith = 0) {
|
||||||
for (let i = startWith; i < this.objects.length; i++) {
|
for (let i = startWith; i < this.objects.length; i++) {
|
||||||
const obj = this.objects[i];
|
const obj = this.objects[i];
|
||||||
if (alive === null || alive == obj.alive) {
|
if (alive === null || alive == obj.alive) {
|
||||||
cb(obj, i);
|
const ret = cb(obj, i);
|
||||||
|
if (ret === null) break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -90,6 +90,11 @@ export class Pointer {
|
|||||||
this.sim.scheduleZoom({x, y}, factor);
|
this.sim.scheduleZoom({x, y}, factor);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// When leaving panning mode, clear panning
|
||||||
|
this.sim.onModeLeave(MODE_PAN_VIEW, () => {
|
||||||
|
this.panning = undefined;
|
||||||
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getPointerVelocity() {
|
getPointerVelocity() {
|
||||||
@ -179,10 +184,6 @@ export class Pointer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Apply update to viewOrigin based on panning
|
// Apply update to viewOrigin based on panning
|
||||||
if (!this.sim.isCurrentMode(MODE_PAN_VIEW)) {
|
|
||||||
this.panning = undefined;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (this.panning) {
|
if (this.panning) {
|
||||||
const {pointerStart, pointerCurrent, viewOriginStart, velocity} = this.sim.pointer.panning;
|
const {pointerStart, pointerCurrent, viewOriginStart, velocity} = this.sim.pointer.panning;
|
||||||
// Convert pointer velocity to sim internal scale
|
// Convert pointer velocity to sim internal scale
|
||||||
|
|||||||
@ -36,7 +36,6 @@ export class Sim {
|
|||||||
this.display = new Display(this);
|
this.display = new Display(this);
|
||||||
this.overlay = new Overlay(this);
|
this.overlay = new Overlay(this);
|
||||||
this.objects = new Objects(this);
|
this.objects = new Objects(this);
|
||||||
this.pointer = new Pointer(this);
|
|
||||||
this.toolbar = new Toolbar(this);
|
this.toolbar = new Toolbar(this);
|
||||||
|
|
||||||
// Set up toolbar
|
// Set up toolbar
|
||||||
@ -45,6 +44,8 @@ export class Sim {
|
|||||||
this.toolbar.addTool(new ModeSwitch(this.toolbar));
|
this.toolbar.addTool(new ModeSwitch(this.toolbar));
|
||||||
this.toolbar.addTool(new Options(this.toolbar));
|
this.toolbar.addTool(new Options(this.toolbar));
|
||||||
|
|
||||||
|
this.pointer = new Pointer(this);
|
||||||
|
|
||||||
// Initiate main loop
|
// Initiate main loop
|
||||||
this.time = document.timeline.currentTime;
|
this.time = document.timeline.currentTime;
|
||||||
requestAnimationFrame(t => this.loop(t));
|
requestAnimationFrame(t => this.loop(t));
|
||||||
|
|||||||
@ -3,6 +3,8 @@ import { Tool } from '../tool.js';
|
|||||||
import {
|
import {
|
||||||
MODE_MASS_GENERATION,
|
MODE_MASS_GENERATION,
|
||||||
MODE_PAN_VIEW,
|
MODE_PAN_VIEW,
|
||||||
|
EVENT_MODE_LEAVE,
|
||||||
|
EVENT_MODE_ENTER,
|
||||||
} from '../config.js';
|
} from '../config.js';
|
||||||
|
|
||||||
export class ModeSwitch extends Tool {
|
export class ModeSwitch extends Tool {
|
||||||
@ -16,9 +18,6 @@ export class ModeSwitch extends Tool {
|
|||||||
constructor(toolbar) {
|
constructor(toolbar) {
|
||||||
super(toolbar);
|
super(toolbar);
|
||||||
|
|
||||||
const [[currentModeID, _]] = this.modes;
|
|
||||||
this.currentMode = currentModeID;
|
|
||||||
|
|
||||||
const modesDiv = document.createElement('div');
|
const modesDiv = document.createElement('div');
|
||||||
const titleDiv = document.createElement('div');
|
const titleDiv = document.createElement('div');
|
||||||
|
|
||||||
@ -41,18 +40,18 @@ export class ModeSwitch extends Tool {
|
|||||||
button.innerHTML = `<h3>${modeTitle}</h3>`;
|
button.innerHTML = `<h3>${modeTitle}</h3>`;
|
||||||
button.classList.add('wide');
|
button.classList.add('wide');
|
||||||
|
|
||||||
button.addEventListener('click', (e) => {
|
button.addEventListener('click', (e) => this.setMode(modeID));
|
||||||
if (this.currentMode !== modeID) {
|
|
||||||
this.currentMode = modeID;
|
|
||||||
this.setModesOpacity();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
this.setModesOpacity();
|
|
||||||
|
// First listed mode is the default
|
||||||
|
const [[currentModeID, _]] = this.modes;
|
||||||
|
this.setMode(currentModeID);
|
||||||
|
|
||||||
// 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;
|
||||||
|
this.sim.onModeLeave = (modeID, cb) => this.onModeLeave(modeID, cb);
|
||||||
|
this.sim.onModeEnter = (modeID, cb) => this.onModeEnter(modeID, cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
setModesOpacity() {
|
setModesOpacity() {
|
||||||
@ -60,7 +59,33 @@ export class ModeSwitch extends Tool {
|
|||||||
button.style.opacity = button.modeID === this.currentMode ? '50%' : '100%';
|
button.style.opacity = button.modeID === this.currentMode ? '50%' : '100%';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setMode(modeID) {
|
||||||
|
if (modeID === this.currentMode) return;
|
||||||
|
const leave = new CustomEvent(EVENT_MODE_LEAVE, {detail: {modeID: this.currentMode}});
|
||||||
|
const enter = new CustomEvent(EVENT_MODE_LEAVE, {detail: {modeID}});
|
||||||
|
this.currentMode = modeID;
|
||||||
|
this.setModesOpacity();
|
||||||
|
this.div.dispatchEvent(leave);
|
||||||
|
this.div.dispatchEvent(enter);
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: on enter / on leave mode / some sort of callbacks on mode transitions
|
// cb: () => {}
|
||||||
|
onModeLeave(modeID, cb) {
|
||||||
|
this.div.addEventListener(EVENT_MODE_LEAVE, (e) => {
|
||||||
|
if (e.detail?.modeID === modeID) {
|
||||||
|
cb();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// cb: () => {}
|
||||||
|
onModeEnter(modeID, cb) {
|
||||||
|
this.div.addEventListener(EVENT_MODE_ENTER, (e) => {
|
||||||
|
if (e.detail?.modeID === modeID) {
|
||||||
|
cb();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
14
tool/zoom.js
14
tool/zoom.js
@ -51,6 +51,20 @@ export class Zoom extends Tool {
|
|||||||
const factor = Math.floor(base2factor) - 1;
|
const factor = Math.floor(base2factor) - 1;
|
||||||
this.sim.scheduleZoom({x, y}, factor);
|
this.sim.scheduleZoom({x, y}, factor);
|
||||||
}
|
}
|
||||||
|
// Determine average velocity and set panning velocity to match
|
||||||
|
const totalVelocity = {x: 0, y: 0};
|
||||||
|
let count = 0;
|
||||||
|
this.sim.objects.forEachObject(obj => {
|
||||||
|
count++;
|
||||||
|
totalVelocity.x += obj.velocity.x;
|
||||||
|
totalVelocity.y += obj.velocity.y;
|
||||||
|
});
|
||||||
|
const vx = totalVelocity.x / count;
|
||||||
|
const vy = totalVelocity.y / count;
|
||||||
|
console.log('zoom, pan', vx, vy);
|
||||||
|
this.sim.pointer.panning = {
|
||||||
|
velocity: {x: vx, y: vy},
|
||||||
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user