@deepkit/desktop-ui
Version:
Library for desktop UI widgets in Angular 10+
135 lines (115 loc) • 4.52 kB
text/typescript
/*
* Deepkit Framework
* Copyright (C) 2021 Deepkit UG, Marc J. Schmidt
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the MIT License.
*
* You should have received a copy of the MIT License along with this program.
*/
import {
AfterViewInit,
ChangeDetectorRef,
Component,
ElementRef,
Injector,
Input,
SkipSelf,
ViewChild,
} from '@angular/core';
import { nextTick } from '@deepkit/core';
import { ngValueAccessor, ValueAccessorBase } from '../../core/form';
import { getHammer } from '../../core/utils';
export class SliderComponent extends ValueAccessorBase<number> implements AfterViewInit {
knob?: ElementRef;
min = 0;
steps = 0.01;
max = 1;
mini: boolean | '' = false;
constructor(
protected injector: Injector,
public readonly cd: ChangeDetectorRef,
public readonly cdParent: ChangeDetectorRef,
protected element: ElementRef,
) {
super(injector, cd, cdParent);
}
getWidth(): number {
return Math.max(0, Math.min(1, ((this.innerValue || this.min) - this.min) / (this.max - this.min)));
}
ngAfterViewInit() {
//move to next render frame, so all newly created sliders are rendered at the same time and don't block he DOM
nextTick(() => {
this.initEvents();
});
}
async initEvents() {
const Hammer = await getHammer();
if (!Hammer) return;
const mc = new Hammer(this.knob!.nativeElement);
mc.add(new Hammer.Pan({ direction: Hammer.DIRECTION_HORIZONTAL, threshold: 1 }));
const mcTab = new Hammer(this.element.nativeElement);
mcTab.add(new Hammer.Tap({}));
mcTab.add(new Hammer.Pan({ direction: Hammer.DIRECTION_HORIZONTAL, threshold: 0 }));
mcTab.add(new Hammer.Press({ threshold: 1 }));
let startXInPixels = 0;
let knobSize = this.knob!.nativeElement.offsetWidth;
let width = (this.element!.nativeElement.offsetWidth - knobSize);
let lastRequest: any;
mc.on('panstart', (event: HammerInput) => {
startXInPixels = this.getWidth() * width;
knobSize = this.knob!.nativeElement.offsetWidth;
width = (this.element!.nativeElement.offsetWidth - knobSize);
});
mcTab.on('panstart', (event: HammerInput) => {
const rect = (this.element!.nativeElement as HTMLElement).getBoundingClientRect();
startXInPixels = event.center.x - (knobSize / 2) - rect.x;
knobSize = this.knob!.nativeElement.offsetWidth;
width = (this.element!.nativeElement.offsetWidth - knobSize);
});
const handleNewLeft = (newLeft: number) => {
if (newLeft === 1.0) {
this.innerValue = this.max;
return;
}
let newPotentialValue = this.min + (newLeft * ((this.max - this.min)));
const shift = (newPotentialValue % this.steps);
this.innerValue = Math.max(this.min, newPotentialValue - shift);
};
const setOnMousePos = (event: HammerInput) => {
const rect = (this.element!.nativeElement as HTMLElement).getBoundingClientRect();
const x = event.center.x - (knobSize / 2) - rect.x;
const newLeft = Math.min(width, Math.max(0, x)) / width;
handleNewLeft(newLeft);
};
mcTab.on('tap', setOnMousePos);
mcTab.on('press', setOnMousePos);
function pan(event: HammerInput) {
if (lastRequest) {
cancelAnimationFrame(lastRequest);
}
lastRequest = nextTick(() => {
const newLeft = Math.min(width, Math.max(0, (startXInPixels + event.deltaX))) / width;
handleNewLeft(newLeft);
});
}
mc.on('pan', pan);
mcTab.on('pan', pan);
}
}