summaryrefslogtreecommitdiff
path: root/scripts
diff options
context:
space:
mode:
authorKyle Gunger <kgunger12@gmail.com>2024-11-13 02:23:34 -0500
committerKyle Gunger <kgunger12@gmail.com>2024-11-13 02:23:34 -0500
commitff981cd5b7ab9274630a1417593af96e36b99e7a (patch)
treeaea5306f3c1f046893c7160b8350fd9808773f91 /scripts
parent53c95ab94cab5163424646d4a798a7ea7fb13ec7 (diff)
Color Wheel Widget
Diffstat (limited to 'scripts')
-rw-r--r--scripts/gui-common/color.js53
-rw-r--r--scripts/gui-common/widgets.js244
-rw-r--r--scripts/main.js2
3 files changed, 231 insertions, 68 deletions
diff --git a/scripts/gui-common/color.js b/scripts/gui-common/color.js
index 90eac14..0b25f68 100644
--- a/scripts/gui-common/color.js
+++ b/scripts/gui-common/color.js
@@ -52,8 +52,61 @@ class Color
{
return new Color(r / 255, g / 255, b / 255, a);
}
+
+ static d(h)
+ {
+ let d = Math.floor((h - (h % PI_THIRDS)) / PI_THIRDS);
+ return (DIVS.length - 1 + d) % (DIVS.length - 1);
+ }
+
+ static from_hsv(h, s, v)
+ {
+ h = (((h % TWO_PI)) + TWO_PI) % TWO_PI;
+
+ let d = Color.d(h);
+
+ h = (h % PI_THIRDS) / PI_THIRDS;
+
+ let out = DIVS[d].interpolate(DIVS[d + 1], h);
+ out = WHITE.interpolate(out, s);
+
+ return BLACK.interpolate(out, v);
+ }
+
+ static from_hsl(h, s, l)
+ {
+ h = (((h % TWO_PI)) + TWO_PI) % TWO_PI;
+
+ let d = Color.d(h);
+
+ h = (h % PI_THIRDS) / PI_THIRDS;
+
+ let out = DIVS[d].interpolate(DIVS[d + 1], h);
+ let L = BLACK.interpolate(WHITE, l);
+
+ if (l < 0.5)
+ out = BLACK.interpolate(out, l / 0.5);
+ else
+ out = out.interpolate(WHITE, (l - 0.5) / 0.5);
+
+ return L.interpolate(out, s);
+ }
}
+const RED = new Color(1, 0, 0, 1);
+const YELLOW = new Color(1, 1, 0, 1);
+const GREEN = new Color(0, 1, 0, 1);
+const CYAN = new Color(0, 1, 1, 1);
+const BLUE = new Color(0, 0, 1, 1);
+const MAGENTA = new Color(1, 0, 1, 1);
+const WHITE = new Color(1, 1, 1, 1);
+const BLACK = new Color(0, 0, 0, 1);
+
+const PI_THIRDS = Math.PI / 3;
+const TWO_PI = Math.PI * 2;
+
+const DIVS = [RED, YELLOW, GREEN, CYAN, BLUE, MAGENTA, RED];
+
/**
* Interpolate between two colors
* @param {Color} a
diff --git a/scripts/gui-common/widgets.js b/scripts/gui-common/widgets.js
index 88f1db8..9ec1712 100644
--- a/scripts/gui-common/widgets.js
+++ b/scripts/gui-common/widgets.js
@@ -28,6 +28,8 @@ class Widget extends EventTarget{
this.element.addEventListener("mouseleave", this.#emitMouseEvent.bind(this));
this.element.addEventListener("mouseenter", this.#emitMouseEvent.bind(this));
+ this.element.addEventListener("click", this.#emitMouseEvent.bind(this));
+
this.element.addEventListener("touchstart", this.#emitTouchEvent.bind(this));
this.element.addEventListener("touchend", this.#emitTouchEvent.bind(this));
this.element.addEventListener("touchmove", this.#emitTouchEvent.bind(this));
@@ -236,7 +238,7 @@ class WidgetCheckbox extends WidgetToggle {
}
}
-class WidgetSlider extends Widget
+class WidgetDragable extends Widget
{
/** @type {number} */
#primed = 0;
@@ -244,13 +246,92 @@ class WidgetSlider extends Widget
/** @type {number} */
#gone = 0;
- #boundUp = null;
- #boundMove = null;
+ /** @type {(e: MouseEvent) => void} */
+ #m_up = null;
+ /** @type {(e: MouseEvent, b: number) => void} */
+ #m_move = null;
+
+ /** @type {(e: TouchEvent) => void} */
+ #t_up = null;
+ /** @type {(e: TouchEvent) => void} */
+ #t_move = null;
+
+
+ /**
+ * Constructor
+ */
+ constructor ()
+ {
+ super();
+
+ this.#m_up = this.#unpress.bind(this);
+ this.#m_move = this.#move.bind(this);
+
+ this.addEventListener("mousedown", this.#press);
+ this.addEventListener("mousemove", this.#move);
+ this.addEventListener("mouseup", this.#unpress);
+ this.addEventListener("mouseleave", this.#leave);
+ this.addEventListener("mouseenter", this.#enter);
+ }
+
+ /** @param {MouseEvent} event */
+ #press(event)
+ {
+ this.#primed |= (1 << event.button);
+ this.#move(event);
+ }
+
+ /** @param {MouseEvent} event */
+ #unpress(event)
+ {
+ if (((1 << event.button) & this.#primed) == 0)
+ return;
+ this.#primed -= (1 << event.button);
+ this.#move(event);
+ if (this.#primed == 0)
+ {
+ if (this.#gone)
+ {
+ this.#gone = 0;
+ window.removeEventListener("mouseup", this.#m_up);
+ window.removeEventListener("mousemove", this.#m_move);
+ }
+ }
+ }
+
+ /** @param {MouseEvent} event */
+ #move(event)
+ {
+ this.move(event, this.#primed);
+ }
+
+ /** @param {MouseEvent} event */
+ #leave(event)
+ {
+ if (this.#primed == 0)
+ return;
+ this.#gone = 1;
+ window.addEventListener("mouseup", this.#m_up);
+ window.addEventListener("mousemove", this.#m_move);
+ }
+
+ /** @param {MouseEvent} event */
+ #enter(event)
+ {
+ if (this.#primed == 0)
+ return;
+ this.#gone = 0;
+ window.removeEventListener("mouseup", this.#m_up);
+ window.removeEventListener("mousemove", this.#m_move);
+ }
+}
+class WidgetSlider extends WidgetDragable
+{
/** @type {HTMLElement} */
#detail = null;
/** @type {(e: HTMLElement, v: number, p: number) => void} */
- #detailUpdater = null;
+ #u_detail = null;
/** @type {number} */
#tmpNum = 0;
@@ -286,37 +367,29 @@ class WidgetSlider extends Widget
this.#detail = document.createElement("div");
this.#detail.classList.add("detail");
this.element.appendChild(this.#detail);
-
- this.addEventListener("mousedown", this.#press);
- this.addEventListener("mousemove", this.#move);
- this.addEventListener("mouseup", this.#unpress);
- this.addEventListener("mouseleave", this.#leave);
- this.addEventListener("mouseenter", this.#enter);
+
this.addEventListener("change", this.#change);
-
- this.#boundUp = this.#unpress.bind(this);
- this.#boundMove = this.#move.bind(this);
+
this.#max = max;
this.#min = min;
this.#step = step;
this.#precision = trunc;
this.#percent = percent;
- this.#detailUpdater = this.update_detail.bind(this);
- }
-
- /** @param {MouseEvent} event */
- #press(event)
- {
- this.#primed |= (1 << event.button);
- this.#move(event);
+ this.#u_detail = this.update_detail.bind(this);
}
- /** @param {MouseEvent} event */
- #move(event)
+ /**
+ * @param {MouseEvent} event
+ * @param {number} btns
+ */
+ move(event, btns)
{
- if (this.#primed == 0)
+ if (btns == 0)
+ {
+ this.set(this.#tmpNum);
return;
+ }
let rect = this.element.getBoundingClientRect();
let top = 0, bot = 0, point = 0;
@@ -361,48 +434,10 @@ class WidgetSlider extends Widget
this.#tmpNum = Math.min(Math.max(this.#tmpNum, this.#min), this.#max);
let percent = (this.#tmpNum - this.#min) / (this.#max - this.#min);
- this.#detailUpdater(this.#detail, this.#tmpNum, percent, this.#percent);
+ this.#u_detail(this.#detail, this.#tmpNum, percent, this.#percent);
this.element.style.setProperty("--percent", percent);
}
- /** @param {MouseEvent} event */
- #unpress(event)
- {
- if (((1 << event.button) & this.#primed) == 0)
- return;
- this.#primed -= (1 << event.button);
- if (this.#primed == 0)
- {
- this.set(this.#tmpNum);
- if (this.#gone)
- {
- this.#gone = 0;
- window.removeEventListener("mouseup", this.#boundUp);
- window.removeEventListener("mousemove", this.#boundMove);
- }
- }
- }
-
- /** @param {MouseEvent} event */
- #leave(event)
- {
- if (this.#primed == 0)
- return;
- this.#gone = 1;
- window.addEventListener("mouseup", this.#boundUp);
- window.addEventListener("mousemove", this.#boundMove);
- }
-
- /** @param {MouseEvent} event */
- #enter(event)
- {
- if (this.#primed == 0)
- return;
- this.#gone = 0;
- window.removeEventListener("mouseup", this.#boundUp);
- window.removeEventListener("mousemove", this.#boundMove);
- }
-
update_detail(el, val, percent)
{
if (this.#percent)
@@ -413,7 +448,7 @@ class WidgetSlider extends Widget
setDetailUpdater(updater)
{
- this.#detailUpdater = updater;
+ this.#u_detail = updater;
}
/** @param {number} m */
@@ -514,10 +549,83 @@ class WidgetColorLight extends WidgetSlider
}
}
-/** @typedef {Widget<number>} WidgetSlider */
-/** @typedef {Widget<string>} WidgetColorWheel */
-/** @typedef {Widget<number>} WidgetColorTemp */
-/** @typedef {Widget<number>} WidgetColorLight */
+class WidgetColorWheel extends WidgetDragable
+{
+ /** @type {Color} */
+ #tmpColor = null;
+ /** @type {HTMLElement} */
+ #detail = null;
+
+ /**
+ * Constructor
+ */
+ constructor ()
+ {
+ super();
+ this.element.classList.add("color-wheel");
+
+ this.#detail = document.createElement("div");
+ this.#detail.classList.add("detail");
+ this.element.appendChild(this.#detail);
+ }
+
+ /**
+ * @param {MouseEvent} event
+ * @param {number} btns
+ */
+ move(event, btns)
+ {
+ if (btns == 0)
+ {
+ this.set(this.#tmpColor);
+ return;
+ }
+
+ let rect = this.element.getBoundingClientRect();
+
+ // Points
+ let tmpX = event.clientX;
+ let tmpY = rect.bottom - event.clientY + rect.top;
+
+ // Percents
+ tmpX = (tmpX - rect.left) / (rect.right - rect.left);
+ tmpY = (tmpY - rect.top) / (rect.bottom - rect.top);
+
+ // Vecs
+ tmpX = (Math.min(Math.max(0.0, tmpX), 1.0) - 0.5) * 2;
+ tmpY = (Math.min(Math.max(0.0, tmpY), 1.0) - 0.5) * 2;
+
+ // Normalized
+ let mag = Math.sqrt(tmpX * tmpX + tmpY * tmpY);
+ if (mag > 1)
+ {
+ tmpX /= mag;
+ tmpY /= mag;
+ }
+
+ this.element.style.setProperty("--pos-x", tmpX);
+ this.element.style.setProperty("--pos-y", tmpY);
+ this.update_detail(tmpX, tmpY, mag);
+ }
+
+ update_detail(x, y, mag)
+ {
+ if (x == 0)
+ {
+ if (y > 0)
+ this.#tmpColor = Color.from_hsv(Math.PI / 2, mag, 1);
+ else
+ this.#tmpColor = Color.from_hsv(-Math.PI / 2, mag, 1);
+ }
+ else if (x < 0)
+ this.#tmpColor = Color.from_hsv(Math.atan(y / x) + Math.PI, mag, 1);
+ else
+ this.#tmpColor = Color.from_hsv(Math.atan(y / x), mag, 1);
+
+ this.element.style.setProperty("--detail", this.#tmpColor.rgb());
+ }
+}
+
/** @typedef {Widget<number> & {getGague: () => number, setGague: (value: number) => void}} WidgetThermostat */
/** @typedef {Widget<any> & {addSelection: (name: string, value: any) => void, setSelection: (name: string) => boolean, removeSelection: (name: string) => void, getSelection: () => string}} WidgetSelectButton */
diff --git a/scripts/main.js b/scripts/main.js
index ac6dbe9..3cdbe12 100644
--- a/scripts/main.js
+++ b/scripts/main.js
@@ -16,6 +16,8 @@ class Client {
content.appendChild(this.temp.element);
this.light = new WidgetColorLight();
content.appendChild(this.light.element);
+ this.wheel = new WidgetColorWheel();
+ content.appendChild(this.wheel.element);
// content.appendChild(Widget("button").el);
// content.appendChild(Widget("checkbox").el);
// content.appendChild(Widget("slider").el);