white-ui-kit
Version:
Модуль компонентов UI Имя модуля: `white-ui-kit`
241 lines (199 loc) • 7.54 kB
text/typescript
import {
Component,
ElementRef,
Input,
OnDestroy,
OnInit,
Renderer2,
ViewChild,
HostBinding,
} from '@angular/core';
// Сенсор
import { ResizeSensor } from 'css-element-queries';
// Интерфейсы
import { IOffset, ISize } from '../../interfaces';
// Перечисления
import { Direction } from '../../enums';
// Сервисы
import { HitScrollService } from '../../services';
// Компоненты
import { HitSliderComponent } from '../hit-slider/hit-slider.component';
// Скролл
export class HitScrollComponent
implements OnInit, OnDestroy {
constructor(
private readonly scrollService: HitScrollService,
private readonly renderer: Renderer2,
) {
this.scrollService.size$.subscribe({
next: (size: ISize): void => {
this.compensation = size;
},
});
}
// Направление прокрутки
public direction: string;
// Максимальная высота по контенту
private _maxHeight: number;
public set maxHeight(value: number) {
this._maxHeight = value;
}
public get hostBasis() {
return this._maxHeight
? 'auto'
: '';
}
public get hostHeight() {
return this._maxHeight
? Math.min(this._maxHeight, this.canvas.height)
: '';
}
// Ссылка на область оболочки отображения
public wrapperRef: ElementRef;
// Ссылка на область отображения
public viewportRef: ElementRef;
// Ссылка на область контента
public canvasRef: ElementRef;
// Ссылка на вертикальный слайдер
public verticalSlider: HitSliderComponent;
// Ссылка на горизонтальный слайдер
public horizontalSlider: HitSliderComponent;
// Размер одной "линии" для прокрутки (px)
public readonly LINE_SIZE = 10;
// Функции для отключения прослушивания события
private scrollListen: () => void;
// Флаги направлений
public get isHorizontal(): boolean {
return this.direction === Direction.Horizontal;
}
public get isVertical(): boolean {
return this.direction === Direction.Vertical;
}
// Сенсор изменения размера wrapper
private resizeSensorWrapper: any;
// Сенсор изменения размера canvas
private resizeSensorCanvas: any;
// Размер компенсации системных слайдеров
public compensation: ISize;
// Размер области оболочки отображения
public readonly wrapper: ISize = {
width: 0,
height: 0,
};
// Размер области контента
public readonly canvas: ISize = {
width: 0,
height: 0,
};
// Смещение области контента в области отображения
public readonly offset: IOffset = {
left: 0,
top: 0,
};
// Слайдеры
public readonly sliders: any = {
width: 0,
height: 0,
isHorizontal: false,
isVertical: false,
};
// --------------------------------------------------------------------------
// Добавить подписку на скролл
private addScrollHandler(): void {
this.scrollListen = this.renderer.listen(
this.viewportRef.nativeElement,
'scroll',
this.updateOffset.bind(this),
);
}
// Добавить сенсоры
private addSensors(): void {
this.resizeSensorWrapper = new ResizeSensor(
this.wrapperRef.nativeElement,
this.updateWrapper.bind(this),
);
this.resizeSensorCanvas = new ResizeSensor(
this.canvasRef.nativeElement,
this.updateCanvas.bind(this),
);
}
// Удалить сенсоры
private removeSensors(): void {
if (this.resizeSensorWrapper) { this.resizeSensorWrapper.detach(); }
if (this.resizeSensorCanvas) { this.resizeSensorCanvas.detach(); }
}
// Удалить обработчик скролла
private removeScrollHandler(): void {
if (this.scrollListen) { this.scrollListen(); }
}
// Обновить смещения
private updateOffset(): void {
this.offset.left = this.viewportRef.nativeElement.scrollLeft;
this.offset.top = this.viewportRef.nativeElement.scrollTop;
}
// Обновить область оболочки отображения
private updateWrapper(): void {
this.wrapper.width = this.wrapperRef.nativeElement.offsetWidth;
this.wrapper.height = this.wrapperRef.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.sliders.isHorizontal =
!this.isVertical &&
this.canvas.width > this.wrapper.width;
this.sliders.isVertical =
!this.isHorizontal &&
this.canvas.height > this.wrapper.height;
const isBoth = this.sliders.isHorizontal && this.sliders.isVertical;
this.sliders.width = isBoth ? this.verticalSlider.sliderCrossSize : 0;
this.sliders.height = isBoth ? this.horizontalSlider.sliderCrossSize : 0;
});
}
// --------------------------------------------------------------------------
// Обработчик горизонтального перемещения слайдера
public onHorizontalSliderMoved(percent: number): void {
this.viewportRef.nativeElement.scrollLeft =
(this.canvas.width - this.wrapper.width) * percent;
}
// Обработчик вертикального перемещения слайдера
public onVerticalSliderMoved(percent: number): void {
this.viewportRef.nativeElement.scrollTop =
(this.canvas.height - this.wrapper.height) * percent;
}
// Обработчик горизонтальной прокрутки
public onHorizontalScroll(delta: number): void {
this.viewportRef.nativeElement.scrollLeft += delta;
}
// Обработчик вертикальной прокрутки
public onVerticalScroll(delta: number): void {
this.viewportRef.nativeElement.scrollTop += delta;
}
// --------------------------------------------------------------------------
// HOOKS
// Инициализация
public ngOnInit(): void {
this.addScrollHandler();
this.addSensors();
this.updateWrapper();
this.updateCanvas();
}
// Уничтожение
public ngOnDestroy(): void {
this.removeScrollHandler();
this.removeSensors();
}
}