type fixes: (#48)

- assigned proper types for all the 'any'
- changed let to const in all the appropriate places
- removed unused code and variables
- add 'private' access for all the internal stuff
This commit is contained in:
sergeypayu 2024-08-28 07:18:15 +02:00 committed by GitHub
parent 4651b629cb
commit 65528874b3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 294 additions and 252 deletions

View file

@ -1,5 +1,5 @@
export interface Properties {
element?: string;
element?: HTMLElement;
doubleTap?: boolean;
doubleTapScale?: number;
zoomControlScale?: number;
@ -10,8 +10,7 @@ export interface Properties {
limitPan?: boolean;
minPanScale?: number;
minScale?: number;
eventHandler?: any;
listeners?: string | 'auto' | 'mouse and touch';
listeners?: 'auto' | 'mouse and touch';
wheel?: boolean;
fullImage?: {
path: string;

View file

@ -1,55 +1,49 @@
import { Touches } from './touches';
import { EventType, Touches } from './touches';
import { Properties } from './interfaces';
import { defaultProperties } from './properties';
type PropertyName = keyof Properties;
export class IvyPinch {
properties: Properties = defaultProperties;
touches: any;
element: any;
elementTarget: any;
parentElement: any;
i: number = 0;
private readonly properties: Properties = defaultProperties;
private touches: Touches;
private readonly element: HTMLElement;
private readonly elementTarget: string;
private parentElement: HTMLElement;
public scale: number = 1;
initialScale: number = 1;
elementPosition: any;
eventType: any;
startX: number = 0;
startY: number = 0;
moveX: number = 0;
moveY: number = 0;
initialMoveX: number = 0;
initialMoveY: number = 0;
moveXC: number = 0;
moveYC: number = 0;
lastTap: number = 0;
draggingMode: boolean = false;
distance: number = 0;
doubleTapTimeout: number = 0;
initialDistance: number = 0;
events: any = {};
maxScale!: number;
defaultMaxScale: number = 3;
private initialScale: number = 1;
private elementPosition: DOMRect;
private eventType: EventType;
private startX: number = 0;
private startY: number = 0;
private moveX: number = 0;
private moveY: number = 0;
private initialMoveX: number = 0;
private initialMoveY: number = 0;
private moveXC: number = 0;
private moveYC: number = 0;
private distance: number = 0;
private initialDistance: number = 0;
public maxScale!: number;
private defaultMaxScale: number = 3;
// Minimum scale at which panning works
get minPanScale() {
get minPanScale(): number {
return this.getPropertiesValue('minPanScale');
}
get fullImage() {
get fullImage(): { path: string; minScale?: number } {
return this.properties.fullImage;
}
constructor(properties: any) {
constructor(properties: Properties) {
this.element = properties.element;
if (!this.element) {
return;
}
if(typeof properties.limitZoom === 'number')
if (typeof properties.limitZoom === 'number') {
this.maxScale = properties.limitZoom;
}
this.elementTarget = this.element.querySelector('*').tagName;
this.parentElement = this.element.parentElement;
this.properties = Object.assign({}, defaultProperties, properties);
@ -96,8 +90,8 @@ export class IvyPinch {
/* Touchstart */
handleTouchstart = (event: any) => {
this.touches.addEventListeners('mousemove', 'handleMousemove');
private handleTouchstart = (event: TouchEvent | MouseEvent): void => {
this.touches.addEventListeners('mousemove');
this.getElementPosition();
if (this.eventType === undefined) {
@ -107,12 +101,10 @@ export class IvyPinch {
/* Touchend */
handleTouchend = (event: any) => {
private handleTouchend = (event: TouchEvent | MouseEvent): void => {
/* touchend */
if (event.type === 'touchend') {
this.i = 0;
this.draggingMode = false;
const touches = event.touches;
const touches = (event as TouchEvent).touches;
// Min scale
if (this.scale < 1) {
@ -148,19 +140,18 @@ export class IvyPinch {
/* mouseup */
if (event.type === 'mouseup') {
this.draggingMode = false;
this.updateInitialValues();
this.eventType = undefined;
}
this.touches.removeEventListeners('mousemove', 'handleMousemove');
this.touches.removeEventListeners('mousemove');
};
/*
* Handlers
*/
handlePan = (event: any) => {
private handlePan = (event: TouchEvent | MouseEvent): void => {
if (this.scale < this.minPanScale || this.properties.disablePan) {
return;
}
@ -190,12 +181,12 @@ export class IvyPinch {
this.transformElement(0);
};
handleDoubleTap = (event: any) => {
private handleDoubleTap = (event: TouchEvent): void => {
this.toggleZoom(event);
return;
};
handlePinch = (event: any) => {
private handlePinch = (event: TouchEvent): void => {
event.preventDefault();
if (this.eventType === undefined || this.eventType === 'pinch') {
@ -230,11 +221,11 @@ export class IvyPinch {
}
};
handleWheel = (event: any) => {
private handleWheel = (event: WheelEvent): void => {
event.preventDefault();
let wheelZoomFactor = this.properties.wheelZoomFactor || 0;
let zoomFactor = event.deltaY < 0 ? wheelZoomFactor : -wheelZoomFactor;
const wheelZoomFactor = this.properties.wheelZoomFactor || 0;
const zoomFactor = event.deltaY < 0 ? wheelZoomFactor : -wheelZoomFactor;
let newScale = this.initialScale + zoomFactor;
/* Round value */
@ -256,8 +247,8 @@ export class IvyPinch {
this.scale = newScale;
/* Get cursor position over image */
let xCenter = event.clientX - this.elementPosition.left - this.initialMoveX;
let yCenter = event.clientY - this.elementPosition.top - this.initialMoveY;
const xCenter = event.clientX - this.elementPosition.left - this.initialMoveX;
const yCenter = event.clientY - this.elementPosition.top - this.initialMoveY;
this.setZoom({
scale: newScale,
@ -265,11 +256,11 @@ export class IvyPinch {
});
};
handleResize = (_event: any) => {
private handleResize = (_event: Event): void => {
this.setAutoHeight();
};
handleLimitZoom() {
private handleLimitZoom(): void {
const limitZoom = this.maxScale;
const minScale = this.properties.minScale || 0;
@ -297,12 +288,12 @@ export class IvyPinch {
}
}
moveLeft(event: any, index: number = 0) {
private moveLeft(event: TouchEvent | MouseEvent, index: number = 0): number {
const clientX = this.getClientPosition(event, index).clientX;
return clientX - this.elementPosition.left;
}
moveTop(event: any, index: number = 0) {
private moveTop(event: TouchEvent | MouseEvent, index: number = 0): number {
const clientY = this.getClientPosition(event, index).clientY;
return clientY - this.elementPosition.top;
}
@ -311,8 +302,8 @@ export class IvyPinch {
* Detection
*/
centeringImage() {
const img = this.element.getElementsByTagName(this.elementTarget)[0];
private centeringImage(): boolean {
const img = this.getImageElement();
const initialMoveX = this.moveX;
const initialMoveY = this.moveY;
@ -336,7 +327,7 @@ export class IvyPinch {
return initialMoveX !== this.moveX || initialMoveY !== this.moveY;
}
limitPanY() {
private limitPanY(): void {
const imgHeight = this.getImageHeight();
const scaledImgHeight = imgHeight * this.scale;
const parentHeight = this.parentElement.offsetHeight;
@ -355,7 +346,7 @@ export class IvyPinch {
}
}
limitPanX() {
private limitPanX(): void {
const imgWidth = this.getImageWidth();
const scaledImgWidth = imgWidth * this.scale;
const parentWidth = this.parentElement.offsetWidth;
@ -374,7 +365,7 @@ export class IvyPinch {
}
}
setBasicStyles() {
private setBasicStyles(): void {
this.element.style.display = 'flex';
this.element.style.alignItems = 'center';
this.element.style.justifyContent = 'center';
@ -383,7 +374,7 @@ export class IvyPinch {
this.setDraggableImage();
}
removeBasicStyles() {
private removeBasicStyles(): void {
this.element.style.display = '';
this.element.style.alignItems = '';
this.element.style.justifyContent = '';
@ -392,7 +383,7 @@ export class IvyPinch {
this.removeDraggableImage();
}
setDraggableImage() {
private setDraggableImage(): void {
const imgElement = this.getImageElement();
if (imgElement) {
@ -400,7 +391,7 @@ export class IvyPinch {
}
}
removeDraggableImage() {
private removeDraggableImage(): void {
const imgElement = this.getImageElement();
if (imgElement) {
@ -408,8 +399,8 @@ export class IvyPinch {
}
}
setImageSize() {
const imgElement = this.element.getElementsByTagName(this.elementTarget);
private setImageSize(): void {
const imgElement = this.getImageElements();
if (imgElement.length) {
imgElement[0].style.maxWidth = '100%';
@ -419,8 +410,8 @@ export class IvyPinch {
}
}
setAutoHeight() {
const imgElement = this.element.getElementsByTagName(this.elementTarget);
private setAutoHeight(): void {
const imgElement = this.getImageElements();
if (!this.properties.autoHeight || !imgElement.length) {
return;
@ -428,14 +419,14 @@ export class IvyPinch {
const imgNaturalWidth = imgElement[0].getAttribute('width');
const imgNaturalHeight = imgElement[0].getAttribute('height');
const sizeRatio = imgNaturalWidth / imgNaturalHeight;
const sizeRatio = +imgNaturalWidth / +imgNaturalHeight;
const parentWidth = this.parentElement.offsetWidth;
imgElement[0].style.maxHeight = parentWidth / sizeRatio + 'px';
}
removeImageSize() {
const imgElement = this.element.getElementsByTagName(this.elementTarget);
private removeImageSize(): void {
const imgElement = this.getImageElements();
if (imgElement.length) {
imgElement[0].style.maxWidth = '';
@ -443,28 +434,28 @@ export class IvyPinch {
}
}
getElementPosition() {
private getElementPosition(): void {
this.elementPosition = this.element.parentElement.getBoundingClientRect();
}
getTouchstartPosition(event: any) {
private getTouchstartPosition(event: TouchEvent | MouseEvent): void {
const { clientX, clientY } = this.getClientPosition(event);
this.startX = clientX - this.elementPosition.left;
this.startY = clientY - this.elementPosition.top;
}
getClientPosition(event: any, index: number = 0) {
let clientX;
let clientY;
private getClientPosition(event: TouchEvent | MouseEvent, index: number = 0): { clientX: number; clientY: number } {
let clientX: number;
let clientY: number;
if (event.type === 'touchstart' || event.type === 'touchmove') {
clientX = event.touches[index].clientX;
clientY = event.touches[index].clientY;
clientX = (event as TouchEvent).touches[index].clientX;
clientY = (event as TouchEvent).touches[index].clientY;
}
if (event.type === 'mousedown' || event.type === 'mousemove') {
clientX = event.clientX;
clientY = event.clientY;
clientX = (event as MouseEvent).clientX;
clientY = (event as MouseEvent).clientY;
}
return {
@ -473,7 +464,7 @@ export class IvyPinch {
};
}
resetScale() {
private resetScale(): void {
this.scale = 1;
this.moveX = 0;
this.moveY = 0;
@ -481,33 +472,43 @@ export class IvyPinch {
this.transformElement(this.properties.transitionDuration);
}
updateInitialValues() {
private updateInitialValues(): void {
this.initialScale = this.scale;
this.initialMoveX = this.moveX;
this.initialMoveY = this.moveY;
}
getDistance(touches: any) {
return Math.sqrt(Math.pow(touches[0].pageX - touches[1].pageX, 2) + Math.pow(touches[0].pageY - touches[1].pageY, 2));
private getDistance(touches: TouchList): number {
return Math.sqrt(
Math.pow(touches[0].pageX - touches[1].pageX, 2) + Math.pow(touches[0].pageY - touches[1].pageY, 2),
);
}
getImageHeight() {
const img = this.element.getElementsByTagName(this.elementTarget)[0];
private getImageHeight(): number {
const img = this.getImageElement() as HTMLImageElement;
return img.offsetHeight;
}
getImageWidth() {
const img = this.element.getElementsByTagName(this.elementTarget)[0];
private getImageWidth(): number {
const img = this.getImageElement() as HTMLImageElement;
return img.offsetWidth;
}
transformElement(duration: any) {
private transformElement(duration: number): void {
this.element.style.transition = 'all ' + duration + 'ms';
this.element.style.transform =
'matrix(' + Number(this.scale) + ', 0, 0, ' + Number(this.scale) + ', ' + Number(this.moveX) + ', ' + Number(this.moveY) + ')';
'matrix(' +
Number(this.scale) +
', 0, 0, ' +
Number(this.scale) +
', ' +
Number(this.moveX) +
', ' +
Number(this.moveY) +
')';
}
isTouchScreen() {
private isTouchScreen(): boolean {
const prefixes = ' -webkit- -moz- -o- -ms- '.split(' ');
if ('ontouchstart' in window) {
@ -520,11 +521,11 @@ export class IvyPinch {
return this.getMatchMedia(query);
}
getMatchMedia(query: any) {
private getMatchMedia(query: string): boolean {
return window.matchMedia(query).matches;
}
isDragging() {
public isDragging(): boolean {
if (this.properties.disablePan) {
return false;
}
@ -533,7 +534,10 @@ export class IvyPinch {
const imgWidth = this.getImageWidth();
if (this.scale > 1) {
return imgHeight * this.scale > this.parentElement.offsetHeight || imgWidth * this.scale > this.parentElement.offsetWidth;
return (
imgHeight * this.scale > this.parentElement.offsetHeight ||
imgWidth * this.scale > this.parentElement.offsetWidth
);
}
if (this.scale === 1) {
return imgHeight > this.parentElement.offsetHeight || imgWidth > this.parentElement.offsetWidth;
@ -542,7 +546,7 @@ export class IvyPinch {
return undefined;
}
detectLimitZoom() {
public detectLimitZoom(): void {
// Assign to default only if it is not passed through constructor
this.maxScale ??= this.defaultMaxScale;
@ -552,9 +556,9 @@ export class IvyPinch {
}
}
pollLimitZoomForOriginalImage() {
let poll = setInterval(() => {
let maxScaleForOriginalImage = this.getMaxScaleForOriginalImage();
private pollLimitZoomForOriginalImage(): void {
const poll = setInterval(() => {
const maxScaleForOriginalImage = this.getMaxScaleForOriginalImage();
if (typeof maxScaleForOriginalImage === 'number') {
this.maxScale = maxScaleForOriginalImage;
clearInterval(poll);
@ -562,9 +566,9 @@ export class IvyPinch {
}, 10);
}
getMaxScaleForOriginalImage() {
private getMaxScaleForOriginalImage(): number {
let maxScale!: number;
let img = this.element.getElementsByTagName('img')[0];
const img = this.element.getElementsByTagName('img')[0];
if (img.naturalWidth && img.offsetWidth) {
maxScale = img.naturalWidth / img.offsetWidth;
@ -573,29 +577,35 @@ export class IvyPinch {
return maxScale;
}
getImageElement() {
private getImageElement(): HTMLElement {
const imgElement = this.element.getElementsByTagName(this.elementTarget);
if (imgElement.length) {
return imgElement[0];
return imgElement[0] as HTMLElement;
}
}
toggleZoom(event: any = false) {
private getImageElements(): HTMLCollectionOf<HTMLElement> {
return this.element.getElementsByTagName(this.elementTarget) as HTMLCollectionOf<HTMLElement>;
}
public toggleZoom(event: TouchEvent | boolean = false): void {
if (this.initialScale === 1) {
if (event && event.changedTouches) {
if (event && (event as TouchEvent).changedTouches) {
if (this.properties.doubleTapScale === undefined) {
return;
}
const changedTouches = event.changedTouches;
const changedTouches = (event as TouchEvent).changedTouches;
this.scale = this.initialScale * this.properties.doubleTapScale;
this.moveX =
this.initialMoveX - (changedTouches[0].clientX - this.elementPosition.left) * (this.properties.doubleTapScale - 1);
this.initialMoveX -
(changedTouches[0].clientX - this.elementPosition.left) * (this.properties.doubleTapScale - 1);
this.moveY =
this.initialMoveY - (changedTouches[0].clientY - this.elementPosition.top) * (this.properties.doubleTapScale - 1);
this.initialMoveY -
(changedTouches[0].clientY - this.elementPosition.top) * (this.properties.doubleTapScale - 1);
} else {
let zoomControlScale = this.properties.zoomControlScale || 0;
const zoomControlScale = this.properties.zoomControlScale || 0;
this.scale = this.initialScale * (zoomControlScale + 1);
this.moveX = this.initialMoveX - (this.element.offsetWidth * (this.scale - 1)) / 2;
this.moveY = this.initialMoveY - (this.element.offsetHeight * (this.scale - 1)) / 2;
@ -609,14 +619,14 @@ export class IvyPinch {
}
}
setZoom(properties: { scale: number; center?: number[] }) {
private setZoom(properties: { scale: number; center?: number[] }): void {
this.scale = properties.scale;
let xCenter;
let yCenter;
let visibleAreaWidth = this.element.offsetWidth;
let visibleAreaHeight = this.element.offsetHeight;
let scalingPercent = (visibleAreaWidth * this.scale) / (visibleAreaWidth * this.initialScale);
const visibleAreaWidth = this.element.offsetWidth;
const visibleAreaHeight = this.element.offsetHeight;
const scalingPercent = (visibleAreaWidth * this.scale) / (visibleAreaWidth * this.initialScale);
if (properties.center) {
xCenter = properties.center[0];
@ -634,7 +644,7 @@ export class IvyPinch {
this.transformElement(this.properties.transitionDuration);
}
alignImage() {
private alignImage(): void {
const isMoveChanged = this.centeringImage();
if (isMoveChanged) {
@ -643,12 +653,12 @@ export class IvyPinch {
}
}
destroy() {
public destroy(): void {
this.removeBasicStyles();
this.touches.destroy();
}
getPropertiesValue(propertyName: PropertyName) {
private getPropertiesValue<K extends keyof Properties>(propertyName: K): Properties[K] {
if (this.properties && this.properties[propertyName]) {
return this.properties[propertyName];
} else {

View file

@ -1,11 +1,12 @@
<div class="pinch-zoom-content" [class.pz-dragging]="isDragging">
<ng-content></ng-content>
<ng-content></ng-content>
</div>
<!-- Control: one button -->
<div
@if (isControl()) {
<div
class="pz-zoom-button pz-zoom-control-position-bottom"
[class.pz-zoom-button-out]="isZoomedIn"
*ngIf="isControl()"
(click)="toggleZoom()"
></div>
></div>
}

View file

@ -1,4 +1,4 @@
import { ChangeDetectorRef, Component, ElementRef, HostBinding, HostListener, Input, OnDestroy, SimpleChanges } from '@angular/core';
import { Component, ElementRef, HostBinding, Input, OnChanges, OnDestroy, OnInit, SimpleChanges } from '@angular/core';
import { Properties } from './interfaces';
import { defaultProperties, backwardCompatibilityProperties } from './properties';
@ -17,24 +17,21 @@ export const _defaultComponentProperties: ComponentProperties = {
backgroundColor: 'rgba(0,0,0,0.85)',
};
type PropertyName = keyof ComponentProperties;
@Component({
selector: 'pinch-zoom, [pinch-zoom]',
exportAs: 'pinchZoom',
templateUrl: './pinch-zoom.component.html',
styleUrls: ['./pinch-zoom.component.sass'],
})
export class PinchZoomComponent implements OnDestroy {
pinchZoom: any;
_properties!: ComponentProperties;
defaultComponentProperties!: ComponentProperties;
zoomControlPositionClass: string | undefined;
_transitionDuration!: number;
_doubleTap!: boolean;
_doubleTapScale!: number;
_autoZoomOut!: boolean;
_limitZoom!: number | 'original image size';
export class PinchZoomComponent implements OnInit, OnDestroy, OnChanges {
private pinchZoom: IvyPinch;
private _properties!: ComponentProperties;
private readonly defaultComponentProperties!: ComponentProperties;
private _transitionDuration!: number;
private _doubleTap!: boolean;
private _doubleTapScale!: number;
private _autoZoomOut!: boolean;
private _limitZoom!: number | 'original image size';
@Input('properties') set properties(value: ComponentProperties) {
if (value) {
@ -42,7 +39,7 @@ export class PinchZoomComponent implements OnDestroy {
}
}
get properties() {
get properties(): ComponentProperties {
return this._properties;
}
@ -59,7 +56,7 @@ export class PinchZoomComponent implements OnDestroy {
}
}
get transitionDuration() {
get transitionDuration(): number {
return this._transitionDuration;
}
@ -76,7 +73,7 @@ export class PinchZoomComponent implements OnDestroy {
}
}
get doubleTap() {
get doubleTap(): boolean {
return this._doubleTap;
}
@ -93,7 +90,7 @@ export class PinchZoomComponent implements OnDestroy {
}
}
get doubleTapScale() {
get doubleTapScale(): number {
return this._doubleTapScale;
}
@ -110,7 +107,7 @@ export class PinchZoomComponent implements OnDestroy {
}
}
get autoZoomOut() {
get autoZoomOut(): boolean {
return this._autoZoomOut;
}
@ -127,7 +124,7 @@ export class PinchZoomComponent implements OnDestroy {
}
}
get limitZoom() {
get limitZoom(): number | 'original image size' {
return this._limitZoom;
}
@ -147,18 +144,18 @@ export class PinchZoomComponent implements OnDestroy {
@Input() draggableImage!: boolean;
@HostBinding('style.overflow')
get hostOverflow() {
get hostOverflow(): 'hidden' | 'visible' {
return this.properties['overflow'];
}
@HostBinding('style.background-color')
get hostBackgroundColor() {
get hostBackgroundColor(): string {
return this.properties['backgroundColor'];
}
get isTouchScreen() {
var prefixes = ' -webkit- -moz- -o- -ms- '.split(' ');
var mq = function (query: any) {
get isTouchScreen(): boolean {
const prefixes = ' -webkit- -moz- -o- -ms- '.split(' ');
const mq = (query: string): boolean => {
return window.matchMedia(query).matches;
};
@ -168,79 +165,81 @@ export class PinchZoomComponent implements OnDestroy {
// include the 'heartz' as a way to have a non matching MQ to help terminate the join
// https://git.io/vznFH
var query = ['(', prefixes.join('touch-enabled),('), 'heartz', ')'].join('');
const query = ['(', prefixes.join('touch-enabled),('), 'heartz', ')'].join('');
return mq(query);
}
get isDragging() {
return this.pinchZoom ? this.pinchZoom.isDragging() : undefined;
get isDragging(): boolean {
return this.pinchZoom?.isDragging();
}
get isDisabled() {
return this.properties['disabled'];
get isDisabled(): boolean {
return this._properties.disabled;
}
get scale() {
get scale(): number {
return this.pinchZoom.scale;
}
get isZoomedIn() {
get isZoomedIn(): boolean {
return this.scale > 1;
}
get scaleLevel() {
get scaleLevel(): number {
return Math.round(this.scale / this._zoomControlScale);
}
get maxScale() {
get maxScale(): number {
return this.pinchZoom.maxScale;
}
get isZoomLimitReached() {
get isZoomLimitReached(): boolean {
return this.scale >= this.maxScale;
}
get _zoomControlScale() {
get _zoomControlScale(): number {
return this.getPropertiesValue('zoomControlScale');
}
constructor(private elementRef: ElementRef) {
constructor(private elementRef: ElementRef<HTMLElement>) {
this.defaultComponentProperties = this.getDefaultComponentProperties();
this.applyPropertiesDefault(this.defaultComponentProperties, {});
}
ngOnInit() {
ngOnInit(): void {
this.initPinchZoom();
/* Calls the method until the image size is available */
this.detectLimitZoom();
}
ngOnChanges(changes: SimpleChanges) {
ngOnChanges(changes: SimpleChanges): void {
let changedProperties = this.getProperties(changes);
changedProperties = this.renameProperties(changedProperties);
this.applyPropertiesDefault(this.defaultComponentProperties, changedProperties);
}
ngOnDestroy() {
ngOnDestroy(): void {
this.destroy();
}
initPinchZoom() {
if (this.properties['disabled']) {
private initPinchZoom(): void {
if (this._properties.disabled) {
return;
}
this.properties.limitZoom = this.limitZoom;
this.properties['element'] = this.elementRef.nativeElement.querySelector('.pinch-zoom-content');
this._properties.limitZoom = this.limitZoom;
this._properties.element = this.elementRef.nativeElement.querySelector('.pinch-zoom-content');
this.pinchZoom = new IvyPinch(this.properties);
}
getProperties(changes: SimpleChanges) {
let properties: any = {};
private getProperties(
changes: SimpleChanges,
): ComponentProperties | Record<keyof typeof backwardCompatibilityProperties, unknown> {
let properties: ComponentProperties = {};
for (var prop in changes) {
for (const prop in changes) {
if (prop !== 'properties') {
properties[prop] = changes[prop].currentValue;
}
@ -251,52 +250,52 @@ export class PinchZoomComponent implements OnDestroy {
return properties;
}
renameProperties(properties: any) {
for (var prop in properties) {
private renameProperties(
properties: ComponentProperties | Record<keyof typeof backwardCompatibilityProperties, unknown>,
): ComponentProperties {
for (const prop in properties) {
if (backwardCompatibilityProperties[prop]) {
properties[backwardCompatibilityProperties[prop]] = properties[prop];
delete properties[prop];
}
}
return properties;
return properties as ComponentProperties;
}
applyPropertiesDefault(defaultProperties: ComponentProperties, properties: ComponentProperties): void {
private applyPropertiesDefault(defaultProperties: ComponentProperties, properties: ComponentProperties): void {
this.properties = Object.assign({}, defaultProperties, properties);
}
toggleZoom() {
this.pinchZoom.toggleZoom();
toggleZoom(): void {
this.pinchZoom?.toggleZoom();
}
isControl() {
isControl(): boolean {
if (this.isDisabled) {
return false;
}
if (this.properties['disableZoomControl'] === 'disable') {
if (this._properties.disableZoomControl === 'disable') {
return false;
}
if (this.isTouchScreen && this.properties['disableZoomControl'] === 'auto') {
if (this.isTouchScreen && this._properties.disableZoomControl === 'auto') {
return false;
}
return true;
}
detectLimitZoom() {
if (this.pinchZoom) {
this.pinchZoom.detectLimitZoom();
}
detectLimitZoom(): void {
this.pinchZoom?.detectLimitZoom();
}
destroy() {
if (this.pinchZoom) this.pinchZoom.destroy();
destroy(): void {
this.pinchZoom?.destroy();
}
getPropertiesValue(propertyName: PropertyName) {
private getPropertiesValue<K extends keyof ComponentProperties>(propertyName: K): ComponentProperties[K] {
if (this.properties && this.properties[propertyName]) {
return this.properties[propertyName];
} else {
@ -304,7 +303,7 @@ export class PinchZoomComponent implements OnDestroy {
}
}
getDefaultComponentProperties() {
private getDefaultComponentProperties(): ComponentProperties {
return { ...defaultProperties, ..._defaultComponentProperties };
}
}

View file

@ -15,7 +15,7 @@ export const defaultProperties: Properties = {
draggableImage: false,
};
export const backwardCompatibilityProperties: any = {
export const backwardCompatibilityProperties = {
'transition-duration': 'transitionDuration',
transitionDurationBackwardCompatibility: 'transitionDuration',
'double-tap': 'doubleTap',

View file

@ -1,56 +1,77 @@
export interface Properties {
element: HTMLElement;
listeners?: 'auto' | 'mouse and touch';
touchListeners?: any;
mouseListeners?: any;
otherListeners?: any;
touchListeners?: TouchListeners;
mouseListeners?: MouseListeners;
otherListeners?: OtherListeners;
resize?: boolean;
}
export type EventType = undefined | 'touchend' | 'pan' | 'pinch' | 'horizontal-swipe' | 'vertical-swipe' | 'tap' | 'longtap';
export type TouchHandler = 'handleTouchstart' | 'handleTouchmove' | 'handleTouchend';
export type MouseHandler = 'handleMousedown' | 'handleMousemove' | 'handleMouseup';
export type EventType =
| undefined
| 'touchstart'
| 'touchend'
| 'touchmove'
| 'mousedown'
| 'mouseup'
| 'mousemove'
| 'pan'
| 'pinch'
| 'horizontal-swipe'
| 'vertical-swipe'
| 'tap'
| 'longtap'
| 'wheel'
| 'double-tap'
| 'resize';
export type TouchHandler ='handleTouchstart' | 'handleTouchmove' | 'handleTouchend';
export type MouseHandler = 'handleMousedown' | 'handleMousemove' | 'handleMouseup' | 'handleWheel';
export type OtherHandler = 'handleResize';
export type TouchListeners = Partial<Record<'touchstart' | 'touchmove' | 'touchend', TouchHandler>>;
export type MouseListeners = Partial<Record<'mousedown' | 'mousemove' | 'mouseup' | 'wheel', MouseHandler>>;
export type OtherListeners = Partial<Record<'resize', OtherHandler>>;
export class Touches {
properties: Properties;
element: HTMLElement;
elementPosition: ClientRect;
eventType: EventType = undefined;
handlers: any = {};
startX = 0;
startY = 0;
lastTap = 0;
doubleTapTimeout: any;
doubleTapMinTimeout = 300;
tapMinTimeout = 200;
touchstartTime = 0;
i: number = 0;
isMousedown = false;
private properties: Properties;
private element: HTMLElement;
private elementPosition: DOMRect;
private eventType: EventType = undefined;
private handlers: TouchListeners | MouseListeners | OtherListeners = {};
private startX = 0;
private startY = 0;
private lastTap = 0;
private doubleTapTimeout: number;
private doubleTapMinTimeout = 300;
private tapMinTimeout = 200;
private touchstartTime = 0;
private i: number = 0;
private isMousedown = false;
_touchListeners: any = {
private _touchListeners: Record<'touchstart' | 'touchmove' | 'touchend', TouchHandler> = {
touchstart: 'handleTouchstart',
touchmove: 'handleTouchmove',
touchend: 'handleTouchend',
};
_mouseListeners: any = {
private _mouseListeners: Record<'mousedown' | 'mousemove' | 'mouseup' | 'wheel', MouseHandler> = {
mousedown: 'handleMousedown',
mousemove: 'handleMousemove',
mouseup: 'handleMouseup',
wheel: 'handleWheel',
};
_otherListeners: any = {
private _otherListeners: Record<'resize', OtherHandler> = {
resize: 'handleResize',
};
get touchListeners() {
private get touchListeners(): TouchListeners {
return this.properties.touchListeners ? this.properties.touchListeners : this._touchListeners;
}
get mouseListeners() {
private get mouseListeners(): MouseListeners {
return this.properties.mouseListeners ? this.properties.mouseListeners : this._mouseListeners;
}
get otherListeners() {
private get otherListeners(): OtherListeners {
return this.properties.otherListeners ? this.properties.otherListeners : this._otherListeners;
}
@ -62,12 +83,12 @@ export class Touches {
this.toggleEventListeners('addEventListener');
}
destroy() {
public destroy(): void {
this.toggleEventListeners('removeEventListener');
}
toggleEventListeners(action: 'addEventListener' | 'removeEventListener') {
let listeners;
private toggleEventListeners(action: 'addEventListener' | 'removeEventListener'): void {
let listeners: TouchListeners | MouseListeners | OtherListeners;
if (this.properties.listeners === 'mouse and touch') {
listeners = Object.assign(this.touchListeners, this.mouseListeners);
@ -79,8 +100,8 @@ export class Touches {
listeners = Object.assign(listeners, this.otherListeners);
}
for (var listener in listeners) {
const handler: MouseHandler = listeners[listener];
for (const listener in listeners) {
const handler = listeners[listener];
// Window
if (listener === 'resize') {
@ -110,12 +131,12 @@ export class Touches {
}
}
addEventListeners(listener: string) {
public addEventListeners(listener: string): void {
const handler: MouseHandler = this._mouseListeners[listener];
window.addEventListener(listener, this[handler], false);
}
removeEventListeners(listener: string) {
public removeEventListeners(listener: string): void {
const handler: MouseHandler = this._mouseListeners[listener];
window.removeEventListener(listener, this[handler], false);
}
@ -126,7 +147,7 @@ export class Touches {
/* Touchstart */
handleTouchstart = (event: any) => {
private handleTouchstart = (event: TouchEvent): void => {
this.elementPosition = this.getElementPosition();
this.touchstartTime = new Date().getTime();
@ -139,7 +160,7 @@ export class Touches {
/* Touchmove */
handleTouchmove = (event: any) => {
private handleTouchmove = (event: TouchEvent): void => {
const touches = event.touches;
// Pan
@ -153,7 +174,7 @@ export class Touches {
}
};
handleLinearSwipe(event: any) {
private handleLinearSwipe(event: any): void {
//event.preventDefault();
this.i++;
@ -173,7 +194,7 @@ export class Touches {
/* Touchend */
handleTouchend = (event: any) => {
private handleTouchend = (event: TouchEvent): void => {
const touches = event.touches;
// Double Tap
@ -195,7 +216,7 @@ export class Touches {
/* Mousedown */
handleMousedown = (event: any) => {
private handleMousedown = (event: MouseEvent): void => {
this.isMousedown = true;
this.elementPosition = this.getElementPosition();
this.touchstartTime = new Date().getTime();
@ -209,7 +230,7 @@ export class Touches {
/* Mousemove */
handleMousemove = (event: any) => {
private handleMousemove = (event: MouseEvent): void => {
//event.preventDefault();
if (!this.isMousedown) {
@ -222,24 +243,32 @@ export class Touches {
// Linear swipe
switch (this.detectLinearSwipe(event)) {
case 'horizontal-swipe':
// FIXME: looks like an error
// @ts-ignore
event.swipeType = 'horizontal-swipe';
this.runHandler('horizontal-swipe', event);
break;
case 'vertical-swipe':
// FIXME: looks like an error
// @ts-ignore
event.swipeType = 'vertical-swipe';
this.runHandler('vertical-swipe', event);
break;
}
// Linear swipe
if (this.detectLinearSwipe(event) || this.eventType === 'horizontal-swipe' || this.eventType === 'vertical-swipe') {
if (
this.detectLinearSwipe(event) ||
this.eventType === 'horizontal-swipe' ||
this.eventType === 'vertical-swipe'
) {
this.handleLinearSwipe(event);
}
};
/* Mouseup */
handleMouseup = (event: any) => {
private handleMouseup = (event: MouseEvent): void => {
// Tap
this.detectTap();
@ -251,19 +280,19 @@ export class Touches {
/* Wheel */
handleWheel = (event: any) => {
private handleWheel = (event: WheelEvent): void => {
this.runHandler('wheel', event);
};
/* Resize */
handleResize = (event: any) => {
private handleResize = (event: Event): void => {
this.runHandler('resize', event);
};
runHandler(eventName: any, response: any) {
private runHandler(eventName: EventType, event: unknown):void {
if (this.handlers[eventName]) {
this.handlers[eventName](response);
this.handlers[eventName](event);
}
}
@ -271,11 +300,11 @@ export class Touches {
* Detection
*/
detectPan(touches: any) {
private detectPan(touches: TouchList): boolean {
return (touches.length === 1 && !this.eventType) || this.eventType === 'pan';
}
detectDoubleTap() {
private detectDoubleTap(): boolean {
if (this.eventType != undefined) {
return;
}
@ -283,13 +312,13 @@ export class Touches {
const currentTime = new Date().getTime();
const tapLength = currentTime - this.lastTap;
clearTimeout(this.doubleTapTimeout);
window.clearTimeout(this.doubleTapTimeout);
if (tapLength < this.doubleTapMinTimeout && tapLength > 0) {
return true;
} else {
this.doubleTapTimeout = setTimeout(() => {
clearTimeout(this.doubleTapTimeout);
this.doubleTapTimeout = window.setTimeout(() => {
window.clearTimeout(this.doubleTapTimeout);
}, this.doubleTapMinTimeout);
}
this.lastTap = currentTime;
@ -297,7 +326,7 @@ export class Touches {
return undefined;
}
detectTap(): void {
private detectTap(): void {
if (this.eventType != undefined) {
return;
}
@ -314,16 +343,20 @@ export class Touches {
}
}
detectPinch(event: any) {
private detectPinch(event: TouchEvent): boolean {
const touches = event.touches;
return (touches.length === 2 && this.eventType === undefined) || this.eventType === 'pinch';
}
detectLinearSwipe(event: any) {
const touches = event.touches;
private detectLinearSwipe(event: MouseEvent | TouchEvent): 'vertical-swipe' | 'horizontal-swipe' {
const touches = (event as TouchEvent).touches;
if (touches) {
if ((touches.length === 1 && !this.eventType) || this.eventType === 'horizontal-swipe' || this.eventType === 'vertical-swipe') {
if (
(touches.length === 1 && !this.eventType) ||
this.eventType === 'horizontal-swipe' ||
this.eventType === 'vertical-swipe'
) {
return this.getLinearSwipeType(event);
}
} else {
@ -335,7 +368,7 @@ export class Touches {
return undefined;
}
getLinearSwipeType(event: any) {
private getLinearSwipeType(event: TouchEvent | MouseEvent): 'vertical-swipe' | 'horizontal-swipe' {
if (this.eventType !== 'horizontal-swipe' && this.eventType !== 'vertical-swipe') {
const movementX = Math.abs(this.moveLeft(0, event) - this.startX);
const movementY = Math.abs(this.moveTop(0, event) - this.startY);
@ -350,43 +383,43 @@ export class Touches {
}
}
getElementPosition() {
private getElementPosition(): DOMRect {
return this.element.getBoundingClientRect();
}
getTouchstartPosition(event: any) {
private getTouchstartPosition(event: TouchEvent): void {
this.startX = event.touches[0].clientX - this.elementPosition.left;
this.startY = event.touches[0].clientY - this.elementPosition.top;
}
getMousedownPosition(event: any) {
private getMousedownPosition(event: MouseEvent): void {
this.startX = event.clientX - this.elementPosition.left;
this.startY = event.clientY - this.elementPosition.top;
}
moveLeft(index: any, event: any) {
const touches = event.touches;
private moveLeft(index: number, event: TouchEvent | MouseEvent): number {
const touches = (event as TouchEvent).touches;
if (touches) {
return touches[index].clientX - this.elementPosition.left;
} else {
return event.clientX - this.elementPosition.left;
return (event as MouseEvent).clientX - this.elementPosition.left;
}
}
moveTop(index: any, event: any) {
const touches = event.touches;
private moveTop(index: number, event: TouchEvent | MouseEvent): number {
const touches = (event as TouchEvent).touches;
if (touches) {
return touches[index].clientY - this.elementPosition.top;
} else {
return event.clientY - this.elementPosition.top;
return (event as MouseEvent).clientY - this.elementPosition.top;
}
}
detectTouchScreen() {
var prefixes = ' -webkit- -moz- -o- -ms- '.split(' ');
var mq = function (query: any) {
private detectTouchScreen(): boolean {
const prefixes = ' -webkit- -moz- -o- -ms- '.split(' ');
const mq = (query: string): boolean => {
return window.matchMedia(query).matches;
};
@ -396,12 +429,12 @@ export class Touches {
// include the 'heartz' as a way to have a non matching MQ to help terminate the join
// https://git.io/vznFH
var query = ['(', prefixes.join('touch-enabled),('), 'heartz', ')'].join('');
const query = ['(', prefixes.join('touch-enabled),('), 'heartz', ')'].join('');
return mq(query);
}
/* Public properties and methods */
on(event: EventType, handler: Function) {
public on(event: EventType, handler: (event: Event) => void): void {
if (event) {
this.handlers[event] = handler;
}