gp-crm-ui
Version:
Модуль компонентов UI Имя модуля: `gp-crm-ui`
272 lines (228 loc) • 7.98 kB
text/typescript
import {
Component,
ElementRef,
Input,
OnDestroy,
OnInit,
Renderer2,
ViewChild
} from '@angular/core';
// Сенсор
import { ResizeSensor } from 'css-element-queries';
// Интерфейсы
import {
IOffset,
ISize
} from '../../interfaces';
// Перечисления
import {
ScrollMode,
SliderType
} from '../../enums';
// Сервисы
import { CrmHelperService } from '../../services';
// Скролл
export class CrmScrollComponent
implements OnInit, OnDestroy {
constructor(private readonly renderer: Renderer2) {}
// Режим скролла
public mode: ScrollMode = ScrollMode.Vertical;
// Тип слайдера
public type: SliderType = SliderType.Default;
// Ссылка на область отображения
public viewportRef: ElementRef;
// Ссылка на область контента
public canvasRef: ElementRef;
// Размер прокрутки колесом мыши (px)
private readonly WHEEL_SIZE: number = 30;
// Ссылка на обьект для touch событий
private touchTarget: Element;
// Последняя позиция касания
private readonly lastTouch: IOffset = {
left: 0,
top: 0
};
// Функции для отключения прослушивания событий
private touchMoveListen: () => void;
private touchEndListen: () => void;
// Сенсор изменения размера view
private resizeSensorView: any;
// Сенсор изменения размера canvas
private resizeSensorCanvas: any;
// Размер области отображения
public readonly viewport: ISize = {
width: 0,
height: 0
};
// Размер области контента
public readonly canvas: ISize = {
width: 0,
height: 0
};
// Смещение области контента в области отображения
public readonly offset: IOffset = {
left: 0,
top: 0
};
// Смещение от левого края
private get offsetLeft(): number {
return this.offset.left;
}
private set offsetLeft(value: number) {
this.offset.left = CrmHelperService.clamp(value, 0, this.maxOffsetLeft);
this.viewportRef.nativeElement.scrollLeft = this.offset.left;
}
// Смещение от верхнего края
private get offsetTop(): number {
return this.offset.top;
}
private set offsetTop(value: number) {
this.offset.top = CrmHelperService.clamp(value, 0, this.maxOffsetTop);
this.viewportRef.nativeElement.scrollTop = this.offset.top;
}
// Максимальное смещение от левого края
private get maxOffsetLeft(): number {
return CrmHelperService.clamp(this.canvas.width - this.viewport.width);
}
// Максимальное смещение от верхнего края
private get maxOffsetTop(): number {
return CrmHelperService.clamp(this.canvas.height - this.viewport.height);
}
// Флаг видимости вертикального слайдера
private _isVerticalSliderVisible: boolean = false;
public get isVerticalSliderVisible(): boolean {
return this._isVerticalSliderVisible;
}
// Флаг видимости горизонтального слайдера
private _isHorizontalSliderVisible: boolean = false;
public get isHorizontalSliderVisible(): boolean {
return this._isHorizontalSliderVisible;
}
// --------------------------------------------------------------------------
// Добавить сенсоры
private addSensors(): void {
this.resizeSensorView = new ResizeSensor(
this.viewportRef.nativeElement,
this.updateViewport.bind(this)
);
this.resizeSensorCanvas = new ResizeSensor(
this.canvasRef.nativeElement,
this.updateCanvas.bind(this)
);
}
// Удалить сенсоры
private removeSensors(): void {
if (this.resizeSensorView) { this.resizeSensorView.detach(); }
if (this.resizeSensorCanvas) { this.resizeSensorCanvas.detach(); }
}
// Обновить область отображения
private updateViewport(): void {
this.viewport.width = this.viewportRef.nativeElement.offsetWidth;
this.viewport.height = this.viewportRef.nativeElement.offsetHeight;
this.updateSliders();
}
// Обновить область контента
private updateCanvas(): void {
this.canvas.width = this.canvasRef.nativeElement.offsetWidth;
this.canvas.height = this.canvasRef.nativeElement.offsetHeight;
this.updateSliders();
}
// Обновить видимость слайдеров
private updateSliders(): void {
// Защита от ложного переключения флагов
setTimeout((): void => {
this._isVerticalSliderVisible = this.canvas.height > this.viewport.height;
this._isHorizontalSliderVisible = this.canvas.width > this.viewport.width;
});
}
// --------------------------------------------------------------------------
// Обработчик прокрутки
public onMouseWheel(event: MouseEvent): void {
const delta = CrmHelperService.getDeltaFromWheelEvent(event);
this.offsetLeft += delta.x * this.WHEEL_SIZE;
this.offsetTop += delta.y * this.WHEEL_SIZE;
}
// Обработчик перемещения вертикального слайдера
public onVerticalSliderMoved(percent: number): void {
this.offsetTop = this.maxOffsetTop * percent;
}
// Обработчик вертикальной прокрутки
public onVerticalScroll(delta: number): void {
this.offsetTop += delta;
}
// Обработчик перемещения горизонтального слайдера
public onHorizontalSliderMoved(percent: number): void {
this.offsetLeft = this.maxOffsetLeft * percent;
}
// Обработчик горизонтальной прокрутки
public onHorizontalScroll(delta: number): void {
this.offsetLeft += delta;
}
// --------------------------------------------------------------------------
// Нажатие на область
public onTouchStart(event: TouchEvent): void {
const touch = event.touches[event.touches.length - 1];
const touchTarget = (
event.target ||
event.srcElement ||
event.currentTarget
) as Element;
if (touch) {
this.touchTarget = touchTarget;
this.touchMoveListen = this.renderer.listen(
this.touchTarget,
'touchmove',
this.onTouchMove.bind(this)
);
this.touchEndListen = this.renderer.listen(
this.touchTarget,
'touchend',
this.onTouchEnd.bind(this)
);
this.lastTouch.left = touch.clientX;
this.lastTouch.top = touch.clientY;
}
}
// Перемещение по области
public onTouchMove(event: TouchEvent): void {
const touch = event.touches[event.touches.length - 1];
this.offsetLeft += this.lastTouch.left - touch.clientX;
this.offsetTop += this.lastTouch.top - touch.clientY;
this.lastTouch.left = touch.clientX;
this.lastTouch.top = touch.clientY;
}
// Отжатие по области
public onTouchEnd(event: TouchEvent): void {
this.removeEvents();
this.removeLinks();
}
// --------------------------------------------------------------------------
// Убрать обработчики
public removeEvents(): void {
if (this.touchMoveListen) { this.touchMoveListen(); }
if (this.touchEndListen) { this.touchEndListen(); }
}
// Очистить ссылки на DOM
public removeLinks(): void {
this.touchTarget = null;
}
// --------------------------------------------------------------------------
// HOOKS
// Инициализация
public ngOnInit(): void {
this.addSensors();
this.updateViewport();
this.updateCanvas();
}
// Уничтожение
public ngOnDestroy(): void {
this.removeEvents();
this.removeLinks();
this.removeSensors();
}
}