Headless CMS and Content Managment Hub
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

145 lines
3.9 KiB

/*
* Squidex Headless CMS
*
* @license
* Copyright (c) Sebastian Stehle. All rights reserved
*/
import { Component, ElementRef, EventEmitter, Input, OnChanges, Output, Renderer, ViewChild } from '@angular/core';
@Component({
selector: 'sqx-slider',
styleUrls: ['./slider.component.scss'],
templateUrl: './slider.component.html'
})
export class SliderComponent implements OnChanges {
private mouseMoveSubscription: Function | null;
private mouseUpSubscription: Function | null;
private centerStartOffset = 0;
private startValue: number;
@ViewChild('bar')
public bar: ElementRef;
@ViewChild('thumb')
public thumb: ElementRef;
@Input()
public min = 0;
@Input()
public max = 100;
@Input()
public value: number;
@Output()
public valueChange = new EventEmitter();
constructor(private readonly renderer: Renderer) { }
public ngOnChanges() {
const relativeValue = (this.value - this.min) / (this.max - this.min);
this.setThumbPosition(relativeValue);
}
public onBarMouseClick(event: MouseEvent) {
const relativeValue = this.getRelativeX(event);
this.setThumbPosition(relativeValue);
const newValue = Math.round(relativeValue * (this.max - this.min) + this.min);
if (newValue !== this.value) {
this.valueChange.emit(newValue);
}
this.stopEvent(event);
}
public onThumbMouseDown(event: MouseEvent) {
this.centerStartOffset = event.offsetX - this.thumb.nativeElement.clientWidth * 0.5;
this.startValue = this.value;
this.mouseMoveSubscription =
this.renderer.listenGlobal('window', 'mousemove', (e: MouseEvent) => {
this.onMouseMove(e);
});
this.mouseUpSubscription =
this.renderer.listenGlobal('window', 'mouseup', (e: MouseEvent) => {
this.onMouseUp(e);
});
this.renderer.setElementClass(this.thumb.nativeElement, 'focused', true);
this.stopEvent(event);
}
private onMouseMove(event: MouseEvent) {
const relativeValue = this.getRelativeX(event);
this.setThumbPosition(relativeValue);
this.stopEvent(event);
}
private onMouseUp(event: MouseEvent) {
const relativeValue = this.getRelativeX(event);
const newValue = Math.round(relativeValue * (this.max - this.min) + this.min);
if (newValue !== this.startValue) {
this.valueChange.emit(newValue);
}
this.releaseMouseHandlers();
this.renderer.setElementClass(this.thumb.nativeElement, 'focused', false);
this.centerStartOffset = 0;
this.stopEvent(event);
}
private getRelativeX(event: MouseEvent): number {
const parentOffsetX = this.getParentX(event, this.bar.nativeElement) - this.centerStartOffset;
const parentWidth = this.bar.nativeElement.clientWidth;
const relativeValue = Math.min(1, Math.max(0, (parentOffsetX - this.centerStartOffset) / parentWidth));
return relativeValue;
}
private getParentX(e: any, container: any): number {
const rect = container.getBoundingClientRect();
const x = !!e.touches ? e.touches[0].pageX : e.pageX;
return x - rect.left;
}
private setThumbPosition(relativeValue: number) {
relativeValue = Math.min(1, Math.max(0, relativeValue));
this.renderer.setElementStyle(this.thumb.nativeElement, 'left', relativeValue * 100 + '%');
}
private stopEvent(event: Event) {
event.preventDefault();
event.stopPropagation();
}
private releaseMouseHandlers() {
if (this.mouseMoveSubscription) {
this.mouseMoveSubscription();
this.mouseMoveSubscription = null;
}
if (this.mouseUpSubscription) {
this.mouseUpSubscription();
this.mouseUpSubscription = null;
}
}
}