Enhancement: options showIf
This commit is contained in:
parent
4eec03dd1f
commit
54ed2838f7
38
helper.js
38
helper.js
@ -1,2 +1,38 @@
|
|||||||
export function makeUtilityButton() {
|
// `items` is an array of which `item` is a member
|
||||||
|
// `item` must let us read/write property `hidden`
|
||||||
|
// `parentEl` is the containing element for `itemEl`
|
||||||
|
// `itemEl` is the
|
||||||
|
export function show({items, item, parentEl, itemEl}) {
|
||||||
|
if (items.length < 2) {
|
||||||
|
parentEl.appendChild(itemEl);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// To determine placement,
|
||||||
|
// Start with our index in the toolbar tools;
|
||||||
|
// iterate through toolbar tools before this one,
|
||||||
|
// and subtract hidden ones from the index.
|
||||||
|
|
||||||
|
let countHidden = 0;
|
||||||
|
let index = items.indexOf(item);
|
||||||
|
for (let i = 0; i < index; i++) {
|
||||||
|
const sibling = items[i];
|
||||||
|
if (sibling.hidden) countHidden += 1;
|
||||||
|
}
|
||||||
|
index -= countHidden;
|
||||||
|
|
||||||
|
// Now we need to find our place.
|
||||||
|
// Add to parent using insertBefore.
|
||||||
|
let idx = 0;
|
||||||
|
let nextEl = parentEl.firstChild;
|
||||||
|
while (idx < index) {
|
||||||
|
nextEl = nextEl.nextSibling;
|
||||||
|
idx += 1;
|
||||||
|
}
|
||||||
|
parentEl.insertBefore(itemEl, nextEl);
|
||||||
|
item.hidden = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function hide({item, parentEl, itemEl}) {
|
||||||
|
parentEl.removeChild(itemEl);
|
||||||
|
item.hidden = true;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,9 +8,9 @@ export const simOptions = {
|
|||||||
velocity: ['Velocity Vectors', 'boolean', true],
|
velocity: ['Velocity Vectors', 'boolean', true],
|
||||||
acceleration: ['Accel Vectors', 'boolean', true],
|
acceleration: ['Accel Vectors', 'boolean', true],
|
||||||
traces: ['Path Traces', 'boolean', true],
|
traces: ['Path Traces', 'boolean', true],
|
||||||
dashedTraces: ['Dashed', 'boolean', false, {tall: true, hideUnless: 'display.traces'}],
|
dashedTraces: ['Dashed', 'boolean', false, {tall: true, showIf: 'display.traces'}],
|
||||||
velocityScale: ['Velocity<br>Vec Scale', 'number', 80, {hideUnless: 'display.velocity'}],
|
velocityScale: ['Velocity<br>Vec Scale', 'number', 80, {showIf: 'display.velocity'}],
|
||||||
accelerationScale: ['Accel<br>Vec Scale', 'number', 800, {hideUnless: 'display.acceleration'}],
|
accelerationScale: ['Accel<br>Vec Scale', 'number', 800, {showIf: 'display.acceleration'}],
|
||||||
zoomVectors: ['Zoom Vectors', 'boolean', true]
|
zoomVectors: ['Zoom Vectors', 'boolean', true]
|
||||||
},
|
},
|
||||||
compensate: {
|
compensate: {
|
||||||
|
|||||||
1
tool.js
1
tool.js
@ -9,6 +9,7 @@ import {
|
|||||||
export class Tool {
|
export class Tool {
|
||||||
container = undefined;
|
container = undefined;
|
||||||
sim = undefined;
|
sim = undefined;
|
||||||
|
hidden = false;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
const div = document.createElement('div');
|
const div = document.createElement('div');
|
||||||
|
|||||||
@ -1,45 +1,92 @@
|
|||||||
// Options picker
|
// Options picker
|
||||||
import {
|
import {
|
||||||
TOOL_INFO_CLASSNAME,
|
|
||||||
OPTION_GROUP_CLASSNAME,
|
OPTION_GROUP_CLASSNAME,
|
||||||
WIDE_CLASSNAME,
|
|
||||||
TALL_CLASSNAME,
|
TALL_CLASSNAME,
|
||||||
|
TOOL_INFO_CLASSNAME,
|
||||||
|
WIDE_CLASSNAME,
|
||||||
} from '../config.js';
|
} from '../config.js';
|
||||||
import { Tool } from '../tool.js';
|
import {Tool} from '../tool.js';
|
||||||
|
import {show, hide} from '../helper.js';
|
||||||
|
|
||||||
export class OptionsTool extends Tool {
|
export class OptionsTool extends Tool {
|
||||||
sections = undefined;
|
sectionNames = undefined;
|
||||||
|
groups = {};
|
||||||
|
|
||||||
constructor(sections) {
|
constructor(sectionNames) {
|
||||||
super();
|
super();
|
||||||
this.sections = sections;
|
this.sectionNames = sectionNames;
|
||||||
}
|
}
|
||||||
|
|
||||||
setContainer(container) {
|
setContainer(container) {
|
||||||
super.setContainer(container);
|
super.setContainer(container);
|
||||||
for (const sectionName of this.sections) {
|
// Initialize
|
||||||
const option = this.sim.options.getSection(sectionName);
|
for (const sectionName of this.sectionNames) {
|
||||||
const item = this.visitItem(option);
|
const group = this.sim.options.getSection(sectionName);
|
||||||
|
const item = this.visitItem(group);
|
||||||
this.div.appendChild(item);
|
this.div.appendChild(item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// For now, `showIf` must be the name of a boolean property, with optional negation
|
||||||
|
shouldShow(option) {
|
||||||
|
if (option.showIf === undefined) return true;
|
||||||
|
const {name, value} = this.deconstructOption(option.showIf);
|
||||||
|
return this.sim.getOption(name) === value;
|
||||||
|
}
|
||||||
|
|
||||||
|
deconstructOption(showIf) {
|
||||||
|
let name = showIf;
|
||||||
|
let value = true;
|
||||||
|
if (name.startsWith('!')) {
|
||||||
|
value = false;
|
||||||
|
name = name.slice(1);
|
||||||
|
}
|
||||||
|
return {name, value};
|
||||||
|
}
|
||||||
|
|
||||||
visitItem(item, path) {
|
visitItem(item, path) {
|
||||||
path = [path, item.name].filter(x => !!x).join('.');
|
path = [path, item.name].filter(x => !!x).join('.');
|
||||||
switch (item.type) {
|
switch (item.type) {
|
||||||
case 'group': {
|
case 'group': {
|
||||||
const group = document.createElement('div');
|
const groupEl = document.createElement('div');
|
||||||
group.classList.add(OPTION_GROUP_CLASSNAME);
|
groupEl.classList.add(OPTION_GROUP_CLASSNAME);
|
||||||
|
const group = {groupEl, items: []};
|
||||||
|
this.groups[path] = group;
|
||||||
if (item.title) {
|
if (item.title) {
|
||||||
const heading = document.createElement('h3');
|
const heading = document.createElement('h3');
|
||||||
heading.innerHTML = item.title;
|
heading.innerHTML = item.title;
|
||||||
group.appendChild(heading);
|
groupEl.appendChild(heading);
|
||||||
|
groupEl.items.push({itemEl: heading});
|
||||||
}
|
}
|
||||||
for (const next of item.items) {
|
for (const next of item.items) {
|
||||||
const child = this.visitItem(next, path);
|
const optionEl = this.visitItem(next, path);
|
||||||
group.appendChild(child);
|
// const option = {itemEl: optionEl};
|
||||||
|
group.items.push(next);
|
||||||
|
if (this.shouldShow(next)) {
|
||||||
|
groupEl.appendChild(optionEl);
|
||||||
|
}
|
||||||
|
if (next.showIf) {
|
||||||
|
const {name} = this.deconstructOption(next.showIf);
|
||||||
|
this.sim.onOptionSet(name, () => {
|
||||||
|
if (this.shouldShow(next)) {
|
||||||
|
show({
|
||||||
|
items: group.items,
|
||||||
|
item: next,
|
||||||
|
parentEl: groupEl,
|
||||||
|
itemEl: optionEl,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
hide({
|
||||||
|
item: next,
|
||||||
|
parentEl: groupEl,
|
||||||
|
itemEl: optionEl,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
return group;
|
return groupEl;
|
||||||
}
|
}
|
||||||
case 'boolean': {
|
case 'boolean': {
|
||||||
const button = document.createElement('button');
|
const button = document.createElement('button');
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user