UNPKG

@mapaxe/ngx-pinch-zoom

Version:

Pinch zoom component for Angular 16.

1 lines 93.9 kB
{"version":3,"file":"mapaxe-ngx-pinch-zoom.mjs","sources":["../../../projects/ngx-pinch-zoom/src/lib/properties.ts","../../../projects/ngx-pinch-zoom/src/lib/touches.ts","../../../projects/ngx-pinch-zoom/src/lib/ivypinch.ts","../../../projects/ngx-pinch-zoom/src/lib/pinch-zoom.component.ts","../../../projects/ngx-pinch-zoom/src/lib/pinch-zoom.component.html","../../../projects/ngx-pinch-zoom/src/lib/pinch-zoom.module.ts","../../../projects/ngx-pinch-zoom/src/public-api.ts","../../../projects/ngx-pinch-zoom/src/mapaxe-ngx-pinch-zoom.ts"],"sourcesContent":["import { Properties } from './interfaces';\r\n\r\nexport const defaultProperties: Properties = {\r\n transitionDuration: 200,\r\n doubleTap: true,\r\n doubleTapScale: 2,\r\n limitZoom: 'original image size',\r\n autoZoomOut: false,\r\n zoomControlScale: 1,\r\n minPanScale: 1.0001,\r\n minScale: 0,\r\n listeners: 'mouse and touch',\r\n wheel: true,\r\n wheelZoomFactor: 0.2,\r\n draggableImage: false,\r\n};\r\n\r\nexport const backwardCompatibilityProperties: any = {\r\n 'transition-duration': 'transitionDuration',\r\n transitionDurationBackwardCompatibility: 'transitionDuration',\r\n 'double-tap': 'doubleTap',\r\n doubleTapBackwardCompatibility: 'doubleTap',\r\n 'double-tap-scale': 'doubleTapScale',\r\n doubleTapScaleBackwardCompatibility: 'doubleTapScale',\r\n 'auto-zoom-out': 'autoZoomOut',\r\n autoZoomOutBackwardCompatibility: 'autoZoomOut',\r\n 'limit-zoom': 'limitZoom',\r\n limitZoomBackwardCompatibility: 'limitZoom',\r\n};\r\n","export interface Properties {\r\n element: HTMLElement;\r\n listeners?: 'auto' | 'mouse and touch';\r\n touchListeners?: any;\r\n mouseListeners?: any;\r\n otherListeners?: any;\r\n resize?: boolean;\r\n}\r\n\r\nexport type EventType = undefined | 'touchend' | 'pan' | 'pinch' | 'horizontal-swipe' | 'vertical-swipe' | 'tap' | 'longtap';\r\nexport type TouchHandler = 'handleTouchstart' | 'handleTouchmove' | 'handleTouchend';\r\nexport type MouseHandler = 'handleMousedown' | 'handleMousemove' | 'handleMouseup';\r\n\r\nexport class Touches {\r\n properties: Properties;\r\n element: HTMLElement;\r\n elementPosition: ClientRect;\r\n eventType: EventType = undefined;\r\n handlers: any = {};\r\n startX = 0;\r\n startY = 0;\r\n lastTap = 0;\r\n doubleTapTimeout: any;\r\n doubleTapMinTimeout = 300;\r\n tapMinTimeout = 200;\r\n touchstartTime = 0;\r\n i: number = 0;\r\n isMousedown = false;\r\n\r\n _touchListeners: any = {\r\n touchstart: 'handleTouchstart',\r\n touchmove: 'handleTouchmove',\r\n touchend: 'handleTouchend',\r\n };\r\n _mouseListeners: any = {\r\n mousedown: 'handleMousedown',\r\n mousemove: 'handleMousemove',\r\n mouseup: 'handleMouseup',\r\n wheel: 'handleWheel',\r\n };\r\n _otherListeners: any = {\r\n resize: 'handleResize',\r\n };\r\n\r\n get touchListeners() {\r\n return this.properties.touchListeners ? this.properties.touchListeners : this._touchListeners;\r\n }\r\n\r\n get mouseListeners() {\r\n return this.properties.mouseListeners ? this.properties.mouseListeners : this._mouseListeners;\r\n }\r\n\r\n get otherListeners() {\r\n return this.properties.otherListeners ? this.properties.otherListeners : this._otherListeners;\r\n }\r\n\r\n constructor(properties: Properties) {\r\n this.properties = properties;\r\n this.element = this.properties.element;\r\n this.elementPosition = this.getElementPosition();\r\n\r\n this.toggleEventListeners('addEventListener');\r\n }\r\n\r\n destroy() {\r\n this.toggleEventListeners('removeEventListener');\r\n }\r\n\r\n toggleEventListeners(action: 'addEventListener' | 'removeEventListener') {\r\n let listeners;\r\n\r\n if (this.properties.listeners === 'mouse and touch') {\r\n listeners = Object.assign(this.touchListeners, this.mouseListeners);\r\n } else {\r\n listeners = this.detectTouchScreen() ? this.touchListeners : this.mouseListeners;\r\n }\r\n\r\n if (this.properties.resize) {\r\n listeners = Object.assign(listeners, this.otherListeners);\r\n }\r\n\r\n for (var listener in listeners) {\r\n const handler: MouseHandler = listeners[listener];\r\n\r\n // Window\r\n if (listener === 'resize') {\r\n if (action === 'addEventListener') {\r\n window.addEventListener(listener, this[handler], false);\r\n }\r\n if (action === 'removeEventListener') {\r\n window.removeEventListener(listener, this[handler], false);\r\n }\r\n // Document\r\n } else if (listener === 'mouseup' || listener === 'mousemove') {\r\n if (action === 'addEventListener') {\r\n document.addEventListener(listener, this[handler], false);\r\n }\r\n if (action === 'removeEventListener') {\r\n document.removeEventListener(listener, this[handler], false);\r\n }\r\n // Element\r\n } else {\r\n if (action === 'addEventListener') {\r\n this.element.addEventListener(listener, this[handler], false);\r\n }\r\n if (action === 'removeEventListener') {\r\n this.element.removeEventListener(listener, this[handler], false);\r\n }\r\n }\r\n }\r\n }\r\n\r\n addEventListeners(listener: string) {\r\n const handler: MouseHandler = this._mouseListeners[listener];\r\n window.addEventListener(listener, this[handler], false);\r\n }\r\n\r\n removeEventListeners(listener: string) {\r\n const handler: MouseHandler = this._mouseListeners[listener];\r\n window.removeEventListener(listener, this[handler], false);\r\n }\r\n\r\n /*\r\n * Listeners\r\n */\r\n\r\n /* Touchstart */\r\n\r\n handleTouchstart = (event: any) => {\r\n this.elementPosition = this.getElementPosition();\r\n this.touchstartTime = new Date().getTime();\r\n\r\n if (this.eventType === undefined) {\r\n this.getTouchstartPosition(event);\r\n }\r\n\r\n this.runHandler('touchstart', event);\r\n };\r\n\r\n /* Touchmove */\r\n\r\n handleTouchmove = (event: any) => {\r\n const touches = event.touches;\r\n\r\n // Pan\r\n if (this.detectPan(touches)) {\r\n this.runHandler('pan', event);\r\n }\r\n\r\n // Pinch\r\n if (this.detectPinch(event)) {\r\n this.runHandler('pinch', event);\r\n }\r\n };\r\n\r\n handleLinearSwipe(event: any) {\r\n //event.preventDefault();\r\n\r\n this.i++;\r\n\r\n if (this.i > 3) {\r\n this.eventType = this.getLinearSwipeType(event);\r\n }\r\n\r\n if (this.eventType === 'horizontal-swipe') {\r\n this.runHandler('horizontal-swipe', event);\r\n }\r\n\r\n if (this.eventType === 'vertical-swipe') {\r\n this.runHandler('vertical-swipe', event);\r\n }\r\n }\r\n\r\n /* Touchend */\r\n\r\n handleTouchend = (event: any) => {\r\n const touches = event.touches;\r\n\r\n // Double Tap\r\n if (this.detectDoubleTap()) {\r\n this.runHandler('double-tap', event);\r\n }\r\n\r\n // Tap\r\n this.detectTap();\r\n\r\n this.runHandler('touchend', event);\r\n this.eventType = 'touchend';\r\n\r\n if (touches && touches.length === 0) {\r\n this.eventType = undefined;\r\n this.i = 0;\r\n }\r\n };\r\n\r\n /* Mousedown */\r\n\r\n handleMousedown = (event: any) => {\r\n this.isMousedown = true;\r\n this.elementPosition = this.getElementPosition();\r\n this.touchstartTime = new Date().getTime();\r\n\r\n if (this.eventType === undefined) {\r\n this.getMousedownPosition(event);\r\n }\r\n\r\n this.runHandler('mousedown', event);\r\n };\r\n\r\n /* Mousemove */\r\n\r\n handleMousemove = (event: any) => {\r\n //event.preventDefault();\r\n\r\n if (!this.isMousedown) {\r\n return;\r\n }\r\n\r\n // Pan\r\n this.runHandler('pan', event);\r\n\r\n // Linear swipe\r\n switch (this.detectLinearSwipe(event)) {\r\n case 'horizontal-swipe':\r\n event.swipeType = 'horizontal-swipe';\r\n this.runHandler('horizontal-swipe', event);\r\n break;\r\n case 'vertical-swipe':\r\n event.swipeType = 'vertical-swipe';\r\n this.runHandler('vertical-swipe', event);\r\n break;\r\n }\r\n\r\n // Linear swipe\r\n if (this.detectLinearSwipe(event) || this.eventType === 'horizontal-swipe' || this.eventType === 'vertical-swipe') {\r\n this.handleLinearSwipe(event);\r\n }\r\n };\r\n\r\n /* Mouseup */\r\n\r\n handleMouseup = (event: any) => {\r\n // Tap\r\n this.detectTap();\r\n\r\n this.isMousedown = false;\r\n this.runHandler('mouseup', event);\r\n this.eventType = undefined;\r\n this.i = 0;\r\n };\r\n\r\n /* Wheel */\r\n\r\n handleWheel = (event: any) => {\r\n this.runHandler('wheel', event);\r\n };\r\n\r\n /* Resize */\r\n\r\n handleResize = (event: any) => {\r\n this.runHandler('resize', event);\r\n };\r\n\r\n runHandler(eventName: any, response: any) {\r\n if (this.handlers[eventName]) {\r\n this.handlers[eventName](response);\r\n }\r\n }\r\n\r\n /*\r\n * Detection\r\n */\r\n\r\n detectPan(touches: any) {\r\n return (touches.length === 1 && !this.eventType) || this.eventType === 'pan';\r\n }\r\n\r\n detectDoubleTap() {\r\n if (this.eventType != undefined) {\r\n return;\r\n }\r\n\r\n const currentTime = new Date().getTime();\r\n const tapLength = currentTime - this.lastTap;\r\n\r\n clearTimeout(this.doubleTapTimeout);\r\n\r\n if (tapLength < this.doubleTapMinTimeout && tapLength > 0) {\r\n return true;\r\n } else {\r\n this.doubleTapTimeout = setTimeout(() => {\r\n clearTimeout(this.doubleTapTimeout);\r\n }, this.doubleTapMinTimeout);\r\n }\r\n this.lastTap = currentTime;\r\n\r\n return undefined;\r\n }\r\n\r\n detectTap(): void {\r\n if (this.eventType != undefined) {\r\n return;\r\n }\r\n\r\n const currentTime = new Date().getTime();\r\n const tapLength = currentTime - this.touchstartTime;\r\n\r\n if (tapLength > 0) {\r\n if (tapLength < this.tapMinTimeout) {\r\n this.runHandler('tap', {});\r\n } else {\r\n this.runHandler('longtap', {});\r\n }\r\n }\r\n }\r\n\r\n detectPinch(event: any) {\r\n const touches = event.touches;\r\n return (touches.length === 2 && this.eventType === undefined) || this.eventType === 'pinch';\r\n }\r\n\r\n detectLinearSwipe(event: any) {\r\n const touches = event.touches;\r\n\r\n if (touches) {\r\n if ((touches.length === 1 && !this.eventType) || this.eventType === 'horizontal-swipe' || this.eventType === 'vertical-swipe') {\r\n return this.getLinearSwipeType(event);\r\n }\r\n } else {\r\n if (!this.eventType || this.eventType === 'horizontal-swipe' || this.eventType === 'vertical-swipe') {\r\n return this.getLinearSwipeType(event);\r\n }\r\n }\r\n\r\n return undefined;\r\n }\r\n\r\n getLinearSwipeType(event: any) {\r\n if (this.eventType !== 'horizontal-swipe' && this.eventType !== 'vertical-swipe') {\r\n const movementX = Math.abs(this.moveLeft(0, event) - this.startX);\r\n const movementY = Math.abs(this.moveTop(0, event) - this.startY);\r\n\r\n if (movementY * 3 > movementX) {\r\n return 'vertical-swipe';\r\n } else {\r\n return 'horizontal-swipe';\r\n }\r\n } else {\r\n return this.eventType;\r\n }\r\n }\r\n\r\n getElementPosition() {\r\n return this.element.getBoundingClientRect();\r\n }\r\n\r\n getTouchstartPosition(event: any) {\r\n this.startX = event.touches[0].clientX - this.elementPosition.left;\r\n this.startY = event.touches[0].clientY - this.elementPosition.top;\r\n }\r\n\r\n getMousedownPosition(event: any) {\r\n this.startX = event.clientX - this.elementPosition.left;\r\n this.startY = event.clientY - this.elementPosition.top;\r\n }\r\n\r\n moveLeft(index: any, event: any) {\r\n const touches = event.touches;\r\n\r\n if (touches) {\r\n return touches[index].clientX - this.elementPosition.left;\r\n } else {\r\n return event.clientX - this.elementPosition.left;\r\n }\r\n }\r\n\r\n moveTop(index: any, event: any) {\r\n const touches = event.touches;\r\n\r\n if (touches) {\r\n return touches[index].clientY - this.elementPosition.top;\r\n } else {\r\n return event.clientY - this.elementPosition.top;\r\n }\r\n }\r\n\r\n detectTouchScreen() {\r\n var prefixes = ' -webkit- -moz- -o- -ms- '.split(' ');\r\n var mq = function (query: any) {\r\n return window.matchMedia(query).matches;\r\n };\r\n\r\n if ('ontouchstart' in window) {\r\n return true;\r\n }\r\n\r\n // include the 'heartz' as a way to have a non matching MQ to help terminate the join\r\n // https://git.io/vznFH\r\n var query = ['(', prefixes.join('touch-enabled),('), 'heartz', ')'].join('');\r\n return mq(query);\r\n }\r\n\r\n /* Public properties and methods */\r\n on(event: EventType, handler: Function) {\r\n if (event) {\r\n this.handlers[event] = handler;\r\n }\r\n }\r\n}\r\n","import { Touches } from './touches';\r\nimport {MouseZoomPoint, PinchZoomProperties, ZoomEvent} from './interfaces';\r\nimport { defaultProperties } from './properties';\r\nimport {EventEmitter} from '@angular/core';\r\n\r\ntype PropertyName = keyof PinchZoomProperties;\r\n\r\nexport class IvyPinch {\r\n properties: PinchZoomProperties = defaultProperties;\r\n private onZoomChange: EventEmitter<ZoomEvent>;\r\n touches: any;\r\n element: any;\r\n elementTarget: any;\r\n parentElement: any;\r\n i: number = 0;\r\n public scale: number = 1;\r\n initialScale: number = 1;\r\n elementPosition: any;\r\n eventType: any;\r\n startX: number = 0;\r\n startY: number = 0;\r\n moveX: number = 0;\r\n moveY: number = 0;\r\n initialMoveX: number = 0;\r\n initialMoveY: number = 0;\r\n moveXC: number = 0;\r\n moveYC: number = 0;\r\n lastTap: number = 0;\r\n draggingMode: boolean = false;\r\n distance: number = 0;\r\n doubleTapTimeout: number = 0;\r\n initialDistance: number = 0;\r\n events: any = {};\r\n maxScale!: number;\r\n defaultMaxScale: number = 3;\r\n\r\n // Minimum scale at which panning works\r\n get minPanScale() {\r\n return this.getPropertiesValue('minPanScale');\r\n }\r\n\r\n get fullImage() {\r\n return this.properties.fullImage;\r\n }\r\n\r\n constructor(properties: PinchZoomProperties, onZoomChange: EventEmitter<ZoomEvent>) {\r\n this.element = properties.element;\r\n this.onZoomChange = onZoomChange;\r\n\r\n if (!this.element) {\r\n return;\r\n }\r\n\r\n this.elementTarget = this.element.querySelector('*').tagName;\r\n this.parentElement = this.element.parentElement;\r\n this.properties = Object.assign({}, defaultProperties, properties);\r\n this.detectLimitZoom();\r\n\r\n this.touches = new Touches({\r\n element: properties.element,\r\n listeners: properties.listeners,\r\n resize: properties.autoHeight,\r\n mouseListeners: {\r\n mousedown: 'handleMousedown',\r\n mouseup: 'handleMouseup',\r\n wheel: 'handleWheel',\r\n },\r\n });\r\n\r\n /* Init */\r\n this.setBasicStyles();\r\n\r\n /*\r\n * Listeners\r\n */\r\n\r\n this.touches.on('touchstart', this.handleTouchstart);\r\n this.touches.on('touchend', this.handleTouchend);\r\n this.touches.on('mousedown', this.handleTouchstart);\r\n this.touches.on('mouseup', this.handleTouchend);\r\n this.touches.on('pan', this.handlePan);\r\n this.touches.on('mousemove', this.handlePan);\r\n this.touches.on('pinch', this.handlePinch);\r\n\r\n if (this.properties.wheel) {\r\n this.touches.on('wheel', this.handleWheel);\r\n }\r\n\r\n if (this.properties.doubleTap) {\r\n this.touches.on('double-tap', this.handleDoubleTap);\r\n }\r\n\r\n if (this.properties.autoHeight) {\r\n this.touches.on('resize', this.handleResize);\r\n }\r\n }\r\n\r\n /* Touchstart */\r\n\r\n handleTouchstart = (event: any) => {\r\n this.touches.addEventListeners('mousemove', 'handleMousemove');\r\n this.getElementPosition();\r\n\r\n if (this.eventType === undefined) {\r\n this.getTouchstartPosition(event);\r\n }\r\n };\r\n\r\n /* Touchend */\r\n\r\n handleTouchend = (event: any) => {\r\n /* touchend */\r\n if (event.type === 'touchend') {\r\n this.i = 0;\r\n this.draggingMode = false;\r\n const touches = event.touches;\r\n\r\n // Min scale\r\n if (this.scale < 1) {\r\n this.scale = 1;\r\n }\r\n\r\n // Auto Zoom Out\r\n if (this.properties.autoZoomOut && this.eventType === 'pinch') {\r\n this.scale = 1;\r\n }\r\n\r\n // Align image\r\n if (this.eventType === 'pinch' || (this.eventType === 'pan' && this.scale > this.minPanScale)) {\r\n this.alignImage();\r\n }\r\n\r\n // Update initial values\r\n if (\r\n this.eventType === 'pinch' ||\r\n this.eventType === 'pan' ||\r\n this.eventType === 'horizontal-swipe' ||\r\n this.eventType === 'vertical-swipe'\r\n ) {\r\n this.updateInitialValues();\r\n }\r\n\r\n this.eventType = 'touchend';\r\n\r\n if (touches && touches.length === 0) {\r\n this.eventType = undefined;\r\n }\r\n }\r\n\r\n /* mouseup */\r\n if (event.type === 'mouseup') {\r\n this.draggingMode = false;\r\n this.updateInitialValues();\r\n this.eventType = undefined;\r\n }\r\n\r\n this.touches.removeEventListeners('mousemove', 'handleMousemove');\r\n };\r\n\r\n /*\r\n * Handlers\r\n */\r\n\r\n handlePan = (event: any) => {\r\n if (this.scale < this.minPanScale || this.properties.disablePan) {\r\n return;\r\n }\r\n\r\n event.preventDefault();\r\n const { clientX, clientY } = this.getClientPosition(event);\r\n\r\n if (!this.eventType) {\r\n this.startX = clientX - this.elementPosition.left;\r\n this.startY = clientY - this.elementPosition.top;\r\n }\r\n\r\n this.eventType = 'pan';\r\n this.moveX = this.initialMoveX + (this.moveLeft(event, 0) - this.startX);\r\n this.moveY = this.initialMoveY + (this.moveTop(event, 0) - this.startY);\r\n\r\n if (this.properties.limitPan) {\r\n this.limitPanY();\r\n this.limitPanX();\r\n }\r\n\r\n /* mousemove */\r\n if (event.type === 'mousemove' && this.scale > this.minPanScale) {\r\n this.centeringImage();\r\n }\r\n\r\n this.transformElement(0);\r\n };\r\n\r\n handleDoubleTap = (event: any) => {\r\n this.toggleZoom(event);\r\n return;\r\n };\r\n\r\n handlePinch = (event: any) => {\r\n event.preventDefault();\r\n\r\n if (this.eventType === undefined || this.eventType === 'pinch') {\r\n const touches = event.touches;\r\n\r\n if (!this.eventType) {\r\n this.initialDistance = this.getDistance(touches);\r\n\r\n const moveLeft0 = this.moveLeft(event, 0);\r\n const moveLeft1 = this.moveLeft(event, 1);\r\n const moveTop0 = this.moveTop(event, 0);\r\n const moveTop1 = this.moveTop(event, 1);\r\n\r\n this.moveXC = (moveLeft0 + moveLeft1) / 2 - this.initialMoveX;\r\n this.moveYC = (moveTop0 + moveTop1) / 2 - this.initialMoveY;\r\n }\r\n\r\n this.eventType = 'pinch';\r\n this.distance = this.getDistance(touches);\r\n this.scale = this.initialScale * (this.distance / this.initialDistance);\r\n this.moveX = this.initialMoveX - ((this.distance / this.initialDistance) * this.moveXC - this.moveXC);\r\n this.moveY = this.initialMoveY - ((this.distance / this.initialDistance) * this.moveYC - this.moveYC);\r\n\r\n this.handleLimitZoom();\r\n\r\n if (this.properties.limitPan) {\r\n this.limitPanY();\r\n this.limitPanX();\r\n }\r\n\r\n this.transformElement(0);\r\n }\r\n };\r\n\r\n handleWheel = (event: any) => {\r\n event.preventDefault();\r\n\r\n let wheelZoomFactor = this.properties.wheelZoomFactor || 0;\r\n let zoomFactor = event.deltaY < 0 ? wheelZoomFactor : -wheelZoomFactor;\r\n let newScale = this.initialScale + zoomFactor;\r\n\r\n /* Round value */\r\n if (newScale < 1 + wheelZoomFactor) {\r\n newScale = 1;\r\n } else if (newScale < this.maxScale && newScale > this.maxScale - wheelZoomFactor) {\r\n newScale = this.maxScale;\r\n }\r\n\r\n if (newScale < 1 || newScale > this.maxScale) {\r\n return;\r\n }\r\n\r\n if (newScale === this.scale) {\r\n return;\r\n }\r\n\r\n this.getElementPosition();\r\n this.scale = newScale;\r\n\r\n /* Get cursor position over image */\r\n let xCenter = event.clientX - this.elementPosition.left - this.initialMoveX;\r\n let yCenter = event.clientY - this.elementPosition.top - this.initialMoveY;\r\n\r\n this.setZoom({\r\n scale: newScale,\r\n center: [xCenter, yCenter],\r\n });\r\n };\r\n\r\n handleResize = (_event: any) => {\r\n this.setAutoHeight();\r\n };\r\n\r\n handleLimitZoom() {\r\n const limitZoom = this.maxScale;\r\n const minScale = this.properties.minScale || 0;\r\n\r\n if (this.scale > limitZoom || this.scale <= minScale) {\r\n const imageWidth = this.getImageWidth();\r\n const imageHeight = this.getImageHeight();\r\n const enlargedImageWidth = imageWidth * this.scale;\r\n const enlargedImageHeight = imageHeight * this.scale;\r\n const moveXRatio = this.moveX / (enlargedImageWidth - imageWidth);\r\n const moveYRatio = this.moveY / (enlargedImageHeight - imageHeight);\r\n\r\n if (this.scale > limitZoom) {\r\n this.scale = limitZoom;\r\n }\r\n\r\n if (this.scale <= minScale) {\r\n this.scale = minScale;\r\n }\r\n\r\n const newImageWidth = imageWidth * this.scale;\r\n const newImageHeight = imageHeight * this.scale;\r\n\r\n this.moveX = -Math.abs(moveXRatio * (newImageWidth - imageWidth));\r\n this.moveY = -Math.abs(-moveYRatio * (newImageHeight - imageHeight));\r\n }\r\n }\r\n\r\n moveLeft(event: any, index: number = 0) {\r\n const clientX = this.getClientPosition(event, index).clientX;\r\n return clientX - this.elementPosition.left;\r\n }\r\n\r\n moveTop(event: any, index: number = 0) {\r\n const clientY = this.getClientPosition(event, index).clientY;\r\n return clientY - this.elementPosition.top;\r\n }\r\n\r\n /*\r\n * Detection\r\n */\r\n\r\n centeringImage() {\r\n const img = this.element.getElementsByTagName(this.elementTarget)[0];\r\n const initialMoveX = this.moveX;\r\n const initialMoveY = this.moveY;\r\n\r\n if (this.moveY > 0) {\r\n this.moveY = 0;\r\n }\r\n if (this.moveX > 0) {\r\n this.moveX = 0;\r\n }\r\n\r\n if (img) {\r\n this.limitPanY();\r\n this.limitPanX();\r\n }\r\n if (img && this.scale < 1) {\r\n if (this.moveX < this.element.offsetWidth * (1 - this.scale)) {\r\n this.moveX = this.element.offsetWidth * (1 - this.scale);\r\n }\r\n }\r\n\r\n return initialMoveX !== this.moveX || initialMoveY !== this.moveY;\r\n }\r\n\r\n limitPanY() {\r\n const imgHeight = this.getImageHeight();\r\n const scaledImgHeight = imgHeight * this.scale;\r\n const parentHeight = this.parentElement.offsetHeight;\r\n const elementHeight = this.element.offsetHeight;\r\n\r\n if (scaledImgHeight < parentHeight) {\r\n this.moveY = (parentHeight - elementHeight * this.scale) / 2;\r\n } else {\r\n const imgOffsetTop = ((imgHeight - elementHeight) * this.scale) / 2;\r\n\r\n if (this.moveY > imgOffsetTop) {\r\n this.moveY = imgOffsetTop;\r\n } else if (scaledImgHeight + Math.abs(imgOffsetTop) - parentHeight + this.moveY < 0) {\r\n this.moveY = -(scaledImgHeight + Math.abs(imgOffsetTop) - parentHeight);\r\n }\r\n }\r\n }\r\n\r\n limitPanX() {\r\n const imgWidth = this.getImageWidth();\r\n const scaledImgWidth = imgWidth * this.scale;\r\n const parentWidth = this.parentElement.offsetWidth;\r\n const elementWidth = this.element.offsetWidth;\r\n\r\n if (scaledImgWidth < parentWidth) {\r\n this.moveX = (parentWidth - elementWidth * this.scale) / 2;\r\n } else {\r\n const imgOffsetLeft = ((imgWidth - elementWidth) * this.scale) / 2;\r\n\r\n if (this.moveX > imgOffsetLeft) {\r\n this.moveX = imgOffsetLeft;\r\n } else if (scaledImgWidth + Math.abs(imgOffsetLeft) - parentWidth + this.moveX < 0) {\r\n this.moveX = -(imgWidth * this.scale + Math.abs(imgOffsetLeft) - parentWidth);\r\n }\r\n }\r\n }\r\n\r\n setBasicStyles() {\r\n this.element.style.display = 'flex';\r\n this.element.style.alignItems = 'center';\r\n this.element.style.justifyContent = 'center';\r\n this.element.style.transformOrigin = '0 0';\r\n this.setImageSize();\r\n this.setDraggableImage();\r\n }\r\n\r\n removeBasicStyles() {\r\n this.element.style.display = '';\r\n this.element.style.alignItems = '';\r\n this.element.style.justifyContent = '';\r\n this.element.style.transformOrigin = '';\r\n this.removeImageSize();\r\n this.removeDraggableImage();\r\n }\r\n\r\n setDraggableImage() {\r\n const imgElement = this.getImageElement();\r\n\r\n if (imgElement) {\r\n imgElement.draggable = this.properties.draggableImage;\r\n }\r\n }\r\n\r\n removeDraggableImage() {\r\n const imgElement = this.getImageElement();\r\n\r\n if (imgElement) {\r\n imgElement.draggable = true;\r\n }\r\n }\r\n\r\n setImageSize() {\r\n const imgElement = this.element.getElementsByTagName(this.elementTarget);\r\n\r\n if (imgElement.length) {\r\n imgElement[0].style.maxWidth = '100%';\r\n imgElement[0].style.maxHeight = '100%';\r\n\r\n this.setAutoHeight();\r\n }\r\n }\r\n\r\n setAutoHeight() {\r\n const imgElement = this.element.getElementsByTagName(this.elementTarget);\r\n\r\n if (!this.properties.autoHeight || !imgElement.length) {\r\n return;\r\n }\r\n\r\n const imgNaturalWidth = imgElement[0].getAttribute('width');\r\n const imgNaturalHeight = imgElement[0].getAttribute('height');\r\n const sizeRatio = imgNaturalWidth / imgNaturalHeight;\r\n const parentWidth = this.parentElement.offsetWidth;\r\n\r\n imgElement[0].style.maxHeight = parentWidth / sizeRatio + 'px';\r\n }\r\n\r\n removeImageSize() {\r\n const imgElement = this.element.getElementsByTagName(this.elementTarget);\r\n\r\n if (imgElement.length) {\r\n imgElement[0].style.maxWidth = '';\r\n imgElement[0].style.maxHeight = '';\r\n }\r\n }\r\n\r\n getElementPosition() {\r\n this.elementPosition = this.element.parentElement.getBoundingClientRect();\r\n }\r\n\r\n getTouchstartPosition(event: any) {\r\n const { clientX, clientY } = this.getClientPosition(event);\r\n\r\n this.startX = clientX - this.elementPosition.left;\r\n this.startY = clientY - this.elementPosition.top;\r\n }\r\n\r\n getClientPosition(event: any, index: number = 0) {\r\n let clientX;\r\n let clientY;\r\n\r\n if (event.type === 'touchstart' || event.type === 'touchmove') {\r\n clientX = event.touches[index].clientX;\r\n clientY = event.touches[index].clientY;\r\n }\r\n if (event.type === 'mousedown' || event.type === 'mousemove') {\r\n clientX = event.clientX;\r\n clientY = event.clientY;\r\n }\r\n\r\n return {\r\n clientX,\r\n clientY,\r\n };\r\n }\r\n\r\n resetScale() {\r\n this.scale = 1;\r\n this.moveX = 0;\r\n this.moveY = 0;\r\n this.updateInitialValues();\r\n this.transformElement(this.properties.transitionDuration);\r\n }\r\n\r\n updateInitialValues() {\r\n this.initialScale = this.scale;\r\n this.initialMoveX = this.moveX;\r\n this.initialMoveY = this.moveY;\r\n\r\n let visibleAreaWidth = this.element.offsetWidth;\r\n let visibleAreaHeight = this.element.offsetHeight;\r\n const event = {\r\n scale: this.initialScale,\r\n moveX: this.initialMoveX,\r\n moveY: this.initialMoveY,\r\n visibleAreaWidth: visibleAreaWidth,\r\n visibleAreaHeight: visibleAreaHeight,\r\n } as ZoomEvent\r\n this.onZoomChange.emit(event);\r\n }\r\n\r\n getDistance(touches: any) {\r\n return Math.sqrt(Math.pow(touches[0].pageX - touches[1].pageX, 2) + Math.pow(touches[0].pageY - touches[1].pageY, 2));\r\n }\r\n\r\n getImageHeight() {\r\n const img = this.element.getElementsByTagName(this.elementTarget)[0];\r\n return img.offsetHeight;\r\n }\r\n\r\n getImageWidth() {\r\n const img = this.element.getElementsByTagName(this.elementTarget)[0];\r\n return img.offsetWidth;\r\n }\r\n\r\n transformElement(duration: any) {\r\n this.element.style.transition = 'all ' + duration + 'ms';\r\n this.element.style.transform =\r\n 'matrix(' + Number(this.scale) + ', 0, 0, ' + Number(this.scale) + ', ' + Number(this.moveX) + ', ' + Number(this.moveY) + ')';\r\n }\r\n\r\n isTouchScreen() {\r\n const prefixes = ' -webkit- -moz- -o- -ms- '.split(' ');\r\n\r\n if ('ontouchstart' in window) {\r\n return true;\r\n }\r\n\r\n // include the 'heartz' as a way to have a non matching MQ to help terminate the join\r\n // https://git.io/vznFH\r\n const query = ['(', prefixes.join('touch-enabled),('), 'heartz', ')'].join('');\r\n return this.getMatchMedia(query);\r\n }\r\n\r\n getMatchMedia(query: any) {\r\n return window.matchMedia(query).matches;\r\n }\r\n\r\n isDragging() {\r\n if (this.properties.disablePan) {\r\n return false;\r\n }\r\n\r\n const imgHeight = this.getImageHeight();\r\n const imgWidth = this.getImageWidth();\r\n\r\n if (this.scale > 1) {\r\n return imgHeight * this.scale > this.parentElement.offsetHeight || imgWidth * this.scale > this.parentElement.offsetWidth;\r\n }\r\n if (this.scale === 1) {\r\n return imgHeight > this.parentElement.offsetHeight || imgWidth > this.parentElement.offsetWidth;\r\n }\r\n\r\n return undefined;\r\n }\r\n\r\n detectLimitZoom() {\r\n this.maxScale = this.defaultMaxScale;\r\n if (this.properties.limitZoom !== 'original image size' && +this.properties.limitZoom > 0) {\r\n this.maxScale = +this.properties.limitZoom;\r\n }\r\n\r\n if (this.properties.limitZoom === 'original image size' && this.elementTarget === 'IMG') {\r\n // We are waiting for the element with the image to be available\r\n this.pollLimitZoomForOriginalImage();\r\n }\r\n }\r\n\r\n pollLimitZoomForOriginalImage() {\r\n let poll = setInterval(() => {\r\n let maxScaleForOriginalImage = this.getMaxScaleForOriginalImage();\r\n if (typeof maxScaleForOriginalImage === 'number') {\r\n this.maxScale = maxScaleForOriginalImage;\r\n clearInterval(poll);\r\n }\r\n }, 10);\r\n }\r\n\r\n getMaxScaleForOriginalImage() {\r\n let maxScale!: number;\r\n let img = this.element.getElementsByTagName('img')[0];\r\n\r\n if (img.naturalWidth && img.offsetWidth) {\r\n maxScale = img.naturalWidth / img.offsetWidth;\r\n }\r\n\r\n return maxScale;\r\n }\r\n\r\n getImageElement() {\r\n const imgElement = this.element.getElementsByTagName(this.elementTarget);\r\n\r\n if (imgElement.length) {\r\n return imgElement[0];\r\n }\r\n }\r\n\r\n toggleZoom(event: any = false) {\r\n if (this.initialScale === 1) {\r\n if (event && event.changedTouches) {\r\n if (this.properties.doubleTapScale === undefined) {\r\n return;\r\n }\r\n\r\n const changedTouches = event.changedTouches;\r\n this.scale = this.initialScale * this.properties.doubleTapScale;\r\n this.moveX =\r\n this.initialMoveX - (changedTouches[0].clientX - this.elementPosition.left) * (this.properties.doubleTapScale - 1);\r\n this.moveY =\r\n this.initialMoveY - (changedTouches[0].clientY - this.elementPosition.top) * (this.properties.doubleTapScale - 1);\r\n } else {\r\n let zoomControlScale = this.properties.zoomControlScale || 0;\r\n this.scale = this.initialScale * (zoomControlScale + 1);\r\n this.moveX = this.initialMoveX - (this.element.offsetWidth * (this.scale - 1)) / 2;\r\n this.moveY = this.initialMoveY - (this.element.offsetHeight * (this.scale - 1)) / 2;\r\n }\r\n\r\n this.centeringImage();\r\n this.updateInitialValues();\r\n this.transformElement(this.properties.transitionDuration);\r\n } else {\r\n this.resetScale();\r\n }\r\n }\r\n\r\n zoomPoint(point: MouseZoomPoint, scale?: number) {\r\n console.warn('zoomPoint', point, scale);\r\n let newScale= scale ?? (this.initialScale + this.properties.stepZoomFactor);\r\n\r\n if (newScale < 1 || newScale > this.maxScale) {\r\n return;\r\n }\r\n\r\n if (newScale === this.scale) {\r\n return;\r\n }\r\n\r\n /* Get cursor position over image */\r\n let newCenter = undefined\r\n if(point){\r\n let xCenter = point.clientX - this.elementPosition.left - this.initialMoveX;\r\n let yCenter = point.clientY - this.elementPosition.top - this.initialMoveY;\r\n newCenter = [xCenter, yCenter];\r\n }\r\n console.warn('newScale2', newScale);\r\n this.getElementPosition();\r\n this.scale = newScale;\r\n\r\n this.setZoom({\r\n scale: newScale,\r\n center: newCenter\r\n });\r\n }\r\n\r\n stepZoom(mode: 'IN' | 'OUT') {\r\n let stepZoomFactor = this.properties.stepZoomFactor ?? 0;\r\n let zoomFactor = 0\r\n if(mode === 'OUT') {\r\n zoomFactor = -stepZoomFactor;\r\n }\r\n if(mode === 'IN') {\r\n zoomFactor = stepZoomFactor;\r\n }\r\n let newScale= this.initialScale + zoomFactor;\r\n console.warn('newScale', newScale);\r\n\r\n /* Round value */\r\n if (newScale < 1 + stepZoomFactor) {\r\n newScale = 1;\r\n } else if (newScale < this.maxScale && newScale > this.maxScale - stepZoomFactor) {\r\n newScale = this.maxScale;\r\n }\r\n\r\n if (newScale < 1 || newScale > this.maxScale) {\r\n return;\r\n }\r\n\r\n if (newScale === this.scale) {\r\n return;\r\n }\r\n\r\n console.warn('newScale2', newScale);\r\n this.getElementPosition();\r\n this.scale = newScale;\r\n\r\n this.setZoom({\r\n scale: newScale,\r\n center: undefined\r\n });\r\n }\r\n\r\n setZoom(properties: { scale: number; center?: number[] }) {\r\n this.scale = properties.scale;\r\n\r\n let xCenter;\r\n let yCenter;\r\n let visibleAreaWidth = this.element.offsetWidth;\r\n let visibleAreaHeight = this.element.offsetHeight;\r\n let scalingPercent = (visibleAreaWidth * this.scale) / (visibleAreaWidth * this.initialScale);\r\n\r\n if (properties.center) {\r\n xCenter = properties.center[0];\r\n yCenter = properties.center[1];\r\n } else {\r\n xCenter = visibleAreaWidth / 2 - this.initialMoveX;\r\n yCenter = visibleAreaHeight / 2 - this.initialMoveY;\r\n }\r\n\r\n this.moveX = this.initialMoveX - (scalingPercent * xCenter - xCenter);\r\n this.moveY = this.initialMoveY - (scalingPercent * yCenter - yCenter);\r\n\r\n this.centeringImage();\r\n this.updateInitialValues();\r\n this.transformElement(this.properties.transitionDuration);\r\n }\r\n\r\n alignImage() {\r\n const isMoveChanged = this.centeringImage();\r\n\r\n if (isMoveChanged) {\r\n this.updateInitialValues();\r\n this.transformElement(this.properties.transitionDuration);\r\n }\r\n }\r\n\r\n destroy() {\r\n this.removeBasicStyles();\r\n this.touches.destroy();\r\n }\r\n\r\n getPropertiesValue(propertyName: PropertyName) {\r\n if (this.properties && this.properties[propertyName]) {\r\n return this.properties[propertyName];\r\n } else {\r\n return defaultProperties[propertyName];\r\n }\r\n }\r\n}\r\n","import {\r\n Component,\r\n ElementRef,\r\n EventEmitter,\r\n HostBinding,\r\n Input,\r\n OnDestroy, OnInit, Output,\r\n SimpleChanges\r\n} from '@angular/core';\r\n\r\nimport {MouseZoomPoint, PinchZoomProperties, ZoomEvent} from './interfaces';\r\nimport { defaultProperties, backwardCompatibilityProperties } from './properties';\r\nimport { IvyPinch } from './ivypinch';\r\n\r\nexport const _defaultComponentProperties: PinchZoomProperties = {\r\n overflow: 'hidden',\r\n disableZoomControl: 'auto',\r\n backgroundColor: 'rgba(0,0,0,0.85)',\r\n};\r\n\r\ntype PropertyName = keyof PinchZoomProperties;\r\n\r\n@Component({\r\n selector: 'pinch-zoom, [pinch-zoom]',\r\n exportAs: 'pinchZoom',\r\n templateUrl: './pinch-zoom.component.html',\r\n styleUrls: ['./pinch-zoom.component.sass'],\r\n})\r\nexport class PinchZoomComponent implements OnInit, OnDestroy {\r\n defaultComponentProperties!: PinchZoomProperties;\r\n private pinchZoom: IvyPinch;\r\n private _properties!: PinchZoomProperties;\r\n private zoomControlPositionClass: string | undefined;\r\n private _transitionDuration!: number;\r\n private _doubleTap!: boolean;\r\n private _doubleTapScale!: number;\r\n private _autoZoomOut!: boolean;\r\n private _limitZoom!: number | 'original image size';\r\n\r\n @Input('properties') set properties(value: PinchZoomProperties) {\r\n if (value) {\r\n this._properties = value;\r\n }\r\n }\r\n\r\n get properties() {\r\n return this._properties;\r\n }\r\n\r\n // transitionDuration\r\n @Input('transition-duration') set transitionDurationBackwardCompatibility(value: number) {\r\n if (value) {\r\n this._transitionDuration = value;\r\n }\r\n }\r\n\r\n @Input('transitionDuration') set transitionDuration(value: number) {\r\n if (value) {\r\n this._transitionDuration = value;\r\n }\r\n }\r\n\r\n get transitionDuration() {\r\n return this._transitionDuration;\r\n }\r\n\r\n // doubleTap\r\n @Input('double-tap') set doubleTapBackwardCompatibility(value: boolean) {\r\n if (value) {\r\n this._doubleTap = value;\r\n }\r\n }\r\n\r\n @Input('doubleTap') set doubleTap(value: boolean) {\r\n if (value) {\r\n this._doubleTap = value;\r\n }\r\n }\r\n\r\n get doubleTap() {\r\n return this._doubleTap;\r\n }\r\n\r\n // doubleTapScale\r\n @Input('double-tap-scale') set doubleTapScaleBackwardCompatibility(value: number) {\r\n if (value) {\r\n this._doubleTapScale = value;\r\n }\r\n }\r\n\r\n @Input('doubleTapScale') set doubleTapScale(value: number) {\r\n if (value) {\r\n this._doubleTapScale = value;\r\n }\r\n }\r\n\r\n get doubleTapScale() {\r\n return this._doubleTapScale;\r\n }\r\n\r\n // autoZoomOut\r\n @Input('auto-zoom-out') set autoZoomOutBackwardCompatibility(value: boolean) {\r\n if (value) {\r\n this._autoZoomOut = value;\r\n }\r\n }\r\n\r\n @Input('autoZoomOut') set autoZoomOut(value: boolean) {\r\n if (value) {\r\n this._autoZoomOut = value;\r\n }\r\n }\r\n\r\n get autoZoomOut() {\r\n return this._autoZoomOut;\r\n }\r\n\r\n // limitZoom\r\n @Input('limit-zoom') set limitZoomBackwardCompatibility(value: number | 'original image size') {\r\n if (value) {\r\n this._limitZoom = value;\r\n }\r\n }\r\n\r\n @Input('limitZoom') set limitZoom(value: number | 'original image size') {\r\n if (value) {\r\n this._limitZoom = value;\r\n }\r\n }\r\n\r\n get limitZoom() {\r\n return this._limitZoom;\r\n }\r\n\r\n @Input() disabled!: boolean;\r\n @Input() disablePan!: boolean;\r\n @Input() overflow!: 'hidden' | 'visible';\r\n @Input() zoomControlScale!: number;\r\n @Input() disableZoomControl!: 'disable' | 'never' | 'auto';\r\n @Input() backgroundColor!: string;\r\n @Input() limitPan!: boolean;\r\n @Input() minPanScale!: number;\r\n @Input() minScale!: number;\r\n @Input() listeners!: 'auto' | 'mouse and touch';\r\n @Input() wheel!: boolean;\r\n @Input() autoHeight!: boolean;\r\n @Input() stepZoomFactor!: number;\r\n @Input() wheelZoomFactor!: number;\r\n @Input() draggableImage!: boolean;\r\n\r\n @Output() onZoomChange: EventEmitter<ZoomEvent> = new EventEmitter<ZoomEvent>();\r\n\r\n @HostBinding('style.overflow')\r\n get hostOverflow() {\r\n return this.properties['overflow'];\r\n }\r\n\r\n @HostBinding('style.background-color')\r\n get hostBackgroundColor() {\r\n return this.properties['backgroundColor'];\r\n }\r\n\r\n get isTouchScreen() {\r\n var prefixes = ' -webkit- -moz- -o- -ms- '.split(' ');\r\n var mq = function (query: any) {\r\n return window.matchMedia(query).matches;\r\n };\r\n\r\n if ('ontouchstart' in window) {\r\n return true;\r\n }\r\n\r\n // include the 'heartz' as a way to have a non matching MQ to help terminate the join\r\n // https://git.io/vznFH\r\n var query = ['(', prefixes.join('touch-enabled),('), 'heartz', ')'].join('');\r\n return mq(query);\r\n }\r\n\r\n get isDragging() {\r\n return this.pinchZoom ? this.pinchZoom.isDragging() : undefined;\r\n }\r\n\r\n get isDisabled() {\r\n return this.properties['disabled'];\r\n }\r\n\r\n get scale() {\r\n return this.pinchZoom.scale;\r\n }\r\n\r\n get isZoomedIn() {\r\n return this.scale > 1;\r\n }\r\n\r\n get scaleLevel() {\r\n return Math.round(this.scale / this._zoomControlScale);\r\n }\r\n\r\n get maxScale() {\r\n return this.pinchZoom.maxScale;\r\n }\r\n\r\n get isZoomLimitReached() {\r\n return this.scale >= this.maxScale;\r\n }\r\n\r\n get _zoomControlScale() {\r\n return this.getPropertiesValue('zoomControlScale');\r\n }\r\n\r\n constructor(private elementRef: ElementRef) {\r\n this.defaultComponentProperties = this.getDefaultComponentProperties();\r\n this.applyPropertiesDefault(this.defaultComponentProperties, {});\r\n }\r\n\r\n ngOnInit() {\r\n this.initPinchZoom();\r\n\r\n /* Calls the method until the image size is available */\r\n this.detectLimitZoom();\r\n }\r\n\r\n isControl() {\r\n if (this.isDisabled) {\r\n return false;\r\n }\r\n\r\n if (this.properties['disableZoomControl'] === 'disable') {\r\n return false;\r\n }\r\n\r\n if (this.isTouchScreen && this.properties['disableZoomControl'] === 'auto') {\r\n return false;\r\n }\r\n\r\n return true;\r\n }\r\n\r\n ngOnChanges(changes: SimpleChanges) {\r\n let changedProperties = this.getProperties(changes);\r\n changedProperties = this.renameProperties(changedProperties);\r\n\r\n this.applyPropertiesDefault(this.defaultComponentProperties, changedProperties);\r\n }\r\n\r\n ngOnDestroy() {\r\n this.destroy();\r\n }\r\n\r\n toggleZoom() {\r\n this.pinchZoom.toggleZoom();\r\n }\r\n\r\n zoomPoint(point: MouseZoomPoint, scale?: number) {\r\n this.pinchZoom.zoomPoint(point, scale);\r\n }\r\n\r\n zoomIn() {\r\n this.pinchZoom.stepZoom('IN');\r\n }\r\n\r\n zoomOut() {\r\n this.pinchZoom.stepZoom('OUT');\r\n }\r\n\r\n resetZoom() {\r\n this.pinchZoom.resetScale();\r\n }\r\n\r\n destroy() {\r\n if (this.pinchZoom) this.pinchZoom.destroy();\r\n }\r\n\r\n private initPinchZoom() {\r\n if (this.properties['disabled']) {\r\n return;\r\n }\r\n\r\n this.properties['element'] = this.elementRef.nativeElement.querySelector('.pinch-zoom-content');\r\n this.pinchZoom = new IvyPinch(this.properties, this.onZoomChange);\r\n }\r\n\r\n private getProperties(changes: SimpleChanges) {\r\n let properties: any = {};\r\n\r\n for (var prop in changes) {\r\n if (prop !== 'properties') {\r\n properties[prop] = changes[prop].currentValue;\r\n }\r\n if (prop === 'properties') {\r\n properties = changes[prop].currentValue;\r\n }\r\n }\r\n return properties;\r\n }\r\n\r\n private renameProperties(properties: any) {\r\n for (var prop in properties) {\r\n if (backwardCompatibilityProperties[prop]) {\r\n properties[backwardCompatibilityProperties[prop]] = properties[prop];\r\n delete properties[prop];\r\n }\r\n }\r\n\r\n return properties;\r\n }\r\n\r\n private applyPropertiesDefault(defaultProperties: PinchZoomProperties, properties: PinchZoomProperties): void {\r\n this.properties = Object.assign({}, defaultProperties, properties);\r\n }\r\n\r\n private detectLimitZoom() {\r\n if (this.pinchZoom) {\r\n this.pinchZoom.detectLimitZoom();\r\n }\r\n }\r\n\r\n private getPropertiesValue(propertyName: PropertyName) {\r\n if (this.properties && this.properties[propertyName]) {\r\n return this.properties[propertyName];\r\n } else {\r\n return this.defaultComponentProperties[propertyName];\r\n }\r\n }\r\n\r\n private getDefaultComponentProperties() {\r\n return { ...defaultProperties, ..._defaultComponentProperties };\r\n }\r\n}\r\n","<div class=\"pinch-zoom-content\" [class.pz-dragging]=\"isDragging\">\r\n <ng-content></ng-content>\r\n</div>\r\n\r\n<!-- Control: one button -->\r\n<div\r\n class=\"pz-zoom-button pz-zoom-control-position-bottom\"\r\n