Changeset - 280be980aaa0
[Not reviewed]
default
0 1 1
drewp@bigasterisk.com - 20 months ago 2023-06-01 21:19:42
drewp@bigasterisk.com
new fader widget
2 files changed with 150 insertions and 20 deletions:
0 comments (0 inline, 0 general)
light9/fade/Light9FadeUi.ts
Show inline comments
 
import { fastSlider, fastSliderLabel, provideFASTDesignSystem } from "@microsoft/fast-components";
 
import debug from "debug";
 
import { css, html, LitElement } from "lit";
 
import { customElement, property, state } from "lit/decorators.js";
 
import { NamedNode } from "n3";
 
import { getTopGraph } from "../web/RdfdbSyncedGraph";
 
import { shortShow, showRoot } from "../web/show_specific";
 
import { SyncedGraph } from "../web/SyncedGraph";
 
import { shortShow, showRoot } from "../web/show_specific";
 
export { EditChoice } from "../web/EditChoice";
 
provideFASTDesignSystem().register(fastSlider(), fastSliderLabel());
 
export { Light9Fader } from "./Light9Fader";
 

	
 
debug.enable("*");
 
const log = debug("fade");
 
@@ -19,6 +18,7 @@ export class Light9FadeUi extends LitEle
 
    css`
 
      :host {
 
        display: block;
 
        user-select: none; /* really this is only desirable during slider drag events */
 
      }
 
    `,
 
  ];
 
@@ -30,7 +30,7 @@ export class Light9FadeUi extends LitEle
 

	
 
      <div id="fps"></div>
 

	
 
      ${this.faders.map((fd) => html` <light9-fader .uri=${fd}></light9-fader> `)}
 
      ${this.faders.map((fd) => html` <light9-effect-fader .uri=${fd}></light9-effect-fader> `)}
 
    `;
 
  }
 

	
 
@@ -62,8 +62,8 @@ export class Light9FadeUi extends LitEle
 
  }
 
}
 

	
 
@customElement("light9-fader")
 
export class Light9Fader extends LitElement {
 
@customElement("light9-effect-fader")
 
export class Light9EffectFader extends LitElement {
 
  static styles = [
 
    css`
 
      :host {
 
@@ -71,24 +71,15 @@ export class Light9Fader extends LitElem
 
        border: 2px gray outset;
 
        background: #272727;
 
      }
 
      fast-slider {
 
        height: 256px;
 
      }
 
      fast-slider > .track {
 
        background: #e3bbc0;
 
        box-shadow: 0 0 8px;
 
      }
 
      fast-slider {
 
        --accent-foreground-rest: #0a0a0c;
 
      light9-fader {
 
        margin: 4px;
 
        width: 100%;
 
      }
 
    `,
 
  ];
 
  render() {
 
    return html`
 
      <fast-slider orientation="vertical" .value=${this.value} step=${1 / 255} min="1" max="0" @change=${this.onSliderInput}>
 
        <fast-slider-label label="0"></fast-slider-label>
 
        <fast-slider-label label="1.0"></fast-slider-label>
 
      </fast-slider>
 
      <light9-fader .value=${this.value} @change=${this.onSliderInput}></light9-fader>
 
      <div>${this.value.toPrecision(3)}</div>
 
      <div>eff: <edit-choice .uri=${this.effect} @edited=${this.onEffectChange}></edit-choice></div>
 
      <div>attr: <edit-choice .uri=${this.effectAttr} @edited=${this.onEffectAttrChange}></edit-choice></div>
 
@@ -153,7 +144,7 @@ export class Light9Fader extends LitElem
 
    }
 
    const U = this.graph.U();
 
    const prev = this.value;
 
    const v: number = (ev.target as any).valueAsNumber;
 
    const v: number = ev.detail.value;
 
    this.value = parseFloat(v.toPrecision(3)); // rewrite pls
 
    if (this.value == prev) {
 
      return;
light9/fade/Light9Fader.ts
Show inline comments
 
new file 100644
 
import debug from "debug";
 
import { css, html, LitElement, PropertyValueMap } from "lit";
 
import { customElement, property, query } from "lit/decorators.js";
 

	
 
import { clamp } from "../web/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: 250px;
 
      }
 
      #handle {
 
        background: gray;
 
        border: 5px gray outset;
 
        position: relative;
 
        left: 0;
 
        right: -25px;
 
      }
 
    `,
 
  ];
 

	
 
  @property() value: number = 0;
 

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

	
 
  troughHeight = 250 - 2 - 2 - 5 - 5;
 
  handleHeight = 20;
 

	
 
  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")) {
 
      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.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 / 120 * -.05;
 
    });
 

	
 
    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;
 
    }
 
  }
 
  onMouseDrag(dy: number) {
 
    if (this.drag === undefined) throw "unexpected";
 
    this.value = this.drag.startDragValue - dy / this.troughHeight;
 
  }
 

	
 
  onMouseUpAnywhere() {
 
    this.drag = undefined;
 
  }
 

	
 
  sliderTopY(value: number): number {
 
    const usableY = this.troughHeight - this.handleHeight;
 
    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);
 
  }
 
}
0 comments (0 inline, 0 general)