fixed option save/load
This commit is contained in:
parent
d6c3db8e45
commit
49feb0c106
@ -39,6 +39,7 @@ export const TOOLBAR_HEADER_CLASSNAME = 'lhg-toolbar-header';
|
||||
export const WIDE_CLASSNAME = 'lhg-wide';
|
||||
export const TALL_CLASSNAME = 'lhg-tall';
|
||||
export const OVERLAY_INFO_BOX_CLASSNAME = 'lhg-overlay-info-box';
|
||||
export const OPTION_GROUP_CLASSNAME = 'lhg-option-group';
|
||||
|
||||
// EVENT NAMES
|
||||
export const EVENT_MODE_LEAVE = 'lhg-mode-leave';
|
||||
|
||||
12
objects.js
12
objects.js
@ -208,14 +208,16 @@ export class Objects {
|
||||
// with the mass creation rate accelerating over time
|
||||
|
||||
// Scaling this parameter because of millisecond conversion
|
||||
const massCreationRate = this.sim.getOption('param.massCreationRate') / 1000;
|
||||
|
||||
if (this.creatingObject !== undefined) {
|
||||
const obj = this.objects[this.creatingObject];
|
||||
const rate = massCreationRate * obj.age;
|
||||
console.log('obj.age', obj.age, 'mass creation rate', rate, 'elapsedTime', elapsedTime);
|
||||
// TODO: After objects merge during creation, mass creation rate can accelerate
|
||||
obj.mass += rate * elapsedTime;
|
||||
// Putting in a somewhat arbitrary scaling factor here
|
||||
let massCreationRate = this.sim.getOption('param.massCreationRate') / 1000;
|
||||
// Mass creation rate acceleration
|
||||
if (this.sim.getOption('param.massAcceleration')) {
|
||||
massCreationRate *= obj.age;
|
||||
}
|
||||
obj.mass += massCreationRate * elapsedTime;
|
||||
}
|
||||
|
||||
// Calculate forces due to gravity.
|
||||
|
||||
29
options.js
29
options.js
@ -24,29 +24,38 @@ export class Options {
|
||||
for (const groupName of Object.keys(options)) {
|
||||
for (const [name, [, , defaultValue]] of Object.entries(this.options[groupName])) {
|
||||
const path = [groupName, name].join('.');
|
||||
let value = this.getOption(path)
|
||||
let value = this.getFromLocalStorage(path);
|
||||
if (value === undefined) {
|
||||
value = defaultValue;
|
||||
this.setOption(path, value);
|
||||
}
|
||||
this.values[path] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getOption(path) {
|
||||
let value = this.values[path];
|
||||
if (value === undefined) {
|
||||
value = localStorage.getItem(this.getStorageKey(path));
|
||||
if (value === 'false') value = false;
|
||||
else if (value === 'true') value = true;
|
||||
this.values[path] = value;
|
||||
toStored(value) {
|
||||
return JSON.stringify(value);
|
||||
}
|
||||
|
||||
fromStored(value) {
|
||||
return JSON.parse(value);
|
||||
}
|
||||
|
||||
getFromLocalStorage(path) {
|
||||
const storageKey = this.getStorageKey(path);
|
||||
const value = this.fromStored(window.localStorage.getItem(storageKey));
|
||||
this.values[path] = value;
|
||||
return value;
|
||||
}
|
||||
|
||||
getOption(path) {
|
||||
return this.values[path];
|
||||
}
|
||||
|
||||
setOption(path, value) {
|
||||
this.values[path] = value;
|
||||
window.localStorage.setItem(this.getStorageKey(path), value);
|
||||
const storageKey = this.getStorageKey(path);
|
||||
window.localStorage.setItem(storageKey, this.toStored(value));
|
||||
const e = new CustomEvent(EVENT_OPTION_SET, {detail: {path, value}});
|
||||
this.sim.div.dispatchEvent(e);
|
||||
}
|
||||
|
||||
29
sim-options.js
Normal file
29
sim-options.js
Normal file
@ -0,0 +1,29 @@
|
||||
export const simOptions = {
|
||||
pauseDuring: {
|
||||
creation: ['Pause While Creating', 'boolean', true],
|
||||
selection: ['Pause While Selecting', 'boolean', true],
|
||||
},
|
||||
display: {
|
||||
velocity: ['Velocity Vector', 'boolean', true],
|
||||
acceleration: ['Accel Vector', 'boolean', true],
|
||||
traces: ['Path Trace', 'boolean', true],
|
||||
dashedTraces: ['Dashed', 'boolean', false, {tall: true}],
|
||||
},
|
||||
collision: {
|
||||
merge: ['Merge Masses<br>on Collision', 'boolean', true, {wide: true}],
|
||||
},
|
||||
param: {
|
||||
gravity: ['Gravity', 'number', 4E4],
|
||||
timeScale: ['Time Scale', 'number', 0.2],
|
||||
massCreationRate: ['Mass Creation Rate', 'number', 10],
|
||||
massAcceleration: ['Mass Rate Accel', 'boolean', true, {wide: true}],
|
||||
},
|
||||
debug: {
|
||||
objectsInfo: ['Objects Info', 'boolean', false],
|
||||
cursorInfo: ['Cursor Info', 'boolean', false],
|
||||
frameRate: ['Frame Rate', 'boolean', false, {wide: true}],
|
||||
currentMode: ['Current Mode', 'boolean', false],
|
||||
panningInfo: ['Panning Info', 'boolean', false],
|
||||
},
|
||||
};
|
||||
|
||||
67
sim-tools.js
Normal file
67
sim-tools.js
Normal file
@ -0,0 +1,67 @@
|
||||
import { Overlay } from './overlay.js';
|
||||
import { Pointer } from './pointer.js';
|
||||
import { ModeSwitch } from './tool/modes.js';
|
||||
import { OptionsTool } from './tool/options.js';
|
||||
import { PlayPause } from './tool/play-pause.js';
|
||||
import { Zoom } from './tool/zoom.js';
|
||||
import { UtilityTool } from './tool/utility.js';
|
||||
import { Toolbar } from './toolbar.js';
|
||||
import { ToolbarGroup } from './toolbar-group.js';
|
||||
|
||||
export function initializeTools(sim) {
|
||||
sim.toolbars = {
|
||||
tools: new Toolbar(sim, 'Tools'),
|
||||
modes: new Toolbar(sim, 'Modes'),
|
||||
utils: new Toolbar(sim, 'Utility', { expanded: false }),
|
||||
options: new Toolbar(sim, 'Options'),
|
||||
params: new Toolbar(sim, 'Parameters'),
|
||||
debug: new Toolbar(sim, 'Debug', { expanded: false }),
|
||||
};
|
||||
const { tools, modes, options, params, debug, utils } = sim.toolbars;
|
||||
sim.toolbarGroups = {
|
||||
left: new ToolbarGroup(sim)
|
||||
.addToolbar(tools)
|
||||
.addToolbar(modes)
|
||||
.addToolbar(utils),
|
||||
right: new ToolbarGroup(sim).topRight()
|
||||
.addToolbar(options)
|
||||
.addToolbar(params)
|
||||
.addToolbar(debug),
|
||||
};
|
||||
sim.overlay = new Overlay(sim);
|
||||
sim.pointer = new Pointer(sim);
|
||||
|
||||
// Configure toolbars
|
||||
|
||||
// Primary
|
||||
tools.addTool(new Zoom(tools));
|
||||
tools.addTool(new PlayPause(tools));
|
||||
|
||||
// Secondary
|
||||
modes.addTool(new ModeSwitch(modes));
|
||||
|
||||
// Utility
|
||||
utils.addTool(new UtilityTool(utils));
|
||||
|
||||
// Options
|
||||
options.addTool(new OptionsTool(options, [
|
||||
'pauseDuring',
|
||||
'display',
|
||||
'collision'
|
||||
]));
|
||||
|
||||
// Parameters
|
||||
params.addTool(new OptionsTool(params, [
|
||||
'param'
|
||||
]));
|
||||
|
||||
// Debug
|
||||
debug.addTool(new OptionsTool(debug, [
|
||||
'debug'
|
||||
]));
|
||||
|
||||
for (const id in sim.toolbars) {
|
||||
const toolbar = sim.toolbars[id];
|
||||
toolbar.applyExpanded();
|
||||
}
|
||||
}
|
||||
58
simulator.js
58
simulator.js
@ -6,16 +6,9 @@ import {
|
||||
} from './config.js';
|
||||
import { Display } from './display.js';
|
||||
import { Objects } from './objects.js';
|
||||
import { Overlay } from './overlay.js';
|
||||
import { Pointer } from './pointer.js';
|
||||
import { Options } from './options.js';
|
||||
import { ModeSwitch } from './tool/modes.js';
|
||||
import { OptionsTool } from './tool/options.js';
|
||||
import { PlayPause } from './tool/play-pause.js';
|
||||
import { Zoom } from './tool/zoom.js';
|
||||
import { UtilityTool } from './tool/utility.js';
|
||||
import { Toolbar } from './toolbar.js';
|
||||
import { ToolbarGroup } from './toolbar-group.js';
|
||||
import { simOptions } from './sim-options.js';
|
||||
import { initializeTools } from './sim-tools.js';
|
||||
|
||||
const simOptions = {
|
||||
pauseDuring: {
|
||||
@ -91,53 +84,8 @@ export class Sim {
|
||||
this.options = new Options(this, simOptions);
|
||||
this.display = new Display(this);
|
||||
this.objects = new Objects(this);
|
||||
this.toolbars = {
|
||||
tools: new Toolbar(this, 'Tools'),
|
||||
modes: new Toolbar(this, 'Modes'),
|
||||
utils: new Toolbar(this, 'Utility', { expanded: false }),
|
||||
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.pointer = new Pointer(this);
|
||||
|
||||
// Configure toolbars
|
||||
|
||||
// Primary
|
||||
tools.addTool(new Zoom(tools));
|
||||
tools.addTool(new PlayPause(tools));
|
||||
|
||||
// Secondary
|
||||
modes.addTool(new ModeSwitch(modes));
|
||||
|
||||
// Utility
|
||||
utils.addTool(new UtilityTool(utils));
|
||||
|
||||
// Options
|
||||
options.addTool(new OptionsTool(options, ['pauseDuring', 'display', 'collision']));
|
||||
|
||||
// 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();
|
||||
}
|
||||
initializeTools(this);
|
||||
|
||||
// Initiate main loop
|
||||
this.rawTime = document.timeline.currentTime;
|
||||
|
||||
@ -108,8 +108,7 @@ div.lhg-tool .lhg-wide {
|
||||
}
|
||||
|
||||
div.lhg-tool .lhg-tall {
|
||||
padding-top: 1em;
|
||||
padding-bottom: 1em;
|
||||
height: 3.666em;
|
||||
}
|
||||
|
||||
div.lhg-overlay-info-box {
|
||||
@ -119,3 +118,8 @@ div.lhg-overlay-info-box {
|
||||
width: fit-content;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
div.lhg-option-group > * {
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
@ -1,16 +1,29 @@
|
||||
// Options picker
|
||||
import {
|
||||
TOOL_INFO_CLASSNAME,
|
||||
OPTION_GROUP_CLASSNAME,
|
||||
WIDE_CLASSNAME,
|
||||
TALL_CLASSNAME,
|
||||
} from '../config.js';
|
||||
import { Tool } from '../tool.js';
|
||||
|
||||
export class OptionsTool extends Tool {
|
||||
constructor(container, sections) {
|
||||
super(container);
|
||||
|
||||
for (const sectionName of sections) {
|
||||
const option = this.sim.options.getSection(sectionName);
|
||||
const child = this.visitItem(option);
|
||||
this.div.appendChild(child);
|
||||
}
|
||||
}
|
||||
|
||||
visitItem(item, path) {
|
||||
path = [path, item.name].filter(x => !!x).join('.');
|
||||
switch (item.type) {
|
||||
case 'group': {
|
||||
const group = document.createElement('div');
|
||||
group.classList.add(OPTION_GROUP_CLASSNAME);
|
||||
if (item.title) {
|
||||
const heading = document.createElement('h3');
|
||||
heading.innerHTML = item.title;
|
||||
@ -25,13 +38,9 @@ export class OptionsTool extends Tool {
|
||||
case 'boolean': {
|
||||
const button = document.createElement('button');
|
||||
button.innerHTML = item.title;
|
||||
if (item.wide === true) {
|
||||
button.classList.add(WIDE_CLASSNAME);
|
||||
}
|
||||
if (item.wide === true) button.classList.add(WIDE_CLASSNAME);
|
||||
if (item.tall === true) button.classList.add(TALL_CLASSNAME);
|
||||
const value = this.sim.getOption(path);
|
||||
if (value === undefined) {
|
||||
this.sim.setOption(path, item.default);
|
||||
}
|
||||
button.style.opacity = value ? '100%' : '50%';
|
||||
this.sim.onOptionSet(path, value => {
|
||||
console.log('option set cb', path, value);
|
||||
@ -43,6 +52,10 @@ export class OptionsTool extends Tool {
|
||||
console.log('click, option value', value);
|
||||
this.sim.setOption(path, !value);
|
||||
});
|
||||
button.addEventListener('click', () => {
|
||||
const value = this.sim.getOption(path);
|
||||
this.setOption(path, !value);
|
||||
});
|
||||
return button;
|
||||
}
|
||||
case 'number': {
|
||||
@ -59,8 +72,7 @@ export class OptionsTool extends Tool {
|
||||
input.classList.add(WIDE_CLASSNAME);
|
||||
}
|
||||
title.innerHTML = item.title;
|
||||
input.value = item.default;
|
||||
this.sim.setOption(path, item.default);
|
||||
input.value = this.sim.getOption(path);
|
||||
|
||||
input.addEventListener('input', () => {
|
||||
input.value = input.value.slice(0, maxLength);
|
||||
@ -77,18 +89,7 @@ export class OptionsTool extends Tool {
|
||||
return div;
|
||||
}
|
||||
default:
|
||||
console.error('Unknown option type', item);
|
||||
throw new Error('Unknown option type');
|
||||
}
|
||||
}
|
||||
|
||||
constructor(container, sections) {
|
||||
super(container);
|
||||
|
||||
for (const sectionName of sections) {
|
||||
const option = this.sim.options.getSection(sectionName);
|
||||
const child = this.visitItem(option);
|
||||
this.div.appendChild(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user