diff options
author | Kyle Gunger <kgunger12@gmail.com> | 2024-11-20 03:50:44 -0500 |
---|---|---|
committer | Kyle Gunger <kgunger12@gmail.com> | 2024-11-20 03:50:44 -0500 |
commit | 40bf0fb9863fbc9b3d7c3a8a8b6efb596881815a (patch) | |
tree | 500945c7eb712912b93dc941ca816748e2e3fc5b | |
parent | 7bcb24e5b2cad3f04c6897ad84184d92c6335653 (diff) |
Widget sets (Button Select not yet implemented)
-rw-r--r-- | index.html | 1 | ||||
-rw-r--r-- | scripts/gui-common/widget-set.js | 319 | ||||
-rw-r--r-- | scripts/gui-common/widgets.js | 28 | ||||
-rw-r--r-- | scripts/main.js | 56 |
4 files changed, 353 insertions, 51 deletions
@@ -37,6 +37,7 @@ <script src="scripts/gui-common/color.js"></script> <script src="scripts/gui-common/widgets.js"></script> + <script src="scripts/gui-common/widget-set.js"></script> <script src="scripts/main.js"></script> </body> </html> diff --git a/scripts/gui-common/widget-set.js b/scripts/gui-common/widget-set.js new file mode 100644 index 0000000..b515831 --- /dev/null +++ b/scripts/gui-common/widget-set.js @@ -0,0 +1,319 @@ +/** + * JSDoc types + */ + +/** + * @typedef {"button" | "toggle" | "checkbox" | "slider" | "color-temp" | "color-light" | "color-wheel" | "thermostat" | "scrubber"} DescType + */ + +/** + * @typedef OSmButtonProps + * @property {string} [text] + * @property {*} [tv] + * @property {*} [fv] + */ + +/** + * @typedef OSmToggleProps + * @property {string} [text] + * @property {*} [tv] + * @property {*} [fv] + */ + +/** + * @typedef OSmSliderProps + * @property {number} min + * @property {number} max + * @property {number} [step] + * @property {number} [precision] + * @property {boolean} [percent] + */ + +/** + * @typedef OSmThermostatProps + * @property {number} gague + * @property {number} [deviation] + * @property {Color} [color_cold] + * @property {Color} [color_temperate] + * @property {Color} [color_warm] + * @property {number} [ct] + * @property {number} [tw] + */ + +/** + * @typedef OSmScrubberProps + * @property {number} max + * @property {number} min + * @property {number} step + * @property {number} [zones] + * @property {number} [speed] + * @property {number} [spring] + */ + +/** + * @typedef {OSmButtonProps | OSmToggleProps | OSmSliderProps | OSmThermostatProps | OSmScrubberProps} OSmAnyProps + */ + +/** + * @typedef {Object} DescBase + * @property {DescType} type + * @property {string} name + */ + +/** + * @typedef {DescBase & {type: "button", props: OSmButtonProps, state: never}} DescButton + */ + +/** + * @typedef {DescBase & {type: "toggle" | "checkbox", props: OSmToggleProps, state: boolean}} DescToggle + */ + +/** + * @typedef {DescBase & {type: "slider", props: OSmSliderProps, state: number}} DescSlider + */ + +/** + * @typedef {DescBase & {type: "color-temp", props: never, state: number}} DescColorTemp + */ + +/** + * @typedef {DescBase & {type: "color-light", props: never, state: number}} DescColorLight + */ + +/** + * @typedef {DescBase & {type: "color-wheel", props: never, state: Color}} DescColorWheel + */ + +/** + * @typedef {DescBase & {type: "thermostat", props: OSmThermostatProps, state: number}} DescThermostat + */ + +/** + * @typedef {DescBase & {type: "scrubber", props: OSmScrubberProps, state: number}} DescScrubber + */ + +/** + * @typedef {DescButton | DescToggle | DescSlider | DescColorTemp | DescColorLight | DescColorWheel | DescThermostat | DescScrubber} DescAny + */ + +class WidgetSet extends EventTarget{ + + #name = ""; + + /** @type {{[key: string]: Widget}} */ + widgets = {}; + + /** + * + * @param {DescAny[]} desc + * @param {string} name + */ + constructor(desc, name) + { + super(); + + this.#name = name; + this.#parse_desc(desc); + + for (let i in this.widgets) + { + this.widgets[i].addEventListener("change", this.#change.bind(this)); + } + } + + + /** + * @param {DescButton} desc + * @returns {WidgetButton} + */ + static parse_button(desc) + { + let merge = {...{tv: true, fv: false, text: ""}, ...desc.props}; + let out = new WidgetButton(merge.tv, merge.fv); + out.setId("name", desc.name); + out.element.innerText = merge.text; + return out; + } + + /** + * @param {DescToggle} desc + * @returns {WidgetToggle} + */ + static parse_toggle(desc) + { + let merge = {...{tv: true, fv: false, text: ""}, ...desc.props}; + let out; + + if (desc.type == "checkbox") + out = new WidgetCheckbox(desc.state ? merge.tv : merge.fv, merge.tv, merge.fv); + else + { + out = new WidgetToggle(desc.state ? merge.tv : merge.fv, merge.tv, merge.fv); + out.element.innerText = merge.text; + } + out.setId("name", desc.name); + + return out; + } + + /** + * @param {DescSlider} desc + * @returns {WidgetSlider} + */ + static parse_slider(desc) + { + let merge = {...{step: 0.1, precision: 1, percent: false}, ...desc.props}; + let out = new WidgetSlider(desc.state, merge.min, merge.max, merge.step, merge.precision, merge.percent); + out.setId("name", desc.name); + return out; + } + + /** + * @param {DescColorLight} desc + * @returns {WidgetColorLight} + */ + static parse_color_light(desc) + { + let out = new WidgetColorLight(Math.max(Math.min(desc.state, 1), 0)); + out.setId("name", desc.name); + return out; + } + + /** + * @param {DescColorTemp} desc + * @returns {WidgetColorTemp} + */ + static parse_color_temp(desc) + { + let out = new WidgetColorTemp(Math.max(Math.min(desc.state, 6000), 2700)); + out.setId("name", desc.name); + return out; + } + + /** + * @param {DescColorWheel} desc + * @returns {WidgetColorWheel} + */ + static parse_color_wheel(desc) + { + let value = new Color(...desc.state.channels); + let out = new WidgetColorWheel(value); + out.setId("name", desc.name); + return out; + } + + /** + * @param {DescThermostat} desc + * @returns {WidgetThermostat} + */ + static parse_thermostat(desc) + { + let merge = {...{ + deviation: 7, + color_cold: Color.from_rgb(0, 133, 255), + color_temperate: Color.from_rgb(18, 229, 82), + color_warm: Color.from_rgb(255, 149, 0), + ct: -2, + tw: 2, + }, ...desc.props}; + + let cc = new Color(...merge.color_cold.channels); + let ct = new Color(...merge.color_temperate.channels); + let cw = new Color(...merge.color_warm.channels); + + let out = new WidgetThermostat(desc.state, merge.gague, merge.deviation, cc, ct, cw, merge.ct, merge.tw); + out.setId("name", desc.name); + return out; + } + + /** + * @param {DescScrubber} desc + * @returns {WidgetScrubber} + */ + static parse_scrubber(desc) + { + let merge = {...{ + zones: 2, + speed: 300, + spring: 1.4 + }, ...desc.props}; + + let out = new WidgetScrubber(desc.state, merge.max, merge.min, merge.step, merge.zones, merge.speed, merge.spring); + out.setId("name", desc.name); + return out; + } + + /** + * + * @param {DescAny[]} desc + */ + #parse_desc (desc) + { + for (let i of desc) + { + let out; + switch (i.type) + { + case "button": + out = WidgetSet.parse_button(i); + break; + case "checkbox": + case "toggle": + out = WidgetSet.parse_toggle(i); + break; + case "slider": + out = WidgetSet.parse_slider(i); + break; + case "color-light": + out = WidgetSet.parse_color_light(i); + break; + case "color-temp": + out = WidgetSet.parse_color_temp(i); + break; + case "color-wheel": + out = WidgetSet.parse_color_wheel(i); + break; + case "thermostat": + out = WidgetSet.parse_thermostat(i); + break; + case "scrubber": + out = WidgetSet.parse_scrubber(i); + break; + } + this.widgets[i.name] = out; + } + } + + /** + * + * @param {CustomEvent} e + */ + #change(e) + { + /** + * @type {{widget: Widget, changed: string}} + */ + let d = e.detail; + + let detail = { + set: this.#name, + name: d.widget.get("name"), + changed: d.changed, + value: d.widget.get(d.changed) + }; + + this.dispatchEvent(new CustomEvent("change", {detail: detail})); + } + + /** + * + * @param {HTMLElement} el + */ + apply_to(el) + { + for (let i in this.widgets) + { + el.appendChild(this.widgets[i].element); + } + } +}
\ No newline at end of file diff --git a/scripts/gui-common/widgets.js b/scripts/gui-common/widgets.js index 40b8bae..89a9004 100644 --- a/scripts/gui-common/widgets.js +++ b/scripts/gui-common/widgets.js @@ -10,7 +10,6 @@ window.addEventListener("scrollend", unscroll); })(); - /** * The base Widget class. Represents an interactible * value-producing object in the browser, like an input. @@ -65,7 +64,7 @@ class Widget extends EventTarget{ set(v) { this.#value["value"] = v; - this.#emitChangeEvent(); + this.#emitChangeEvent("value"); } /** @@ -77,7 +76,7 @@ class Widget extends EventTarget{ { this.#value[id] = v; if (emit) - this.#emitChangeEvent(); + this.#emitChangeEvent(id); else if (id == "value") this.update(); } @@ -552,7 +551,7 @@ class WidgetSlider extends WidgetDragable * @param {number} [precision] Decimal places to keep * @param {boolean} [percent] Whether to show a percentage instead of the raw number */ - constructor (max = 10, min = 1, value = 5, step = 0.1, precision = 1, percent = false) + constructor (value = 5, min = 1, max = 10, step = 0.1, precision = 1, percent = false) { super(1); this.element.classList.add("slider"); @@ -698,9 +697,9 @@ class WidgetColorTemp extends WidgetSlider /** @type {Color} */ static BLUE = Color.from_rgb(190, 200, 255); - constructor () + constructor (value = 2700) { - super(6000, 2700, 2700, 100); + super(value, 2700, 6000, 100); this.element.classList.replace("slider", "color-temp"); this.setDetailUpdater(this.#update_detail.bind(this)); @@ -734,9 +733,9 @@ class WidgetColorLight extends WidgetSlider /** @type {Color} */ BLACK = new Color(0, 0, 0); - constructor () + constructor (value = 1) { - super(1, 0, 1, 0.01); + super(value, 0, 1, 0.01); this.element.classList.replace("slider", "color-light"); this.setDetailUpdater(this.#update_detail.bind(this)); @@ -772,7 +771,7 @@ class WidgetColorWheel extends WidgetDragable * Constructor * @param {Color} color */ - constructor () + constructor (value = Color.from_rgb(255, 255, 255)) { super(1); this.element.classList.add("color-wheel"); @@ -782,6 +781,7 @@ class WidgetColorWheel extends WidgetDragable this.element.appendChild(this.#detail); this.addEventListener("change", this.update); + this.set(value); } #common_move(x, y) @@ -894,8 +894,8 @@ class WidgetThermostat extends Widget /** * Constructor - * @param {number} temp Initial set point - * @param {number} gague Gague point + * @param {number} value Current set point + * @param {number} gague Current temperature being read from sensor(s) * @param {number} [dev] The deviation of the arch (how far in degrees (temperature) from the middle to each end of the arc) * @param {Color} [cold_col] The color the arch will display when in "cold" temperatures * @param {Color} [temp_col] The color the arch will display when in "temperate" temperatures @@ -904,7 +904,7 @@ class WidgetThermostat extends Widget * @param {number} [tw] The point at which we swap from temperate to warm */ constructor( - temp, + value, gague, dev = 7, cold_col = Color.from_rgb(0, 133, 255), @@ -933,7 +933,7 @@ class WidgetThermostat extends Widget super.setId("ct", ct); super.setId("tw", tw); super.setId("gague", gague); - this.set(temp); + this.set(value); } update() @@ -1194,7 +1194,7 @@ class WidgetScrubber extends WidgetDragable * @param {number} zones Zones on either side of the zero-point * @param {number} speed Speed per value change (ms) */ - constructor(value = 5, max = 10, min = 1, step = 0.5, zones = 3, speed = 350, spring = 1.5) + constructor(value = 5, max = 10, min = 1, step = 0.5, zones = 2, speed = 350, spring = 1.5) { super(1); diff --git a/scripts/main.js b/scripts/main.js index dbbd1ca..9f384ff 100644 --- a/scripts/main.js +++ b/scripts/main.js @@ -1,53 +1,35 @@ class Client { - - /** * @param {HTMLElement} content The base element where page content is placed */ constructor (content) { - /** @type {WidgetToggle} */ - this.cb = new WidgetCheckbox(); - content.appendChild(this.cb.element); - this.toggle = new WidgetToggle(); - content.appendChild(this.toggle.element); - this.button = new WidgetButton(); - content.appendChild(this.button.element); - this.slider = new WidgetSlider(); - content.appendChild(this.slider.element); - this.temp = new WidgetColorTemp(); - content.appendChild(this.temp.element); - this.light = new WidgetColorLight(); - content.appendChild(this.light.element); - this.wheel = new WidgetColorWheel(); - content.appendChild(this.wheel.element); - this.therm = new WidgetThermostat(72, 69); - content.appendChild(this.therm.element); - this.sel_b = new WidgetSelectButton(2); - this.sel_b.addOption("Heat", "heat"); - this.sel_b.addOption("Cool", "cool"); - this.sel_b.addOption("Eco", "eco"); - content.appendChild(this.sel_b.element); - this.scrubber = new WidgetScrubber(72, 80, 60, 1, 3); - content.appendChild(this.scrubber.element); + /** @type {DescAny[]} */ + let desc = [ + { type: "button", name: "bt", props: {}, }, + { type: "checkbox", name: "cb", props: {}, state: true }, + { type: "toggle", name: "tg", props: {}, state: false }, + { type: "slider", name: "sli", props: {max: 10, min: 1}, state: 6 }, + { type: "color-light", name: "cli", state: 0.7 }, + { type: "color-temp", name: "ctp", state: 3000 }, + { type: "color-wheel", name: "cwh", state: Color.from_rgb(255, 200, 200) }, + { type: "thermostat", name: "thm", props: {gague: 69}, state: 72 }, + { type: "scrubber", name: "scb", props: {min: 60, max: 80, step: 1}, state: 72 } + ]; + + this.set = new WidgetSet(desc, "set"); + this.set.apply_to(content); - this.scrubber.addEventListener("change", this.changeThermostat.bind(this)); - // content.appendChild(Widget("button").el); - // content.appendChild(Widget("checkbox").el); - // content.appendChild(Widget("slider").el); - // content.appendChild(Widget("color-wheel").el); - // content.appendChild(Widget("color-temp").el); - // content.appendChild(Widget("color-light").el); - // content.appendChild(Widget("thermostat").el); - // content.appendChild(Widget("sel-button").el); + this.set.addEventListener("change", this.changeSet.bind(this)); this.content = content; } /** @param {CustomEvent} e */ - changeThermostat(e) + changeSet(e) { - this.therm.set(e.detail.widget.get()); + if (e.detail.name == "scb" && e.detail.changed == "value") + this.set.widgets["thm"].set(e.detail.value); } } |