Mercurial > code > home > repos > light9
annotate web/fade/Light9Fader.ts @ 2450:a4052905ca7d default tip
notes about how rdfdb syncs, or should sync
author | drewp@bigasterisk.com |
---|---|
date | Mon, 03 Jun 2024 23:01:54 -0700 |
parents | 9a4bc2ea264e |
children |
rev | line source |
---|---|
2320 | 1 import debug from "debug"; |
2 import { css, html, LitElement, PropertyValueMap } from "lit"; | |
3 import { customElement, property, query } from "lit/decorators.js"; | |
4 | |
2372
06bf6dae8e64
reorg tools into light9/web/ and a single vite instance
drewp@bigasterisk.com
parents:
2355
diff
changeset
|
5 import { clamp } from "../floating_color_picker"; |
2320 | 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; | |
2355 | 20 height: 80px; |
2320 | 21 } |
22 #handle { | |
23 background: gray; | |
2400 | 24 border: 3px outset #838499; |
2320 | 25 position: relative; |
2400 | 26 left: 0px; |
2320 | 27 right: -25px; |
2400 | 28 border-radius: 4px; |
29 margin: 0 1px; | |
2320 | 30 } |
31 `, | |
32 ]; | |
33 | |
34 @property() value: number = 0; | |
35 | |
36 @query("#handle") handleEl!: HTMLElement; | |
37 | |
2355 | 38 troughHeight = 80 - 2 - 2 - 5 - 5; |
2400 | 39 handleHeight = 16; |
2320 | 40 |
41 drag?: Drag; | |
42 unmutedValue: number = 1; | |
43 | |
44 render() { | |
45 return html` <div id="handle"><hr /></div> `; | |
46 } | |
47 | |
48 protected update(changedProperties: PropertyValueMap<any> | Map<PropertyKey, unknown>): void { | |
49 super.update(changedProperties); | |
50 if (changedProperties.has("value")) { | |
51 } | |
52 } | |
2339
2210d934d62d
fader was echoing external edits as patches back into the graph. This fixes that the wrong way, circumventing lit
drewp@bigasterisk.com
parents:
2331
diff
changeset
|
53 valueChangedFromUi() { |
2400 | 54 this.value = clamp(this.value, 0, 1); |
2339
2210d934d62d
fader was echoing external edits as patches back into the graph. This fixes that the wrong way, circumventing lit
drewp@bigasterisk.com
parents:
2331
diff
changeset
|
55 this.dispatchEvent(new CustomEvent("change", { detail: { value: this.value } })); |
2210d934d62d
fader was echoing external edits as patches back into the graph. This fixes that the wrong way, circumventing lit
drewp@bigasterisk.com
parents:
2331
diff
changeset
|
56 } |
2320 | 57 |
58 protected updated(_changedProperties: PropertyValueMap<any> | Map<PropertyKey, unknown>): void { | |
59 super.updated(_changedProperties); | |
60 const y = this.sliderTopY(this.value); | |
61 this.handleEl.style.top = y + "px"; | |
62 } | |
63 | |
64 protected firstUpdated(_changedProperties: PropertyValueMap<any> | Map<PropertyKey, unknown>): void { | |
65 super.firstUpdated(_changedProperties); | |
66 this.handleEl.style.height = this.handleHeight + "px"; | |
67 this.events(); | |
68 } | |
69 | |
70 events() { | |
71 const hand = this.handleEl; | |
72 hand.addEventListener("mousedown", (ev: MouseEvent) => { | |
73 ev.stopPropagation(); | |
74 if (ev.buttons == 1) { | |
75 this.drag = new Drag(ev.clientY, this.value); | |
76 } else if (ev.buttons == 2) { | |
77 this.onRmb(); | |
78 } | |
79 }); | |
80 this.addEventListener("mousedown", (ev: MouseEvent) => { | |
81 ev.stopPropagation(); | |
82 if (ev.buttons == 1) { | |
83 this.value = this.sliderValue(ev.offsetY); | |
2400 | 84 this.valueChangedFromUi(); |
2320 | 85 this.drag = new Drag(ev.clientY, this.value); |
86 } else if (ev.buttons == 2) { | |
87 // RMB in trough | |
88 this.onRmb(); | |
89 } | |
90 }); | |
91 | |
92 this.addEventListener("contextmenu", (event) => { | |
93 event.preventDefault(); | |
94 }); | |
95 | |
96 this.addEventListener("wheel", (ev: WheelEvent) => { | |
97 ev.preventDefault(); | |
2400 | 98 this.value += (ev.deltaY / this.troughHeight) * -0.03; |
99 this.valueChangedFromUi(); | |
2320 | 100 }); |
101 | |
102 const maybeDrag = (ev: MouseEvent) => { | |
103 if (ev.buttons != 1) return; | |
104 if (this.drag === undefined) return; | |
105 ev.stopPropagation(); | |
106 this.onMouseDrag(ev.clientY - this.drag.startDragPxY!); | |
107 }; | |
108 hand.addEventListener("mousemove", maybeDrag); | |
109 this.addEventListener("mousemove", maybeDrag); | |
110 window.addEventListener("mousemove", maybeDrag); | |
111 | |
112 hand.addEventListener("mouseup", this.onMouseUpAnywhere.bind(this)); | |
113 this.addEventListener("mouseup", this.onMouseUpAnywhere.bind(this)); | |
114 window.addEventListener("mouseup", this.onMouseUpAnywhere.bind(this)); | |
115 } | |
116 onRmb() { | |
117 if (this.value > 0.1) { | |
118 // mute | |
119 this.unmutedValue = this.value; | |
120 this.value = 0; | |
121 } else { | |
122 // unmute | |
123 this.value = this.unmutedValue; | |
124 } | |
2400 | 125 this.valueChangedFromUi(); |
2320 | 126 } |
127 onMouseDrag(dy: number) { | |
128 if (this.drag === undefined) throw "unexpected"; | |
129 this.value = this.drag.startDragValue - dy / this.troughHeight; | |
2400 | 130 this.valueChangedFromUi(); |
2320 | 131 } |
132 | |
133 onMouseUpAnywhere() { | |
134 this.drag = undefined; | |
135 } | |
136 | |
137 sliderTopY(value: number): number { | |
2400 | 138 const usableY = this.troughHeight - this.handleHeight / 2 - 1; |
2320 | 139 const yAdj = this.handleHeight / 2 - 5 - 2; |
140 return (1 - value) * usableY + yAdj; | |
141 } | |
142 sliderValue(offsetY: number): number { | |
143 const usableY = this.troughHeight - this.handleHeight; | |
144 const yAdj = this.handleHeight / 2 - 5 - 2; | |
145 return clamp(1 - (offsetY - yAdj) / usableY, 0, 1); | |
146 } | |
147 } |