Mercurial > code > home > repos > light9
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 } |