UNPKG

gp-crm-ui

Version:

Модуль компонентов UI Имя модуля: `gp-crm-ui`

272 lines (228 loc) 7.98 kB
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'; // Скролл @Component({ selector: 'crm-scroll', templateUrl: './crm-scroll.component.html', styleUrls: ['./crm-scroll.component.scss'] }) export class CrmScrollComponent implements OnInit, OnDestroy { constructor(private readonly renderer: Renderer2) {} // Режим скролла @Input() public mode: ScrollMode = ScrollMode.Vertical; // Тип слайдера @Input() public type: SliderType = SliderType.Default; // Ссылка на область отображения @ViewChild('viewportRef') public viewportRef: ElementRef; // Ссылка на область контента @ViewChild('canvasRef') 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(); } }