diff options
| author | Kyle Gunger <kgunger12@gmail.com> | 2024-11-13 02:23:34 -0500 | 
|---|---|---|
| committer | Kyle Gunger <kgunger12@gmail.com> | 2024-11-13 02:23:34 -0500 | 
| commit | ff981cd5b7ab9274630a1417593af96e36b99e7a (patch) | |
| tree | aea5306f3c1f046893c7160b8350fd9808773f91 /scripts | |
| parent | 53c95ab94cab5163424646d4a798a7ea7fb13ec7 (diff) | |
Color Wheel Widget
Diffstat (limited to 'scripts')
| -rw-r--r-- | scripts/gui-common/color.js | 53 | ||||
| -rw-r--r-- | scripts/gui-common/widgets.js | 244 | ||||
| -rw-r--r-- | scripts/main.js | 2 | 
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);  |