summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKyle Gunger <kgunger12@gmail.com>2024-11-20 03:50:44 -0500
committerKyle Gunger <kgunger12@gmail.com>2024-11-20 03:50:44 -0500
commit40bf0fb9863fbc9b3d7c3a8a8b6efb596881815a (patch)
tree500945c7eb712912b93dc941ca816748e2e3fc5b
parent7bcb24e5b2cad3f04c6897ad84184d92c6335653 (diff)
Widget sets (Button Select not yet implemented)
-rw-r--r--index.html1
-rw-r--r--scripts/gui-common/widget-set.js319
-rw-r--r--scripts/gui-common/widgets.js28
-rw-r--r--scripts/main.js56
4 files changed, 353 insertions, 51 deletions
diff --git a/index.html b/index.html
index c075753..2cc253b 100644
--- a/index.html
+++ b/index.html
@@ -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);
}
}