UNPKG

agentscript

Version:

AgentScript Model in Model/View architecture

152 lines (128 loc) 4.64 kB
import * as util from '../src/utils.js' // import dat from 'https://cdn.skypack.dev/dat.gui' import dat from '../vendor/dat.gui.js' /** @class */ class GUI { /** * @param {Object} template A set of name/object pairs, one per UI element * * @example * const gui = new GUI ({ * opacity: { // slider * val: [canvas.opacity, [0, 1, 0.1]], * cmd: val => canvas.setOpacity(val), * }, * download: { // button * cmd: () => util.downloadBlob(data, 'data.json', false), * }, * ... * }) */ constructor(template) { this.template = template this.controllers = {} this.folders = {} this.values = {} // the key/val's from each template this.baseGui = this.gui = new dat.GUI() // this.folders['default'] = this.baseGui util.forLoop(template, (obj, key) => { if (util.isString(obj)) { if (obj === 'default') { this.gui = this.baseGui } else { this.gui = this.baseGui.addFolder(obj) this.folders[key] = this.gui } } else { this.controllers[key] = this.addUI(obj, key) } }) this.gui = this.baseGui } type(obj) { const { val, cmd } = obj const valType = util.typeOf(val) const cmdType = util.typeOf(cmd) if (this.isDatColor(val)) return 'color' if (valType === 'undefined') return 'button' // if (cmdType === 'undefined') return 'message' if (valType === 'boolean') return 'toggle' if (valType === 'string') return 'input' if (val === 'listen') return 'monitor' if (valType === 'array' && val.length === 2) { if (util.typeOf(val[0]) === 'number') return 'slider' if (util.typeOf(val[0]) === 'string') return 'chooser' } throw Error('GUI type error, val: ' + val + ' cmd: ' + cmd) } /** * * @param {Object} obj A gui object with two optional objects: 'val' and 'cmd' * @param {string} key The name of the gui * @returns A dat.gui control object */ addUI(obj, key) { // console.log(obj, key) let { val, cmd } = obj const type = this.type(obj) let control, extent if (util.typeOf(val) === 'array') [val, extent] = val if (type === 'button') [val, cmd] = [cmd, val] this.values[key] = val switch (type) { case 'slider': const [min, max, step = 1] = extent control = this.gui.add(this.values, key, min, max).step(step) break case 'chooser': control = this.gui.add(this.values, key, extent) break case 'color': control = this.gui.addColor(this.values, key) break case 'button': case 'toggle': case 'input': case 'monitor': control = this.gui.add(this.values, key) break default: throw Error(`Controller.addUI: bad type: ${type}`) } // initialize: set model etc initial values to this value if (cmd && val !== 'listen' && val) cmd(val) if (val === 'listen') this.setListener(key, cmd) if (cmd) { if (val === 'listen') control.listen() else control.onChange(cmd) } return control } isDatColor(val) { if (util.typeOf(val) === 'string') { if (val[0] === '#') return val.length === 7 || val.length === 4 if (val.startsWith('rgb(') || val.startsWith('rgba(')) return val.endsWith(')') if (val.startsWith('hsl(') || val.startsWith('hsla(')) return val.endsWith(')') if (val.startsWith('hsv(') || val.startsWith('hsva(')) return val.endsWith(')') } if (util.typeOf(val) === 'object') return val.h != null && val.s != null && val.v != null // if (util.typeOf(val) === 'array') { // if (val.length === 3 || val.length === 4) // return val.every(i => util.typeOf(i) === 'number') // } return false } setListener(key, cmd) { this.values[key] = cmd() } update() { util.forLoop(this.template, (obj, key) => { if (obj.val === 'listen') this.setListener(key, obj.cmd) }) } } export default GUI