Mercurial > code > home > repos > light9
view web/fade/Light9Fader.ts @ 2405:69ca2b2fc133
overcomplicated attempt at persisting the pane layout in the rdf graph
this was hard because we have to somehow wait for the graph to load before config'ing the panes
author | drewp@bigasterisk.com |
---|---|
date | Fri, 17 May 2024 16:58:26 -0700 |
parents | 9a4bc2ea264e |
children |
line wrap: on
line source
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); } }