Files @ ffa69645e9dc
Branch filter:

Location: light9/web/fade/Light9Fader.ts - annotation

drewp@bigasterisk.com
refactor
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
9a4bc2ea264e
4556eebe5d73
9a4bc2ea264e
4556eebe5d73
9a4bc2ea264e
9a4bc2ea264e
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
9a4bc2ea264e
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
9a4bc2ea264e
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
9a4bc2ea264e
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
9a4bc2ea264e
9a4bc2ea264e
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
9a4bc2ea264e
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
9a4bc2ea264e
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
9a4bc2ea264e
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
import debug from "debug";
import { css, html, LitElement, PropertyValueMap } from "lit";
import { customElement, property, query } from "lit/decorators.js";

import { clamp } from "../floating_color_picker";
const log = debug("fade");

class Drag {
  constructor(public startDragPxY: number, public startDragValue: number) {}
}

@customElement("light9-fader")
export class Light9Fader extends LitElement {
  static styles = [
    css`
      :host {
        display: inline-block;
        border: 2px gray inset;
        background: #000;
        height: 80px;
      }
      #handle {
        background: gray;
        border: 3px outset #838499;
        position: relative;
        left: 0px;
        right: -25px;
        border-radius: 4px;
        margin: 0 1px;
      }
    `,
  ];

  @property() value: number = 0;

  @query("#handle") handleEl!: HTMLElement;

  troughHeight = 80 - 2 - 2 - 5 - 5;
  handleHeight = 16;

  drag?: Drag;
  unmutedValue: number = 1;

  render() {
    return html` <div id="handle"><hr /></div> `;
  }

  protected update(changedProperties: PropertyValueMap<any> | Map<PropertyKey, unknown>): void {
    super.update(changedProperties);
    if (changedProperties.has("value")) {
    }
  }
  valueChangedFromUi() {
    this.value = clamp(this.value, 0, 1);
    this.dispatchEvent(new CustomEvent("change", { detail: { value: this.value } }));
  }

  protected updated(_changedProperties: PropertyValueMap<any> | Map<PropertyKey, unknown>): void {
    super.updated(_changedProperties);
    const y = this.sliderTopY(this.value);
    this.handleEl.style.top = y + "px";
  }

  protected firstUpdated(_changedProperties: PropertyValueMap<any> | Map<PropertyKey, unknown>): void {
    super.firstUpdated(_changedProperties);
    this.handleEl.style.height = this.handleHeight + "px";
    this.events();
  }

  events() {
    const hand = this.handleEl;
    hand.addEventListener("mousedown", (ev: MouseEvent) => {
      ev.stopPropagation();
      if (ev.buttons == 1) {
        this.drag = new Drag(ev.clientY, this.value);
      } else if (ev.buttons == 2) {
        this.onRmb();
      }
    });
    this.addEventListener("mousedown", (ev: MouseEvent) => {
      ev.stopPropagation();
      if (ev.buttons == 1) {
        this.value = this.sliderValue(ev.offsetY);
        this.valueChangedFromUi();
        this.drag = new Drag(ev.clientY, this.value);
      } else if (ev.buttons == 2) {
        // RMB in trough
        this.onRmb();
      }
    });

    this.addEventListener("contextmenu", (event) => {
      event.preventDefault();
    });

    this.addEventListener("wheel", (ev: WheelEvent) => {
      ev.preventDefault();
      this.value += (ev.deltaY / this.troughHeight) * -0.03;
      this.valueChangedFromUi();
    });

    const maybeDrag = (ev: MouseEvent) => {
      if (ev.buttons != 1) return;
      if (this.drag === undefined) return;
      ev.stopPropagation();
      this.onMouseDrag(ev.clientY - this.drag.startDragPxY!);
    };
    hand.addEventListener("mousemove", maybeDrag);
    this.addEventListener("mousemove", maybeDrag);
    window.addEventListener("mousemove", maybeDrag);

    hand.addEventListener("mouseup", this.onMouseUpAnywhere.bind(this));
    this.addEventListener("mouseup", this.onMouseUpAnywhere.bind(this));
    window.addEventListener("mouseup", this.onMouseUpAnywhere.bind(this));
  }
  onRmb() {
    if (this.value > 0.1) {
      // mute
      this.unmutedValue = this.value;
      this.value = 0;
    } else {
      // unmute
      this.value = this.unmutedValue;
    }
    this.valueChangedFromUi();
  }
  onMouseDrag(dy: number) {
    if (this.drag === undefined) throw "unexpected";
    this.value = this.drag.startDragValue - dy / this.troughHeight;
    this.valueChangedFromUi();
  }

  onMouseUpAnywhere() {
    this.drag = undefined;
  }

  sliderTopY(value: number): number {
    const usableY = this.troughHeight - this.handleHeight / 2 - 1;
    const yAdj = this.handleHeight / 2 - 5 - 2;
    return (1 - value) * usableY + yAdj;
  }
  sliderValue(offsetY: number): number {
    const usableY = this.troughHeight - this.handleHeight;
    const yAdj = this.handleHeight / 2 - 5 - 2;
    return clamp(1 - (offsetY - yAdj) / usableY, 0, 1);
  }
}