comparison web/fade/Light9Fader.ts @ 2376:4556eebe5d73

topdir reorgs; let pdm have its src/ dir; separate vite area from light9/
author drewp@bigasterisk.com
date Sun, 12 May 2024 19:02:10 -0700
parents light9/web/fade/Light9Fader.ts@06bf6dae8e64
children 9a4bc2ea264e
comparison
equal deleted inserted replaced
2375:623836db99af 2376:4556eebe5d73
1 import debug from "debug";
2 import { css, html, LitElement, PropertyValueMap } from "lit";
3 import { customElement, property, query } from "lit/decorators.js";
4
5 import { clamp } from "../floating_color_picker";
6 const log = debug("fade");
7
8 class Drag {
9 constructor(public startDragPxY: number, public startDragValue: number) {}
10 }
11
12 @customElement("light9-fader")
13 export class Light9Fader extends LitElement {
14 static styles = [
15 css`
16 :host {
17 display: inline-block;
18 border: 2px gray inset;
19 background: #000;
20 height: 80px;
21 }
22 #handle {
23 background: gray;
24 border: 5px gray outset;
25 position: relative;
26 left: 0;
27 right: -25px;
28 }
29 `,
30 ];
31
32 @property() value: number = 0;
33
34 @query("#handle") handleEl!: HTMLElement;
35
36 troughHeight = 80 - 2 - 2 - 5 - 5;
37 handleHeight = 10;
38
39 drag?: Drag;
40 unmutedValue: number = 1;
41
42 render() {
43 return html` <div id="handle"><hr /></div> `;
44 }
45
46 protected update(changedProperties: PropertyValueMap<any> | Map<PropertyKey, unknown>): void {
47 super.update(changedProperties);
48 if (changedProperties.has("value")) {
49
50 }
51 }
52 valueChangedFromUi() {
53 this.value= clamp(this.value, 0, 1)
54 this.dispatchEvent(new CustomEvent("change", { detail: { value: this.value } }));
55 }
56
57 protected updated(_changedProperties: PropertyValueMap<any> | Map<PropertyKey, unknown>): void {
58 super.updated(_changedProperties);
59 const y = this.sliderTopY(this.value);
60 this.handleEl.style.top = y + "px";
61 }
62
63 protected firstUpdated(_changedProperties: PropertyValueMap<any> | Map<PropertyKey, unknown>): void {
64 super.firstUpdated(_changedProperties);
65 this.handleEl.style.height = this.handleHeight + "px";
66 this.events();
67 }
68
69 events() {
70 const hand = this.handleEl;
71 hand.addEventListener("mousedown", (ev: MouseEvent) => {
72 ev.stopPropagation();
73 if (ev.buttons == 1) {
74 this.drag = new Drag(ev.clientY, this.value);
75 } else if (ev.buttons == 2) {
76 this.onRmb();
77 }
78 });
79 this.addEventListener("mousedown", (ev: MouseEvent) => {
80 ev.stopPropagation();
81 if (ev.buttons == 1) {
82 this.value = this.sliderValue(ev.offsetY);
83 this.valueChangedFromUi()
84 this.drag = new Drag(ev.clientY, this.value);
85 } else if (ev.buttons == 2) {
86 // RMB in trough
87 this.onRmb();
88 }
89 });
90
91 this.addEventListener("contextmenu", (event) => {
92 event.preventDefault();
93 });
94
95 this.addEventListener("wheel", (ev: WheelEvent) => {
96 ev.preventDefault();
97 this.value += ev.deltaY / this.troughHeight * -.05;
98 this.valueChangedFromUi()
99 });
100
101 const maybeDrag = (ev: MouseEvent) => {
102 if (ev.buttons != 1) return;
103 if (this.drag === undefined) return;
104 ev.stopPropagation();
105 this.onMouseDrag(ev.clientY - this.drag.startDragPxY!);
106 };
107 hand.addEventListener("mousemove", maybeDrag);
108 this.addEventListener("mousemove", maybeDrag);
109 window.addEventListener("mousemove", maybeDrag);
110
111 hand.addEventListener("mouseup", this.onMouseUpAnywhere.bind(this));
112 this.addEventListener("mouseup", this.onMouseUpAnywhere.bind(this));
113 window.addEventListener("mouseup", this.onMouseUpAnywhere.bind(this));
114 }
115 onRmb() {
116 if (this.value > 0.1) {
117 // mute
118 this.unmutedValue = this.value;
119 this.value = 0;
120 } else {
121 // unmute
122 this.value = this.unmutedValue;
123 }
124 this.valueChangedFromUi()
125 }
126 onMouseDrag(dy: number) {
127 if (this.drag === undefined) throw "unexpected";
128 this.value = this.drag.startDragValue - dy / this.troughHeight;
129 this.valueChangedFromUi()
130 }
131
132 onMouseUpAnywhere() {
133 this.drag = undefined;
134 }
135
136 sliderTopY(value: number): number {
137 const usableY = this.troughHeight - this.handleHeight;
138 const yAdj = this.handleHeight / 2 - 5 - 2;
139 return (1 - value) * usableY + yAdj;
140 }
141 sliderValue(offsetY: number): number {
142 const usableY = this.troughHeight - this.handleHeight;
143 const yAdj = this.handleHeight / 2 - 5 - 2;
144 return clamp(1 - (offsetY - yAdj) / usableY, 0, 1);
145 }
146 }