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: 5px gray outset;
position: relative;
left: 0;
right: -25px;
}
`,
];
@property() value: number = 0;
@query("#handle") handleEl!: HTMLElement;
troughHeight = 80 - 2 - 2 - 5 - 5;
handleHeight = 10;
drag?: Drag;
unmutedValue: number = 1;
render() {
return html`
`;
}
protected update(changedProperties: PropertyValueMap | Map): 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 | Map): void {
super.updated(_changedProperties);
const y = this.sliderTopY(this.value);
this.handleEl.style.top = y + "px";
}
protected firstUpdated(_changedProperties: PropertyValueMap | Map): 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 * -.05;
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;
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);
}
}