moved Zero Momentum to Utilities toolbar
This commit is contained in:
parent
d869bc5a6f
commit
ef51f436c3
@ -13,7 +13,7 @@ Screenshots
|
|||||||
TODO
|
TODO
|
||||||
----
|
----
|
||||||
|
|
||||||
- [ ] Parameter Slider
|
- [ ] Parameter Slider (Invisible, mouse/touch drag)
|
||||||
- [ ] Selection Box
|
- [ ] Selection Box
|
||||||
- [ ] Object List
|
- [ ] Object List
|
||||||
- [ ] Object Detail
|
- [ ] Object Detail
|
||||||
|
|||||||
@ -1,11 +1,3 @@
|
|||||||
// DISPLAY
|
|
||||||
export const DISPLAY_OBJECTS_INFO = false;
|
|
||||||
export const DISPLAY_CURSOR_INFO = true;
|
|
||||||
export const DISPLAY_CANVAS_SIZE = false;
|
|
||||||
export const DISPLAY_CURRENT_SCALE = false;
|
|
||||||
export const DISPLAY_CURRENT_MODE = false;
|
|
||||||
export const DISPLAY_PANNING_INFO = true;
|
|
||||||
|
|
||||||
// VELOCITY
|
// VELOCITY
|
||||||
export const VELOCITY_VECTOR_SCALE = 8E0;
|
export const VELOCITY_VECTOR_SCALE = 8E0;
|
||||||
export const VELOCITY_VECTOR_COLOR = 'rgba(150, 150, 150, 0.8)'; // optionally set to 'object color'
|
export const VELOCITY_VECTOR_COLOR = 'rgba(150, 150, 150, 0.8)'; // optionally set to 'object color'
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
import {
|
import {
|
||||||
ARROWHEAD_LENGTH,
|
ARROWHEAD_LENGTH,
|
||||||
ARROWHEAD_WIDTH,
|
ARROWHEAD_WIDTH,
|
||||||
DISPLAY_CANVAS_SIZE,
|
|
||||||
} from './config.js';
|
} from './config.js';
|
||||||
|
|
||||||
export class Display {
|
export class Display {
|
||||||
@ -60,12 +59,12 @@ export class Display {
|
|||||||
fullscreen() {
|
fullscreen() {
|
||||||
this.canvas.width = document.documentElement.clientWidth;
|
this.canvas.width = document.documentElement.clientWidth;
|
||||||
this.canvas.height = document.documentElement.clientHeight;
|
this.canvas.height = document.documentElement.clientHeight;
|
||||||
if (DISPLAY_CANVAS_SIZE) {
|
if (this.sim.getOption('debug.canvasSize')) {
|
||||||
this.sim.info['Canvas'] = `${this.canvas.width} x ${this.canvas.height}`;
|
this.sim.info['Canvas'] = [`${this.canvas.width}`, `${this.canvas.height}`];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fillCanvas() {
|
fillCanvas() {
|
||||||
const ctx = this.ctx;
|
const ctx = this.ctx;
|
||||||
ctx.fillStyle = '#000';
|
ctx.fillStyle = '#000';
|
||||||
ctx.fillRect(this.viewOrigin.x, this.viewOrigin.y, this.width, this.height);
|
ctx.fillRect(this.viewOrigin.x, this.viewOrigin.y, this.width, this.height);
|
||||||
|
|||||||
27
objects.js
27
objects.js
@ -1,8 +1,5 @@
|
|||||||
import { MassObject } from './object.js';
|
import { MassObject } from './object.js';
|
||||||
import {
|
import { ZOOM_TO_FIT_PADDING } from './config.js';
|
||||||
DISPLAY_OBJECTS_INFO,
|
|
||||||
ZOOM_TO_FIT_PADDING,
|
|
||||||
} from './config.js';
|
|
||||||
|
|
||||||
export class Objects {
|
export class Objects {
|
||||||
objects = [];
|
objects = [];
|
||||||
@ -299,7 +296,7 @@ export class Objects {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Display objects info
|
// Display objects info
|
||||||
if (DISPLAY_OBJECTS_INFO) {
|
if (this.sim.getOption('debug.objectsInfo')) {
|
||||||
this.forEachObject((obj, i) => {
|
this.forEachObject((obj, i) => {
|
||||||
const speed = Math.pow(obj.velocity.x ** 2 + obj.velocity.y ** 2, 1/2);
|
const speed = Math.pow(obj.velocity.x ** 2 + obj.velocity.y ** 2, 1/2);
|
||||||
// Invert y so that the angle is counterclockwise from x-axis
|
// Invert y so that the angle is counterclockwise from x-axis
|
||||||
@ -330,17 +327,25 @@ export class Objects {
|
|||||||
count: 0,
|
count: 0,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!count) return;
|
const centerOfMass = count ? {
|
||||||
|
|
||||||
const centerOfMass = {
|
|
||||||
x: totalMassLocation.x / totalMass,
|
x: totalMassLocation.x / totalMass,
|
||||||
y: totalMassLocation.y / totalMass,
|
y: totalMassLocation.y / totalMass,
|
||||||
};
|
} : {x: 0, y: 0};
|
||||||
|
|
||||||
return { totalMass, count, totalMassLocation, centerOfMass };
|
// Determine average momentum
|
||||||
|
const netMomentum = this.sim.objects.reduce((acc, obj) => ({
|
||||||
|
x: acc.x + obj.mass * obj.velocity.x,
|
||||||
|
y: acc.y + obj.mass * obj.velocity.y,
|
||||||
|
}), { x: 0, y: 0 });
|
||||||
|
|
||||||
|
return { totalMass, count, totalMassLocation, centerOfMass, netMomentum };
|
||||||
}
|
}
|
||||||
|
|
||||||
computeSystemAngularMomentum(centerOfMass) {
|
computeSystemAngularMomentum(centerOfMass) {
|
||||||
|
if (!centerOfMass) {
|
||||||
|
const sys = this.computeSystemCenter();
|
||||||
|
centerOfMass = sys.centerOfMass;
|
||||||
|
}
|
||||||
return this.reduce((acc, obj) => {
|
return this.reduce((acc, obj) => {
|
||||||
// Angular momentum for each object is m * s / d
|
// Angular momentum for each object is m * s / d
|
||||||
// where d is the distance of the object from the global center of mass
|
// where d is the distance of the object from the global center of mass
|
||||||
|
|||||||
@ -20,7 +20,14 @@ export const optionsLayout = {
|
|||||||
gravity: ['Gravity', 'number', 4E4],
|
gravity: ['Gravity', 'number', 4E4],
|
||||||
timeScale: ['Time Scale', 'number', 0.2],
|
timeScale: ['Time Scale', 'number', 0.2],
|
||||||
massCreationRate: ['Mass Creation Rate', 'number', 10],
|
massCreationRate: ['Mass Creation Rate', 'number', 10],
|
||||||
}
|
},
|
||||||
|
debug: {
|
||||||
|
objectsInfo: ['Objects Info', 'boolean', false],
|
||||||
|
cursorInfo: ['Cursor Info', 'boolean', false],
|
||||||
|
canvasSize: ['Canvas Size', 'boolean', false],
|
||||||
|
currentMode: ['Current Mode', 'boolean', false],
|
||||||
|
panningInfo: ['Panning Info', 'boolean', false],
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export class Options {
|
export class Options {
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
import {
|
import {
|
||||||
DISPLAY_CURSOR_INFO,
|
|
||||||
MODE_MASS_GENERATION,
|
MODE_MASS_GENERATION,
|
||||||
MODE_OBJECT_SELECT,
|
MODE_OBJECT_SELECT,
|
||||||
MODE_PAN_VIEW,
|
MODE_PAN_VIEW,
|
||||||
@ -25,7 +24,7 @@ export class Pointer {
|
|||||||
const el = window;
|
const el = window;
|
||||||
|
|
||||||
el.addEventListener('pointermove', e => {
|
el.addEventListener('pointermove', e => {
|
||||||
if (DISPLAY_CURSOR_INFO) {
|
if (this.sim.getOption('debug.cursorInfo')) {
|
||||||
this.sim.info['pointermove'] = [`${e.clientX.toPrecision(6)}, `, `${e.clientY.toPrecision(6)}`];
|
this.sim.info['pointermove'] = [`${e.clientX.toPrecision(6)}, `, `${e.clientY.toPrecision(6)}`];
|
||||||
}
|
}
|
||||||
this.handlePointerMove({x: e.clientX, y: e.clientY});
|
this.handlePointerMove({x: e.clientX, y: e.clientY});
|
||||||
|
|||||||
84
simulator.js
84
simulator.js
@ -1,7 +1,4 @@
|
|||||||
import {
|
import {
|
||||||
DISPLAY_CURRENT_MODE,
|
|
||||||
DISPLAY_CURRENT_SCALE,
|
|
||||||
DISPLAY_PANNING_INFO,
|
|
||||||
EVENT_ZOOM,
|
EVENT_ZOOM,
|
||||||
SCALE_POWER_MAX,
|
SCALE_POWER_MAX,
|
||||||
SCALE_POWER_MIN,
|
SCALE_POWER_MIN,
|
||||||
@ -15,6 +12,7 @@ import { ModeSwitch } from './tool/modes.js';
|
|||||||
import { OptionsTool } from './tool/options.js';
|
import { OptionsTool } from './tool/options.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 { UtilityTool } from './tool/utility.js';
|
||||||
import { Toolbar } from './toolbar.js';
|
import { Toolbar } from './toolbar.js';
|
||||||
import { ToolbarGroup } from './toolbar-group.js';
|
import { ToolbarGroup } from './toolbar-group.js';
|
||||||
|
|
||||||
@ -48,35 +46,52 @@ export class Sim {
|
|||||||
this.options = new Options(this);
|
this.options = new Options(this);
|
||||||
this.display = new Display(this);
|
this.display = new Display(this);
|
||||||
this.objects = new Objects(this);
|
this.objects = new Objects(this);
|
||||||
this.toolbarGroups = {
|
|
||||||
left: new ToolbarGroup(this),
|
|
||||||
right: new ToolbarGroup(this).topRight(),
|
|
||||||
};
|
|
||||||
this.toolbars = {
|
this.toolbars = {
|
||||||
tools: new Toolbar(this, 'Tools', this.toolbarGroups.left),
|
tools: new Toolbar(this, 'Tools'),
|
||||||
modes: new Toolbar(this, 'Modes', this.toolbarGroups.left),
|
modes: new Toolbar(this, 'Modes'),
|
||||||
options: new Toolbar(this, 'Options', this.toolbarGroups.right),
|
utils: new Toolbar(this, 'Utility'),
|
||||||
params: new Toolbar(this, 'Parameters', this.toolbarGroups.right),
|
options: new Toolbar(this, 'Options'),
|
||||||
}
|
params: new Toolbar(this, 'Parameters'),
|
||||||
|
debug: new Toolbar(this, 'Debug', { expanded: false }),
|
||||||
|
};
|
||||||
|
const { tools, modes, options, params, debug, utils } = this.toolbars;
|
||||||
|
this.toolbarGroups = {
|
||||||
|
left: new ToolbarGroup(this)
|
||||||
|
.addToolbar(tools)
|
||||||
|
.addToolbar(modes)
|
||||||
|
.addToolbar(utils),
|
||||||
|
right: new ToolbarGroup(this).topRight()
|
||||||
|
.addToolbar(options)
|
||||||
|
.addToolbar(params)
|
||||||
|
.addToolbar(debug),
|
||||||
|
};
|
||||||
this.overlay = new Overlay(this);
|
this.overlay = new Overlay(this);
|
||||||
this.pointer = new Pointer(this);
|
this.pointer = new Pointer(this);
|
||||||
|
|
||||||
{
|
// Configure toolbars
|
||||||
// Configure toolbars
|
|
||||||
const { tools, modes, options, params } = this.toolbars;
|
// Primary
|
||||||
// Primary Toolbar
|
tools.addTool(new Zoom(tools));
|
||||||
tools.addTool(new Zoom(tools));
|
tools.addTool(new PlayPause(tools));
|
||||||
tools.addTool(new PlayPause(tools));
|
|
||||||
// Secondary Toolbar: Mode Switches
|
// Secondary
|
||||||
modes.addTool(new ModeSwitch(modes));
|
modes.addTool(new ModeSwitch(modes));
|
||||||
// Options Toolbar
|
|
||||||
options.addTool(new OptionsTool(options, [
|
// Utility
|
||||||
'pauseDuring', 'display', 'collision'
|
utils.addTool(new UtilityTool(utils));
|
||||||
]));
|
|
||||||
// Parameters Toolbar
|
// Options
|
||||||
params.addTool(new OptionsTool(params, [
|
options.addTool(new OptionsTool(options, ['pauseDuring', 'display', 'collision']));
|
||||||
'param'
|
|
||||||
]));
|
// Parameters
|
||||||
|
params.addTool(new OptionsTool(params, ['param']));
|
||||||
|
|
||||||
|
// Debug
|
||||||
|
debug.addTool(new OptionsTool(debug, ['debug']));
|
||||||
|
|
||||||
|
for (const id in this.toolbars) {
|
||||||
|
const toolbar = this.toolbars[id];
|
||||||
|
toolbar.applyExpanded();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initiate main loop
|
// Initiate main loop
|
||||||
@ -156,7 +171,7 @@ export class Sim {
|
|||||||
this.time += elapsedTime;
|
this.time += elapsedTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (DISPLAY_CURRENT_MODE) {
|
if (this.getOption('debug.currentMode')) {
|
||||||
this.info['Mode'] = this.getCurrentMode();
|
this.info['Mode'] = this.getCurrentMode();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -165,13 +180,12 @@ export class Sim {
|
|||||||
this.nextZoom = undefined;
|
this.nextZoom = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (DISPLAY_CURRENT_SCALE) {
|
if (this.getOption('debug.panningInfo')) {
|
||||||
this.info['Scale'] = this.getScaleDisplay();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (DISPLAY_PANNING_INFO) {
|
|
||||||
const {x, y} = this.panning?.velocity ?? {};
|
const {x, y} = this.panning?.velocity ?? {};
|
||||||
this.info['Panning'] = [`${x?.toPrecision(6)}, `, y?.toPrecision(6)];
|
this.info['Panning Velocity'] = [`${x?.toPrecision(6)}, `, y?.toPrecision(6)];
|
||||||
|
const { centerOfMass } = this.objects.computeSystemCenter();
|
||||||
|
this.info['Center of Mass'] = [`${centerOfMass.x.toPrecision(6)}, `, centerOfMass.y.toPrecision(6)];
|
||||||
|
this.info['Net Angular Momentum'] = this.objects.computeSystemAngularMomentum().toPrecision(6);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.display.computePanning(elapsedTime);
|
this.display.computePanning(elapsedTime);
|
||||||
|
|||||||
@ -2,8 +2,6 @@ import {TOOLBAR_HEADER_CLASSNAME} from '../config.js';
|
|||||||
import { Tool } from '../tool.js';
|
import { Tool } from '../tool.js';
|
||||||
|
|
||||||
export class Header extends Tool {
|
export class Header extends Tool {
|
||||||
expanded = true;
|
|
||||||
|
|
||||||
constructor(toolbar, title = 'Tools') {
|
constructor(toolbar, title = 'Tools') {
|
||||||
super(toolbar);
|
super(toolbar);
|
||||||
this.title = document.createElement('h1');
|
this.title = document.createElement('h1');
|
||||||
@ -24,27 +22,12 @@ export class Header extends Tool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
updateButton() {
|
updateButton() {
|
||||||
this.toggleButton.innerHTML = this.expanded ? '˄' : '˅';
|
this.toggleButton.innerHTML = this.toolbar.expanded ? '˄' : '˅';
|
||||||
}
|
}
|
||||||
|
|
||||||
toggle() {
|
toggle() {
|
||||||
this.expanded = !this.expanded;
|
this.toolbar.expanded = !this.toolbar.expanded;
|
||||||
|
this.toolbar.applyExpanded();
|
||||||
this.updateButton();
|
this.updateButton();
|
||||||
this.apply();
|
|
||||||
}
|
|
||||||
|
|
||||||
apply() {
|
|
||||||
for (const tool of this.toolbar.tools) {
|
|
||||||
if (tool === this) continue;
|
|
||||||
if (this.expanded) {
|
|
||||||
if (!this.toolbar.div.contains(tool.div)) {
|
|
||||||
this.toolbar.div.appendChild(tool.div);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (this.toolbar.div.contains(tool.div)) {
|
|
||||||
this.toolbar.div.removeChild(tool.div);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
34
tool/utility.js
Normal file
34
tool/utility.js
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
import {Tool} from '../tool.js';
|
||||||
|
import {
|
||||||
|
WIDE_CLASSNAME,
|
||||||
|
} from '../config.js';
|
||||||
|
|
||||||
|
export class UtilityTool extends Tool {
|
||||||
|
|
||||||
|
constructor(toolbar) {
|
||||||
|
super(toolbar);
|
||||||
|
|
||||||
|
const zeroVelocity = document.createElement('button');
|
||||||
|
this.div.appendChild(zeroVelocity);
|
||||||
|
zeroVelocity.classList.add(WIDE_CLASSNAME);
|
||||||
|
zeroVelocity.innerHTML = 'Zero Momentum';
|
||||||
|
|
||||||
|
zeroVelocity.addEventListener('click', () => {
|
||||||
|
// Determine center of mass and average momentum
|
||||||
|
const { totalMass, netMomentum } = this.sim.objects.computeSystemCenter();
|
||||||
|
const netVelocity = {
|
||||||
|
x: netMomentum.x / totalMass,
|
||||||
|
y: netMomentum.y / totalMass,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Apply offset to all object velocities
|
||||||
|
this.sim.objects.forEachObject(obj => {
|
||||||
|
obj.velocity.x -= netVelocity.x;
|
||||||
|
obj.velocity.y -= netVelocity.y;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Cancel panning
|
||||||
|
this.sim.panning = undefined;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
40
tool/zoom.js
40
tool/zoom.js
@ -22,23 +22,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');
|
const zoomAll = document.createElement('button');
|
||||||
const zeroVelocity = document.createElement('button');
|
|
||||||
|
|
||||||
this.div.appendChild(currentScale);
|
this.div.appendChild(currentScale);
|
||||||
this.div.appendChild(zoomOut);
|
this.div.appendChild(zoomOut);
|
||||||
this.div.appendChild(zoomIn);
|
this.div.appendChild(zoomIn);
|
||||||
this.div.appendChild(zoomAll);
|
this.div.appendChild(zoomAll);
|
||||||
this.div.appendChild(zeroVelocity);
|
|
||||||
|
|
||||||
zoomAll.classList.add(WIDE_CLASSNAME);
|
zoomAll.classList.add(WIDE_CLASSNAME);
|
||||||
zeroVelocity.classList.add(WIDE_CLASSNAME);
|
|
||||||
currentScale.classList.add(WIDE_CLASSNAME);
|
currentScale.classList.add(WIDE_CLASSNAME);
|
||||||
currentScale.classList.add(TOOL_INFO_CLASSNAME);
|
currentScale.classList.add(TOOL_INFO_CLASSNAME);
|
||||||
|
|
||||||
zoomOut.innerHTML = 'Zoom<br>Out';
|
zoomOut.innerHTML = 'Zoom<br>Out';
|
||||||
zoomIn.innerHTML = 'Zoom<br>In';
|
zoomIn.innerHTML = 'Zoom<br>In';
|
||||||
zoomAll.innerHTML = 'Zoom to Fit';
|
zoomAll.innerHTML = 'Zoom to Fit';
|
||||||
zeroVelocity.innerHTML = 'Zero Momentum';
|
|
||||||
currentScale.innerHTML = this.displayScaleText;
|
currentScale.innerHTML = this.displayScaleText;
|
||||||
|
|
||||||
this.sim.onZoom(() => {
|
this.sim.onZoom(() => {
|
||||||
@ -88,41 +84,5 @@ export class Zoom extends Tool {
|
|||||||
};
|
};
|
||||||
this.sim.scheduleZoom({x, y}, factor, netVelocity)
|
this.sim.scheduleZoom({x, y}, factor, netVelocity)
|
||||||
});
|
});
|
||||||
|
|
||||||
zeroVelocity.addEventListener('click', () => {
|
|
||||||
// TODO: Zero net angular momentum
|
|
||||||
// Determine center of mass
|
|
||||||
const { totalMass, centerOfMass } =
|
|
||||||
this.sim.objects.computeSystemCenter();
|
|
||||||
|
|
||||||
// Determine total angular momentum
|
|
||||||
const netAngularMomentum = this.sim.objects
|
|
||||||
.computeSystemAngularMomentum(centerOfMass);
|
|
||||||
console.log('net angular momentum', netAngularMomentum);
|
|
||||||
const netAngularVelocity = netAngularMomentum / totalMass;
|
|
||||||
console.log('net angular velocity', netAngularVelocity);
|
|
||||||
|
|
||||||
// TODO: Camera rotation
|
|
||||||
|
|
||||||
// Determine average momentum
|
|
||||||
const netMomentum = this.sim.objects.reduce((acc, obj) => ({
|
|
||||||
x: acc.x + obj.mass * obj.velocity.x,
|
|
||||||
y: acc.y + obj.mass * obj.velocity.y,
|
|
||||||
}), { x: 0, y: 0 });
|
|
||||||
|
|
||||||
const netVelocity = {
|
|
||||||
x: netMomentum.x / totalMass,
|
|
||||||
y: netMomentum.y / totalMass,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Apply offset to all object velocities
|
|
||||||
this.sim.objects.forEachObject(obj => {
|
|
||||||
obj.velocity.x -= netVelocity.x;
|
|
||||||
obj.velocity.y -= netVelocity.y;
|
|
||||||
});
|
|
||||||
|
|
||||||
// Cancel panning
|
|
||||||
this.sim.panning = undefined;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
26
toolbar.js
26
toolbar.js
@ -6,22 +6,21 @@ import {Header} from './tool/header.js';
|
|||||||
export class Toolbar {
|
export class Toolbar {
|
||||||
sim = undefined;
|
sim = undefined;
|
||||||
tools = [];
|
tools = [];
|
||||||
|
expanded = undefined;
|
||||||
|
header = undefined;
|
||||||
|
|
||||||
constructor(sim, title, group) {
|
constructor(sim, title, { expanded } = {}) {
|
||||||
this.sim = sim;
|
this.sim = sim;
|
||||||
|
this.expanded = expanded ?? true;
|
||||||
|
|
||||||
// Create ourselves a div, as child of sim's div
|
// Create ourselves a div, as child of sim's div
|
||||||
const div = document.createElement('div');
|
const div = document.createElement('div');
|
||||||
this.div = div;
|
this.div = div;
|
||||||
if (group) {
|
|
||||||
group.addToolbar(this);
|
|
||||||
} else {
|
|
||||||
this.sim.div.appendChild(div);
|
|
||||||
}
|
|
||||||
div.classList.add(TOOLBAR_CLASSNAME);
|
div.classList.add(TOOLBAR_CLASSNAME);
|
||||||
|
|
||||||
// Create a collapse/expand tool
|
// Create a collapse/expand tool
|
||||||
const header = new Header(this, title);
|
const header = new Header(this, title);
|
||||||
|
this.header = header;
|
||||||
this.addTool(header);
|
this.addTool(header);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -37,4 +36,19 @@ export class Toolbar {
|
|||||||
tool.frame();
|
tool.frame();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
applyExpanded() {
|
||||||
|
for (const tool of this.tools) {
|
||||||
|
if (tool === this.header) continue;
|
||||||
|
if (this.expanded) {
|
||||||
|
if (!this.div.contains(tool.div)) {
|
||||||
|
this.div.appendChild(tool.div);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (this.div.contains(tool.div)) {
|
||||||
|
this.div.removeChild(tool.div);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user