From 230c40e1ec1a1c5de2dd384e7a260ad77b67cd93 Mon Sep 17 00:00:00 2001 From: Thomas Vo Date: Thu, 23 Jan 2025 11:55:52 -0800 Subject: [PATCH] Expose `onLayoutMeasured` event (#132) * fix * bump * fix * doc * doc * children * fix * format --------- Co-authored-by: thomasvo --- README.md | 25 +++++------ lib/commonjs/ReactNativeZoomableView.js | 48 +++++++++++++-------- lib/commonjs/ReactNativeZoomableView.js.map | 2 +- lib/commonjs/typings/index.js.map | 2 +- lib/module/ReactNativeZoomableView.js | 48 +++++++++++++-------- lib/module/ReactNativeZoomableView.js.map | 2 +- lib/module/typings/index.js.map | 2 +- lib/typescript/ReactNativeZoomableView.d.ts | 2 +- lib/typescript/typings/index.d.ts | 7 ++- package.json | 2 +- src/ReactNativeZoomableView.tsx | 28 +++++++----- src/typings/index.ts | 6 ++- 12 files changed, 105 insertions(+), 69 deletions(-) diff --git a/README.md b/README.md index 64bb50b..0bb0eeb 100644 --- a/README.md +++ b/README.md @@ -186,18 +186,19 @@ These optional props can be used to keep a "static" pin in the centre of the scr These events can be used to work with data after specific events. -| name | description | params | expected return | -| ----------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------- | ------------------------------------------------------------------------------------------ | -| onTransform | Will be called when the transformation configuration (zoom level and offset) changes | zoomableViewEventObject | void | -| onDoubleTapBefore | Will be called, at the start of a double tap | event, gestureState, zoomableViewEventObject | void | -| onDoubleTapAfter | Will be called at the end of a double tap | event, gestureState, zoomableViewEventObject | void | -| onShiftingBefore | Will be called, when user taps and moves the view, but before our view movement work kicks in (so this is the place to interrupt movement, if you need to) | event, gestureState, zoomableViewEventObject | {boolean} if this returns true, ZoomableView will not process the shift, otherwise it will | -| onShiftingAfter | Will be called, when user taps and moves the view, but after the values have changed already | event, gestureState, zoomableViewEventObject | void | -| onShiftingEnd | Will be called, when user stops a tap and move gesture | event, gestureState, zoomableViewEventObject | void | -| onZoomBefore | Will be called, while the user pinches the screen, but before our zoom work kicks in (so this is the place to interrupt zooming, if you need to) | event, gestureState, zoomableViewEventObject | {boolean} if this returns true, ZoomableView will not process the pinch, otherwise it will | -| onZoomAfter | Will be called, while the user pinches the screen, but after the values have changed already | event, gestureState, zoomableViewEventObject | {boolean} if this returns true, ZoomableView will not process the pinch, otherwise it will | -| onZoomEnd | Will be called after pinchzooming has ended | event, gestureState, zoomableViewEventObject | {boolean} if this returns true, ZoomableView will not process the pinch, otherwise it will | -| onLongPress | Will be called after the user pressed on the image for a while | event, gestureState | void | +| name | description | params | expected return | +| ----------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------- | ------------------------------------------------------------------------------------------ | +| onTransform | Will be called when the transformation configuration (zoom level and offset) changes | zoomableViewEventObject | void | +| onDoubleTapBefore | Will be called, at the start of a double tap | event, gestureState, zoomableViewEventObject | void | +| onDoubleTapAfter | Will be called at the end of a double tap | event, gestureState, zoomableViewEventObject | void | +| onShiftingBefore | Will be called, when user taps and moves the view, but before our view movement work kicks in (so this is the place to interrupt movement, if you need to) | event, gestureState, zoomableViewEventObject | {boolean} if this returns true, ZoomableView will not process the shift, otherwise it will | +| onShiftingAfter | Will be called, when user taps and moves the view, but after the values have changed already | event, gestureState, zoomableViewEventObject | void | +| onShiftingEnd | Will be called, when user stops a tap and move gesture | event, gestureState, zoomableViewEventObject | void | +| onZoomBefore | Will be called, while the user pinches the screen, but before our zoom work kicks in (so this is the place to interrupt zooming, if you need to) | event, gestureState, zoomableViewEventObject | {boolean} if this returns true, ZoomableView will not process the pinch, otherwise it will | +| onZoomAfter | Will be called, while the user pinches the screen, but after the values have changed already | event, gestureState, zoomableViewEventObject | {boolean} if this returns true, ZoomableView will not process the pinch, otherwise it will | +| onZoomEnd | Will be called after pinchzooming has ended | event, gestureState, zoomableViewEventObject | {boolean} if this returns true, ZoomableView will not process the pinch, otherwise it will | +| onLongPress | Will be called after the user pressed on the image for a while | event, gestureState | void | +| onLayoutMeasured | Will be called when the layout of the zoomable view changes. This is different from `View`'s `onLayout` in that we're using the measurements from `measureInWindow`. Using this allows you to stay in-sync with the internal measurement states of the component | width, height, x, y (from `measureInWindow`) | void | #### Methods diff --git a/lib/commonjs/ReactNativeZoomableView.js b/lib/commonjs/ReactNativeZoomableView.js index 2dbbd9d..556d48e 100644 --- a/lib/commonjs/ReactNativeZoomableView.js +++ b/lib/commonjs/ReactNativeZoomableView.js @@ -120,7 +120,7 @@ class ReactNativeZoomableView extends _react.Component { return (_this$props$onStaticP = (_this$props = this.props).onStaticPinPositionChange) === null || _this$props$onStaticP === void 0 ? void 0 : _this$props$onStaticP.call(_this$props, position); }, 100)); - _defineProperty(this, "grabZoomSubjectOriginalMeasurements", () => { + _defineProperty(this, "measureZoomSubject", () => { // make sure we measure after animations are complete requestAnimationFrame(() => { // this setTimeout is here to fix a weird issue on iOS where the measurements are all `0` @@ -577,7 +577,22 @@ class ReactNativeZoomableView extends _react.Component { const currState = this.state; const originalMeasurementsChanged = currState.originalHeight !== prevState.originalHeight || currState.originalWidth !== prevState.originalWidth || currState.originalPageX !== prevState.originalPageX || currState.originalPageY !== prevState.originalPageY; - const staticPinPositionChanged = ((_prevProps$staticPinP = prevProps.staticPinPosition) === null || _prevProps$staticPinP === void 0 ? void 0 : _prevProps$staticPinP.x) !== ((_this$props$staticPin = this.props.staticPinPosition) === null || _this$props$staticPin === void 0 ? void 0 : _this$props$staticPin.x) || ((_prevProps$staticPinP2 = prevProps.staticPinPosition) === null || _prevProps$staticPinP2 === void 0 ? void 0 : _prevProps$staticPinP2.y) !== ((_this$props$staticPin2 = this.props.staticPinPosition) === null || _this$props$staticPin2 === void 0 ? void 0 : _this$props$staticPin2.y); + const staticPinPositionChanged = ((_prevProps$staticPinP = prevProps.staticPinPosition) === null || _prevProps$staticPinP === void 0 ? void 0 : _prevProps$staticPinP.x) !== ((_this$props$staticPin = this.props.staticPinPosition) === null || _this$props$staticPin === void 0 ? void 0 : _this$props$staticPin.x) || ((_prevProps$staticPinP2 = prevProps.staticPinPosition) === null || _prevProps$staticPinP2 === void 0 ? void 0 : _prevProps$staticPinP2.y) !== ((_this$props$staticPin2 = this.props.staticPinPosition) === null || _this$props$staticPin2 === void 0 ? void 0 : _this$props$staticPin2.y); // We use a custom `onLayout` event because: + // a) View's `onLayout` sometimes doesn't get called + // b) we use `measureInWindow` internally to keep track of layout changes + // When the client uses this, they can stay in-sync with the internal measurements, + // thus applying transformations at more accurate timings + + if (originalMeasurementsChanged) { + var _this$props$onLayoutM, _this$props14; + + (_this$props$onLayoutM = (_this$props14 = this.props).onLayoutMeasured) === null || _this$props$onLayoutM === void 0 ? void 0 : _this$props$onLayoutM.call(_this$props14, { + width: currState.originalWidth, + height: currState.originalHeight, + x: currState.originalPageX, + y: currState.originalPageY + }); + } if (this.onTransformInvocationInitialized && (originalMeasurementsChanged || staticPinPositionChanged)) { this._invokeOnTransform(); @@ -585,7 +600,7 @@ class ReactNativeZoomableView extends _react.Component { } componentDidMount() { - this.grabZoomSubjectOriginalMeasurements(); // We've already run `grabZoomSubjectOriginalMeasurements` at various events + this.measureZoomSubject(); // We've already run `grabZoomSubjectOriginalMeasurements` at various events // to make sure the measurements are promptly updated. // However, there might be cases we haven't accounted for, especially when // native processes are involved. To account for those cases, @@ -593,7 +608,7 @@ class ReactNativeZoomableView extends _react.Component { // The `setState` in `grabZoomSubjectOriginalMeasurements` won't trigger a rerender // if the values given haven't changed, so we're not running performance risk here. - this.measureZoomSubjectInterval = setInterval(this.grabZoomSubjectOriginalMeasurements, 1e3); + this.measureZoomSubjectInterval = setInterval(this.measureZoomSubject, 1e3); } componentWillUnmount() { @@ -605,7 +620,7 @@ class ReactNativeZoomableView extends _react.Component { * @private */ _invokeOnTransform() { - var _this$props$onTransfo, _this$props14; + var _this$props$onTransfo, _this$props15; const zoomableViewEvent = this._getZoomableViewEventObject(); @@ -614,12 +629,12 @@ class ReactNativeZoomableView extends _react.Component { if (!zoomableViewEvent.originalWidth || !zoomableViewEvent.originalHeight) return { successful: false }; - (_this$props$onTransfo = (_this$props14 = this.props).onTransform) === null || _this$props$onTransfo === void 0 ? void 0 : _this$props$onTransfo.call(_this$props14, zoomableViewEvent); + (_this$props$onTransfo = (_this$props15 = this.props).onTransform) === null || _this$props$onTransfo === void 0 ? void 0 : _this$props$onTransfo.call(_this$props15, zoomableViewEvent); if (position) { - var _this$props$onStaticP3, _this$props15; + var _this$props$onStaticP3, _this$props16; - (_this$props$onStaticP3 = (_this$props15 = this.props).onStaticPinPositionMove) === null || _this$props$onStaticP3 === void 0 ? void 0 : _this$props$onStaticP3.call(_this$props15, position); + (_this$props$onStaticP3 = (_this$props16 = this.props).onStaticPinPositionMove) === null || _this$props$onStaticP3 === void 0 ? void 0 : _this$props$onStaticP3.call(_this$props16, position); this.debouncedOnStaticPinPositionChange(position); } @@ -664,7 +679,7 @@ class ReactNativeZoomableView extends _react.Component { * @private */ _handlePinching(e, gestureState) { - var _this$props$onZoomAft, _this$props16; + var _this$props$onZoomAft, _this$props17; if (!this.props.zoomEnabled) return; const { @@ -745,7 +760,7 @@ class ReactNativeZoomableView extends _react.Component { y: this.offsetY }); this.zoomAnim.setValue(this.zoomLevel); - (_this$props$onZoomAft = (_this$props16 = this.props).onZoomAfter) === null || _this$props$onZoomAft === void 0 ? void 0 : _this$props$onZoomAft.call(_this$props16, e, gestureState, this._getZoomableViewEventObject()); + (_this$props$onZoomAft = (_this$props17 = this.props).onZoomAfter) === null || _this$props$onZoomAft === void 0 ? void 0 : _this$props$onZoomAft.call(_this$props17, e, gestureState, this._getZoomableViewEventObject()); } /** * Used to debug pinch events @@ -976,12 +991,12 @@ class ReactNativeZoomableView extends _react.Component { zoomTo(newZoomLevel, zoomCenter) { - var _this$props$onZoomBef, _this$props17, _this$props$onZoomAft2, _this$props18; + var _this$props$onZoomBef, _this$props18, _this$props$onZoomAft2, _this$props19; if (!this.props.zoomEnabled) return false; if (this.props.maxZoom && newZoomLevel > this.props.maxZoom) return false; if (this.props.minZoom && newZoomLevel < this.props.minZoom) return false; - (_this$props$onZoomBef = (_this$props17 = this.props).onZoomBefore) === null || _this$props$onZoomBef === void 0 ? void 0 : _this$props$onZoomBef.call(_this$props17, null, null, this._getZoomableViewEventObject()); // == Perform Pan Animation to preserve the zoom center while zooming == + (_this$props$onZoomBef = (_this$props18 = this.props).onZoomBefore) === null || _this$props$onZoomBef === void 0 ? void 0 : _this$props$onZoomBef.call(_this$props18, null, null, this._getZoomableViewEventObject()); // == Perform Pan Animation to preserve the zoom center while zooming == let listenerId = ''; @@ -1008,7 +1023,7 @@ class ReactNativeZoomableView extends _react.Component { this.zoomAnim.removeListener(listenerId); }); // == Zoom Animation Ends == - (_this$props$onZoomAft2 = (_this$props18 = this.props).onZoomAfter) === null || _this$props$onZoomAft2 === void 0 ? void 0 : _this$props$onZoomAft2.call(_this$props18, null, null, this._getZoomableViewEventObject()); + (_this$props$onZoomAft2 = (_this$props19 = this.props).onZoomAfter) === null || _this$props$onZoomAft2 === void 0 ? void 0 : _this$props$onZoomAft2.call(_this$props19, null, null, this._getZoomableViewEventObject()); return true; } /** @@ -1090,12 +1105,7 @@ class ReactNativeZoomableView extends _react.Component { style: styles.container }, this.gestureHandlers.panHandlers, { ref: this.zoomSubjectWrapperRef, - onLayout: event => { - var _this$props$onLayout, _this$props19; - - (_this$props$onLayout = (_this$props19 = this.props).onLayout) === null || _this$props$onLayout === void 0 ? void 0 : _this$props$onLayout.call(_this$props19, event); - this.grabZoomSubjectOriginalMeasurements(); - } + onLayout: this.measureZoomSubject }), /*#__PURE__*/_react.default.createElement(_reactNative.Animated.View, { style: [styles.zoomSubject, this.props.style, { transform: [{ diff --git a/lib/commonjs/ReactNativeZoomableView.js.map b/lib/commonjs/ReactNativeZoomableView.js.map index dcc6a9f..7fc0b12 100644 --- a/lib/commonjs/ReactNativeZoomableView.js.map +++ b/lib/commonjs/ReactNativeZoomableView.js.map @@ -1 +1 @@ -{"version":3,"sources":["ReactNativeZoomableView.tsx"],"names":["initialState","originalWidth","originalHeight","originalPageX","originalPageY","pinSize","width","height","ReactNativeZoomableView","Component","gestureStarted","v","_gestureStarted","constructor","props","Animated","ValueXY","x","y","Value","value","boundaryCrossedAnimInEffect","position","onStaticPinPositionChange","requestAnimationFrame","setTimeout","zoomSubjectWrapperRef","current","measureInWindow","state","setState","e","gestureState","onStartShouldSetPanResponder","_getZoomableViewEventObject","onLongPress","longPressTimeout","longPressDuration","onPanResponderGrant","panAnim","stopAnimation","zoomAnim","raisePin","gestureType","_resolveAndHandleTap","debugPoints","lastGestureCenterPosition","disableMomentum","panEnabled","disablePanOnInitialZoom","zoomLevel","initialZoom","vx","vy","start","clearTimeout","onPanResponderEnd","onZoomEnd","onShiftingEnd","staticPinPosition","_updateStaticPin","dropPin","onPanResponderMove","numberActiveTouches","_handlePanResponderGrant","_handlePanResponderEnd","lastGestureTouchDistance","_handlePinching","Math","abs","dx","dy","isShiftGesture","_handleShifting","now","Date","doubleTapFirstTapReleaseTimestamp","doubleTapDelay","doubleTapFirstTap","_addTouch","id","toString","isSecondTap","singleTapTimeoutId","_handleDoubleTap","nativeEvent","pageX","pageY","persist","tapX","tapY","timing","toValue","offsetX","offsetY","useNativeDriver","duration","onSingleTap","contentWidth","contentHeight","pinX","pinY","setValue","viewportPosition","imageSize","zoomableEvent","_staticPinPosition","gestureHandlers","PanResponder","create","_handleStartShouldSetPanResponder","_handlePanResponderMove","onPanResponderRelease","onPanResponderTerminate","evt","onPanResponderTerminationRequest","onShouldBlockNativeResponder","onStartShouldSetPanResponderCapture","onMoveShouldSetPanResponderCapture","zoomAnimatedValue","panAnimatedValueXY","initialOffsetX","initialOffsetY","addListener","animatePin","pinAnim","easing","Easing","out","ease","__setOffset","__getOffset","axis","offset","offsetState","__offsets","bindToBorders","containerSize","contentSize","boundOffset","panBoundaryPadding","boundariesApplied","toFixed","componentDidUpdate","prevProps","prevState","zoomEnabled","onTransformInvocationInitialized","_invokeOnTransform","successful","currState","originalMeasurementsChanged","staticPinPositionChanged","componentDidMount","grabZoomSubjectOriginalMeasurements","measureZoomSubjectInterval","setInterval","componentWillUnmount","clearInterval","zoomableViewEvent","onTransform","onStaticPinPositionMove","debouncedOnStaticPinPositionChange","overwriteObj","maxZoom","minZoom","pinchToZoomInSensitivity","pinchToZoomOutSensitivity","distance","onZoomBefore","zoomGrowthFromLastGestureState","pinchToZoomSensitivity","deltaGrowth","deltaGrowthAdjustedBySensitivity","newZoomLevel","gestureCenterPoint","zoomCenter","debug","_setPinchDebugPoints","oldOffsetX","oldOffsetY","oldScale","newScale","offsetShift","_calcOffsetShiftSinceLastGestureState","onZoomAfter","gestureResponderEvent","points","touches","movementSensibility","shift","shiftX","shiftY","moveX","moveY","_setNewOffsetPosition","newOffsetX","newOffsetY","onShiftingBefore","onShiftingAfter","touch","push","_removeTouch","splice","indexOf","onDoubleTapBefore","onDoubleTapAfter","doubleTapZoomToCenter","nextZoomStep","_getNextZoomStep","zoomPositionCoordinates","zoomTo","zoomStep","listenerId","prevScale","removeListener","zoomBy","zoomLevelChange","moveTo","moveBy","offsetChangeX","offsetChangeY","render","staticPinIcon","children","visualTouchFeedbackEnabled","onStaticPinLongPress","onStaticPinPress","pinProps","styles","container","panHandlers","event","onLayout","zoomSubject","style","transform","scale","getTranslateTransform","map","index","size","undefined","StyleSheet","alignItems","flex","justifyContent","overflow"],"mappings":"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","sourcesContent":["import React, { Component, createRef, RefObject } from 'react';\nimport {\n Animated,\n Easing,\n GestureResponderEvent,\n PanResponder,\n PanResponderCallbacks,\n PanResponderGestureState,\n PanResponderInstance,\n StyleSheet,\n View,\n} from 'react-native';\n\nimport {\n Vec2D,\n ReactNativeZoomableViewProps,\n ReactNativeZoomableViewState,\n TouchPoint,\n ZoomableViewEvent,\n Size2D,\n} from './typings';\n\nimport { AnimatedTouchFeedback } from './components';\nimport { DebugTouchPoint } from './debugHelper';\nimport {\n calcGestureCenterPoint,\n calcGestureTouchDistance,\n calcNewScaledOffsetForZoomCentering,\n} from './helper';\nimport { applyPanBoundariesToOffset } from './helper/applyPanBoundariesToOffset';\nimport { viewportPositionToImagePosition } from './helper/coordinateConversion';\nimport { StaticPin } from './components/StaticPin';\nimport { debounce } from 'lodash';\nimport {\n getBoundaryCrossedAnim,\n getPanMomentumDecayAnim,\n getZoomToAnimation,\n} from './animations';\n\nconst initialState: ReactNativeZoomableViewState = {\n originalWidth: 0,\n originalHeight: 0,\n originalPageX: 0,\n originalPageY: 0,\n pinSize: { width: 0, height: 0 },\n};\n\nclass ReactNativeZoomableView extends Component<\n ReactNativeZoomableViewProps,\n ReactNativeZoomableViewState\n> {\n zoomSubjectWrapperRef: RefObject;\n gestureHandlers: PanResponderInstance;\n doubleTapFirstTapReleaseTimestamp: number | undefined;\n\n static defaultProps = {\n zoomEnabled: true,\n panEnabled: true,\n initialZoom: 1,\n initialOffsetX: 0,\n initialOffsetY: 0,\n maxZoom: 1.5,\n minZoom: 0.5,\n pinchToZoomInSensitivity: 1,\n pinchToZoomOutSensitivity: 1,\n movementSensibility: 1,\n doubleTapDelay: 300,\n bindToBorders: true,\n zoomStep: 0.5,\n onLongPress: null,\n longPressDuration: 700,\n contentWidth: undefined,\n contentHeight: undefined,\n panBoundaryPadding: 0,\n visualTouchFeedbackEnabled: true,\n staticPinPosition: undefined,\n staticPinIcon: undefined,\n onStaticPinPositionChange: undefined,\n onStaticPinPositionMove: undefined,\n animatePin: true,\n disablePanOnInitialZoom: false,\n };\n\n private panAnim = new Animated.ValueXY({ x: 0, y: 0 });\n private zoomAnim = new Animated.Value(1);\n private pinAnim = new Animated.ValueXY({ x: 0, y: 0 });\n\n private __offsets = {\n x: {\n value: 0,\n boundaryCrossedAnimInEffect: false,\n },\n y: {\n value: 0,\n boundaryCrossedAnimInEffect: false,\n },\n };\n\n private zoomLevel = 1;\n private lastGestureCenterPosition: { x: number; y: number } | null = null;\n private lastGestureTouchDistance: number | null = null;\n private gestureType: 'pinch' | 'shift' | null;\n\n private _gestureStarted = false;\n private set gestureStarted(v: boolean) {\n this._gestureStarted = v;\n }\n\n public get gestureStarted() {\n return this._gestureStarted;\n }\n\n /**\n * Last press time (used to evaluate whether user double tapped)\n * @type {number}\n */\n private longPressTimeout: NodeJS.Timeout | null = null;\n private onTransformInvocationInitialized: boolean | undefined;\n private singleTapTimeoutId: NodeJS.Timeout | undefined;\n private touches: TouchPoint[] = [];\n private doubleTapFirstTap: TouchPoint | undefined;\n private measureZoomSubjectInterval: NodeJS.Timer | undefined;\n\n constructor(props: ReactNativeZoomableViewProps) {\n super(props);\n // This needs to be done before anything else to initialize the state.\n // Otherwise, the logic below may reference the state when it's undefined,\n // causing runtime errors.\n this.state = { ...initialState };\n\n this.gestureHandlers = PanResponder.create({\n onStartShouldSetPanResponder: this._handleStartShouldSetPanResponder,\n onPanResponderGrant: this._handlePanResponderGrant,\n onPanResponderMove: this._handlePanResponderMove,\n onPanResponderRelease: this._handlePanResponderEnd,\n onPanResponderTerminate: (evt, gestureState) => {\n // We should also call _handlePanResponderEnd\n // to properly perform cleanups when the gesture is terminated\n // (aka gesture handling responsibility is taken over by another component).\n // This also fixes a weird issue where\n // on real device, sometimes onPanResponderRelease is not called when you lift 2 fingers up,\n // but onPanResponderTerminate is called instead for no apparent reason.\n this._handlePanResponderEnd(evt, gestureState);\n this.props.onPanResponderTerminate?.(\n evt,\n gestureState,\n this._getZoomableViewEventObject()\n );\n },\n onPanResponderTerminationRequest: (evt, gestureState) =>\n !!this.props.onPanResponderTerminationRequest?.(\n evt,\n gestureState,\n this._getZoomableViewEventObject()\n ),\n // Defaults to true to prevent parent components, such as React Navigation's tab view, from taking over as responder.\n onShouldBlockNativeResponder: (evt, gestureState) =>\n this.props.onShouldBlockNativeResponder?.(\n evt,\n gestureState,\n this._getZoomableViewEventObject()\n ) ?? true,\n onStartShouldSetPanResponderCapture: (evt, gestureState) =>\n !!this.props.onStartShouldSetPanResponderCapture?.(evt, gestureState),\n onMoveShouldSetPanResponderCapture: (evt, gestureState) =>\n !!this.props.onMoveShouldSetPanResponderCapture?.(evt, gestureState),\n });\n\n this.zoomSubjectWrapperRef = createRef();\n\n if (this.props.zoomAnimatedValue)\n this.zoomAnim = this.props.zoomAnimatedValue;\n if (this.props.panAnimatedValueXY)\n this.panAnim = this.props.panAnimatedValueXY;\n\n if (this.props.initialZoom) this.zoomLevel = this.props.initialZoom;\n if (this.props.initialOffsetX != null)\n this.offsetX = this.props.initialOffsetX;\n if (this.props.initialOffsetY != null)\n this.offsetY = this.props.initialOffsetY;\n\n this.panAnim.setValue({ x: this.offsetX, y: this.offsetY });\n this.zoomAnim.setValue(this.zoomLevel);\n this.panAnim.addListener(({ x, y }) => {\n this.offsetX = x;\n this.offsetY = y;\n });\n this.zoomAnim.addListener(({ value }) => {\n this.zoomLevel = value;\n });\n\n this.lastGestureTouchDistance = 150;\n\n this.gestureType = null;\n }\n\n private raisePin() {\n if (!this.props.animatePin) return;\n Animated.timing(this.pinAnim, {\n toValue: { x: 0, y: -10 },\n useNativeDriver: true,\n easing: Easing.out(Easing.ease),\n duration: 100,\n }).start();\n }\n\n private dropPin() {\n if (!this.props.animatePin) return;\n Animated.timing(this.pinAnim, {\n toValue: { x: 0, y: 0 },\n useNativeDriver: true,\n easing: Easing.out(Easing.ease),\n duration: 100,\n }).start();\n }\n\n private set offsetX(x: number) {\n this.__setOffset('x', x);\n }\n\n private set offsetY(y: number) {\n this.__setOffset('y', y);\n }\n\n private get offsetX() {\n return this.__getOffset('x');\n }\n\n private get offsetY() {\n return this.__getOffset('y');\n }\n\n private __setOffset(axis: 'x' | 'y', offset: number) {\n const offsetState = this.__offsets[axis];\n\n if (this.props.bindToBorders) {\n const containerSize =\n axis === 'x' ? this.state.originalWidth : this.state.originalHeight;\n const contentSize =\n axis === 'x'\n ? this.props.contentWidth || this.state.originalWidth\n : this.props.contentHeight || this.state.originalHeight;\n\n const boundOffset =\n contentSize && containerSize && this.props.panBoundaryPadding != null\n ? applyPanBoundariesToOffset(\n offset,\n containerSize,\n contentSize,\n this.zoomLevel,\n this.props.panBoundaryPadding\n )\n : offset;\n\n if (!this.gestureType && !offsetState.boundaryCrossedAnimInEffect) {\n const boundariesApplied =\n boundOffset !== offset &&\n boundOffset.toFixed(3) !== offset.toFixed(3);\n if (boundariesApplied) {\n offsetState.boundaryCrossedAnimInEffect = true;\n getBoundaryCrossedAnim(this.panAnim[axis], boundOffset).start(() => {\n offsetState.boundaryCrossedAnimInEffect = false;\n });\n return;\n }\n }\n }\n\n offsetState.value = offset;\n }\n\n private __getOffset(axis: 'x' | 'y') {\n return this.__offsets[axis].value;\n }\n\n componentDidUpdate(\n prevProps: ReactNativeZoomableViewProps,\n prevState: ReactNativeZoomableViewState\n ) {\n const { zoomEnabled, initialZoom } = this.props;\n if (prevProps.zoomEnabled && !zoomEnabled && initialZoom) {\n this.zoomLevel = initialZoom;\n this.zoomAnim.setValue(this.zoomLevel);\n }\n if (\n !this.onTransformInvocationInitialized &&\n this._invokeOnTransform().successful\n ) {\n this.panAnim.addListener(() => this._invokeOnTransform());\n this.zoomAnim.addListener(() => this._invokeOnTransform());\n this.onTransformInvocationInitialized = true;\n }\n\n const currState = this.state;\n const originalMeasurementsChanged =\n currState.originalHeight !== prevState.originalHeight ||\n currState.originalWidth !== prevState.originalWidth ||\n currState.originalPageX !== prevState.originalPageX ||\n currState.originalPageY !== prevState.originalPageY;\n\n const staticPinPositionChanged =\n prevProps.staticPinPosition?.x !== this.props.staticPinPosition?.x ||\n prevProps.staticPinPosition?.y !== this.props.staticPinPosition?.y;\n\n if (\n this.onTransformInvocationInitialized &&\n (originalMeasurementsChanged || staticPinPositionChanged)\n ) {\n this._invokeOnTransform();\n }\n }\n\n componentDidMount() {\n this.grabZoomSubjectOriginalMeasurements();\n // We've already run `grabZoomSubjectOriginalMeasurements` at various events\n // to make sure the measurements are promptly updated.\n // However, there might be cases we haven't accounted for, especially when\n // native processes are involved. To account for those cases,\n // we'll use an interval here to ensure we're always up-to-date.\n // The `setState` in `grabZoomSubjectOriginalMeasurements` won't trigger a rerender\n // if the values given haven't changed, so we're not running performance risk here.\n this.measureZoomSubjectInterval = setInterval(\n this.grabZoomSubjectOriginalMeasurements,\n 1e3\n );\n }\n\n componentWillUnmount() {\n this.measureZoomSubjectInterval &&\n clearInterval(this.measureZoomSubjectInterval);\n }\n\n debouncedOnStaticPinPositionChange = debounce(\n (position: Vec2D) => this.props.onStaticPinPositionChange?.(position),\n 100\n );\n\n /**\n * try to invoke onTransform\n * @private\n */\n _invokeOnTransform() {\n const zoomableViewEvent = this._getZoomableViewEventObject();\n const position = this._staticPinPosition();\n\n if (!zoomableViewEvent.originalWidth || !zoomableViewEvent.originalHeight)\n return { successful: false };\n\n this.props.onTransform?.(zoomableViewEvent);\n\n if (position) {\n this.props.onStaticPinPositionMove?.(position);\n this.debouncedOnStaticPinPositionChange(position);\n }\n\n return { successful: true };\n }\n\n /**\n * Returns additional information about components current state for external event hooks\n *\n * @returns {{}}\n * @private\n */\n _getZoomableViewEventObject(overwriteObj = {}): ZoomableViewEvent {\n return {\n zoomLevel: this.zoomLevel,\n offsetX: this.offsetX,\n offsetY: this.offsetY,\n originalHeight: this.state.originalHeight,\n originalWidth: this.state.originalWidth,\n originalPageX: this.state.originalPageX,\n originalPageY: this.state.originalPageY,\n ...overwriteObj,\n } as ZoomableViewEvent;\n }\n\n /**\n * Get the original box dimensions and save them for later use.\n * (They will be used to calculate boxBorders)\n *\n * @private\n */\n private grabZoomSubjectOriginalMeasurements = () => {\n // make sure we measure after animations are complete\n requestAnimationFrame(() => {\n // this setTimeout is here to fix a weird issue on iOS where the measurements are all `0`\n // when navigating back (react-navigation stack) from another view\n // while closing the keyboard at the same time\n setTimeout(() => {\n // In normal conditions, we're supposed to measure zoomSubject instead of its wrapper.\n // However, our zoomSubject may have been transformed by an initial zoomLevel or offset,\n // in which case these measurements will not represent the true \"original\" measurements.\n // We just need to make sure the zoomSubjectWrapper perfectly aligns with the zoomSubject\n // (no border, space, or anything between them)\n const zoomSubjectWrapperRef = this.zoomSubjectWrapperRef;\n // we don't wanna measure when zoomSubjectWrapperRef is not yet available or has been unmounted\n zoomSubjectWrapperRef.current?.measureInWindow(\n (x, y, width, height) => {\n // When the component is off-screen, these become all 0s, so we don't set them\n // to avoid messing up calculations, especially ones that are done right after\n // the component transitions from hidden to visible.\n if (!x && !y && !width && !height) return;\n\n // If these values are all the same, don't re-set them in state\n // this way we don't re-render\n if (\n this.state.originalWidth === width &&\n this.state.originalHeight === height &&\n this.state.originalPageX === x &&\n this.state.originalPageY === y\n ) {\n return;\n }\n\n this.setState({\n originalWidth: width,\n originalHeight: height,\n originalPageX: x,\n originalPageY: y,\n });\n }\n );\n });\n });\n };\n\n /**\n * Handles the start of touch events and checks for taps\n *\n * @param e\n * @param gestureState\n * @returns {boolean}\n *\n * @private\n */\n _handleStartShouldSetPanResponder = (\n e: GestureResponderEvent,\n gestureState: PanResponderGestureState\n ) => {\n if (this.props.onStartShouldSetPanResponder) {\n this.props.onStartShouldSetPanResponder(\n e,\n gestureState,\n this._getZoomableViewEventObject(),\n false\n );\n }\n\n // Always set pan responder on start\n // of gesture so we can handle tap.\n // \"Pan threshold validation\" will be handled\n // in `onPanResponderMove` instead of in `onMoveShouldSetPanResponder`\n return true;\n };\n\n /**\n * Calculates pinch distance\n *\n * @param e\n * @param gestureState\n * @private\n */\n _handlePanResponderGrant: NonNullable<\n PanResponderCallbacks['onPanResponderGrant']\n > = (e, gestureState) => {\n if (this.props.onLongPress) {\n this.longPressTimeout = setTimeout(() => {\n this.props.onLongPress?.(\n e,\n gestureState,\n this._getZoomableViewEventObject()\n );\n this.longPressTimeout = null;\n }, this.props.longPressDuration);\n }\n\n this.props.onPanResponderGrant?.(\n e,\n gestureState,\n this._getZoomableViewEventObject()\n );\n\n this.panAnim.stopAnimation();\n this.zoomAnim.stopAnimation();\n this.gestureStarted = true;\n\n this.raisePin();\n };\n\n /**\n * Handles the end of touch events\n *\n * @param e\n * @param gestureState\n *\n * @private\n */\n _handlePanResponderEnd: NonNullable<\n PanResponderCallbacks['onPanResponderEnd']\n > = (e, gestureState) => {\n if (!this.gestureType) {\n this._resolveAndHandleTap(e);\n }\n\n this.setState({ debugPoints: [] });\n\n this.lastGestureCenterPosition = null;\n\n const disableMomentum =\n this.props.disableMomentum ||\n (this.props.panEnabled &&\n this.gestureType === 'shift' &&\n this.props.disablePanOnInitialZoom &&\n this.zoomLevel === this.props.initialZoom);\n\n // Trigger final shift animation unless disablePanOnInitialZoom is set and we're on the initial zoom level\n // or disableMomentum\n if (!disableMomentum) {\n getPanMomentumDecayAnim(this.panAnim, {\n x: gestureState.vx / this.zoomLevel,\n y: gestureState.vy / this.zoomLevel,\n }).start();\n }\n\n if (this.longPressTimeout) {\n clearTimeout(this.longPressTimeout);\n this.longPressTimeout = null;\n }\n\n this.props.onPanResponderEnd?.(\n e,\n gestureState,\n this._getZoomableViewEventObject()\n );\n\n if (this.gestureType === 'pinch') {\n this.props.onZoomEnd?.(\n e,\n gestureState,\n this._getZoomableViewEventObject()\n );\n } else if (this.gestureType === 'shift') {\n this.props.onShiftingEnd?.(\n e,\n gestureState,\n this._getZoomableViewEventObject()\n );\n }\n\n if (this.props.staticPinPosition) {\n this._updateStaticPin();\n }\n\n this.dropPin();\n\n this.gestureType = null;\n this.gestureStarted = false;\n };\n\n /**\n * Handles the actual movement of our pan responder\n *\n * @param e\n * @param gestureState\n *\n * @private\n */\n _handlePanResponderMove = (\n e: GestureResponderEvent,\n gestureState: PanResponderGestureState\n ) => {\n if (this.props.onPanResponderMove) {\n if (\n this.props.onPanResponderMove(\n e,\n gestureState,\n this._getZoomableViewEventObject()\n )\n ) {\n return false;\n }\n }\n\n // Only supports 2 touches and below,\n // any invalid number will cause the gesture to end.\n if (gestureState.numberActiveTouches <= 2) {\n if (!this.gestureStarted) {\n this._handlePanResponderGrant(e, gestureState);\n }\n } else {\n if (this.gestureStarted) {\n this._handlePanResponderEnd(e, gestureState);\n }\n return true;\n }\n\n if (gestureState.numberActiveTouches === 2) {\n if (this.longPressTimeout) {\n clearTimeout(this.longPressTimeout);\n this.longPressTimeout = null;\n }\n\n // change some measurement states when switching gesture to ensure a smooth transition\n if (this.gestureType !== 'pinch') {\n this.lastGestureCenterPosition = calcGestureCenterPoint(\n e,\n gestureState\n );\n this.lastGestureTouchDistance = calcGestureTouchDistance(\n e,\n gestureState\n );\n }\n this.gestureType = 'pinch';\n this._handlePinching(e, gestureState);\n } else if (gestureState.numberActiveTouches === 1) {\n if (\n this.longPressTimeout &&\n (Math.abs(gestureState.dx) > 5 || Math.abs(gestureState.dy) > 5)\n ) {\n clearTimeout(this.longPressTimeout);\n this.longPressTimeout = null;\n }\n // change some measurement states when switching gesture to ensure a smooth transition\n if (this.gestureType !== 'shift') {\n this.lastGestureCenterPosition = calcGestureCenterPoint(\n e,\n gestureState\n );\n }\n\n const { dx, dy } = gestureState;\n const isShiftGesture = Math.abs(dx) > 2 || Math.abs(dy) > 2;\n if (isShiftGesture) {\n this.gestureType = 'shift';\n this._handleShifting(gestureState);\n }\n }\n };\n\n /**\n * Handles the pinch movement and zooming\n *\n * @param e\n * @param gestureState\n *\n * @private\n */\n _handlePinching(\n e: GestureResponderEvent,\n gestureState: PanResponderGestureState\n ) {\n if (!this.props.zoomEnabled) return;\n\n const {\n maxZoom,\n minZoom,\n pinchToZoomInSensitivity,\n pinchToZoomOutSensitivity,\n } = this.props;\n\n const distance = calcGestureTouchDistance(e, gestureState);\n\n if (\n this.props.onZoomBefore &&\n this.props.onZoomBefore(\n e,\n gestureState,\n this._getZoomableViewEventObject()\n )\n ) {\n return;\n }\n\n if (!distance) return;\n if (!this.lastGestureTouchDistance) return;\n\n // define the new zoom level and take zoom level sensitivity into consideration\n const zoomGrowthFromLastGestureState =\n distance / this.lastGestureTouchDistance;\n this.lastGestureTouchDistance = distance;\n\n const pinchToZoomSensitivity =\n zoomGrowthFromLastGestureState < 1\n ? pinchToZoomOutSensitivity\n : pinchToZoomInSensitivity;\n\n if (pinchToZoomSensitivity == null) return;\n const deltaGrowth = zoomGrowthFromLastGestureState - 1;\n // 0 - no resistance\n // 10 - 90% resistance\n const deltaGrowthAdjustedBySensitivity =\n deltaGrowth * (1 - (pinchToZoomSensitivity * 9) / 100);\n\n let newZoomLevel = this.zoomLevel * (1 + deltaGrowthAdjustedBySensitivity);\n\n // make sure max and min zoom levels are respected\n if (maxZoom != null && newZoomLevel > maxZoom) {\n newZoomLevel = maxZoom;\n }\n\n if (minZoom != null && newZoomLevel < minZoom) {\n newZoomLevel = minZoom;\n }\n\n const gestureCenterPoint = calcGestureCenterPoint(e, gestureState);\n\n if (!gestureCenterPoint) return;\n\n let zoomCenter = {\n x: gestureCenterPoint.x - this.state.originalPageX,\n y: gestureCenterPoint.y - this.state.originalPageY,\n };\n\n if (this.props.staticPinPosition) {\n // When we use a static pin position, the zoom centre is the same as that position,\n // otherwise the pin moves around way too much while zooming.\n zoomCenter = {\n x: this.props.staticPinPosition.x,\n y: this.props.staticPinPosition.y,\n };\n }\n\n // Uncomment to debug\n this.props.debug && this._setPinchDebugPoints(e, zoomCenter);\n\n const { originalHeight, originalWidth } = this.state;\n\n const oldOffsetX = this.offsetX;\n const oldOffsetY = this.offsetY;\n const oldScale = this.zoomLevel;\n const newScale = newZoomLevel;\n\n if (!originalHeight || !originalWidth) return;\n\n let offsetY = calcNewScaledOffsetForZoomCentering(\n oldOffsetY,\n originalHeight,\n oldScale,\n newScale,\n zoomCenter.y\n );\n let offsetX = calcNewScaledOffsetForZoomCentering(\n oldOffsetX,\n originalWidth,\n oldScale,\n newScale,\n zoomCenter.x\n );\n\n const offsetShift =\n this._calcOffsetShiftSinceLastGestureState(gestureCenterPoint);\n if (offsetShift) {\n offsetX += offsetShift.x;\n offsetY += offsetShift.y;\n }\n\n this.offsetX = offsetX;\n this.offsetY = offsetY;\n this.zoomLevel = newScale;\n\n this.panAnim.setValue({ x: this.offsetX, y: this.offsetY });\n this.zoomAnim.setValue(this.zoomLevel);\n\n this.props.onZoomAfter?.(\n e,\n gestureState,\n this._getZoomableViewEventObject()\n );\n }\n\n /**\n * Used to debug pinch events\n * @param gestureResponderEvent\n * @param zoomCenter\n * @param points\n */\n _setPinchDebugPoints(\n gestureResponderEvent: GestureResponderEvent,\n zoomCenter: Vec2D,\n ...points: Vec2D[]\n ) {\n const { touches } = gestureResponderEvent.nativeEvent;\n const { originalPageY, originalPageX } = this.state;\n\n this.setState({\n debugPoints: [\n {\n x: touches[0].pageX - originalPageX,\n y: touches[0].pageY - originalPageY,\n },\n {\n x: touches[1].pageX - originalPageX,\n y: touches[1].pageY - originalPageY,\n },\n zoomCenter,\n ...points,\n ],\n });\n }\n\n /**\n * Calculates the amount the offset should shift since the last position during panning\n *\n * @param {Vec2D} gestureCenterPoint\n *\n * @private\n */\n _calcOffsetShiftSinceLastGestureState(gestureCenterPoint: Vec2D) {\n const { movementSensibility } = this.props;\n\n let shift = null;\n\n if (this.lastGestureCenterPosition && movementSensibility) {\n const dx = gestureCenterPoint.x - this.lastGestureCenterPosition.x;\n const dy = gestureCenterPoint.y - this.lastGestureCenterPosition.y;\n\n const shiftX = dx / this.zoomLevel / movementSensibility;\n const shiftY = dy / this.zoomLevel / movementSensibility;\n\n shift = {\n x: shiftX,\n y: shiftY,\n };\n }\n\n this.lastGestureCenterPosition = gestureCenterPoint;\n\n return shift;\n }\n\n /**\n * Handles movement by tap and move\n *\n * @param gestureState\n *\n * @private\n */\n _handleShifting(gestureState: PanResponderGestureState) {\n // Skips shifting if panEnabled is false or disablePanOnInitialZoom is true and we're on the initial zoom level\n if (\n !this.props.panEnabled ||\n (this.props.disablePanOnInitialZoom &&\n this.zoomLevel === this.props.initialZoom)\n ) {\n return;\n }\n const shift = this._calcOffsetShiftSinceLastGestureState({\n x: gestureState.moveX,\n y: gestureState.moveY,\n });\n if (!shift) return;\n\n const offsetX = this.offsetX + shift.x;\n const offsetY = this.offsetY + shift.y;\n\n if (\n this.props.debug &&\n this.state.originalPageX &&\n this.state.originalPageY\n ) {\n const x = gestureState.moveX - this.state.originalPageX;\n const y = gestureState.moveY - this.state.originalPageY;\n this.setState({ debugPoints: [{ x, y }] });\n }\n\n this._setNewOffsetPosition(offsetX, offsetY);\n\n this.raisePin();\n }\n\n /**\n * Set the state to offset moved\n *\n * @param {number} newOffsetX\n * @param {number} newOffsetY\n * @returns\n */\n _setNewOffsetPosition(newOffsetX: number, newOffsetY: number) {\n const { onShiftingBefore, onShiftingAfter } = this.props;\n\n if (onShiftingBefore?.(null, null, this._getZoomableViewEventObject())) {\n return;\n }\n\n this.offsetX = newOffsetX;\n this.offsetY = newOffsetY;\n\n this.panAnim.setValue({ x: this.offsetX, y: this.offsetY });\n this.zoomAnim.setValue(this.zoomLevel);\n\n onShiftingAfter?.(null, null, this._getZoomableViewEventObject());\n }\n\n /**\n * Check whether the press event is double tap\n * or single tap and handle the event accordingly\n *\n * @param e\n *\n * @private\n */\n private _resolveAndHandleTap = (e: GestureResponderEvent) => {\n const now = Date.now();\n if (\n this.doubleTapFirstTapReleaseTimestamp &&\n this.props.doubleTapDelay &&\n now - this.doubleTapFirstTapReleaseTimestamp < this.props.doubleTapDelay\n ) {\n this.doubleTapFirstTap &&\n this._addTouch({\n ...this.doubleTapFirstTap,\n id: now.toString(),\n isSecondTap: true,\n });\n this.singleTapTimeoutId && clearTimeout(this.singleTapTimeoutId);\n delete this.doubleTapFirstTapReleaseTimestamp;\n delete this.singleTapTimeoutId;\n delete this.doubleTapFirstTap;\n this._handleDoubleTap(e);\n } else {\n this.doubleTapFirstTapReleaseTimestamp = now;\n this.doubleTapFirstTap = {\n id: now.toString(),\n x: e.nativeEvent.pageX - this.state.originalPageX,\n y: e.nativeEvent.pageY - this.state.originalPageY,\n };\n this._addTouch(this.doubleTapFirstTap);\n\n // persist event so e.nativeEvent is preserved after a timeout delay\n e.persist();\n this.singleTapTimeoutId = setTimeout(() => {\n delete this.doubleTapFirstTapReleaseTimestamp;\n delete this.singleTapTimeoutId;\n\n // Pan to the tapped location\n if (this.props.staticPinPosition && this.doubleTapFirstTap) {\n const tapX =\n this.props.staticPinPosition.x - this.doubleTapFirstTap.x;\n const tapY =\n this.props.staticPinPosition.y - this.doubleTapFirstTap.y;\n\n Animated.timing(this.panAnim, {\n toValue: {\n x: this.offsetX + tapX / this.zoomLevel,\n y: this.offsetY + tapY / this.zoomLevel,\n },\n useNativeDriver: true,\n duration: 200,\n }).start(() => {\n this._updateStaticPin();\n });\n }\n\n this.props.onSingleTap?.(e, this._getZoomableViewEventObject());\n }, this.props.doubleTapDelay);\n }\n };\n\n moveStaticPinTo = (position: Vec2D, duration?: number) => {\n const { originalWidth, originalHeight } = this.state;\n const { staticPinPosition, contentWidth, contentHeight } = this.props;\n\n if (!staticPinPosition) return;\n if (!originalWidth || !originalHeight) return;\n if (!contentWidth || !contentHeight) return;\n\n // Offset for the static pin\n const pinX = staticPinPosition.x - originalWidth / 2;\n const pinY = staticPinPosition.y - originalHeight / 2;\n\n this.offsetX = contentWidth / 2 - position.x + pinX / this.zoomLevel;\n this.offsetY = contentHeight / 2 - position.y + pinY / this.zoomLevel;\n\n if (duration) {\n Animated.timing(this.panAnim, {\n toValue: { x: this.offsetX, y: this.offsetY },\n useNativeDriver: true,\n duration,\n }).start();\n } else {\n this.panAnim.setValue({ x: this.offsetX, y: this.offsetY });\n }\n };\n\n private _staticPinPosition = () => {\n if (!this.props.staticPinPosition) return;\n if (!this.props.contentWidth || !this.props.contentHeight) return;\n\n return viewportPositionToImagePosition({\n viewportPosition: {\n x: this.props.staticPinPosition.x,\n y: this.props.staticPinPosition.y,\n },\n imageSize: {\n height: this.props.contentHeight,\n width: this.props.contentWidth,\n },\n zoomableEvent: {\n ...this._getZoomableViewEventObject(),\n offsetX: this.offsetX,\n offsetY: this.offsetY,\n zoomLevel: this.zoomLevel,\n },\n });\n };\n\n private _updateStaticPin = () => {\n const position = this._staticPinPosition();\n if (!position) return;\n this.props.onStaticPinPositionChange?.(position);\n };\n\n private _addTouch(touch: TouchPoint) {\n this.touches.push(touch);\n this.setState({ touches: [...this.touches] });\n }\n\n private _removeTouch(touch: TouchPoint) {\n this.touches.splice(this.touches.indexOf(touch), 1);\n this.setState({ touches: [...this.touches] });\n }\n\n /**\n * Handles the double tap event\n *\n * @param e\n *\n * @private\n */\n _handleDoubleTap(e: GestureResponderEvent) {\n const { onDoubleTapBefore, onDoubleTapAfter, doubleTapZoomToCenter } =\n this.props;\n\n onDoubleTapBefore?.(e, this._getZoomableViewEventObject());\n\n const nextZoomStep = this._getNextZoomStep();\n if (nextZoomStep == null) return;\n\n const { originalPageX, originalPageY } = this.state;\n\n // define new zoom position coordinates\n const zoomPositionCoordinates = {\n x: e.nativeEvent.pageX - originalPageX,\n y: e.nativeEvent.pageY - originalPageY,\n };\n\n // if doubleTapZoomToCenter enabled -> always zoom to center instead\n if (doubleTapZoomToCenter) {\n zoomPositionCoordinates.x = 0;\n zoomPositionCoordinates.y = 0;\n }\n\n this.zoomTo(nextZoomStep, zoomPositionCoordinates);\n\n onDoubleTapAfter?.(\n e,\n this._getZoomableViewEventObject({ zoomLevel: nextZoomStep })\n );\n }\n\n /**\n * Returns the next zoom step based on current step and zoomStep property.\n * If we are zoomed all the way in -> return to initialzoom\n *\n * @returns {*}\n */\n _getNextZoomStep() {\n const { zoomStep, maxZoom, initialZoom } = this.props;\n const { zoomLevel } = this;\n\n if (maxZoom == null) return;\n\n if (zoomLevel.toFixed(2) === maxZoom.toFixed(2)) {\n return initialZoom;\n }\n\n if (zoomStep == null) return;\n\n const nextZoomStep = zoomLevel * (1 + zoomStep);\n if (nextZoomStep > maxZoom) {\n return maxZoom;\n }\n\n return nextZoomStep;\n }\n\n /**\n * Zooms to a specific level. A \"zoom center\" can be provided, which specifies\n * the point that will remain in the same position on the screen after the zoom.\n * The coordinates of the zoom center is relative to the zoom subject.\n * { x: 0, y: 0 } is the very center of the zoom subject.\n *\n * @param newZoomLevel\n * @param zoomCenter - If not supplied, the container's center is the zoom center\n */\n zoomTo(newZoomLevel: number, zoomCenter?: Vec2D) {\n if (!this.props.zoomEnabled) return false;\n if (this.props.maxZoom && newZoomLevel > this.props.maxZoom) return false;\n if (this.props.minZoom && newZoomLevel < this.props.minZoom) return false;\n\n this.props.onZoomBefore?.(null, null, this._getZoomableViewEventObject());\n\n // == Perform Pan Animation to preserve the zoom center while zooming ==\n let listenerId = '';\n if (zoomCenter) {\n // Calculates panAnim values based on changes in zoomAnim.\n let prevScale = this.zoomLevel;\n // Since zoomAnim is calculated in native driver,\n // it will jitter panAnim once in a while,\n // because here panAnim is being calculated in js.\n // However the jittering should mostly occur in simulator.\n listenerId = this.zoomAnim.addListener(({ value: newScale }) => {\n this.panAnim.setValue({\n x: calcNewScaledOffsetForZoomCentering(\n this.offsetX,\n this.state.originalWidth,\n prevScale,\n newScale,\n zoomCenter.x\n ),\n y: calcNewScaledOffsetForZoomCentering(\n this.offsetY,\n this.state.originalHeight,\n prevScale,\n newScale,\n zoomCenter.y\n ),\n });\n prevScale = newScale;\n });\n }\n\n // == Perform Zoom Animation ==\n getZoomToAnimation(this.zoomAnim, newZoomLevel).start(() => {\n this.zoomAnim.removeListener(listenerId);\n });\n // == Zoom Animation Ends ==\n\n this.props.onZoomAfter?.(null, null, this._getZoomableViewEventObject());\n return true;\n }\n\n /**\n * Zooms in or out by a specified change level\n * Use a positive number for `zoomLevelChange` to zoom in\n * Use a negative number for `zoomLevelChange` to zoom out\n *\n * Returns a promise if everything was updated and a boolean, whether it could be updated or if it exceeded the min/max zoom limits.\n *\n * @param {number | null} zoomLevelChange\n *\n * @return {bool}\n */\n zoomBy(zoomLevelChange: number) {\n // if no zoom level Change given -> just use zoom step\n zoomLevelChange ||= this.props.zoomStep || 0;\n return this.zoomTo(this.zoomLevel + zoomLevelChange);\n }\n\n /**\n * Moves the zoomed view to a specified position\n * Returns a promise when finished\n *\n * @param {number} newOffsetX the new position we want to move it to (x-axis)\n * @param {number} newOffsetY the new position we want to move it to (y-axis)\n *\n * @return {bool}\n */\n moveTo(newOffsetX: number, newOffsetY: number) {\n const { originalWidth, originalHeight } = this.state;\n if (!originalWidth || !originalHeight) return;\n\n const offsetX = (newOffsetX - originalWidth / 2) / this.zoomLevel;\n const offsetY = (newOffsetY - originalHeight / 2) / this.zoomLevel;\n\n this._setNewOffsetPosition(-offsetX, -offsetY);\n }\n\n /**\n * Moves the zoomed view by a certain amount.\n *\n * Returns a promise when finished\n *\n * @param {number} offsetChangeX the amount we want to move the offset by (x-axis)\n * @param {number} offsetChangeY the amount we want to move the offset by (y-axis)\n *\n * @return {bool}\n */\n moveBy(offsetChangeX: number, offsetChangeY: number) {\n const offsetX =\n (this.offsetX * this.zoomLevel - offsetChangeX) / this.zoomLevel;\n const offsetY =\n (this.offsetY * this.zoomLevel - offsetChangeY) / this.zoomLevel;\n\n this._setNewOffsetPosition(offsetX, offsetY);\n }\n\n render() {\n const {\n staticPinIcon,\n children,\n visualTouchFeedbackEnabled,\n doubleTapDelay,\n staticPinPosition,\n onStaticPinLongPress,\n onStaticPinPress,\n pinProps,\n } = this.props;\n const { pinSize, touches, debugPoints = [] } = this.state;\n\n return (\n {\n this.props.onLayout?.(event);\n this.grabZoomSubjectOriginalMeasurements();\n }}\n >\n \n {children}\n \n\n {visualTouchFeedbackEnabled &&\n touches?.map(\n (touch) =>\n doubleTapDelay && (\n {\n this._removeTouch(touch);\n }}\n />\n )\n )}\n\n {/* For Debugging Only */}\n {debugPoints.map(({ x, y }, index) => {\n return ;\n })}\n\n {staticPinPosition && (\n {\n this.setState({ pinSize: size });\n }}\n pinProps={pinProps}\n />\n )}\n \n );\n }\n}\n\nconst styles = StyleSheet.create({\n container: {\n alignItems: 'center',\n flex: 1,\n justifyContent: 'center',\n overflow: 'hidden',\n position: 'relative',\n },\n zoomSubject: {\n alignItems: 'center',\n flex: 1,\n justifyContent: 'center',\n width: '100%',\n },\n});\n\nexport default ReactNativeZoomableView;\n\nexport { ReactNativeZoomableView };\n"]} \ No newline at end of file +{"version":3,"sources":["ReactNativeZoomableView.tsx"],"names":["initialState","originalWidth","originalHeight","originalPageX","originalPageY","pinSize","width","height","ReactNativeZoomableView","Component","gestureStarted","v","_gestureStarted","constructor","props","Animated","ValueXY","x","y","Value","value","boundaryCrossedAnimInEffect","position","onStaticPinPositionChange","requestAnimationFrame","setTimeout","zoomSubjectWrapperRef","current","measureInWindow","state","setState","e","gestureState","onStartShouldSetPanResponder","_getZoomableViewEventObject","onLongPress","longPressTimeout","longPressDuration","onPanResponderGrant","panAnim","stopAnimation","zoomAnim","raisePin","gestureType","_resolveAndHandleTap","debugPoints","lastGestureCenterPosition","disableMomentum","panEnabled","disablePanOnInitialZoom","zoomLevel","initialZoom","vx","vy","start","clearTimeout","onPanResponderEnd","onZoomEnd","onShiftingEnd","staticPinPosition","_updateStaticPin","dropPin","onPanResponderMove","numberActiveTouches","_handlePanResponderGrant","_handlePanResponderEnd","lastGestureTouchDistance","_handlePinching","Math","abs","dx","dy","isShiftGesture","_handleShifting","now","Date","doubleTapFirstTapReleaseTimestamp","doubleTapDelay","doubleTapFirstTap","_addTouch","id","toString","isSecondTap","singleTapTimeoutId","_handleDoubleTap","nativeEvent","pageX","pageY","persist","tapX","tapY","timing","toValue","offsetX","offsetY","useNativeDriver","duration","onSingleTap","contentWidth","contentHeight","pinX","pinY","setValue","viewportPosition","imageSize","zoomableEvent","_staticPinPosition","gestureHandlers","PanResponder","create","_handleStartShouldSetPanResponder","_handlePanResponderMove","onPanResponderRelease","onPanResponderTerminate","evt","onPanResponderTerminationRequest","onShouldBlockNativeResponder","onStartShouldSetPanResponderCapture","onMoveShouldSetPanResponderCapture","zoomAnimatedValue","panAnimatedValueXY","initialOffsetX","initialOffsetY","addListener","animatePin","pinAnim","easing","Easing","out","ease","__setOffset","__getOffset","axis","offset","offsetState","__offsets","bindToBorders","containerSize","contentSize","boundOffset","panBoundaryPadding","boundariesApplied","toFixed","componentDidUpdate","prevProps","prevState","zoomEnabled","onTransformInvocationInitialized","_invokeOnTransform","successful","currState","originalMeasurementsChanged","staticPinPositionChanged","onLayoutMeasured","componentDidMount","measureZoomSubject","measureZoomSubjectInterval","setInterval","componentWillUnmount","clearInterval","zoomableViewEvent","onTransform","onStaticPinPositionMove","debouncedOnStaticPinPositionChange","overwriteObj","maxZoom","minZoom","pinchToZoomInSensitivity","pinchToZoomOutSensitivity","distance","onZoomBefore","zoomGrowthFromLastGestureState","pinchToZoomSensitivity","deltaGrowth","deltaGrowthAdjustedBySensitivity","newZoomLevel","gestureCenterPoint","zoomCenter","debug","_setPinchDebugPoints","oldOffsetX","oldOffsetY","oldScale","newScale","offsetShift","_calcOffsetShiftSinceLastGestureState","onZoomAfter","gestureResponderEvent","points","touches","movementSensibility","shift","shiftX","shiftY","moveX","moveY","_setNewOffsetPosition","newOffsetX","newOffsetY","onShiftingBefore","onShiftingAfter","touch","push","_removeTouch","splice","indexOf","onDoubleTapBefore","onDoubleTapAfter","doubleTapZoomToCenter","nextZoomStep","_getNextZoomStep","zoomPositionCoordinates","zoomTo","zoomStep","listenerId","prevScale","removeListener","zoomBy","zoomLevelChange","moveTo","moveBy","offsetChangeX","offsetChangeY","render","staticPinIcon","children","visualTouchFeedbackEnabled","onStaticPinLongPress","onStaticPinPress","pinProps","styles","container","panHandlers","zoomSubject","style","transform","scale","getTranslateTransform","map","index","size","undefined","StyleSheet","alignItems","flex","justifyContent","overflow"],"mappings":";;;;;;;AAAA;;AACA;;AAqBA;;AACA;;AACA;;AAKA;;AACA;;AACA;;AACA;;AACA;;;;;;;;;;AAMA,MAAMA,YAA0C,GAAG;AACjDC,EAAAA,aAAa,EAAE,CADkC;AAEjDC,EAAAA,cAAc,EAAE,CAFiC;AAGjDC,EAAAA,aAAa,EAAE,CAHkC;AAIjDC,EAAAA,aAAa,EAAE,CAJkC;AAKjDC,EAAAA,OAAO,EAAE;AAAEC,IAAAA,KAAK,EAAE,CAAT;AAAYC,IAAAA,MAAM,EAAE;AAApB;AALwC,CAAnD;;AAQA,MAAMC,uBAAN,SAAsCC,gBAAtC,CAGE;AAsD0B,MAAdC,cAAc,CAACC,CAAD,EAAa;AACrC,SAAKC,eAAL,GAAuBD,CAAvB;AACD;;AAEwB,MAAdD,cAAc,GAAG;AAC1B,WAAO,KAAKE,eAAZ;AACD;AAED;AACF;AACA;AACA;;;AAQEC,EAAAA,WAAW,CAACC,KAAD,EAAsC;AAC/C,UAAMA,KAAN,EAD+C,CAE/C;AACA;AACA;;AAJ+C;;AAAA;;AAAA;;AAAA,qCAxC/B,IAAIC,sBAASC,OAAb,CAAqB;AAAEC,MAAAA,CAAC,EAAE,CAAL;AAAQC,MAAAA,CAAC,EAAE;AAAX,KAArB,CAwC+B;;AAAA,sCAvC9B,IAAIH,sBAASI,KAAb,CAAmB,CAAnB,CAuC8B;;AAAA,qCAtC/B,IAAIJ,sBAASC,OAAb,CAAqB;AAAEC,MAAAA,CAAC,EAAE,CAAL;AAAQC,MAAAA,CAAC,EAAE;AAAX,KAArB,CAsC+B;;AAAA,uCApC7B;AAClBD,MAAAA,CAAC,EAAE;AACDG,QAAAA,KAAK,EAAE,CADN;AAEDC,QAAAA,2BAA2B,EAAE;AAF5B,OADe;AAKlBH,MAAAA,CAAC,EAAE;AACDE,QAAAA,KAAK,EAAE,CADN;AAEDC,QAAAA,2BAA2B,EAAE;AAF5B;AALe,KAoC6B;;AAAA,uCAzB7B,CAyB6B;;AAAA,uDAxBoB,IAwBpB;;AAAA,sDAvBC,IAuBD;;AAAA;;AAAA,6CApBvB,KAoBuB;;AAAA,8CAPC,IAOD;;AAAA;;AAAA;;AAAA,qCAJjB,EAIiB;;AAAA;;AAAA;;AAAA,gEA4NZ,sBAClCC,QAAD;AAAA;;AAAA,sCAAqB,oBAAKR,KAAL,EAAWS,yBAAhC,0DAAqB,wCAAuCD,QAAvC,CAArB;AAAA,KADmC,EAEnC,GAFmC,CA5NY;;AAAA,gDA+QpB,MAAM;AACjC;AACAE,MAAAA,qBAAqB,CAAC,MAAM;AAC1B;AACA;AACA;AACAC,QAAAA,UAAU,CAAC,MAAM;AAAA;;AACf;AACA;AACA;AACA;AACA;AACA,gBAAMC,qBAAqB,GAAG,KAAKA,qBAAnC,CANe,CAOf;;AACA,mCAAAA,qBAAqB,CAACC,OAAtB,gFAA+BC,eAA/B,CACE,CAACX,CAAD,EAAIC,CAAJ,EAAOZ,KAAP,EAAcC,MAAd,KAAyB;AACvB;AACA;AACA;AACA,gBAAI,CAACU,CAAD,IAAM,CAACC,CAAP,IAAY,CAACZ,KAAb,IAAsB,CAACC,MAA3B,EAAmC,OAJZ,CAMvB;AACA;;AACA,gBACE,KAAKsB,KAAL,CAAW5B,aAAX,KAA6BK,KAA7B,IACA,KAAKuB,KAAL,CAAW3B,cAAX,KAA8BK,MAD9B,IAEA,KAAKsB,KAAL,CAAW1B,aAAX,KAA6Bc,CAF7B,IAGA,KAAKY,KAAL,CAAWzB,aAAX,KAA6Bc,CAJ/B,EAKE;AACA;AACD;;AAED,iBAAKY,QAAL,CAAc;AACZ7B,cAAAA,aAAa,EAAEK,KADH;AAEZJ,cAAAA,cAAc,EAAEK,MAFJ;AAGZJ,cAAAA,aAAa,EAAEc,CAHH;AAIZb,cAAAA,aAAa,EAAEc;AAJH,aAAd;AAMD,WAxBH;AA0BD,SAlCS,CAAV;AAmCD,OAvCoB,CAArB;AAwCD,KAzTgD;;AAAA,+DAoUb,CAClCa,CADkC,EAElCC,YAFkC,KAG/B;AACH,UAAI,KAAKlB,KAAL,CAAWmB,4BAAf,EAA6C;AAC3C,aAAKnB,KAAL,CAAWmB,4BAAX,CACEF,CADF,EAEEC,YAFF,EAGE,KAAKE,2BAAL,EAHF,EAIE,KAJF;AAMD,OARE,CAUH;AACA;AACA;AACA;;;AACA,aAAO,IAAP;AACD,KAtVgD;;AAAA,sDAiW7C,CAACH,CAAD,EAAIC,YAAJ,KAAqB;AAAA;;AACvB,UAAI,KAAKlB,KAAL,CAAWqB,WAAf,EAA4B;AAC1B,aAAKC,gBAAL,GAAwBX,UAAU,CAAC,MAAM;AAAA;;AACvC,wDAAKX,KAAL,EAAWqB,WAAX,mGACEJ,CADF,EAEEC,YAFF,EAGE,KAAKE,2BAAL,EAHF;AAKA,eAAKE,gBAAL,GAAwB,IAAxB;AACD,SAPiC,EAO/B,KAAKtB,KAAL,CAAWuB,iBAPoB,CAAlC;AAQD;;AAED,oDAAKvB,KAAL,EAAWwB,mBAAX,mGACEP,CADF,EAEEC,YAFF,EAGE,KAAKE,2BAAL,EAHF;AAMA,WAAKK,OAAL,CAAaC,aAAb;AACA,WAAKC,QAAL,CAAcD,aAAd;AACA,WAAK9B,cAAL,GAAsB,IAAtB;AAEA,WAAKgC,QAAL;AACD,KAxXgD;;AAAA,oDAoY7C,CAACX,CAAD,EAAIC,YAAJ,KAAqB;AAAA;;AACvB,UAAI,CAAC,KAAKW,WAAV,EAAuB;AACrB,aAAKC,oBAAL,CAA0Bb,CAA1B;AACD;;AAED,WAAKD,QAAL,CAAc;AAAEe,QAAAA,WAAW,EAAE;AAAf,OAAd;AAEA,WAAKC,yBAAL,GAAiC,IAAjC;AAEA,YAAMC,eAAe,GACnB,KAAKjC,KAAL,CAAWiC,eAAX,IACC,KAAKjC,KAAL,CAAWkC,UAAX,IACC,KAAKL,WAAL,KAAqB,OADtB,IAEC,KAAK7B,KAAL,CAAWmC,uBAFZ,IAGC,KAAKC,SAAL,KAAmB,KAAKpC,KAAL,CAAWqC,WALlC,CATuB,CAgBvB;AACA;;AACA,UAAI,CAACJ,eAAL,EAAsB;AACpB,iDAAwB,KAAKR,OAA7B,EAAsC;AACpCtB,UAAAA,CAAC,EAAEe,YAAY,CAACoB,EAAb,GAAkB,KAAKF,SADU;AAEpChC,UAAAA,CAAC,EAAEc,YAAY,CAACqB,EAAb,GAAkB,KAAKH;AAFU,SAAtC,EAGGI,KAHH;AAID;;AAED,UAAI,KAAKlB,gBAAT,EAA2B;AACzBmB,QAAAA,YAAY,CAAC,KAAKnB,gBAAN,CAAZ;AACA,aAAKA,gBAAL,GAAwB,IAAxB;AACD;;AAED,qDAAKtB,KAAL,EAAW0C,iBAAX,qGACEzB,CADF,EAEEC,YAFF,EAGE,KAAKE,2BAAL,EAHF;;AAMA,UAAI,KAAKS,WAAL,KAAqB,OAAzB,EAAkC;AAAA;;AAChC,sDAAK7B,KAAL,EAAW2C,SAAX,mGACE1B,CADF,EAEEC,YAFF,EAGE,KAAKE,2BAAL,EAHF;AAKD,OAND,MAMO,IAAI,KAAKS,WAAL,KAAqB,OAAzB,EAAkC;AAAA;;AACvC,sDAAK7B,KAAL,EAAW4C,aAAX,mGACE3B,CADF,EAEEC,YAFF,EAGE,KAAKE,2BAAL,EAHF;AAKD;;AAED,UAAI,KAAKpB,KAAL,CAAW6C,iBAAf,EAAkC;AAChC,aAAKC,gBAAL;AACD;;AAED,WAAKC,OAAL;AAEA,WAAKlB,WAAL,GAAmB,IAAnB;AACA,WAAKjC,cAAL,GAAsB,KAAtB;AACD,KA9bgD;;AAAA,qDAwcvB,CACxBqB,CADwB,EAExBC,YAFwB,KAGrB;AACH,UAAI,KAAKlB,KAAL,CAAWgD,kBAAf,EAAmC;AACjC,YACE,KAAKhD,KAAL,CAAWgD,kBAAX,CACE/B,CADF,EAEEC,YAFF,EAGE,KAAKE,2BAAL,EAHF,CADF,EAME;AACA,iBAAO,KAAP;AACD;AACF,OAXE,CAaH;AACA;;;AACA,UAAIF,YAAY,CAAC+B,mBAAb,IAAoC,CAAxC,EAA2C;AACzC,YAAI,CAAC,KAAKrD,cAAV,EAA0B;AACxB,eAAKsD,wBAAL,CAA8BjC,CAA9B,EAAiCC,YAAjC;AACD;AACF,OAJD,MAIO;AACL,YAAI,KAAKtB,cAAT,EAAyB;AACvB,eAAKuD,sBAAL,CAA4BlC,CAA5B,EAA+BC,YAA/B;AACD;;AACD,eAAO,IAAP;AACD;;AAED,UAAIA,YAAY,CAAC+B,mBAAb,KAAqC,CAAzC,EAA4C;AAC1C,YAAI,KAAK3B,gBAAT,EAA2B;AACzBmB,UAAAA,YAAY,CAAC,KAAKnB,gBAAN,CAAZ;AACA,eAAKA,gBAAL,GAAwB,IAAxB;AACD,SAJyC,CAM1C;;;AACA,YAAI,KAAKO,WAAL,KAAqB,OAAzB,EAAkC;AAChC,eAAKG,yBAAL,GAAiC,oCAC/Bf,CAD+B,EAE/BC,YAF+B,CAAjC;AAIA,eAAKkC,wBAAL,GAAgC,sCAC9BnC,CAD8B,EAE9BC,YAF8B,CAAhC;AAID;;AACD,aAAKW,WAAL,GAAmB,OAAnB;;AACA,aAAKwB,eAAL,CAAqBpC,CAArB,EAAwBC,YAAxB;AACD,OAnBD,MAmBO,IAAIA,YAAY,CAAC+B,mBAAb,KAAqC,CAAzC,EAA4C;AACjD,YACE,KAAK3B,gBAAL,KACCgC,IAAI,CAACC,GAAL,CAASrC,YAAY,CAACsC,EAAtB,IAA4B,CAA5B,IAAiCF,IAAI,CAACC,GAAL,CAASrC,YAAY,CAACuC,EAAtB,IAA4B,CAD9D,CADF,EAGE;AACAhB,UAAAA,YAAY,CAAC,KAAKnB,gBAAN,CAAZ;AACA,eAAKA,gBAAL,GAAwB,IAAxB;AACD,SAPgD,CAQjD;;;AACA,YAAI,KAAKO,WAAL,KAAqB,OAAzB,EAAkC;AAChC,eAAKG,yBAAL,GAAiC,oCAC/Bf,CAD+B,EAE/BC,YAF+B,CAAjC;AAID;;AAED,cAAM;AAAEsC,UAAAA,EAAF;AAAMC,UAAAA;AAAN,YAAavC,YAAnB;AACA,cAAMwC,cAAc,GAAGJ,IAAI,CAACC,GAAL,CAASC,EAAT,IAAe,CAAf,IAAoBF,IAAI,CAACC,GAAL,CAASE,EAAT,IAAe,CAA1D;;AACA,YAAIC,cAAJ,EAAoB;AAClB,eAAK7B,WAAL,GAAmB,OAAnB;;AACA,eAAK8B,eAAL,CAAqBzC,YAArB;AACD;AACF;AACF,KA/gBgD;;AAAA,kDAuxBjBD,CAAD,IAA8B;AAC3D,YAAM2C,GAAG,GAAGC,IAAI,CAACD,GAAL,EAAZ;;AACA,UACE,KAAKE,iCAAL,IACA,KAAK9D,KAAL,CAAW+D,cADX,IAEAH,GAAG,GAAG,KAAKE,iCAAX,GAA+C,KAAK9D,KAAL,CAAW+D,cAH5D,EAIE;AACA,aAAKC,iBAAL,IACE,KAAKC,SAAL,CAAe,EACb,GAAG,KAAKD,iBADK;AAEbE,UAAAA,EAAE,EAAEN,GAAG,CAACO,QAAJ,EAFS;AAGbC,UAAAA,WAAW,EAAE;AAHA,SAAf,CADF;AAMA,aAAKC,kBAAL,IAA2B5B,YAAY,CAAC,KAAK4B,kBAAN,CAAvC;AACA,eAAO,KAAKP,iCAAZ;AACA,eAAO,KAAKO,kBAAZ;AACA,eAAO,KAAKL,iBAAZ;;AACA,aAAKM,gBAAL,CAAsBrD,CAAtB;AACD,OAhBD,MAgBO;AACL,aAAK6C,iCAAL,GAAyCF,GAAzC;AACA,aAAKI,iBAAL,GAAyB;AACvBE,UAAAA,EAAE,EAAEN,GAAG,CAACO,QAAJ,EADmB;AAEvBhE,UAAAA,CAAC,EAAEc,CAAC,CAACsD,WAAF,CAAcC,KAAd,GAAsB,KAAKzD,KAAL,CAAW1B,aAFb;AAGvBe,UAAAA,CAAC,EAAEa,CAAC,CAACsD,WAAF,CAAcE,KAAd,GAAsB,KAAK1D,KAAL,CAAWzB;AAHb,SAAzB;;AAKA,aAAK2E,SAAL,CAAe,KAAKD,iBAApB,EAPK,CASL;;;AACA/C,QAAAA,CAAC,CAACyD,OAAF;AACA,aAAKL,kBAAL,GAA0B1D,UAAU,CAAC,MAAM;AAAA;;AACzC,iBAAO,KAAKmD,iCAAZ;AACA,iBAAO,KAAKO,kBAAZ,CAFyC,CAIzC;;AACA,cAAI,KAAKrE,KAAL,CAAW6C,iBAAX,IAAgC,KAAKmB,iBAAzC,EAA4D;AAC1D,kBAAMW,IAAI,GACR,KAAK3E,KAAL,CAAW6C,iBAAX,CAA6B1C,CAA7B,GAAiC,KAAK6D,iBAAL,CAAuB7D,CAD1D;AAEA,kBAAMyE,IAAI,GACR,KAAK5E,KAAL,CAAW6C,iBAAX,CAA6BzC,CAA7B,GAAiC,KAAK4D,iBAAL,CAAuB5D,CAD1D;;AAGAH,kCAAS4E,MAAT,CAAgB,KAAKpD,OAArB,EAA8B;AAC5BqD,cAAAA,OAAO,EAAE;AACP3E,gBAAAA,CAAC,EAAE,KAAK4E,OAAL,GAAeJ,IAAI,GAAG,KAAKvC,SADvB;AAEPhC,gBAAAA,CAAC,EAAE,KAAK4E,OAAL,GAAeJ,IAAI,GAAG,KAAKxC;AAFvB,eADmB;AAK5B6C,cAAAA,eAAe,EAAE,IALW;AAM5BC,cAAAA,QAAQ,EAAE;AANkB,aAA9B,EAOG1C,KAPH,CAOS,MAAM;AACb,mBAAKM,gBAAL;AACD,aATD;AAUD;;AAED,wDAAK9C,KAAL,EAAWmF,WAAX,mGAAyBlE,CAAzB,EAA4B,KAAKG,2BAAL,EAA5B;AACD,SAxBmC,EAwBjC,KAAKpB,KAAL,CAAW+D,cAxBsB,CAApC;AAyBD;AACF,KA90BgD;;AAAA,6CAg1B/B,CAACvD,QAAD,EAAkB0E,QAAlB,KAAwC;AACxD,YAAM;AAAE/F,QAAAA,aAAF;AAAiBC,QAAAA;AAAjB,UAAoC,KAAK2B,KAA/C;AACA,YAAM;AAAE8B,QAAAA,iBAAF;AAAqBuC,QAAAA,YAArB;AAAmCC,QAAAA;AAAnC,UAAqD,KAAKrF,KAAhE;AAEA,UAAI,CAAC6C,iBAAL,EAAwB;AACxB,UAAI,CAAC1D,aAAD,IAAkB,CAACC,cAAvB,EAAuC;AACvC,UAAI,CAACgG,YAAD,IAAiB,CAACC,aAAtB,EAAqC,OANmB,CAQxD;;AACA,YAAMC,IAAI,GAAGzC,iBAAiB,CAAC1C,CAAlB,GAAsBhB,aAAa,GAAG,CAAnD;AACA,YAAMoG,IAAI,GAAG1C,iBAAiB,CAACzC,CAAlB,GAAsBhB,cAAc,GAAG,CAApD;AAEA,WAAK2F,OAAL,GAAeK,YAAY,GAAG,CAAf,GAAmB5E,QAAQ,CAACL,CAA5B,GAAgCmF,IAAI,GAAG,KAAKlD,SAA3D;AACA,WAAK4C,OAAL,GAAeK,aAAa,GAAG,CAAhB,GAAoB7E,QAAQ,CAACJ,CAA7B,GAAiCmF,IAAI,GAAG,KAAKnD,SAA5D;;AAEA,UAAI8C,QAAJ,EAAc;AACZjF,8BAAS4E,MAAT,CAAgB,KAAKpD,OAArB,EAA8B;AAC5BqD,UAAAA,OAAO,EAAE;AAAE3E,YAAAA,CAAC,EAAE,KAAK4E,OAAV;AAAmB3E,YAAAA,CAAC,EAAE,KAAK4E;AAA3B,WADmB;AAE5BC,UAAAA,eAAe,EAAE,IAFW;AAG5BC,UAAAA;AAH4B,SAA9B,EAIG1C,KAJH;AAKD,OAND,MAMO;AACL,aAAKf,OAAL,CAAa+D,QAAb,CAAsB;AAAErF,UAAAA,CAAC,EAAE,KAAK4E,OAAV;AAAmB3E,UAAAA,CAAC,EAAE,KAAK4E;AAA3B,SAAtB;AACD;AACF,KAx2BgD;;AAAA,gDA02BpB,MAAM;AACjC,UAAI,CAAC,KAAKhF,KAAL,CAAW6C,iBAAhB,EAAmC;AACnC,UAAI,CAAC,KAAK7C,KAAL,CAAWoF,YAAZ,IAA4B,CAAC,KAAKpF,KAAL,CAAWqF,aAA5C,EAA2D;AAE3D,aAAO,2DAAgC;AACrCI,QAAAA,gBAAgB,EAAE;AAChBtF,UAAAA,CAAC,EAAE,KAAKH,KAAL,CAAW6C,iBAAX,CAA6B1C,CADhB;AAEhBC,UAAAA,CAAC,EAAE,KAAKJ,KAAL,CAAW6C,iBAAX,CAA6BzC;AAFhB,SADmB;AAKrCsF,QAAAA,SAAS,EAAE;AACTjG,UAAAA,MAAM,EAAE,KAAKO,KAAL,CAAWqF,aADV;AAET7F,UAAAA,KAAK,EAAE,KAAKQ,KAAL,CAAWoF;AAFT,SAL0B;AASrCO,QAAAA,aAAa,EAAE,EACb,GAAG,KAAKvE,2BAAL,EADU;AAEb2D,UAAAA,OAAO,EAAE,KAAKA,OAFD;AAGbC,UAAAA,OAAO,EAAE,KAAKA,OAHD;AAIb5C,UAAAA,SAAS,EAAE,KAAKA;AAJH;AATsB,OAAhC,CAAP;AAgBD,KA93BgD;;AAAA,8CAg4BtB,MAAM;AAAA;;AAC/B,YAAM5B,QAAQ,GAAG,KAAKoF,kBAAL,EAAjB;;AACA,UAAI,CAACpF,QAAL,EAAe;AACf,qDAAKR,KAAL,EAAWS,yBAAX,qGAAuCD,QAAvC;AACD,KAp4BgD;;AAK/C,SAAKO,KAAL,GAAa,EAAE,GAAG7B;AAAL,KAAb;AAEA,SAAK2G,eAAL,GAAuBC,0BAAaC,MAAb,CAAoB;AACzC5E,MAAAA,4BAA4B,EAAE,KAAK6E,iCADM;AAEzCxE,MAAAA,mBAAmB,EAAE,KAAK0B,wBAFe;AAGzCF,MAAAA,kBAAkB,EAAE,KAAKiD,uBAHgB;AAIzCC,MAAAA,qBAAqB,EAAE,KAAK/C,sBAJa;AAKzCgD,MAAAA,uBAAuB,EAAE,CAACC,GAAD,EAAMlF,YAAN,KAAuB;AAAA;;AAC9C;AACA;AACA;AACA;AACA;AACA;AACA,aAAKiC,sBAAL,CAA4BiD,GAA5B,EAAiClF,YAAjC;;AACA,uDAAKlB,KAAL,EAAWmG,uBAAX,qGACEC,GADF,EAEElF,YAFF,EAGE,KAAKE,2BAAL,EAHF;AAKD,OAlBwC;AAmBzCiF,MAAAA,gCAAgC,EAAE,CAACD,GAAD,EAAMlF,YAAN;AAAA;;AAAA,eAChC,CAAC,4BAAC,sBAAKlB,KAAL,EAAWqG,gCAAZ,mDAAC,2CACAD,GADA,EAEAlF,YAFA,EAGA,KAAKE,2BAAL,EAHA,CAAD,CAD+B;AAAA,OAnBO;AAyBzC;AACAkF,MAAAA,4BAA4B,EAAE,CAACF,GAAD,EAAMlF,YAAN;AAAA;;AAAA,kEAC5B,sBAAKlB,KAAL,EAAWsG,4BADiB,2DAC5B,2CACEF,GADF,EAEElF,YAFF,EAGE,KAAKE,2BAAL,EAHF,CAD4B,yEAKvB,IALuB;AAAA,OA1BW;AAgCzCmF,MAAAA,mCAAmC,EAAE,CAACH,GAAD,EAAMlF,YAAN;AAAA;;AAAA,eACnC,CAAC,2BAAC,sBAAKlB,KAAL,EAAWuG,mCAAZ,kDAAC,0CAAiDH,GAAjD,EAAsDlF,YAAtD,CAAD,CADkC;AAAA,OAhCI;AAkCzCsF,MAAAA,kCAAkC,EAAE,CAACJ,GAAD,EAAMlF,YAAN;AAAA;;AAAA,eAClC,CAAC,2BAAC,sBAAKlB,KAAL,EAAWwG,kCAAZ,kDAAC,0CAAgDJ,GAAhD,EAAqDlF,YAArD,CAAD,CADiC;AAAA;AAlCK,KAApB,CAAvB;AAsCA,SAAKN,qBAAL,gBAA6B,uBAA7B;AAEA,QAAI,KAAKZ,KAAL,CAAWyG,iBAAf,EACE,KAAK9E,QAAL,GAAgB,KAAK3B,KAAL,CAAWyG,iBAA3B;AACF,QAAI,KAAKzG,KAAL,CAAW0G,kBAAf,EACE,KAAKjF,OAAL,GAAe,KAAKzB,KAAL,CAAW0G,kBAA1B;AAEF,QAAI,KAAK1G,KAAL,CAAWqC,WAAf,EAA4B,KAAKD,SAAL,GAAiB,KAAKpC,KAAL,CAAWqC,WAA5B;AAC5B,QAAI,KAAKrC,KAAL,CAAW2G,cAAX,IAA6B,IAAjC,EACE,KAAK5B,OAAL,GAAe,KAAK/E,KAAL,CAAW2G,cAA1B;AACF,QAAI,KAAK3G,KAAL,CAAW4G,cAAX,IAA6B,IAAjC,EACE,KAAK5B,OAAL,GAAe,KAAKhF,KAAL,CAAW4G,cAA1B;AAEF,SAAKnF,OAAL,CAAa+D,QAAb,CAAsB;AAAErF,MAAAA,CAAC,EAAE,KAAK4E,OAAV;AAAmB3E,MAAAA,CAAC,EAAE,KAAK4E;AAA3B,KAAtB;AACA,SAAKrD,QAAL,CAAc6D,QAAd,CAAuB,KAAKpD,SAA5B;AACA,SAAKX,OAAL,CAAaoF,WAAb,CAAyB,CAAC;AAAE1G,MAAAA,CAAF;AAAKC,MAAAA;AAAL,KAAD,KAAc;AACrC,WAAK2E,OAAL,GAAe5E,CAAf;AACA,WAAK6E,OAAL,GAAe5E,CAAf;AACD,KAHD;AAIA,SAAKuB,QAAL,CAAckF,WAAd,CAA0B,CAAC;AAAEvG,MAAAA;AAAF,KAAD,KAAe;AACvC,WAAK8B,SAAL,GAAiB9B,KAAjB;AACD,KAFD;AAIA,SAAK8C,wBAAL,GAAgC,GAAhC;AAEA,SAAKvB,WAAL,GAAmB,IAAnB;AACD;;AAEOD,EAAAA,QAAQ,GAAG;AACjB,QAAI,CAAC,KAAK5B,KAAL,CAAW8G,UAAhB,EAA4B;;AAC5B7G,0BAAS4E,MAAT,CAAgB,KAAKkC,OAArB,EAA8B;AAC5BjC,MAAAA,OAAO,EAAE;AAAE3E,QAAAA,CAAC,EAAE,CAAL;AAAQC,QAAAA,CAAC,EAAE,CAAC;AAAZ,OADmB;AAE5B6E,MAAAA,eAAe,EAAE,IAFW;AAG5B+B,MAAAA,MAAM,EAAEC,oBAAOC,GAAP,CAAWD,oBAAOE,IAAlB,CAHoB;AAI5BjC,MAAAA,QAAQ,EAAE;AAJkB,KAA9B,EAKG1C,KALH;AAMD;;AAEOO,EAAAA,OAAO,GAAG;AAChB,QAAI,CAAC,KAAK/C,KAAL,CAAW8G,UAAhB,EAA4B;;AAC5B7G,0BAAS4E,MAAT,CAAgB,KAAKkC,OAArB,EAA8B;AAC5BjC,MAAAA,OAAO,EAAE;AAAE3E,QAAAA,CAAC,EAAE,CAAL;AAAQC,QAAAA,CAAC,EAAE;AAAX,OADmB;AAE5B6E,MAAAA,eAAe,EAAE,IAFW;AAG5B+B,MAAAA,MAAM,EAAEC,oBAAOC,GAAP,CAAWD,oBAAOE,IAAlB,CAHoB;AAI5BjC,MAAAA,QAAQ,EAAE;AAJkB,KAA9B,EAKG1C,KALH;AAMD;;AAEkB,MAAPuC,OAAO,CAAC5E,CAAD,EAAY;AAC7B,SAAKiH,WAAL,CAAiB,GAAjB,EAAsBjH,CAAtB;AACD;;AAEkB,MAAP6E,OAAO,CAAC5E,CAAD,EAAY;AAC7B,SAAKgH,WAAL,CAAiB,GAAjB,EAAsBhH,CAAtB;AACD;;AAEkB,MAAP2E,OAAO,GAAG;AACpB,WAAO,KAAKsC,WAAL,CAAiB,GAAjB,CAAP;AACD;;AAEkB,MAAPrC,OAAO,GAAG;AACpB,WAAO,KAAKqC,WAAL,CAAiB,GAAjB,CAAP;AACD;;AAEOD,EAAAA,WAAW,CAACE,IAAD,EAAkBC,MAAlB,EAAkC;AACnD,UAAMC,WAAW,GAAG,KAAKC,SAAL,CAAeH,IAAf,CAApB;;AAEA,QAAI,KAAKtH,KAAL,CAAW0H,aAAf,EAA8B;AAC5B,YAAMC,aAAa,GACjBL,IAAI,KAAK,GAAT,GAAe,KAAKvG,KAAL,CAAW5B,aAA1B,GAA0C,KAAK4B,KAAL,CAAW3B,cADvD;AAEA,YAAMwI,WAAW,GACfN,IAAI,KAAK,GAAT,GACI,KAAKtH,KAAL,CAAWoF,YAAX,IAA2B,KAAKrE,KAAL,CAAW5B,aAD1C,GAEI,KAAKa,KAAL,CAAWqF,aAAX,IAA4B,KAAKtE,KAAL,CAAW3B,cAH7C;AAKA,YAAMyI,WAAW,GACfD,WAAW,IAAID,aAAf,IAAgC,KAAK3H,KAAL,CAAW8H,kBAAX,IAAiC,IAAjE,GACI,4DACEP,MADF,EAEEI,aAFF,EAGEC,WAHF,EAIE,KAAKxF,SAJP,EAKE,KAAKpC,KAAL,CAAW8H,kBALb,CADJ,GAQIP,MATN;;AAWA,UAAI,CAAC,KAAK1F,WAAN,IAAqB,CAAC2F,WAAW,CAACjH,2BAAtC,EAAmE;AACjE,cAAMwH,iBAAiB,GACrBF,WAAW,KAAKN,MAAhB,IACAM,WAAW,CAACG,OAAZ,CAAoB,CAApB,MAA2BT,MAAM,CAACS,OAAP,CAAe,CAAf,CAF7B;;AAGA,YAAID,iBAAJ,EAAuB;AACrBP,UAAAA,WAAW,CAACjH,2BAAZ,GAA0C,IAA1C;AACA,kDAAuB,KAAKkB,OAAL,CAAa6F,IAAb,CAAvB,EAA2CO,WAA3C,EAAwDrF,KAAxD,CAA8D,MAAM;AAClEgF,YAAAA,WAAW,CAACjH,2BAAZ,GAA0C,KAA1C;AACD,WAFD;AAGA;AACD;AACF;AACF;;AAEDiH,IAAAA,WAAW,CAAClH,KAAZ,GAAoBiH,MAApB;AACD;;AAEOF,EAAAA,WAAW,CAACC,IAAD,EAAkB;AACnC,WAAO,KAAKG,SAAL,CAAeH,IAAf,EAAqBhH,KAA5B;AACD;;AAED2H,EAAAA,kBAAkB,CAChBC,SADgB,EAEhBC,SAFgB,EAGhB;AAAA;;AACA,UAAM;AAAEC,MAAAA,WAAF;AAAe/F,MAAAA;AAAf,QAA+B,KAAKrC,KAA1C;;AACA,QAAIkI,SAAS,CAACE,WAAV,IAAyB,CAACA,WAA1B,IAAyC/F,WAA7C,EAA0D;AACxD,WAAKD,SAAL,GAAiBC,WAAjB;AACA,WAAKV,QAAL,CAAc6D,QAAd,CAAuB,KAAKpD,SAA5B;AACD;;AACD,QACE,CAAC,KAAKiG,gCAAN,IACA,KAAKC,kBAAL,GAA0BC,UAF5B,EAGE;AACA,WAAK9G,OAAL,CAAaoF,WAAb,CAAyB,MAAM,KAAKyB,kBAAL,EAA/B;AACA,WAAK3G,QAAL,CAAckF,WAAd,CAA0B,MAAM,KAAKyB,kBAAL,EAAhC;AACA,WAAKD,gCAAL,GAAwC,IAAxC;AACD;;AAED,UAAMG,SAAS,GAAG,KAAKzH,KAAvB;AACA,UAAM0H,2BAA2B,GAC/BD,SAAS,CAACpJ,cAAV,KAA6B+I,SAAS,CAAC/I,cAAvC,IACAoJ,SAAS,CAACrJ,aAAV,KAA4BgJ,SAAS,CAAChJ,aADtC,IAEAqJ,SAAS,CAACnJ,aAAV,KAA4B8I,SAAS,CAAC9I,aAFtC,IAGAmJ,SAAS,CAAClJ,aAAV,KAA4B6I,SAAS,CAAC7I,aAJxC;AAMA,UAAMoJ,wBAAwB,GAC5B,0BAAAR,SAAS,CAACrF,iBAAV,gFAA6B1C,CAA7B,gCAAmC,KAAKH,KAAL,CAAW6C,iBAA9C,0DAAmC,sBAA8B1C,CAAjE,KACA,2BAAA+H,SAAS,CAACrF,iBAAV,kFAA6BzC,CAA7B,iCAAmC,KAAKJ,KAAL,CAAW6C,iBAA9C,2DAAmC,uBAA8BzC,CAAjE,CAFF,CAtBA,CA0BA;AACA;AACA;AACA;AACA;;AACA,QAAIqI,2BAAJ,EAAiC;AAAA;;AAC/B,qDAAKzI,KAAL,EAAW2I,gBAAX,oGAA8B;AAC5BnJ,QAAAA,KAAK,EAAEgJ,SAAS,CAACrJ,aADW;AAE5BM,QAAAA,MAAM,EAAE+I,SAAS,CAACpJ,cAFU;AAG5Be,QAAAA,CAAC,EAAEqI,SAAS,CAACnJ,aAHe;AAI5Be,QAAAA,CAAC,EAAEoI,SAAS,CAAClJ;AAJe,OAA9B;AAMD;;AAED,QACE,KAAK+I,gCAAL,KACCI,2BAA2B,IAAIC,wBADhC,CADF,EAGE;AACA,WAAKJ,kBAAL;AACD;AACF;;AAEDM,EAAAA,iBAAiB,GAAG;AAClB,SAAKC,kBAAL,GADkB,CAElB;AACA;AACA;AACA;AACA;AACA;AACA;;AACA,SAAKC,0BAAL,GAAkCC,WAAW,CAAC,KAAKF,kBAAN,EAA0B,GAA1B,CAA7C;AACD;;AAEDG,EAAAA,oBAAoB,GAAG;AACrB,SAAKF,0BAAL,IACEG,aAAa,CAAC,KAAKH,0BAAN,CADf;AAED;;AAOD;AACF;AACA;AACA;AACER,EAAAA,kBAAkB,GAAG;AAAA;;AACnB,UAAMY,iBAAiB,GAAG,KAAK9H,2BAAL,EAA1B;;AACA,UAAMZ,QAAQ,GAAG,KAAKoF,kBAAL,EAAjB;;AAEA,QAAI,CAACsD,iBAAiB,CAAC/J,aAAnB,IAAoC,CAAC+J,iBAAiB,CAAC9J,cAA3D,EACE,OAAO;AAAEmJ,MAAAA,UAAU,EAAE;AAAd,KAAP;AAEF,mDAAKvI,KAAL,EAAWmJ,WAAX,oGAAyBD,iBAAzB;;AAEA,QAAI1I,QAAJ,EAAc;AAAA;;AACZ,sDAAKR,KAAL,EAAWoJ,uBAAX,sGAAqC5I,QAArC;AACA,WAAK6I,kCAAL,CAAwC7I,QAAxC;AACD;;AAED,WAAO;AAAE+H,MAAAA,UAAU,EAAE;AAAd,KAAP;AACD;AAED;AACF;AACA;AACA;AACA;AACA;;;AACEnH,EAAAA,2BAA2B,CAACkI,YAAY,GAAG,EAAhB,EAAuC;AAChE,WAAO;AACLlH,MAAAA,SAAS,EAAE,KAAKA,SADX;AAEL2C,MAAAA,OAAO,EAAE,KAAKA,OAFT;AAGLC,MAAAA,OAAO,EAAE,KAAKA,OAHT;AAIL5F,MAAAA,cAAc,EAAE,KAAK2B,KAAL,CAAW3B,cAJtB;AAKLD,MAAAA,aAAa,EAAE,KAAK4B,KAAL,CAAW5B,aALrB;AAMLE,MAAAA,aAAa,EAAE,KAAK0B,KAAL,CAAW1B,aANrB;AAOLC,MAAAA,aAAa,EAAE,KAAKyB,KAAL,CAAWzB,aAPrB;AAQL,SAAGgK;AARE,KAAP;AAUD;AAED;AACF;AACA;AACA;AACA;AACA;;;AAmQE;AACF;AACA;AACA;AACA;AACA;AACA;AACA;AACEjG,EAAAA,eAAe,CACbpC,CADa,EAEbC,YAFa,EAGb;AAAA;;AACA,QAAI,CAAC,KAAKlB,KAAL,CAAWoI,WAAhB,EAA6B;AAE7B,UAAM;AACJmB,MAAAA,OADI;AAEJC,MAAAA,OAFI;AAGJC,MAAAA,wBAHI;AAIJC,MAAAA;AAJI,QAKF,KAAK1J,KALT;AAOA,UAAM2J,QAAQ,GAAG,sCAAyB1I,CAAzB,EAA4BC,YAA5B,CAAjB;;AAEA,QACE,KAAKlB,KAAL,CAAW4J,YAAX,IACA,KAAK5J,KAAL,CAAW4J,YAAX,CACE3I,CADF,EAEEC,YAFF,EAGE,KAAKE,2BAAL,EAHF,CAFF,EAOE;AACA;AACD;;AAED,QAAI,CAACuI,QAAL,EAAe;AACf,QAAI,CAAC,KAAKvG,wBAAV,EAAoC,OAxBpC,CA0BA;;AACA,UAAMyG,8BAA8B,GAClCF,QAAQ,GAAG,KAAKvG,wBADlB;AAEA,SAAKA,wBAAL,GAAgCuG,QAAhC;AAEA,UAAMG,sBAAsB,GAC1BD,8BAA8B,GAAG,CAAjC,GACIH,yBADJ,GAEID,wBAHN;AAKA,QAAIK,sBAAsB,IAAI,IAA9B,EAAoC;AACpC,UAAMC,WAAW,GAAGF,8BAA8B,GAAG,CAArD,CArCA,CAsCA;AACA;;AACA,UAAMG,gCAAgC,GACpCD,WAAW,IAAI,IAAKD,sBAAsB,GAAG,CAA1B,GAA+B,GAAvC,CADb;AAGA,QAAIG,YAAY,GAAG,KAAK7H,SAAL,IAAkB,IAAI4H,gCAAtB,CAAnB,CA3CA,CA6CA;;AACA,QAAIT,OAAO,IAAI,IAAX,IAAmBU,YAAY,GAAGV,OAAtC,EAA+C;AAC7CU,MAAAA,YAAY,GAAGV,OAAf;AACD;;AAED,QAAIC,OAAO,IAAI,IAAX,IAAmBS,YAAY,GAAGT,OAAtC,EAA+C;AAC7CS,MAAAA,YAAY,GAAGT,OAAf;AACD;;AAED,UAAMU,kBAAkB,GAAG,oCAAuBjJ,CAAvB,EAA0BC,YAA1B,CAA3B;AAEA,QAAI,CAACgJ,kBAAL,EAAyB;AAEzB,QAAIC,UAAU,GAAG;AACfhK,MAAAA,CAAC,EAAE+J,kBAAkB,CAAC/J,CAAnB,GAAuB,KAAKY,KAAL,CAAW1B,aADtB;AAEfe,MAAAA,CAAC,EAAE8J,kBAAkB,CAAC9J,CAAnB,GAAuB,KAAKW,KAAL,CAAWzB;AAFtB,KAAjB;;AAKA,QAAI,KAAKU,KAAL,CAAW6C,iBAAf,EAAkC;AAChC;AACA;AACAsH,MAAAA,UAAU,GAAG;AACXhK,QAAAA,CAAC,EAAE,KAAKH,KAAL,CAAW6C,iBAAX,CAA6B1C,CADrB;AAEXC,QAAAA,CAAC,EAAE,KAAKJ,KAAL,CAAW6C,iBAAX,CAA6BzC;AAFrB,OAAb;AAID,KAtED,CAwEA;;;AACA,SAAKJ,KAAL,CAAWoK,KAAX,IAAoB,KAAKC,oBAAL,CAA0BpJ,CAA1B,EAA6BkJ,UAA7B,CAApB;AAEA,UAAM;AAAE/K,MAAAA,cAAF;AAAkBD,MAAAA;AAAlB,QAAoC,KAAK4B,KAA/C;AAEA,UAAMuJ,UAAU,GAAG,KAAKvF,OAAxB;AACA,UAAMwF,UAAU,GAAG,KAAKvF,OAAxB;AACA,UAAMwF,QAAQ,GAAG,KAAKpI,SAAtB;AACA,UAAMqI,QAAQ,GAAGR,YAAjB;AAEA,QAAI,CAAC7K,cAAD,IAAmB,CAACD,aAAxB,EAAuC;AAEvC,QAAI6F,OAAO,GAAG,iDACZuF,UADY,EAEZnL,cAFY,EAGZoL,QAHY,EAIZC,QAJY,EAKZN,UAAU,CAAC/J,CALC,CAAd;AAOA,QAAI2E,OAAO,GAAG,iDACZuF,UADY,EAEZnL,aAFY,EAGZqL,QAHY,EAIZC,QAJY,EAKZN,UAAU,CAAChK,CALC,CAAd;;AAQA,UAAMuK,WAAW,GACf,KAAKC,qCAAL,CAA2CT,kBAA3C,CADF;;AAEA,QAAIQ,WAAJ,EAAiB;AACf3F,MAAAA,OAAO,IAAI2F,WAAW,CAACvK,CAAvB;AACA6E,MAAAA,OAAO,IAAI0F,WAAW,CAACtK,CAAvB;AACD;;AAED,SAAK2E,OAAL,GAAeA,OAAf;AACA,SAAKC,OAAL,GAAeA,OAAf;AACA,SAAK5C,SAAL,GAAiBqI,QAAjB;AAEA,SAAKhJ,OAAL,CAAa+D,QAAb,CAAsB;AAAErF,MAAAA,CAAC,EAAE,KAAK4E,OAAV;AAAmB3E,MAAAA,CAAC,EAAE,KAAK4E;AAA3B,KAAtB;AACA,SAAKrD,QAAL,CAAc6D,QAAd,CAAuB,KAAKpD,SAA5B;AAEA,mDAAKpC,KAAL,EAAW4K,WAAX,oGACE3J,CADF,EAEEC,YAFF,EAGE,KAAKE,2BAAL,EAHF;AAKD;AAED;AACF;AACA;AACA;AACA;AACA;;;AACEiJ,EAAAA,oBAAoB,CAClBQ,qBADkB,EAElBV,UAFkB,EAGlB,GAAGW,MAHe,EAIlB;AACA,UAAM;AAAEC,MAAAA;AAAF,QAAcF,qBAAqB,CAACtG,WAA1C;AACA,UAAM;AAAEjF,MAAAA,aAAF;AAAiBD,MAAAA;AAAjB,QAAmC,KAAK0B,KAA9C;AAEA,SAAKC,QAAL,CAAc;AACZe,MAAAA,WAAW,EAAE,CACX;AACE5B,QAAAA,CAAC,EAAE4K,OAAO,CAAC,CAAD,CAAP,CAAWvG,KAAX,GAAmBnF,aADxB;AAEEe,QAAAA,CAAC,EAAE2K,OAAO,CAAC,CAAD,CAAP,CAAWtG,KAAX,GAAmBnF;AAFxB,OADW,EAKX;AACEa,QAAAA,CAAC,EAAE4K,OAAO,CAAC,CAAD,CAAP,CAAWvG,KAAX,GAAmBnF,aADxB;AAEEe,QAAAA,CAAC,EAAE2K,OAAO,CAAC,CAAD,CAAP,CAAWtG,KAAX,GAAmBnF;AAFxB,OALW,EASX6K,UATW,EAUX,GAAGW,MAVQ;AADD,KAAd;AAcD;AAED;AACF;AACA;AACA;AACA;AACA;AACA;;;AACEH,EAAAA,qCAAqC,CAACT,kBAAD,EAA4B;AAC/D,UAAM;AAAEc,MAAAA;AAAF,QAA0B,KAAKhL,KAArC;AAEA,QAAIiL,KAAK,GAAG,IAAZ;;AAEA,QAAI,KAAKjJ,yBAAL,IAAkCgJ,mBAAtC,EAA2D;AACzD,YAAMxH,EAAE,GAAG0G,kBAAkB,CAAC/J,CAAnB,GAAuB,KAAK6B,yBAAL,CAA+B7B,CAAjE;AACA,YAAMsD,EAAE,GAAGyG,kBAAkB,CAAC9J,CAAnB,GAAuB,KAAK4B,yBAAL,CAA+B5B,CAAjE;AAEA,YAAM8K,MAAM,GAAG1H,EAAE,GAAG,KAAKpB,SAAV,GAAsB4I,mBAArC;AACA,YAAMG,MAAM,GAAG1H,EAAE,GAAG,KAAKrB,SAAV,GAAsB4I,mBAArC;AAEAC,MAAAA,KAAK,GAAG;AACN9K,QAAAA,CAAC,EAAE+K,MADG;AAEN9K,QAAAA,CAAC,EAAE+K;AAFG,OAAR;AAID;;AAED,SAAKnJ,yBAAL,GAAiCkI,kBAAjC;AAEA,WAAOe,KAAP;AACD;AAED;AACF;AACA;AACA;AACA;AACA;AACA;;;AACEtH,EAAAA,eAAe,CAACzC,YAAD,EAAyC;AACtD;AACA,QACE,CAAC,KAAKlB,KAAL,CAAWkC,UAAZ,IACC,KAAKlC,KAAL,CAAWmC,uBAAX,IACC,KAAKC,SAAL,KAAmB,KAAKpC,KAAL,CAAWqC,WAHlC,EAIE;AACA;AACD;;AACD,UAAM4I,KAAK,GAAG,KAAKN,qCAAL,CAA2C;AACvDxK,MAAAA,CAAC,EAAEe,YAAY,CAACkK,KADuC;AAEvDhL,MAAAA,CAAC,EAAEc,YAAY,CAACmK;AAFuC,KAA3C,CAAd;;AAIA,QAAI,CAACJ,KAAL,EAAY;AAEZ,UAAMlG,OAAO,GAAG,KAAKA,OAAL,GAAekG,KAAK,CAAC9K,CAArC;AACA,UAAM6E,OAAO,GAAG,KAAKA,OAAL,GAAeiG,KAAK,CAAC7K,CAArC;;AAEA,QACE,KAAKJ,KAAL,CAAWoK,KAAX,IACA,KAAKrJ,KAAL,CAAW1B,aADX,IAEA,KAAK0B,KAAL,CAAWzB,aAHb,EAIE;AACA,YAAMa,CAAC,GAAGe,YAAY,CAACkK,KAAb,GAAqB,KAAKrK,KAAL,CAAW1B,aAA1C;AACA,YAAMe,CAAC,GAAGc,YAAY,CAACmK,KAAb,GAAqB,KAAKtK,KAAL,CAAWzB,aAA1C;AACA,WAAK0B,QAAL,CAAc;AAAEe,QAAAA,WAAW,EAAE,CAAC;AAAE5B,UAAAA,CAAF;AAAKC,UAAAA;AAAL,SAAD;AAAf,OAAd;AACD;;AAED,SAAKkL,qBAAL,CAA2BvG,OAA3B,EAAoCC,OAApC;;AAEA,SAAKpD,QAAL;AACD;AAED;AACF;AACA;AACA;AACA;AACA;AACA;;;AACE0J,EAAAA,qBAAqB,CAACC,UAAD,EAAqBC,UAArB,EAAyC;AAC5D,UAAM;AAAEC,MAAAA,gBAAF;AAAoBC,MAAAA;AAApB,QAAwC,KAAK1L,KAAnD;;AAEA,QAAIyL,gBAAJ,aAAIA,gBAAJ,eAAIA,gBAAgB,CAAG,IAAH,EAAS,IAAT,EAAe,KAAKrK,2BAAL,EAAf,CAApB,EAAwE;AACtE;AACD;;AAED,SAAK2D,OAAL,GAAewG,UAAf;AACA,SAAKvG,OAAL,GAAewG,UAAf;AAEA,SAAK/J,OAAL,CAAa+D,QAAb,CAAsB;AAAErF,MAAAA,CAAC,EAAE,KAAK4E,OAAV;AAAmB3E,MAAAA,CAAC,EAAE,KAAK4E;AAA3B,KAAtB;AACA,SAAKrD,QAAL,CAAc6D,QAAd,CAAuB,KAAKpD,SAA5B;AAEAsJ,IAAAA,eAAe,SAAf,IAAAA,eAAe,WAAf,YAAAA,eAAe,CAAG,IAAH,EAAS,IAAT,EAAe,KAAKtK,2BAAL,EAAf,CAAf;AACD;AAED;AACF;AACA;AACA;AACA;AACA;AACA;AACA;;;AAgHU6C,EAAAA,SAAS,CAAC0H,KAAD,EAAoB;AACnC,SAAKZ,OAAL,CAAaa,IAAb,CAAkBD,KAAlB;AACA,SAAK3K,QAAL,CAAc;AAAE+J,MAAAA,OAAO,EAAE,CAAC,GAAG,KAAKA,OAAT;AAAX,KAAd;AACD;;AAEOc,EAAAA,YAAY,CAACF,KAAD,EAAoB;AACtC,SAAKZ,OAAL,CAAae,MAAb,CAAoB,KAAKf,OAAL,CAAagB,OAAb,CAAqBJ,KAArB,CAApB,EAAiD,CAAjD;AACA,SAAK3K,QAAL,CAAc;AAAE+J,MAAAA,OAAO,EAAE,CAAC,GAAG,KAAKA,OAAT;AAAX,KAAd;AACD;AAED;AACF;AACA;AACA;AACA;AACA;AACA;;;AACEzG,EAAAA,gBAAgB,CAACrD,CAAD,EAA2B;AACzC,UAAM;AAAE+K,MAAAA,iBAAF;AAAqBC,MAAAA,gBAArB;AAAuCC,MAAAA;AAAvC,QACJ,KAAKlM,KADP;AAGAgM,IAAAA,iBAAiB,SAAjB,IAAAA,iBAAiB,WAAjB,YAAAA,iBAAiB,CAAG/K,CAAH,EAAM,KAAKG,2BAAL,EAAN,CAAjB;;AAEA,UAAM+K,YAAY,GAAG,KAAKC,gBAAL,EAArB;;AACA,QAAID,YAAY,IAAI,IAApB,EAA0B;AAE1B,UAAM;AAAE9M,MAAAA,aAAF;AAAiBC,MAAAA;AAAjB,QAAmC,KAAKyB,KAA9C,CATyC,CAWzC;;AACA,UAAMsL,uBAAuB,GAAG;AAC9BlM,MAAAA,CAAC,EAAEc,CAAC,CAACsD,WAAF,CAAcC,KAAd,GAAsBnF,aADK;AAE9Be,MAAAA,CAAC,EAAEa,CAAC,CAACsD,WAAF,CAAcE,KAAd,GAAsBnF;AAFK,KAAhC,CAZyC,CAiBzC;;AACA,QAAI4M,qBAAJ,EAA2B;AACzBG,MAAAA,uBAAuB,CAAClM,CAAxB,GAA4B,CAA5B;AACAkM,MAAAA,uBAAuB,CAACjM,CAAxB,GAA4B,CAA5B;AACD;;AAED,SAAKkM,MAAL,CAAYH,YAAZ,EAA0BE,uBAA1B;AAEAJ,IAAAA,gBAAgB,SAAhB,IAAAA,gBAAgB,WAAhB,YAAAA,gBAAgB,CACdhL,CADc,EAEd,KAAKG,2BAAL,CAAiC;AAAEgB,MAAAA,SAAS,EAAE+J;AAAb,KAAjC,CAFc,CAAhB;AAID;AAED;AACF;AACA;AACA;AACA;AACA;;;AACEC,EAAAA,gBAAgB,GAAG;AACjB,UAAM;AAAEG,MAAAA,QAAF;AAAYhD,MAAAA,OAAZ;AAAqBlH,MAAAA;AAArB,QAAqC,KAAKrC,KAAhD;AACA,UAAM;AAAEoC,MAAAA;AAAF,QAAgB,IAAtB;AAEA,QAAImH,OAAO,IAAI,IAAf,EAAqB;;AAErB,QAAInH,SAAS,CAAC4F,OAAV,CAAkB,CAAlB,MAAyBuB,OAAO,CAACvB,OAAR,CAAgB,CAAhB,CAA7B,EAAiD;AAC/C,aAAO3F,WAAP;AACD;;AAED,QAAIkK,QAAQ,IAAI,IAAhB,EAAsB;AAEtB,UAAMJ,YAAY,GAAG/J,SAAS,IAAI,IAAImK,QAAR,CAA9B;;AACA,QAAIJ,YAAY,GAAG5C,OAAnB,EAA4B;AAC1B,aAAOA,OAAP;AACD;;AAED,WAAO4C,YAAP;AACD;AAED;AACF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AACEG,EAAAA,MAAM,CAACrC,YAAD,EAAuBE,UAAvB,EAA2C;AAAA;;AAC/C,QAAI,CAAC,KAAKnK,KAAL,CAAWoI,WAAhB,EAA6B,OAAO,KAAP;AAC7B,QAAI,KAAKpI,KAAL,CAAWuJ,OAAX,IAAsBU,YAAY,GAAG,KAAKjK,KAAL,CAAWuJ,OAApD,EAA6D,OAAO,KAAP;AAC7D,QAAI,KAAKvJ,KAAL,CAAWwJ,OAAX,IAAsBS,YAAY,GAAG,KAAKjK,KAAL,CAAWwJ,OAApD,EAA6D,OAAO,KAAP;AAE7D,mDAAKxJ,KAAL,EAAW4J,YAAX,oGAA0B,IAA1B,EAAgC,IAAhC,EAAsC,KAAKxI,2BAAL,EAAtC,EAL+C,CAO/C;;AACA,QAAIoL,UAAU,GAAG,EAAjB;;AACA,QAAIrC,UAAJ,EAAgB;AACd;AACA,UAAIsC,SAAS,GAAG,KAAKrK,SAArB,CAFc,CAGd;AACA;AACA;AACA;;AACAoK,MAAAA,UAAU,GAAG,KAAK7K,QAAL,CAAckF,WAAd,CAA0B,CAAC;AAAEvG,QAAAA,KAAK,EAAEmK;AAAT,OAAD,KAAyB;AAC9D,aAAKhJ,OAAL,CAAa+D,QAAb,CAAsB;AACpBrF,UAAAA,CAAC,EAAE,iDACD,KAAK4E,OADJ,EAED,KAAKhE,KAAL,CAAW5B,aAFV,EAGDsN,SAHC,EAIDhC,QAJC,EAKDN,UAAU,CAAChK,CALV,CADiB;AAQpBC,UAAAA,CAAC,EAAE,iDACD,KAAK4E,OADJ,EAED,KAAKjE,KAAL,CAAW3B,cAFV,EAGDqN,SAHC,EAIDhC,QAJC,EAKDN,UAAU,CAAC/J,CALV;AARiB,SAAtB;AAgBAqM,QAAAA,SAAS,GAAGhC,QAAZ;AACD,OAlBY,CAAb;AAmBD,KAnC8C,CAqC/C;;;AACA,wCAAmB,KAAK9I,QAAxB,EAAkCsI,YAAlC,EAAgDzH,KAAhD,CAAsD,MAAM;AAC1D,WAAKb,QAAL,CAAc+K,cAAd,CAA6BF,UAA7B;AACD,KAFD,EAtC+C,CAyC/C;;AAEA,oDAAKxM,KAAL,EAAW4K,WAAX,sGAAyB,IAAzB,EAA+B,IAA/B,EAAqC,KAAKxJ,2BAAL,EAArC;AACA,WAAO,IAAP;AACD;AAED;AACF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AACEuL,EAAAA,MAAM,CAACC,eAAD,EAA0B;AAC9B;AACAA,IAAAA,eAAe,KAAfA,eAAe,GAAK,KAAK5M,KAAL,CAAWuM,QAAX,IAAuB,CAA5B,CAAf;AACA,WAAO,KAAKD,MAAL,CAAY,KAAKlK,SAAL,GAAiBwK,eAA7B,CAAP;AACD;AAED;AACF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AACEC,EAAAA,MAAM,CAACtB,UAAD,EAAqBC,UAArB,EAAyC;AAC7C,UAAM;AAAErM,MAAAA,aAAF;AAAiBC,MAAAA;AAAjB,QAAoC,KAAK2B,KAA/C;AACA,QAAI,CAAC5B,aAAD,IAAkB,CAACC,cAAvB,EAAuC;AAEvC,UAAM2F,OAAO,GAAG,CAACwG,UAAU,GAAGpM,aAAa,GAAG,CAA9B,IAAmC,KAAKiD,SAAxD;AACA,UAAM4C,OAAO,GAAG,CAACwG,UAAU,GAAGpM,cAAc,GAAG,CAA/B,IAAoC,KAAKgD,SAAzD;;AAEA,SAAKkJ,qBAAL,CAA2B,CAACvG,OAA5B,EAAqC,CAACC,OAAtC;AACD;AAED;AACF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AACE8H,EAAAA,MAAM,CAACC,aAAD,EAAwBC,aAAxB,EAA+C;AACnD,UAAMjI,OAAO,GACX,CAAC,KAAKA,OAAL,GAAe,KAAK3C,SAApB,GAAgC2K,aAAjC,IAAkD,KAAK3K,SADzD;AAEA,UAAM4C,OAAO,GACX,CAAC,KAAKA,OAAL,GAAe,KAAK5C,SAApB,GAAgC4K,aAAjC,IAAkD,KAAK5K,SADzD;;AAGA,SAAKkJ,qBAAL,CAA2BvG,OAA3B,EAAoCC,OAApC;AACD;;AAEDiI,EAAAA,MAAM,GAAG;AACP,UAAM;AACJC,MAAAA,aADI;AAEJC,MAAAA,QAFI;AAGJC,MAAAA,0BAHI;AAIJrJ,MAAAA,cAJI;AAKJlB,MAAAA,iBALI;AAMJwK,MAAAA,oBANI;AAOJC,MAAAA,gBAPI;AAQJC,MAAAA;AARI,QASF,KAAKvN,KATT;AAUA,UAAM;AAAET,MAAAA,OAAF;AAAWwL,MAAAA,OAAX;AAAoBhJ,MAAAA,WAAW,GAAG;AAAlC,QAAyC,KAAKhB,KAApD;AAEA,wBACE,6BAAC,iBAAD;AACE,MAAA,KAAK,EAAEyM,MAAM,CAACC;AADhB,OAEM,KAAK5H,eAAL,CAAqB6H,WAF3B;AAGE,MAAA,GAAG,EAAE,KAAK9M,qBAHZ;AAIE,MAAA,QAAQ,EAAE,KAAKiI;AAJjB,qBAME,6BAAC,qBAAD,CAAU,IAAV;AACE,MAAA,KAAK,EAAE,CACL2E,MAAM,CAACG,WADF,EAEL,KAAK3N,KAAL,CAAW4N,KAFN,EAGL;AACEC,QAAAA,SAAS,EAAE,CACT;AAAEC,UAAAA,KAAK,EAAE,KAAKnM;AAAd,SADS,EAET,GAAG,KAAKF,OAAL,CAAasM,qBAAb,EAFM;AADb,OAHK;AADT,OAYGZ,QAZH,CANF,EAqBGC,0BAA0B,KACzBrC,OADyB,aACzBA,OADyB,uBACzBA,OAAO,CAAEiD,GAAT,CACGrC,KAAD,IACE5H,cAAc,iBACZ,6BAAC,iCAAD;AACE,MAAA,CAAC,EAAE4H,KAAK,CAACxL,CADX;AAEE,MAAA,CAAC,EAAEwL,KAAK,CAACvL,CAFX;AAGE,MAAA,GAAG,EAAEuL,KAAK,CAACzH,EAHb;AAIE,MAAA,iBAAiB,EAAEH,cAJrB;AAKE,MAAA,eAAe,EAAE,MAAM;AACrB,aAAK8H,YAAL,CAAkBF,KAAlB;AACD;AAPH,MAHN,CADyB,CArB7B,EAsCG5J,WAAW,CAACiM,GAAZ,CAAgB,CAAC;AAAE7N,MAAAA,CAAF;AAAKC,MAAAA;AAAL,KAAD,EAAW6N,KAAX,KAAqB;AACpC,0BAAO,6BAAC,4BAAD;AAAiB,QAAA,GAAG,EAAEA,KAAtB;AAA6B,QAAA,CAAC,EAAE9N,CAAhC;AAAmC,QAAA,CAAC,EAAEC;AAAtC,QAAP;AACD,KAFA,CAtCH,EA0CGyC,iBAAiB,iBAChB,6BAAC,oBAAD;AACE,MAAA,aAAa,EAAEqK,aADjB;AAEE,MAAA,iBAAiB,EAAErK,iBAFrB;AAGE,MAAA,OAAO,EAAEtD,OAHX;AAIE,MAAA,OAAO,EAAE+N,gBAJX;AAKE,MAAA,WAAW,EAAED,oBALf;AAME,MAAA,YAAY,EAAE,KAAKpH,uBANrB;AAOE,MAAA,OAAO,EAAE,KAAKc,OAPhB;AAQE,MAAA,UAAU,EAAGmH,IAAD,IAAkB;AAC5B,aAAKlN,QAAL,CAAc;AAAEzB,UAAAA,OAAO,EAAE2O;AAAX,SAAd;AACD,OAVH;AAWE,MAAA,QAAQ,EAAEX;AAXZ,MA3CJ,CADF;AA4DD;;AAjtCD;;;;gBAHI7N,uB,kBAQkB;AACpB0I,EAAAA,WAAW,EAAE,IADO;AAEpBlG,EAAAA,UAAU,EAAE,IAFQ;AAGpBG,EAAAA,WAAW,EAAE,CAHO;AAIpBsE,EAAAA,cAAc,EAAE,CAJI;AAKpBC,EAAAA,cAAc,EAAE,CALI;AAMpB2C,EAAAA,OAAO,EAAE,GANW;AAOpBC,EAAAA,OAAO,EAAE,GAPW;AAQpBC,EAAAA,wBAAwB,EAAE,CARN;AASpBC,EAAAA,yBAAyB,EAAE,CATP;AAUpBsB,EAAAA,mBAAmB,EAAE,CAVD;AAWpBjH,EAAAA,cAAc,EAAE,GAXI;AAYpB2D,EAAAA,aAAa,EAAE,IAZK;AAapB6E,EAAAA,QAAQ,EAAE,GAbU;AAcpBlL,EAAAA,WAAW,EAAE,IAdO;AAepBE,EAAAA,iBAAiB,EAAE,GAfC;AAgBpB6D,EAAAA,YAAY,EAAE+I,SAhBM;AAiBpB9I,EAAAA,aAAa,EAAE8I,SAjBK;AAkBpBrG,EAAAA,kBAAkB,EAAE,CAlBA;AAmBpBsF,EAAAA,0BAA0B,EAAE,IAnBR;AAoBpBvK,EAAAA,iBAAiB,EAAEsL,SApBC;AAqBpBjB,EAAAA,aAAa,EAAEiB,SArBK;AAsBpB1N,EAAAA,yBAAyB,EAAE0N,SAtBP;AAuBpB/E,EAAAA,uBAAuB,EAAE+E,SAvBL;AAwBpBrH,EAAAA,UAAU,EAAE,IAxBQ;AAyBpB3E,EAAAA,uBAAuB,EAAE;AAzBL,C;;AA+sCxB,MAAMqL,MAAM,GAAGY,wBAAWrI,MAAX,CAAkB;AAC/B0H,EAAAA,SAAS,EAAE;AACTY,IAAAA,UAAU,EAAE,QADH;AAETC,IAAAA,IAAI,EAAE,CAFG;AAGTC,IAAAA,cAAc,EAAE,QAHP;AAITC,IAAAA,QAAQ,EAAE,QAJD;AAKThO,IAAAA,QAAQ,EAAE;AALD,GADoB;AAQ/BmN,EAAAA,WAAW,EAAE;AACXU,IAAAA,UAAU,EAAE,QADD;AAEXC,IAAAA,IAAI,EAAE,CAFK;AAGXC,IAAAA,cAAc,EAAE,QAHL;AAIX/O,IAAAA,KAAK,EAAE;AAJI;AARkB,CAAlB,CAAf;;eAgBeE,uB","sourcesContent":["import React, { Component, createRef, RefObject } from 'react';\nimport {\n Animated,\n Easing,\n GestureResponderEvent,\n PanResponder,\n PanResponderCallbacks,\n PanResponderGestureState,\n PanResponderInstance,\n StyleSheet,\n View,\n} from 'react-native';\n\nimport {\n Vec2D,\n ReactNativeZoomableViewProps,\n ReactNativeZoomableViewState,\n TouchPoint,\n ZoomableViewEvent,\n Size2D,\n} from './typings';\n\nimport { AnimatedTouchFeedback } from './components';\nimport { DebugTouchPoint } from './debugHelper';\nimport {\n calcGestureCenterPoint,\n calcGestureTouchDistance,\n calcNewScaledOffsetForZoomCentering,\n} from './helper';\nimport { applyPanBoundariesToOffset } from './helper/applyPanBoundariesToOffset';\nimport { viewportPositionToImagePosition } from './helper/coordinateConversion';\nimport { StaticPin } from './components/StaticPin';\nimport { debounce } from 'lodash';\nimport {\n getBoundaryCrossedAnim,\n getPanMomentumDecayAnim,\n getZoomToAnimation,\n} from './animations';\n\nconst initialState: ReactNativeZoomableViewState = {\n originalWidth: 0,\n originalHeight: 0,\n originalPageX: 0,\n originalPageY: 0,\n pinSize: { width: 0, height: 0 },\n};\n\nclass ReactNativeZoomableView extends Component<\n ReactNativeZoomableViewProps,\n ReactNativeZoomableViewState\n> {\n zoomSubjectWrapperRef: RefObject;\n gestureHandlers: PanResponderInstance;\n doubleTapFirstTapReleaseTimestamp: number | undefined;\n\n static defaultProps = {\n zoomEnabled: true,\n panEnabled: true,\n initialZoom: 1,\n initialOffsetX: 0,\n initialOffsetY: 0,\n maxZoom: 1.5,\n minZoom: 0.5,\n pinchToZoomInSensitivity: 1,\n pinchToZoomOutSensitivity: 1,\n movementSensibility: 1,\n doubleTapDelay: 300,\n bindToBorders: true,\n zoomStep: 0.5,\n onLongPress: null,\n longPressDuration: 700,\n contentWidth: undefined,\n contentHeight: undefined,\n panBoundaryPadding: 0,\n visualTouchFeedbackEnabled: true,\n staticPinPosition: undefined,\n staticPinIcon: undefined,\n onStaticPinPositionChange: undefined,\n onStaticPinPositionMove: undefined,\n animatePin: true,\n disablePanOnInitialZoom: false,\n };\n\n private panAnim = new Animated.ValueXY({ x: 0, y: 0 });\n private zoomAnim = new Animated.Value(1);\n private pinAnim = new Animated.ValueXY({ x: 0, y: 0 });\n\n private __offsets = {\n x: {\n value: 0,\n boundaryCrossedAnimInEffect: false,\n },\n y: {\n value: 0,\n boundaryCrossedAnimInEffect: false,\n },\n };\n\n private zoomLevel = 1;\n private lastGestureCenterPosition: { x: number; y: number } | null = null;\n private lastGestureTouchDistance: number | null = null;\n private gestureType: 'pinch' | 'shift' | null;\n\n private _gestureStarted = false;\n private set gestureStarted(v: boolean) {\n this._gestureStarted = v;\n }\n\n public get gestureStarted() {\n return this._gestureStarted;\n }\n\n /**\n * Last press time (used to evaluate whether user double tapped)\n * @type {number}\n */\n private longPressTimeout: NodeJS.Timeout | null = null;\n private onTransformInvocationInitialized: boolean | undefined;\n private singleTapTimeoutId: NodeJS.Timeout | undefined;\n private touches: TouchPoint[] = [];\n private doubleTapFirstTap: TouchPoint | undefined;\n private measureZoomSubjectInterval: NodeJS.Timer | undefined;\n\n constructor(props: ReactNativeZoomableViewProps) {\n super(props);\n // This needs to be done before anything else to initialize the state.\n // Otherwise, the logic below may reference the state when it's undefined,\n // causing runtime errors.\n this.state = { ...initialState };\n\n this.gestureHandlers = PanResponder.create({\n onStartShouldSetPanResponder: this._handleStartShouldSetPanResponder,\n onPanResponderGrant: this._handlePanResponderGrant,\n onPanResponderMove: this._handlePanResponderMove,\n onPanResponderRelease: this._handlePanResponderEnd,\n onPanResponderTerminate: (evt, gestureState) => {\n // We should also call _handlePanResponderEnd\n // to properly perform cleanups when the gesture is terminated\n // (aka gesture handling responsibility is taken over by another component).\n // This also fixes a weird issue where\n // on real device, sometimes onPanResponderRelease is not called when you lift 2 fingers up,\n // but onPanResponderTerminate is called instead for no apparent reason.\n this._handlePanResponderEnd(evt, gestureState);\n this.props.onPanResponderTerminate?.(\n evt,\n gestureState,\n this._getZoomableViewEventObject()\n );\n },\n onPanResponderTerminationRequest: (evt, gestureState) =>\n !!this.props.onPanResponderTerminationRequest?.(\n evt,\n gestureState,\n this._getZoomableViewEventObject()\n ),\n // Defaults to true to prevent parent components, such as React Navigation's tab view, from taking over as responder.\n onShouldBlockNativeResponder: (evt, gestureState) =>\n this.props.onShouldBlockNativeResponder?.(\n evt,\n gestureState,\n this._getZoomableViewEventObject()\n ) ?? true,\n onStartShouldSetPanResponderCapture: (evt, gestureState) =>\n !!this.props.onStartShouldSetPanResponderCapture?.(evt, gestureState),\n onMoveShouldSetPanResponderCapture: (evt, gestureState) =>\n !!this.props.onMoveShouldSetPanResponderCapture?.(evt, gestureState),\n });\n\n this.zoomSubjectWrapperRef = createRef();\n\n if (this.props.zoomAnimatedValue)\n this.zoomAnim = this.props.zoomAnimatedValue;\n if (this.props.panAnimatedValueXY)\n this.panAnim = this.props.panAnimatedValueXY;\n\n if (this.props.initialZoom) this.zoomLevel = this.props.initialZoom;\n if (this.props.initialOffsetX != null)\n this.offsetX = this.props.initialOffsetX;\n if (this.props.initialOffsetY != null)\n this.offsetY = this.props.initialOffsetY;\n\n this.panAnim.setValue({ x: this.offsetX, y: this.offsetY });\n this.zoomAnim.setValue(this.zoomLevel);\n this.panAnim.addListener(({ x, y }) => {\n this.offsetX = x;\n this.offsetY = y;\n });\n this.zoomAnim.addListener(({ value }) => {\n this.zoomLevel = value;\n });\n\n this.lastGestureTouchDistance = 150;\n\n this.gestureType = null;\n }\n\n private raisePin() {\n if (!this.props.animatePin) return;\n Animated.timing(this.pinAnim, {\n toValue: { x: 0, y: -10 },\n useNativeDriver: true,\n easing: Easing.out(Easing.ease),\n duration: 100,\n }).start();\n }\n\n private dropPin() {\n if (!this.props.animatePin) return;\n Animated.timing(this.pinAnim, {\n toValue: { x: 0, y: 0 },\n useNativeDriver: true,\n easing: Easing.out(Easing.ease),\n duration: 100,\n }).start();\n }\n\n private set offsetX(x: number) {\n this.__setOffset('x', x);\n }\n\n private set offsetY(y: number) {\n this.__setOffset('y', y);\n }\n\n private get offsetX() {\n return this.__getOffset('x');\n }\n\n private get offsetY() {\n return this.__getOffset('y');\n }\n\n private __setOffset(axis: 'x' | 'y', offset: number) {\n const offsetState = this.__offsets[axis];\n\n if (this.props.bindToBorders) {\n const containerSize =\n axis === 'x' ? this.state.originalWidth : this.state.originalHeight;\n const contentSize =\n axis === 'x'\n ? this.props.contentWidth || this.state.originalWidth\n : this.props.contentHeight || this.state.originalHeight;\n\n const boundOffset =\n contentSize && containerSize && this.props.panBoundaryPadding != null\n ? applyPanBoundariesToOffset(\n offset,\n containerSize,\n contentSize,\n this.zoomLevel,\n this.props.panBoundaryPadding\n )\n : offset;\n\n if (!this.gestureType && !offsetState.boundaryCrossedAnimInEffect) {\n const boundariesApplied =\n boundOffset !== offset &&\n boundOffset.toFixed(3) !== offset.toFixed(3);\n if (boundariesApplied) {\n offsetState.boundaryCrossedAnimInEffect = true;\n getBoundaryCrossedAnim(this.panAnim[axis], boundOffset).start(() => {\n offsetState.boundaryCrossedAnimInEffect = false;\n });\n return;\n }\n }\n }\n\n offsetState.value = offset;\n }\n\n private __getOffset(axis: 'x' | 'y') {\n return this.__offsets[axis].value;\n }\n\n componentDidUpdate(\n prevProps: ReactNativeZoomableViewProps,\n prevState: ReactNativeZoomableViewState\n ) {\n const { zoomEnabled, initialZoom } = this.props;\n if (prevProps.zoomEnabled && !zoomEnabled && initialZoom) {\n this.zoomLevel = initialZoom;\n this.zoomAnim.setValue(this.zoomLevel);\n }\n if (\n !this.onTransformInvocationInitialized &&\n this._invokeOnTransform().successful\n ) {\n this.panAnim.addListener(() => this._invokeOnTransform());\n this.zoomAnim.addListener(() => this._invokeOnTransform());\n this.onTransformInvocationInitialized = true;\n }\n\n const currState = this.state;\n const originalMeasurementsChanged =\n currState.originalHeight !== prevState.originalHeight ||\n currState.originalWidth !== prevState.originalWidth ||\n currState.originalPageX !== prevState.originalPageX ||\n currState.originalPageY !== prevState.originalPageY;\n\n const staticPinPositionChanged =\n prevProps.staticPinPosition?.x !== this.props.staticPinPosition?.x ||\n prevProps.staticPinPosition?.y !== this.props.staticPinPosition?.y;\n\n // We use a custom `onLayout` event because:\n // a) View's `onLayout` sometimes doesn't get called\n // b) we use `measureInWindow` internally to keep track of layout changes\n // When the client uses this, they can stay in-sync with the internal measurements,\n // thus applying transformations at more accurate timings\n if (originalMeasurementsChanged) {\n this.props.onLayoutMeasured?.({\n width: currState.originalWidth,\n height: currState.originalHeight,\n x: currState.originalPageX,\n y: currState.originalPageY,\n });\n }\n\n if (\n this.onTransformInvocationInitialized &&\n (originalMeasurementsChanged || staticPinPositionChanged)\n ) {\n this._invokeOnTransform();\n }\n }\n\n componentDidMount() {\n this.measureZoomSubject();\n // We've already run `grabZoomSubjectOriginalMeasurements` at various events\n // to make sure the measurements are promptly updated.\n // However, there might be cases we haven't accounted for, especially when\n // native processes are involved. To account for those cases,\n // we'll use an interval here to ensure we're always up-to-date.\n // The `setState` in `grabZoomSubjectOriginalMeasurements` won't trigger a rerender\n // if the values given haven't changed, so we're not running performance risk here.\n this.measureZoomSubjectInterval = setInterval(this.measureZoomSubject, 1e3);\n }\n\n componentWillUnmount() {\n this.measureZoomSubjectInterval &&\n clearInterval(this.measureZoomSubjectInterval);\n }\n\n debouncedOnStaticPinPositionChange = debounce(\n (position: Vec2D) => this.props.onStaticPinPositionChange?.(position),\n 100\n );\n\n /**\n * try to invoke onTransform\n * @private\n */\n _invokeOnTransform() {\n const zoomableViewEvent = this._getZoomableViewEventObject();\n const position = this._staticPinPosition();\n\n if (!zoomableViewEvent.originalWidth || !zoomableViewEvent.originalHeight)\n return { successful: false };\n\n this.props.onTransform?.(zoomableViewEvent);\n\n if (position) {\n this.props.onStaticPinPositionMove?.(position);\n this.debouncedOnStaticPinPositionChange(position);\n }\n\n return { successful: true };\n }\n\n /**\n * Returns additional information about components current state for external event hooks\n *\n * @returns {{}}\n * @private\n */\n _getZoomableViewEventObject(overwriteObj = {}): ZoomableViewEvent {\n return {\n zoomLevel: this.zoomLevel,\n offsetX: this.offsetX,\n offsetY: this.offsetY,\n originalHeight: this.state.originalHeight,\n originalWidth: this.state.originalWidth,\n originalPageX: this.state.originalPageX,\n originalPageY: this.state.originalPageY,\n ...overwriteObj,\n } as ZoomableViewEvent;\n }\n\n /**\n * Get the original box dimensions and save them for later use.\n * (They will be used to calculate boxBorders)\n *\n * @private\n */\n private measureZoomSubject = () => {\n // make sure we measure after animations are complete\n requestAnimationFrame(() => {\n // this setTimeout is here to fix a weird issue on iOS where the measurements are all `0`\n // when navigating back (react-navigation stack) from another view\n // while closing the keyboard at the same time\n setTimeout(() => {\n // In normal conditions, we're supposed to measure zoomSubject instead of its wrapper.\n // However, our zoomSubject may have been transformed by an initial zoomLevel or offset,\n // in which case these measurements will not represent the true \"original\" measurements.\n // We just need to make sure the zoomSubjectWrapper perfectly aligns with the zoomSubject\n // (no border, space, or anything between them)\n const zoomSubjectWrapperRef = this.zoomSubjectWrapperRef;\n // we don't wanna measure when zoomSubjectWrapperRef is not yet available or has been unmounted\n zoomSubjectWrapperRef.current?.measureInWindow(\n (x, y, width, height) => {\n // When the component is off-screen, these become all 0s, so we don't set them\n // to avoid messing up calculations, especially ones that are done right after\n // the component transitions from hidden to visible.\n if (!x && !y && !width && !height) return;\n\n // If these values are all the same, don't re-set them in state\n // this way we don't re-render\n if (\n this.state.originalWidth === width &&\n this.state.originalHeight === height &&\n this.state.originalPageX === x &&\n this.state.originalPageY === y\n ) {\n return;\n }\n\n this.setState({\n originalWidth: width,\n originalHeight: height,\n originalPageX: x,\n originalPageY: y,\n });\n }\n );\n });\n });\n };\n\n /**\n * Handles the start of touch events and checks for taps\n *\n * @param e\n * @param gestureState\n * @returns {boolean}\n *\n * @private\n */\n _handleStartShouldSetPanResponder = (\n e: GestureResponderEvent,\n gestureState: PanResponderGestureState\n ) => {\n if (this.props.onStartShouldSetPanResponder) {\n this.props.onStartShouldSetPanResponder(\n e,\n gestureState,\n this._getZoomableViewEventObject(),\n false\n );\n }\n\n // Always set pan responder on start\n // of gesture so we can handle tap.\n // \"Pan threshold validation\" will be handled\n // in `onPanResponderMove` instead of in `onMoveShouldSetPanResponder`\n return true;\n };\n\n /**\n * Calculates pinch distance\n *\n * @param e\n * @param gestureState\n * @private\n */\n _handlePanResponderGrant: NonNullable<\n PanResponderCallbacks['onPanResponderGrant']\n > = (e, gestureState) => {\n if (this.props.onLongPress) {\n this.longPressTimeout = setTimeout(() => {\n this.props.onLongPress?.(\n e,\n gestureState,\n this._getZoomableViewEventObject()\n );\n this.longPressTimeout = null;\n }, this.props.longPressDuration);\n }\n\n this.props.onPanResponderGrant?.(\n e,\n gestureState,\n this._getZoomableViewEventObject()\n );\n\n this.panAnim.stopAnimation();\n this.zoomAnim.stopAnimation();\n this.gestureStarted = true;\n\n this.raisePin();\n };\n\n /**\n * Handles the end of touch events\n *\n * @param e\n * @param gestureState\n *\n * @private\n */\n _handlePanResponderEnd: NonNullable<\n PanResponderCallbacks['onPanResponderEnd']\n > = (e, gestureState) => {\n if (!this.gestureType) {\n this._resolveAndHandleTap(e);\n }\n\n this.setState({ debugPoints: [] });\n\n this.lastGestureCenterPosition = null;\n\n const disableMomentum =\n this.props.disableMomentum ||\n (this.props.panEnabled &&\n this.gestureType === 'shift' &&\n this.props.disablePanOnInitialZoom &&\n this.zoomLevel === this.props.initialZoom);\n\n // Trigger final shift animation unless disablePanOnInitialZoom is set and we're on the initial zoom level\n // or disableMomentum\n if (!disableMomentum) {\n getPanMomentumDecayAnim(this.panAnim, {\n x: gestureState.vx / this.zoomLevel,\n y: gestureState.vy / this.zoomLevel,\n }).start();\n }\n\n if (this.longPressTimeout) {\n clearTimeout(this.longPressTimeout);\n this.longPressTimeout = null;\n }\n\n this.props.onPanResponderEnd?.(\n e,\n gestureState,\n this._getZoomableViewEventObject()\n );\n\n if (this.gestureType === 'pinch') {\n this.props.onZoomEnd?.(\n e,\n gestureState,\n this._getZoomableViewEventObject()\n );\n } else if (this.gestureType === 'shift') {\n this.props.onShiftingEnd?.(\n e,\n gestureState,\n this._getZoomableViewEventObject()\n );\n }\n\n if (this.props.staticPinPosition) {\n this._updateStaticPin();\n }\n\n this.dropPin();\n\n this.gestureType = null;\n this.gestureStarted = false;\n };\n\n /**\n * Handles the actual movement of our pan responder\n *\n * @param e\n * @param gestureState\n *\n * @private\n */\n _handlePanResponderMove = (\n e: GestureResponderEvent,\n gestureState: PanResponderGestureState\n ) => {\n if (this.props.onPanResponderMove) {\n if (\n this.props.onPanResponderMove(\n e,\n gestureState,\n this._getZoomableViewEventObject()\n )\n ) {\n return false;\n }\n }\n\n // Only supports 2 touches and below,\n // any invalid number will cause the gesture to end.\n if (gestureState.numberActiveTouches <= 2) {\n if (!this.gestureStarted) {\n this._handlePanResponderGrant(e, gestureState);\n }\n } else {\n if (this.gestureStarted) {\n this._handlePanResponderEnd(e, gestureState);\n }\n return true;\n }\n\n if (gestureState.numberActiveTouches === 2) {\n if (this.longPressTimeout) {\n clearTimeout(this.longPressTimeout);\n this.longPressTimeout = null;\n }\n\n // change some measurement states when switching gesture to ensure a smooth transition\n if (this.gestureType !== 'pinch') {\n this.lastGestureCenterPosition = calcGestureCenterPoint(\n e,\n gestureState\n );\n this.lastGestureTouchDistance = calcGestureTouchDistance(\n e,\n gestureState\n );\n }\n this.gestureType = 'pinch';\n this._handlePinching(e, gestureState);\n } else if (gestureState.numberActiveTouches === 1) {\n if (\n this.longPressTimeout &&\n (Math.abs(gestureState.dx) > 5 || Math.abs(gestureState.dy) > 5)\n ) {\n clearTimeout(this.longPressTimeout);\n this.longPressTimeout = null;\n }\n // change some measurement states when switching gesture to ensure a smooth transition\n if (this.gestureType !== 'shift') {\n this.lastGestureCenterPosition = calcGestureCenterPoint(\n e,\n gestureState\n );\n }\n\n const { dx, dy } = gestureState;\n const isShiftGesture = Math.abs(dx) > 2 || Math.abs(dy) > 2;\n if (isShiftGesture) {\n this.gestureType = 'shift';\n this._handleShifting(gestureState);\n }\n }\n };\n\n /**\n * Handles the pinch movement and zooming\n *\n * @param e\n * @param gestureState\n *\n * @private\n */\n _handlePinching(\n e: GestureResponderEvent,\n gestureState: PanResponderGestureState\n ) {\n if (!this.props.zoomEnabled) return;\n\n const {\n maxZoom,\n minZoom,\n pinchToZoomInSensitivity,\n pinchToZoomOutSensitivity,\n } = this.props;\n\n const distance = calcGestureTouchDistance(e, gestureState);\n\n if (\n this.props.onZoomBefore &&\n this.props.onZoomBefore(\n e,\n gestureState,\n this._getZoomableViewEventObject()\n )\n ) {\n return;\n }\n\n if (!distance) return;\n if (!this.lastGestureTouchDistance) return;\n\n // define the new zoom level and take zoom level sensitivity into consideration\n const zoomGrowthFromLastGestureState =\n distance / this.lastGestureTouchDistance;\n this.lastGestureTouchDistance = distance;\n\n const pinchToZoomSensitivity =\n zoomGrowthFromLastGestureState < 1\n ? pinchToZoomOutSensitivity\n : pinchToZoomInSensitivity;\n\n if (pinchToZoomSensitivity == null) return;\n const deltaGrowth = zoomGrowthFromLastGestureState - 1;\n // 0 - no resistance\n // 10 - 90% resistance\n const deltaGrowthAdjustedBySensitivity =\n deltaGrowth * (1 - (pinchToZoomSensitivity * 9) / 100);\n\n let newZoomLevel = this.zoomLevel * (1 + deltaGrowthAdjustedBySensitivity);\n\n // make sure max and min zoom levels are respected\n if (maxZoom != null && newZoomLevel > maxZoom) {\n newZoomLevel = maxZoom;\n }\n\n if (minZoom != null && newZoomLevel < minZoom) {\n newZoomLevel = minZoom;\n }\n\n const gestureCenterPoint = calcGestureCenterPoint(e, gestureState);\n\n if (!gestureCenterPoint) return;\n\n let zoomCenter = {\n x: gestureCenterPoint.x - this.state.originalPageX,\n y: gestureCenterPoint.y - this.state.originalPageY,\n };\n\n if (this.props.staticPinPosition) {\n // When we use a static pin position, the zoom centre is the same as that position,\n // otherwise the pin moves around way too much while zooming.\n zoomCenter = {\n x: this.props.staticPinPosition.x,\n y: this.props.staticPinPosition.y,\n };\n }\n\n // Uncomment to debug\n this.props.debug && this._setPinchDebugPoints(e, zoomCenter);\n\n const { originalHeight, originalWidth } = this.state;\n\n const oldOffsetX = this.offsetX;\n const oldOffsetY = this.offsetY;\n const oldScale = this.zoomLevel;\n const newScale = newZoomLevel;\n\n if (!originalHeight || !originalWidth) return;\n\n let offsetY = calcNewScaledOffsetForZoomCentering(\n oldOffsetY,\n originalHeight,\n oldScale,\n newScale,\n zoomCenter.y\n );\n let offsetX = calcNewScaledOffsetForZoomCentering(\n oldOffsetX,\n originalWidth,\n oldScale,\n newScale,\n zoomCenter.x\n );\n\n const offsetShift =\n this._calcOffsetShiftSinceLastGestureState(gestureCenterPoint);\n if (offsetShift) {\n offsetX += offsetShift.x;\n offsetY += offsetShift.y;\n }\n\n this.offsetX = offsetX;\n this.offsetY = offsetY;\n this.zoomLevel = newScale;\n\n this.panAnim.setValue({ x: this.offsetX, y: this.offsetY });\n this.zoomAnim.setValue(this.zoomLevel);\n\n this.props.onZoomAfter?.(\n e,\n gestureState,\n this._getZoomableViewEventObject()\n );\n }\n\n /**\n * Used to debug pinch events\n * @param gestureResponderEvent\n * @param zoomCenter\n * @param points\n */\n _setPinchDebugPoints(\n gestureResponderEvent: GestureResponderEvent,\n zoomCenter: Vec2D,\n ...points: Vec2D[]\n ) {\n const { touches } = gestureResponderEvent.nativeEvent;\n const { originalPageY, originalPageX } = this.state;\n\n this.setState({\n debugPoints: [\n {\n x: touches[0].pageX - originalPageX,\n y: touches[0].pageY - originalPageY,\n },\n {\n x: touches[1].pageX - originalPageX,\n y: touches[1].pageY - originalPageY,\n },\n zoomCenter,\n ...points,\n ],\n });\n }\n\n /**\n * Calculates the amount the offset should shift since the last position during panning\n *\n * @param {Vec2D} gestureCenterPoint\n *\n * @private\n */\n _calcOffsetShiftSinceLastGestureState(gestureCenterPoint: Vec2D) {\n const { movementSensibility } = this.props;\n\n let shift = null;\n\n if (this.lastGestureCenterPosition && movementSensibility) {\n const dx = gestureCenterPoint.x - this.lastGestureCenterPosition.x;\n const dy = gestureCenterPoint.y - this.lastGestureCenterPosition.y;\n\n const shiftX = dx / this.zoomLevel / movementSensibility;\n const shiftY = dy / this.zoomLevel / movementSensibility;\n\n shift = {\n x: shiftX,\n y: shiftY,\n };\n }\n\n this.lastGestureCenterPosition = gestureCenterPoint;\n\n return shift;\n }\n\n /**\n * Handles movement by tap and move\n *\n * @param gestureState\n *\n * @private\n */\n _handleShifting(gestureState: PanResponderGestureState) {\n // Skips shifting if panEnabled is false or disablePanOnInitialZoom is true and we're on the initial zoom level\n if (\n !this.props.panEnabled ||\n (this.props.disablePanOnInitialZoom &&\n this.zoomLevel === this.props.initialZoom)\n ) {\n return;\n }\n const shift = this._calcOffsetShiftSinceLastGestureState({\n x: gestureState.moveX,\n y: gestureState.moveY,\n });\n if (!shift) return;\n\n const offsetX = this.offsetX + shift.x;\n const offsetY = this.offsetY + shift.y;\n\n if (\n this.props.debug &&\n this.state.originalPageX &&\n this.state.originalPageY\n ) {\n const x = gestureState.moveX - this.state.originalPageX;\n const y = gestureState.moveY - this.state.originalPageY;\n this.setState({ debugPoints: [{ x, y }] });\n }\n\n this._setNewOffsetPosition(offsetX, offsetY);\n\n this.raisePin();\n }\n\n /**\n * Set the state to offset moved\n *\n * @param {number} newOffsetX\n * @param {number} newOffsetY\n * @returns\n */\n _setNewOffsetPosition(newOffsetX: number, newOffsetY: number) {\n const { onShiftingBefore, onShiftingAfter } = this.props;\n\n if (onShiftingBefore?.(null, null, this._getZoomableViewEventObject())) {\n return;\n }\n\n this.offsetX = newOffsetX;\n this.offsetY = newOffsetY;\n\n this.panAnim.setValue({ x: this.offsetX, y: this.offsetY });\n this.zoomAnim.setValue(this.zoomLevel);\n\n onShiftingAfter?.(null, null, this._getZoomableViewEventObject());\n }\n\n /**\n * Check whether the press event is double tap\n * or single tap and handle the event accordingly\n *\n * @param e\n *\n * @private\n */\n private _resolveAndHandleTap = (e: GestureResponderEvent) => {\n const now = Date.now();\n if (\n this.doubleTapFirstTapReleaseTimestamp &&\n this.props.doubleTapDelay &&\n now - this.doubleTapFirstTapReleaseTimestamp < this.props.doubleTapDelay\n ) {\n this.doubleTapFirstTap &&\n this._addTouch({\n ...this.doubleTapFirstTap,\n id: now.toString(),\n isSecondTap: true,\n });\n this.singleTapTimeoutId && clearTimeout(this.singleTapTimeoutId);\n delete this.doubleTapFirstTapReleaseTimestamp;\n delete this.singleTapTimeoutId;\n delete this.doubleTapFirstTap;\n this._handleDoubleTap(e);\n } else {\n this.doubleTapFirstTapReleaseTimestamp = now;\n this.doubleTapFirstTap = {\n id: now.toString(),\n x: e.nativeEvent.pageX - this.state.originalPageX,\n y: e.nativeEvent.pageY - this.state.originalPageY,\n };\n this._addTouch(this.doubleTapFirstTap);\n\n // persist event so e.nativeEvent is preserved after a timeout delay\n e.persist();\n this.singleTapTimeoutId = setTimeout(() => {\n delete this.doubleTapFirstTapReleaseTimestamp;\n delete this.singleTapTimeoutId;\n\n // Pan to the tapped location\n if (this.props.staticPinPosition && this.doubleTapFirstTap) {\n const tapX =\n this.props.staticPinPosition.x - this.doubleTapFirstTap.x;\n const tapY =\n this.props.staticPinPosition.y - this.doubleTapFirstTap.y;\n\n Animated.timing(this.panAnim, {\n toValue: {\n x: this.offsetX + tapX / this.zoomLevel,\n y: this.offsetY + tapY / this.zoomLevel,\n },\n useNativeDriver: true,\n duration: 200,\n }).start(() => {\n this._updateStaticPin();\n });\n }\n\n this.props.onSingleTap?.(e, this._getZoomableViewEventObject());\n }, this.props.doubleTapDelay);\n }\n };\n\n moveStaticPinTo = (position: Vec2D, duration?: number) => {\n const { originalWidth, originalHeight } = this.state;\n const { staticPinPosition, contentWidth, contentHeight } = this.props;\n\n if (!staticPinPosition) return;\n if (!originalWidth || !originalHeight) return;\n if (!contentWidth || !contentHeight) return;\n\n // Offset for the static pin\n const pinX = staticPinPosition.x - originalWidth / 2;\n const pinY = staticPinPosition.y - originalHeight / 2;\n\n this.offsetX = contentWidth / 2 - position.x + pinX / this.zoomLevel;\n this.offsetY = contentHeight / 2 - position.y + pinY / this.zoomLevel;\n\n if (duration) {\n Animated.timing(this.panAnim, {\n toValue: { x: this.offsetX, y: this.offsetY },\n useNativeDriver: true,\n duration,\n }).start();\n } else {\n this.panAnim.setValue({ x: this.offsetX, y: this.offsetY });\n }\n };\n\n private _staticPinPosition = () => {\n if (!this.props.staticPinPosition) return;\n if (!this.props.contentWidth || !this.props.contentHeight) return;\n\n return viewportPositionToImagePosition({\n viewportPosition: {\n x: this.props.staticPinPosition.x,\n y: this.props.staticPinPosition.y,\n },\n imageSize: {\n height: this.props.contentHeight,\n width: this.props.contentWidth,\n },\n zoomableEvent: {\n ...this._getZoomableViewEventObject(),\n offsetX: this.offsetX,\n offsetY: this.offsetY,\n zoomLevel: this.zoomLevel,\n },\n });\n };\n\n private _updateStaticPin = () => {\n const position = this._staticPinPosition();\n if (!position) return;\n this.props.onStaticPinPositionChange?.(position);\n };\n\n private _addTouch(touch: TouchPoint) {\n this.touches.push(touch);\n this.setState({ touches: [...this.touches] });\n }\n\n private _removeTouch(touch: TouchPoint) {\n this.touches.splice(this.touches.indexOf(touch), 1);\n this.setState({ touches: [...this.touches] });\n }\n\n /**\n * Handles the double tap event\n *\n * @param e\n *\n * @private\n */\n _handleDoubleTap(e: GestureResponderEvent) {\n const { onDoubleTapBefore, onDoubleTapAfter, doubleTapZoomToCenter } =\n this.props;\n\n onDoubleTapBefore?.(e, this._getZoomableViewEventObject());\n\n const nextZoomStep = this._getNextZoomStep();\n if (nextZoomStep == null) return;\n\n const { originalPageX, originalPageY } = this.state;\n\n // define new zoom position coordinates\n const zoomPositionCoordinates = {\n x: e.nativeEvent.pageX - originalPageX,\n y: e.nativeEvent.pageY - originalPageY,\n };\n\n // if doubleTapZoomToCenter enabled -> always zoom to center instead\n if (doubleTapZoomToCenter) {\n zoomPositionCoordinates.x = 0;\n zoomPositionCoordinates.y = 0;\n }\n\n this.zoomTo(nextZoomStep, zoomPositionCoordinates);\n\n onDoubleTapAfter?.(\n e,\n this._getZoomableViewEventObject({ zoomLevel: nextZoomStep })\n );\n }\n\n /**\n * Returns the next zoom step based on current step and zoomStep property.\n * If we are zoomed all the way in -> return to initialzoom\n *\n * @returns {*}\n */\n _getNextZoomStep() {\n const { zoomStep, maxZoom, initialZoom } = this.props;\n const { zoomLevel } = this;\n\n if (maxZoom == null) return;\n\n if (zoomLevel.toFixed(2) === maxZoom.toFixed(2)) {\n return initialZoom;\n }\n\n if (zoomStep == null) return;\n\n const nextZoomStep = zoomLevel * (1 + zoomStep);\n if (nextZoomStep > maxZoom) {\n return maxZoom;\n }\n\n return nextZoomStep;\n }\n\n /**\n * Zooms to a specific level. A \"zoom center\" can be provided, which specifies\n * the point that will remain in the same position on the screen after the zoom.\n * The coordinates of the zoom center is relative to the zoom subject.\n * { x: 0, y: 0 } is the very center of the zoom subject.\n *\n * @param newZoomLevel\n * @param zoomCenter - If not supplied, the container's center is the zoom center\n */\n zoomTo(newZoomLevel: number, zoomCenter?: Vec2D) {\n if (!this.props.zoomEnabled) return false;\n if (this.props.maxZoom && newZoomLevel > this.props.maxZoom) return false;\n if (this.props.minZoom && newZoomLevel < this.props.minZoom) return false;\n\n this.props.onZoomBefore?.(null, null, this._getZoomableViewEventObject());\n\n // == Perform Pan Animation to preserve the zoom center while zooming ==\n let listenerId = '';\n if (zoomCenter) {\n // Calculates panAnim values based on changes in zoomAnim.\n let prevScale = this.zoomLevel;\n // Since zoomAnim is calculated in native driver,\n // it will jitter panAnim once in a while,\n // because here panAnim is being calculated in js.\n // However the jittering should mostly occur in simulator.\n listenerId = this.zoomAnim.addListener(({ value: newScale }) => {\n this.panAnim.setValue({\n x: calcNewScaledOffsetForZoomCentering(\n this.offsetX,\n this.state.originalWidth,\n prevScale,\n newScale,\n zoomCenter.x\n ),\n y: calcNewScaledOffsetForZoomCentering(\n this.offsetY,\n this.state.originalHeight,\n prevScale,\n newScale,\n zoomCenter.y\n ),\n });\n prevScale = newScale;\n });\n }\n\n // == Perform Zoom Animation ==\n getZoomToAnimation(this.zoomAnim, newZoomLevel).start(() => {\n this.zoomAnim.removeListener(listenerId);\n });\n // == Zoom Animation Ends ==\n\n this.props.onZoomAfter?.(null, null, this._getZoomableViewEventObject());\n return true;\n }\n\n /**\n * Zooms in or out by a specified change level\n * Use a positive number for `zoomLevelChange` to zoom in\n * Use a negative number for `zoomLevelChange` to zoom out\n *\n * Returns a promise if everything was updated and a boolean, whether it could be updated or if it exceeded the min/max zoom limits.\n *\n * @param {number | null} zoomLevelChange\n *\n * @return {bool}\n */\n zoomBy(zoomLevelChange: number) {\n // if no zoom level Change given -> just use zoom step\n zoomLevelChange ||= this.props.zoomStep || 0;\n return this.zoomTo(this.zoomLevel + zoomLevelChange);\n }\n\n /**\n * Moves the zoomed view to a specified position\n * Returns a promise when finished\n *\n * @param {number} newOffsetX the new position we want to move it to (x-axis)\n * @param {number} newOffsetY the new position we want to move it to (y-axis)\n *\n * @return {bool}\n */\n moveTo(newOffsetX: number, newOffsetY: number) {\n const { originalWidth, originalHeight } = this.state;\n if (!originalWidth || !originalHeight) return;\n\n const offsetX = (newOffsetX - originalWidth / 2) / this.zoomLevel;\n const offsetY = (newOffsetY - originalHeight / 2) / this.zoomLevel;\n\n this._setNewOffsetPosition(-offsetX, -offsetY);\n }\n\n /**\n * Moves the zoomed view by a certain amount.\n *\n * Returns a promise when finished\n *\n * @param {number} offsetChangeX the amount we want to move the offset by (x-axis)\n * @param {number} offsetChangeY the amount we want to move the offset by (y-axis)\n *\n * @return {bool}\n */\n moveBy(offsetChangeX: number, offsetChangeY: number) {\n const offsetX =\n (this.offsetX * this.zoomLevel - offsetChangeX) / this.zoomLevel;\n const offsetY =\n (this.offsetY * this.zoomLevel - offsetChangeY) / this.zoomLevel;\n\n this._setNewOffsetPosition(offsetX, offsetY);\n }\n\n render() {\n const {\n staticPinIcon,\n children,\n visualTouchFeedbackEnabled,\n doubleTapDelay,\n staticPinPosition,\n onStaticPinLongPress,\n onStaticPinPress,\n pinProps,\n } = this.props;\n const { pinSize, touches, debugPoints = [] } = this.state;\n\n return (\n \n \n {children}\n \n\n {visualTouchFeedbackEnabled &&\n touches?.map(\n (touch) =>\n doubleTapDelay && (\n {\n this._removeTouch(touch);\n }}\n />\n )\n )}\n\n {/* For Debugging Only */}\n {debugPoints.map(({ x, y }, index) => {\n return ;\n })}\n\n {staticPinPosition && (\n {\n this.setState({ pinSize: size });\n }}\n pinProps={pinProps}\n />\n )}\n \n );\n }\n}\n\nconst styles = StyleSheet.create({\n container: {\n alignItems: 'center',\n flex: 1,\n justifyContent: 'center',\n overflow: 'hidden',\n position: 'relative',\n },\n zoomSubject: {\n alignItems: 'center',\n flex: 1,\n justifyContent: 'center',\n width: '100%',\n },\n});\n\nexport default ReactNativeZoomableView;\n\nexport { ReactNativeZoomableView };\n"]} \ No newline at end of file diff --git a/lib/commonjs/typings/index.js.map b/lib/commonjs/typings/index.js.map index be56215..2e3b9d5 100644 --- a/lib/commonjs/typings/index.js.map +++ b/lib/commonjs/typings/index.js.map @@ -1 +1 @@ -{"version":3,"sources":["index.ts"],"names":["SwipeDirection"],"mappings":";;;;;;IAOYA,c;;;WAAAA,c;AAAAA,EAAAA,c;AAAAA,EAAAA,c;AAAAA,EAAAA,c;AAAAA,EAAAA,c;GAAAA,c,8BAAAA,c","sourcesContent":["import {\n Animated,\n GestureResponderEvent,\n PanResponderGestureState,\n ViewProps,\n} from 'react-native';\n\nexport enum SwipeDirection {\n SWIPE_UP = 'SWIPE_UP',\n SWIPE_DOWN = 'SWIPE_DOWN',\n SWIPE_LEFT = 'SWIPE_LEFT',\n SWIPE_RIGHT = 'SWIPE_RIGHT',\n}\n\nexport interface ZoomableViewEvent {\n zoomLevel: number;\n offsetX: number;\n offsetY: number;\n originalHeight: number;\n originalWidth: number;\n originalPageX: number;\n originalPageY: number;\n}\n\nexport interface ReactNativeZoomableViewProps extends ViewProps {\n // options\n zoomEnabled?: boolean;\n panEnabled?: boolean;\n initialZoom?: number;\n initialOffsetX?: number;\n initialOffsetY?: number;\n contentWidth?: number;\n contentHeight?: number;\n panBoundaryPadding?: number;\n maxZoom?: number;\n minZoom?: number;\n doubleTapDelay?: number;\n doubleTapZoomToCenter?: boolean;\n bindToBorders?: boolean;\n zoomStep?: number;\n pinchToZoomInSensitivity?: number;\n pinchToZoomOutSensitivity?: number;\n movementSensibility?: number;\n longPressDuration?: number;\n visualTouchFeedbackEnabled?: boolean;\n disablePanOnInitialZoom?: boolean;\n\n // Zoom animated value ref\n zoomAnimatedValue?: Animated.Value;\n panAnimatedValueXY?: Animated.ValueXY;\n\n // debug\n debug?: boolean;\n\n // callbacks\n onTransform?: (zoomableViewEventObject: ZoomableViewEvent) => void;\n onSingleTap?: (\n event: GestureResponderEvent,\n zoomableViewEventObject: ZoomableViewEvent\n ) => void;\n onDoubleTapBefore?: (\n event: GestureResponderEvent,\n zoomableViewEventObject: ZoomableViewEvent\n ) => void;\n onDoubleTapAfter?: (\n event: GestureResponderEvent,\n zoomableViewEventObject: ZoomableViewEvent\n ) => void;\n onShiftingBefore?: (\n event: GestureResponderEvent | null,\n gestureState: PanResponderGestureState | null,\n zoomableViewEventObject: ZoomableViewEvent\n ) => boolean;\n onShiftingAfter?: (\n event: GestureResponderEvent | null,\n gestureState: PanResponderGestureState | null,\n zoomableViewEventObject: ZoomableViewEvent\n ) => boolean;\n onShiftingEnd?: (\n event: GestureResponderEvent,\n gestureState: PanResponderGestureState,\n zoomableViewEventObject: ZoomableViewEvent\n ) => void;\n onZoomBefore?: (\n event: GestureResponderEvent | null,\n gestureState: PanResponderGestureState | null,\n zoomableViewEventObject: ZoomableViewEvent\n ) => boolean | undefined;\n onZoomAfter?: (\n event: GestureResponderEvent | null,\n gestureState: PanResponderGestureState | null,\n zoomableViewEventObject: ZoomableViewEvent\n ) => void;\n onZoomEnd?: (\n event: GestureResponderEvent,\n gestureState: PanResponderGestureState,\n zoomableViewEventObject: ZoomableViewEvent\n ) => void;\n onLongPress?: (\n event: GestureResponderEvent,\n gestureState: PanResponderGestureState,\n zoomableViewEventObject: ZoomableViewEvent\n ) => void;\n onStartShouldSetPanResponder?: (\n event: GestureResponderEvent,\n gestureState: PanResponderGestureState,\n zoomableViewEventObject: ZoomableViewEvent,\n baseComponentResult: boolean\n ) => boolean;\n onPanResponderGrant?: (\n event: GestureResponderEvent,\n gestureState: PanResponderGestureState,\n zoomableViewEventObject: ZoomableViewEvent\n ) => void;\n onPanResponderEnd?: (\n event: GestureResponderEvent,\n gestureState: PanResponderGestureState,\n zoomableViewEventObject: ZoomableViewEvent\n ) => void;\n onPanResponderMove?: (\n event: GestureResponderEvent,\n gestureState: PanResponderGestureState,\n zoomableViewEventObject: ZoomableViewEvent\n ) => boolean;\n onPanResponderTerminate?: (\n event: GestureResponderEvent,\n gestureState: PanResponderGestureState,\n zoomableViewEventObject: ZoomableViewEvent\n ) => void;\n onPanResponderTerminationRequest?: (\n event: GestureResponderEvent,\n gestureState: PanResponderGestureState,\n zoomableViewEventObject: ZoomableViewEvent\n ) => boolean;\n onShouldBlockNativeResponder?: (\n event: GestureResponderEvent,\n gestureState: PanResponderGestureState,\n zoomableViewEventObject: ZoomableViewEvent\n ) => boolean;\n onStartShouldSetPanResponderCapture?: (\n event: GestureResponderEvent,\n gestureState: PanResponderGestureState\n ) => boolean;\n onMoveShouldSetPanResponderCapture?: (\n event: GestureResponderEvent,\n gestureState: PanResponderGestureState\n ) => boolean;\n onStaticPinPress?: (event: GestureResponderEvent) => void;\n onStaticPinLongPress?: (event: GestureResponderEvent) => void;\n staticPinPosition?: Vec2D;\n staticPinIcon?: React.ReactElement;\n onStaticPinPositionChange?: (position: Vec2D) => void;\n onStaticPinPositionMove?: (position: Vec2D) => void;\n animatePin: boolean;\n pinProps?: ViewProps;\n disableMomentum?: boolean;\n}\n\nexport interface Vec2D {\n x: number;\n y: number;\n}\n\nexport interface Size2D {\n width: number;\n height: number;\n}\n\nexport interface TouchPoint extends Vec2D {\n id: string;\n isSecondTap?: boolean;\n}\n\nexport interface ReactNativeZoomableViewState {\n touches?: TouchPoint[];\n originalWidth: number;\n originalHeight: number;\n originalPageX: number;\n originalPageY: number;\n debugPoints?: undefined | Vec2D[];\n pinSize: Size2D;\n}\n\nexport interface ReactNativeZoomableViewWithGesturesProps\n extends ReactNativeZoomableViewProps {\n swipeLengthThreshold?: number;\n swipeVelocityThreshold?: number;\n swipeDirectionalThreshold?: number;\n swipeMinZoom?: number;\n swipeMaxZoom?: number;\n swipeDisabled?: boolean;\n onSwipe?: (\n swipeDirection: SwipeDirection,\n gestureState: PanResponderGestureState\n ) => void;\n onSwipeUp?: (gestureState: PanResponderGestureState) => void;\n onSwipeDown?: (gestureState: PanResponderGestureState) => void;\n onSwipeLeft?: (gestureState: PanResponderGestureState) => void;\n onSwipeRight?: (gestureState: PanResponderGestureState) => void;\n}\n"]} \ No newline at end of file +{"version":3,"sources":["index.ts"],"names":["SwipeDirection"],"mappings":";;;;;;IAQYA,c;;;WAAAA,c;AAAAA,EAAAA,c;AAAAA,EAAAA,c;AAAAA,EAAAA,c;AAAAA,EAAAA,c;GAAAA,c,8BAAAA,c","sourcesContent":["import {\n Animated,\n GestureResponderEvent,\n PanResponderGestureState,\n ViewProps,\n} from 'react-native';\nimport { ReactNode } from 'react';\n\nexport enum SwipeDirection {\n SWIPE_UP = 'SWIPE_UP',\n SWIPE_DOWN = 'SWIPE_DOWN',\n SWIPE_LEFT = 'SWIPE_LEFT',\n SWIPE_RIGHT = 'SWIPE_RIGHT',\n}\n\nexport interface ZoomableViewEvent {\n zoomLevel: number;\n offsetX: number;\n offsetY: number;\n originalHeight: number;\n originalWidth: number;\n originalPageX: number;\n originalPageY: number;\n}\n\nexport interface ReactNativeZoomableViewProps {\n // options\n style?: ViewProps['style'];\n children?: ReactNode;\n zoomEnabled?: boolean;\n panEnabled?: boolean;\n initialZoom?: number;\n initialOffsetX?: number;\n initialOffsetY?: number;\n contentWidth?: number;\n contentHeight?: number;\n panBoundaryPadding?: number;\n maxZoom?: number;\n minZoom?: number;\n doubleTapDelay?: number;\n doubleTapZoomToCenter?: boolean;\n bindToBorders?: boolean;\n zoomStep?: number;\n pinchToZoomInSensitivity?: number;\n pinchToZoomOutSensitivity?: number;\n movementSensibility?: number;\n longPressDuration?: number;\n visualTouchFeedbackEnabled?: boolean;\n disablePanOnInitialZoom?: boolean;\n\n // Zoom animated value ref\n zoomAnimatedValue?: Animated.Value;\n panAnimatedValueXY?: Animated.ValueXY;\n\n // debug\n debug?: boolean;\n\n // callbacks\n onLayoutMeasured?: (size: Size2D & Vec2D) => void;\n onTransform?: (zoomableViewEventObject: ZoomableViewEvent) => void;\n onSingleTap?: (\n event: GestureResponderEvent,\n zoomableViewEventObject: ZoomableViewEvent\n ) => void;\n onDoubleTapBefore?: (\n event: GestureResponderEvent,\n zoomableViewEventObject: ZoomableViewEvent\n ) => void;\n onDoubleTapAfter?: (\n event: GestureResponderEvent,\n zoomableViewEventObject: ZoomableViewEvent\n ) => void;\n onShiftingBefore?: (\n event: GestureResponderEvent | null,\n gestureState: PanResponderGestureState | null,\n zoomableViewEventObject: ZoomableViewEvent\n ) => boolean;\n onShiftingAfter?: (\n event: GestureResponderEvent | null,\n gestureState: PanResponderGestureState | null,\n zoomableViewEventObject: ZoomableViewEvent\n ) => boolean;\n onShiftingEnd?: (\n event: GestureResponderEvent,\n gestureState: PanResponderGestureState,\n zoomableViewEventObject: ZoomableViewEvent\n ) => void;\n onZoomBefore?: (\n event: GestureResponderEvent | null,\n gestureState: PanResponderGestureState | null,\n zoomableViewEventObject: ZoomableViewEvent\n ) => boolean | undefined;\n onZoomAfter?: (\n event: GestureResponderEvent | null,\n gestureState: PanResponderGestureState | null,\n zoomableViewEventObject: ZoomableViewEvent\n ) => void;\n onZoomEnd?: (\n event: GestureResponderEvent,\n gestureState: PanResponderGestureState,\n zoomableViewEventObject: ZoomableViewEvent\n ) => void;\n onLongPress?: (\n event: GestureResponderEvent,\n gestureState: PanResponderGestureState,\n zoomableViewEventObject: ZoomableViewEvent\n ) => void;\n onStartShouldSetPanResponder?: (\n event: GestureResponderEvent,\n gestureState: PanResponderGestureState,\n zoomableViewEventObject: ZoomableViewEvent,\n baseComponentResult: boolean\n ) => boolean;\n onPanResponderGrant?: (\n event: GestureResponderEvent,\n gestureState: PanResponderGestureState,\n zoomableViewEventObject: ZoomableViewEvent\n ) => void;\n onPanResponderEnd?: (\n event: GestureResponderEvent,\n gestureState: PanResponderGestureState,\n zoomableViewEventObject: ZoomableViewEvent\n ) => void;\n onPanResponderMove?: (\n event: GestureResponderEvent,\n gestureState: PanResponderGestureState,\n zoomableViewEventObject: ZoomableViewEvent\n ) => boolean;\n onPanResponderTerminate?: (\n event: GestureResponderEvent,\n gestureState: PanResponderGestureState,\n zoomableViewEventObject: ZoomableViewEvent\n ) => void;\n onPanResponderTerminationRequest?: (\n event: GestureResponderEvent,\n gestureState: PanResponderGestureState,\n zoomableViewEventObject: ZoomableViewEvent\n ) => boolean;\n onShouldBlockNativeResponder?: (\n event: GestureResponderEvent,\n gestureState: PanResponderGestureState,\n zoomableViewEventObject: ZoomableViewEvent\n ) => boolean;\n onStartShouldSetPanResponderCapture?: (\n event: GestureResponderEvent,\n gestureState: PanResponderGestureState\n ) => boolean;\n onMoveShouldSetPanResponderCapture?: (\n event: GestureResponderEvent,\n gestureState: PanResponderGestureState\n ) => boolean;\n onStaticPinPress?: (event: GestureResponderEvent) => void;\n onStaticPinLongPress?: (event: GestureResponderEvent) => void;\n staticPinPosition?: Vec2D;\n staticPinIcon?: React.ReactElement;\n onStaticPinPositionChange?: (position: Vec2D) => void;\n onStaticPinPositionMove?: (position: Vec2D) => void;\n animatePin: boolean;\n pinProps?: ViewProps;\n disableMomentum?: boolean;\n}\n\nexport interface Vec2D {\n x: number;\n y: number;\n}\n\nexport interface Size2D {\n width: number;\n height: number;\n}\n\nexport interface TouchPoint extends Vec2D {\n id: string;\n isSecondTap?: boolean;\n}\n\nexport interface ReactNativeZoomableViewState {\n touches?: TouchPoint[];\n originalWidth: number;\n originalHeight: number;\n originalPageX: number;\n originalPageY: number;\n debugPoints?: undefined | Vec2D[];\n pinSize: Size2D;\n}\n\nexport interface ReactNativeZoomableViewWithGesturesProps\n extends ReactNativeZoomableViewProps {\n swipeLengthThreshold?: number;\n swipeVelocityThreshold?: number;\n swipeDirectionalThreshold?: number;\n swipeMinZoom?: number;\n swipeMaxZoom?: number;\n swipeDisabled?: boolean;\n onSwipe?: (\n swipeDirection: SwipeDirection,\n gestureState: PanResponderGestureState\n ) => void;\n onSwipeUp?: (gestureState: PanResponderGestureState) => void;\n onSwipeDown?: (gestureState: PanResponderGestureState) => void;\n onSwipeLeft?: (gestureState: PanResponderGestureState) => void;\n onSwipeRight?: (gestureState: PanResponderGestureState) => void;\n}\n"]} \ No newline at end of file diff --git a/lib/module/ReactNativeZoomableView.js b/lib/module/ReactNativeZoomableView.js index 2b8d901..2bbbdbf 100644 --- a/lib/module/ReactNativeZoomableView.js +++ b/lib/module/ReactNativeZoomableView.js @@ -99,7 +99,7 @@ class ReactNativeZoomableView extends Component { return (_this$props$onStaticP = (_this$props = this.props).onStaticPinPositionChange) === null || _this$props$onStaticP === void 0 ? void 0 : _this$props$onStaticP.call(_this$props, position); }, 100)); - _defineProperty(this, "grabZoomSubjectOriginalMeasurements", () => { + _defineProperty(this, "measureZoomSubject", () => { // make sure we measure after animations are complete requestAnimationFrame(() => { // this setTimeout is here to fix a weird issue on iOS where the measurements are all `0` @@ -553,7 +553,22 @@ class ReactNativeZoomableView extends Component { const currState = this.state; const originalMeasurementsChanged = currState.originalHeight !== prevState.originalHeight || currState.originalWidth !== prevState.originalWidth || currState.originalPageX !== prevState.originalPageX || currState.originalPageY !== prevState.originalPageY; - const staticPinPositionChanged = ((_prevProps$staticPinP = prevProps.staticPinPosition) === null || _prevProps$staticPinP === void 0 ? void 0 : _prevProps$staticPinP.x) !== ((_this$props$staticPin = this.props.staticPinPosition) === null || _this$props$staticPin === void 0 ? void 0 : _this$props$staticPin.x) || ((_prevProps$staticPinP2 = prevProps.staticPinPosition) === null || _prevProps$staticPinP2 === void 0 ? void 0 : _prevProps$staticPinP2.y) !== ((_this$props$staticPin2 = this.props.staticPinPosition) === null || _this$props$staticPin2 === void 0 ? void 0 : _this$props$staticPin2.y); + const staticPinPositionChanged = ((_prevProps$staticPinP = prevProps.staticPinPosition) === null || _prevProps$staticPinP === void 0 ? void 0 : _prevProps$staticPinP.x) !== ((_this$props$staticPin = this.props.staticPinPosition) === null || _this$props$staticPin === void 0 ? void 0 : _this$props$staticPin.x) || ((_prevProps$staticPinP2 = prevProps.staticPinPosition) === null || _prevProps$staticPinP2 === void 0 ? void 0 : _prevProps$staticPinP2.y) !== ((_this$props$staticPin2 = this.props.staticPinPosition) === null || _this$props$staticPin2 === void 0 ? void 0 : _this$props$staticPin2.y); // We use a custom `onLayout` event because: + // a) View's `onLayout` sometimes doesn't get called + // b) we use `measureInWindow` internally to keep track of layout changes + // When the client uses this, they can stay in-sync with the internal measurements, + // thus applying transformations at more accurate timings + + if (originalMeasurementsChanged) { + var _this$props$onLayoutM, _this$props14; + + (_this$props$onLayoutM = (_this$props14 = this.props).onLayoutMeasured) === null || _this$props$onLayoutM === void 0 ? void 0 : _this$props$onLayoutM.call(_this$props14, { + width: currState.originalWidth, + height: currState.originalHeight, + x: currState.originalPageX, + y: currState.originalPageY + }); + } if (this.onTransformInvocationInitialized && (originalMeasurementsChanged || staticPinPositionChanged)) { this._invokeOnTransform(); @@ -561,7 +576,7 @@ class ReactNativeZoomableView extends Component { } componentDidMount() { - this.grabZoomSubjectOriginalMeasurements(); // We've already run `grabZoomSubjectOriginalMeasurements` at various events + this.measureZoomSubject(); // We've already run `grabZoomSubjectOriginalMeasurements` at various events // to make sure the measurements are promptly updated. // However, there might be cases we haven't accounted for, especially when // native processes are involved. To account for those cases, @@ -569,7 +584,7 @@ class ReactNativeZoomableView extends Component { // The `setState` in `grabZoomSubjectOriginalMeasurements` won't trigger a rerender // if the values given haven't changed, so we're not running performance risk here. - this.measureZoomSubjectInterval = setInterval(this.grabZoomSubjectOriginalMeasurements, 1e3); + this.measureZoomSubjectInterval = setInterval(this.measureZoomSubject, 1e3); } componentWillUnmount() { @@ -581,7 +596,7 @@ class ReactNativeZoomableView extends Component { * @private */ _invokeOnTransform() { - var _this$props$onTransfo, _this$props14; + var _this$props$onTransfo, _this$props15; const zoomableViewEvent = this._getZoomableViewEventObject(); @@ -590,12 +605,12 @@ class ReactNativeZoomableView extends Component { if (!zoomableViewEvent.originalWidth || !zoomableViewEvent.originalHeight) return { successful: false }; - (_this$props$onTransfo = (_this$props14 = this.props).onTransform) === null || _this$props$onTransfo === void 0 ? void 0 : _this$props$onTransfo.call(_this$props14, zoomableViewEvent); + (_this$props$onTransfo = (_this$props15 = this.props).onTransform) === null || _this$props$onTransfo === void 0 ? void 0 : _this$props$onTransfo.call(_this$props15, zoomableViewEvent); if (position) { - var _this$props$onStaticP3, _this$props15; + var _this$props$onStaticP3, _this$props16; - (_this$props$onStaticP3 = (_this$props15 = this.props).onStaticPinPositionMove) === null || _this$props$onStaticP3 === void 0 ? void 0 : _this$props$onStaticP3.call(_this$props15, position); + (_this$props$onStaticP3 = (_this$props16 = this.props).onStaticPinPositionMove) === null || _this$props$onStaticP3 === void 0 ? void 0 : _this$props$onStaticP3.call(_this$props16, position); this.debouncedOnStaticPinPositionChange(position); } @@ -640,7 +655,7 @@ class ReactNativeZoomableView extends Component { * @private */ _handlePinching(e, gestureState) { - var _this$props$onZoomAft, _this$props16; + var _this$props$onZoomAft, _this$props17; if (!this.props.zoomEnabled) return; const { @@ -721,7 +736,7 @@ class ReactNativeZoomableView extends Component { y: this.offsetY }); this.zoomAnim.setValue(this.zoomLevel); - (_this$props$onZoomAft = (_this$props16 = this.props).onZoomAfter) === null || _this$props$onZoomAft === void 0 ? void 0 : _this$props$onZoomAft.call(_this$props16, e, gestureState, this._getZoomableViewEventObject()); + (_this$props$onZoomAft = (_this$props17 = this.props).onZoomAfter) === null || _this$props$onZoomAft === void 0 ? void 0 : _this$props$onZoomAft.call(_this$props17, e, gestureState, this._getZoomableViewEventObject()); } /** * Used to debug pinch events @@ -952,12 +967,12 @@ class ReactNativeZoomableView extends Component { zoomTo(newZoomLevel, zoomCenter) { - var _this$props$onZoomBef, _this$props17, _this$props$onZoomAft2, _this$props18; + var _this$props$onZoomBef, _this$props18, _this$props$onZoomAft2, _this$props19; if (!this.props.zoomEnabled) return false; if (this.props.maxZoom && newZoomLevel > this.props.maxZoom) return false; if (this.props.minZoom && newZoomLevel < this.props.minZoom) return false; - (_this$props$onZoomBef = (_this$props17 = this.props).onZoomBefore) === null || _this$props$onZoomBef === void 0 ? void 0 : _this$props$onZoomBef.call(_this$props17, null, null, this._getZoomableViewEventObject()); // == Perform Pan Animation to preserve the zoom center while zooming == + (_this$props$onZoomBef = (_this$props18 = this.props).onZoomBefore) === null || _this$props$onZoomBef === void 0 ? void 0 : _this$props$onZoomBef.call(_this$props18, null, null, this._getZoomableViewEventObject()); // == Perform Pan Animation to preserve the zoom center while zooming == let listenerId = ''; @@ -984,7 +999,7 @@ class ReactNativeZoomableView extends Component { this.zoomAnim.removeListener(listenerId); }); // == Zoom Animation Ends == - (_this$props$onZoomAft2 = (_this$props18 = this.props).onZoomAfter) === null || _this$props$onZoomAft2 === void 0 ? void 0 : _this$props$onZoomAft2.call(_this$props18, null, null, this._getZoomableViewEventObject()); + (_this$props$onZoomAft2 = (_this$props19 = this.props).onZoomAfter) === null || _this$props$onZoomAft2 === void 0 ? void 0 : _this$props$onZoomAft2.call(_this$props19, null, null, this._getZoomableViewEventObject()); return true; } /** @@ -1066,12 +1081,7 @@ class ReactNativeZoomableView extends Component { style: styles.container }, this.gestureHandlers.panHandlers, { ref: this.zoomSubjectWrapperRef, - onLayout: event => { - var _this$props$onLayout, _this$props19; - - (_this$props$onLayout = (_this$props19 = this.props).onLayout) === null || _this$props$onLayout === void 0 ? void 0 : _this$props$onLayout.call(_this$props19, event); - this.grabZoomSubjectOriginalMeasurements(); - } + onLayout: this.measureZoomSubject }), /*#__PURE__*/React.createElement(Animated.View, { style: [styles.zoomSubject, this.props.style, { transform: [{ diff --git a/lib/module/ReactNativeZoomableView.js.map b/lib/module/ReactNativeZoomableView.js.map index 5e40ffd..b622850 100644 --- a/lib/module/ReactNativeZoomableView.js.map +++ b/lib/module/ReactNativeZoomableView.js.map @@ -1 +1 @@ -{"version":3,"sources":["ReactNativeZoomableView.tsx"],"names":["React","Component","createRef","Animated","Easing","PanResponder","StyleSheet","View","AnimatedTouchFeedback","DebugTouchPoint","calcGestureCenterPoint","calcGestureTouchDistance","calcNewScaledOffsetForZoomCentering","applyPanBoundariesToOffset","viewportPositionToImagePosition","StaticPin","debounce","getBoundaryCrossedAnim","getPanMomentumDecayAnim","getZoomToAnimation","initialState","originalWidth","originalHeight","originalPageX","originalPageY","pinSize","width","height","ReactNativeZoomableView","gestureStarted","v","_gestureStarted","constructor","props","ValueXY","x","y","Value","value","boundaryCrossedAnimInEffect","position","onStaticPinPositionChange","requestAnimationFrame","setTimeout","zoomSubjectWrapperRef","current","measureInWindow","state","setState","e","gestureState","onStartShouldSetPanResponder","_getZoomableViewEventObject","onLongPress","longPressTimeout","longPressDuration","onPanResponderGrant","panAnim","stopAnimation","zoomAnim","raisePin","gestureType","_resolveAndHandleTap","debugPoints","lastGestureCenterPosition","disableMomentum","panEnabled","disablePanOnInitialZoom","zoomLevel","initialZoom","vx","vy","start","clearTimeout","onPanResponderEnd","onZoomEnd","onShiftingEnd","staticPinPosition","_updateStaticPin","dropPin","onPanResponderMove","numberActiveTouches","_handlePanResponderGrant","_handlePanResponderEnd","lastGestureTouchDistance","_handlePinching","Math","abs","dx","dy","isShiftGesture","_handleShifting","now","Date","doubleTapFirstTapReleaseTimestamp","doubleTapDelay","doubleTapFirstTap","_addTouch","id","toString","isSecondTap","singleTapTimeoutId","_handleDoubleTap","nativeEvent","pageX","pageY","persist","tapX","tapY","timing","toValue","offsetX","offsetY","useNativeDriver","duration","onSingleTap","contentWidth","contentHeight","pinX","pinY","setValue","viewportPosition","imageSize","zoomableEvent","_staticPinPosition","gestureHandlers","create","_handleStartShouldSetPanResponder","_handlePanResponderMove","onPanResponderRelease","onPanResponderTerminate","evt","onPanResponderTerminationRequest","onShouldBlockNativeResponder","onStartShouldSetPanResponderCapture","onMoveShouldSetPanResponderCapture","zoomAnimatedValue","panAnimatedValueXY","initialOffsetX","initialOffsetY","addListener","animatePin","pinAnim","easing","out","ease","__setOffset","__getOffset","axis","offset","offsetState","__offsets","bindToBorders","containerSize","contentSize","boundOffset","panBoundaryPadding","boundariesApplied","toFixed","componentDidUpdate","prevProps","prevState","zoomEnabled","onTransformInvocationInitialized","_invokeOnTransform","successful","currState","originalMeasurementsChanged","staticPinPositionChanged","componentDidMount","grabZoomSubjectOriginalMeasurements","measureZoomSubjectInterval","setInterval","componentWillUnmount","clearInterval","zoomableViewEvent","onTransform","onStaticPinPositionMove","debouncedOnStaticPinPositionChange","overwriteObj","maxZoom","minZoom","pinchToZoomInSensitivity","pinchToZoomOutSensitivity","distance","onZoomBefore","zoomGrowthFromLastGestureState","pinchToZoomSensitivity","deltaGrowth","deltaGrowthAdjustedBySensitivity","newZoomLevel","gestureCenterPoint","zoomCenter","debug","_setPinchDebugPoints","oldOffsetX","oldOffsetY","oldScale","newScale","offsetShift","_calcOffsetShiftSinceLastGestureState","onZoomAfter","gestureResponderEvent","points","touches","movementSensibility","shift","shiftX","shiftY","moveX","moveY","_setNewOffsetPosition","newOffsetX","newOffsetY","onShiftingBefore","onShiftingAfter","touch","push","_removeTouch","splice","indexOf","onDoubleTapBefore","onDoubleTapAfter","doubleTapZoomToCenter","nextZoomStep","_getNextZoomStep","zoomPositionCoordinates","zoomTo","zoomStep","listenerId","prevScale","removeListener","zoomBy","zoomLevelChange","moveTo","moveBy","offsetChangeX","offsetChangeY","render","staticPinIcon","children","visualTouchFeedbackEnabled","onStaticPinLongPress","onStaticPinPress","pinProps","styles","container","panHandlers","event","onLayout","zoomSubject","style","transform","scale","getTranslateTransform","map","index","size","undefined","alignItems","flex","justifyContent","overflow"],"mappings":"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","sourcesContent":["import React, { Component, createRef, RefObject } from 'react';\nimport {\n Animated,\n Easing,\n GestureResponderEvent,\n PanResponder,\n PanResponderCallbacks,\n PanResponderGestureState,\n PanResponderInstance,\n StyleSheet,\n View,\n} from 'react-native';\n\nimport {\n Vec2D,\n ReactNativeZoomableViewProps,\n ReactNativeZoomableViewState,\n TouchPoint,\n ZoomableViewEvent,\n Size2D,\n} from './typings';\n\nimport { AnimatedTouchFeedback } from './components';\nimport { DebugTouchPoint } from './debugHelper';\nimport {\n calcGestureCenterPoint,\n calcGestureTouchDistance,\n calcNewScaledOffsetForZoomCentering,\n} from './helper';\nimport { applyPanBoundariesToOffset } from './helper/applyPanBoundariesToOffset';\nimport { viewportPositionToImagePosition } from './helper/coordinateConversion';\nimport { StaticPin } from './components/StaticPin';\nimport { debounce } from 'lodash';\nimport {\n getBoundaryCrossedAnim,\n getPanMomentumDecayAnim,\n getZoomToAnimation,\n} from './animations';\n\nconst initialState: ReactNativeZoomableViewState = {\n originalWidth: 0,\n originalHeight: 0,\n originalPageX: 0,\n originalPageY: 0,\n pinSize: { width: 0, height: 0 },\n};\n\nclass ReactNativeZoomableView extends Component<\n ReactNativeZoomableViewProps,\n ReactNativeZoomableViewState\n> {\n zoomSubjectWrapperRef: RefObject;\n gestureHandlers: PanResponderInstance;\n doubleTapFirstTapReleaseTimestamp: number | undefined;\n\n static defaultProps = {\n zoomEnabled: true,\n panEnabled: true,\n initialZoom: 1,\n initialOffsetX: 0,\n initialOffsetY: 0,\n maxZoom: 1.5,\n minZoom: 0.5,\n pinchToZoomInSensitivity: 1,\n pinchToZoomOutSensitivity: 1,\n movementSensibility: 1,\n doubleTapDelay: 300,\n bindToBorders: true,\n zoomStep: 0.5,\n onLongPress: null,\n longPressDuration: 700,\n contentWidth: undefined,\n contentHeight: undefined,\n panBoundaryPadding: 0,\n visualTouchFeedbackEnabled: true,\n staticPinPosition: undefined,\n staticPinIcon: undefined,\n onStaticPinPositionChange: undefined,\n onStaticPinPositionMove: undefined,\n animatePin: true,\n disablePanOnInitialZoom: false,\n };\n\n private panAnim = new Animated.ValueXY({ x: 0, y: 0 });\n private zoomAnim = new Animated.Value(1);\n private pinAnim = new Animated.ValueXY({ x: 0, y: 0 });\n\n private __offsets = {\n x: {\n value: 0,\n boundaryCrossedAnimInEffect: false,\n },\n y: {\n value: 0,\n boundaryCrossedAnimInEffect: false,\n },\n };\n\n private zoomLevel = 1;\n private lastGestureCenterPosition: { x: number; y: number } | null = null;\n private lastGestureTouchDistance: number | null = null;\n private gestureType: 'pinch' | 'shift' | null;\n\n private _gestureStarted = false;\n private set gestureStarted(v: boolean) {\n this._gestureStarted = v;\n }\n\n public get gestureStarted() {\n return this._gestureStarted;\n }\n\n /**\n * Last press time (used to evaluate whether user double tapped)\n * @type {number}\n */\n private longPressTimeout: NodeJS.Timeout | null = null;\n private onTransformInvocationInitialized: boolean | undefined;\n private singleTapTimeoutId: NodeJS.Timeout | undefined;\n private touches: TouchPoint[] = [];\n private doubleTapFirstTap: TouchPoint | undefined;\n private measureZoomSubjectInterval: NodeJS.Timer | undefined;\n\n constructor(props: ReactNativeZoomableViewProps) {\n super(props);\n // This needs to be done before anything else to initialize the state.\n // Otherwise, the logic below may reference the state when it's undefined,\n // causing runtime errors.\n this.state = { ...initialState };\n\n this.gestureHandlers = PanResponder.create({\n onStartShouldSetPanResponder: this._handleStartShouldSetPanResponder,\n onPanResponderGrant: this._handlePanResponderGrant,\n onPanResponderMove: this._handlePanResponderMove,\n onPanResponderRelease: this._handlePanResponderEnd,\n onPanResponderTerminate: (evt, gestureState) => {\n // We should also call _handlePanResponderEnd\n // to properly perform cleanups when the gesture is terminated\n // (aka gesture handling responsibility is taken over by another component).\n // This also fixes a weird issue where\n // on real device, sometimes onPanResponderRelease is not called when you lift 2 fingers up,\n // but onPanResponderTerminate is called instead for no apparent reason.\n this._handlePanResponderEnd(evt, gestureState);\n this.props.onPanResponderTerminate?.(\n evt,\n gestureState,\n this._getZoomableViewEventObject()\n );\n },\n onPanResponderTerminationRequest: (evt, gestureState) =>\n !!this.props.onPanResponderTerminationRequest?.(\n evt,\n gestureState,\n this._getZoomableViewEventObject()\n ),\n // Defaults to true to prevent parent components, such as React Navigation's tab view, from taking over as responder.\n onShouldBlockNativeResponder: (evt, gestureState) =>\n this.props.onShouldBlockNativeResponder?.(\n evt,\n gestureState,\n this._getZoomableViewEventObject()\n ) ?? true,\n onStartShouldSetPanResponderCapture: (evt, gestureState) =>\n !!this.props.onStartShouldSetPanResponderCapture?.(evt, gestureState),\n onMoveShouldSetPanResponderCapture: (evt, gestureState) =>\n !!this.props.onMoveShouldSetPanResponderCapture?.(evt, gestureState),\n });\n\n this.zoomSubjectWrapperRef = createRef();\n\n if (this.props.zoomAnimatedValue)\n this.zoomAnim = this.props.zoomAnimatedValue;\n if (this.props.panAnimatedValueXY)\n this.panAnim = this.props.panAnimatedValueXY;\n\n if (this.props.initialZoom) this.zoomLevel = this.props.initialZoom;\n if (this.props.initialOffsetX != null)\n this.offsetX = this.props.initialOffsetX;\n if (this.props.initialOffsetY != null)\n this.offsetY = this.props.initialOffsetY;\n\n this.panAnim.setValue({ x: this.offsetX, y: this.offsetY });\n this.zoomAnim.setValue(this.zoomLevel);\n this.panAnim.addListener(({ x, y }) => {\n this.offsetX = x;\n this.offsetY = y;\n });\n this.zoomAnim.addListener(({ value }) => {\n this.zoomLevel = value;\n });\n\n this.lastGestureTouchDistance = 150;\n\n this.gestureType = null;\n }\n\n private raisePin() {\n if (!this.props.animatePin) return;\n Animated.timing(this.pinAnim, {\n toValue: { x: 0, y: -10 },\n useNativeDriver: true,\n easing: Easing.out(Easing.ease),\n duration: 100,\n }).start();\n }\n\n private dropPin() {\n if (!this.props.animatePin) return;\n Animated.timing(this.pinAnim, {\n toValue: { x: 0, y: 0 },\n useNativeDriver: true,\n easing: Easing.out(Easing.ease),\n duration: 100,\n }).start();\n }\n\n private set offsetX(x: number) {\n this.__setOffset('x', x);\n }\n\n private set offsetY(y: number) {\n this.__setOffset('y', y);\n }\n\n private get offsetX() {\n return this.__getOffset('x');\n }\n\n private get offsetY() {\n return this.__getOffset('y');\n }\n\n private __setOffset(axis: 'x' | 'y', offset: number) {\n const offsetState = this.__offsets[axis];\n\n if (this.props.bindToBorders) {\n const containerSize =\n axis === 'x' ? this.state.originalWidth : this.state.originalHeight;\n const contentSize =\n axis === 'x'\n ? this.props.contentWidth || this.state.originalWidth\n : this.props.contentHeight || this.state.originalHeight;\n\n const boundOffset =\n contentSize && containerSize && this.props.panBoundaryPadding != null\n ? applyPanBoundariesToOffset(\n offset,\n containerSize,\n contentSize,\n this.zoomLevel,\n this.props.panBoundaryPadding\n )\n : offset;\n\n if (!this.gestureType && !offsetState.boundaryCrossedAnimInEffect) {\n const boundariesApplied =\n boundOffset !== offset &&\n boundOffset.toFixed(3) !== offset.toFixed(3);\n if (boundariesApplied) {\n offsetState.boundaryCrossedAnimInEffect = true;\n getBoundaryCrossedAnim(this.panAnim[axis], boundOffset).start(() => {\n offsetState.boundaryCrossedAnimInEffect = false;\n });\n return;\n }\n }\n }\n\n offsetState.value = offset;\n }\n\n private __getOffset(axis: 'x' | 'y') {\n return this.__offsets[axis].value;\n }\n\n componentDidUpdate(\n prevProps: ReactNativeZoomableViewProps,\n prevState: ReactNativeZoomableViewState\n ) {\n const { zoomEnabled, initialZoom } = this.props;\n if (prevProps.zoomEnabled && !zoomEnabled && initialZoom) {\n this.zoomLevel = initialZoom;\n this.zoomAnim.setValue(this.zoomLevel);\n }\n if (\n !this.onTransformInvocationInitialized &&\n this._invokeOnTransform().successful\n ) {\n this.panAnim.addListener(() => this._invokeOnTransform());\n this.zoomAnim.addListener(() => this._invokeOnTransform());\n this.onTransformInvocationInitialized = true;\n }\n\n const currState = this.state;\n const originalMeasurementsChanged =\n currState.originalHeight !== prevState.originalHeight ||\n currState.originalWidth !== prevState.originalWidth ||\n currState.originalPageX !== prevState.originalPageX ||\n currState.originalPageY !== prevState.originalPageY;\n\n const staticPinPositionChanged =\n prevProps.staticPinPosition?.x !== this.props.staticPinPosition?.x ||\n prevProps.staticPinPosition?.y !== this.props.staticPinPosition?.y;\n\n if (\n this.onTransformInvocationInitialized &&\n (originalMeasurementsChanged || staticPinPositionChanged)\n ) {\n this._invokeOnTransform();\n }\n }\n\n componentDidMount() {\n this.grabZoomSubjectOriginalMeasurements();\n // We've already run `grabZoomSubjectOriginalMeasurements` at various events\n // to make sure the measurements are promptly updated.\n // However, there might be cases we haven't accounted for, especially when\n // native processes are involved. To account for those cases,\n // we'll use an interval here to ensure we're always up-to-date.\n // The `setState` in `grabZoomSubjectOriginalMeasurements` won't trigger a rerender\n // if the values given haven't changed, so we're not running performance risk here.\n this.measureZoomSubjectInterval = setInterval(\n this.grabZoomSubjectOriginalMeasurements,\n 1e3\n );\n }\n\n componentWillUnmount() {\n this.measureZoomSubjectInterval &&\n clearInterval(this.measureZoomSubjectInterval);\n }\n\n debouncedOnStaticPinPositionChange = debounce(\n (position: Vec2D) => this.props.onStaticPinPositionChange?.(position),\n 100\n );\n\n /**\n * try to invoke onTransform\n * @private\n */\n _invokeOnTransform() {\n const zoomableViewEvent = this._getZoomableViewEventObject();\n const position = this._staticPinPosition();\n\n if (!zoomableViewEvent.originalWidth || !zoomableViewEvent.originalHeight)\n return { successful: false };\n\n this.props.onTransform?.(zoomableViewEvent);\n\n if (position) {\n this.props.onStaticPinPositionMove?.(position);\n this.debouncedOnStaticPinPositionChange(position);\n }\n\n return { successful: true };\n }\n\n /**\n * Returns additional information about components current state for external event hooks\n *\n * @returns {{}}\n * @private\n */\n _getZoomableViewEventObject(overwriteObj = {}): ZoomableViewEvent {\n return {\n zoomLevel: this.zoomLevel,\n offsetX: this.offsetX,\n offsetY: this.offsetY,\n originalHeight: this.state.originalHeight,\n originalWidth: this.state.originalWidth,\n originalPageX: this.state.originalPageX,\n originalPageY: this.state.originalPageY,\n ...overwriteObj,\n } as ZoomableViewEvent;\n }\n\n /**\n * Get the original box dimensions and save them for later use.\n * (They will be used to calculate boxBorders)\n *\n * @private\n */\n private grabZoomSubjectOriginalMeasurements = () => {\n // make sure we measure after animations are complete\n requestAnimationFrame(() => {\n // this setTimeout is here to fix a weird issue on iOS where the measurements are all `0`\n // when navigating back (react-navigation stack) from another view\n // while closing the keyboard at the same time\n setTimeout(() => {\n // In normal conditions, we're supposed to measure zoomSubject instead of its wrapper.\n // However, our zoomSubject may have been transformed by an initial zoomLevel or offset,\n // in which case these measurements will not represent the true \"original\" measurements.\n // We just need to make sure the zoomSubjectWrapper perfectly aligns with the zoomSubject\n // (no border, space, or anything between them)\n const zoomSubjectWrapperRef = this.zoomSubjectWrapperRef;\n // we don't wanna measure when zoomSubjectWrapperRef is not yet available or has been unmounted\n zoomSubjectWrapperRef.current?.measureInWindow(\n (x, y, width, height) => {\n // When the component is off-screen, these become all 0s, so we don't set them\n // to avoid messing up calculations, especially ones that are done right after\n // the component transitions from hidden to visible.\n if (!x && !y && !width && !height) return;\n\n // If these values are all the same, don't re-set them in state\n // this way we don't re-render\n if (\n this.state.originalWidth === width &&\n this.state.originalHeight === height &&\n this.state.originalPageX === x &&\n this.state.originalPageY === y\n ) {\n return;\n }\n\n this.setState({\n originalWidth: width,\n originalHeight: height,\n originalPageX: x,\n originalPageY: y,\n });\n }\n );\n });\n });\n };\n\n /**\n * Handles the start of touch events and checks for taps\n *\n * @param e\n * @param gestureState\n * @returns {boolean}\n *\n * @private\n */\n _handleStartShouldSetPanResponder = (\n e: GestureResponderEvent,\n gestureState: PanResponderGestureState\n ) => {\n if (this.props.onStartShouldSetPanResponder) {\n this.props.onStartShouldSetPanResponder(\n e,\n gestureState,\n this._getZoomableViewEventObject(),\n false\n );\n }\n\n // Always set pan responder on start\n // of gesture so we can handle tap.\n // \"Pan threshold validation\" will be handled\n // in `onPanResponderMove` instead of in `onMoveShouldSetPanResponder`\n return true;\n };\n\n /**\n * Calculates pinch distance\n *\n * @param e\n * @param gestureState\n * @private\n */\n _handlePanResponderGrant: NonNullable<\n PanResponderCallbacks['onPanResponderGrant']\n > = (e, gestureState) => {\n if (this.props.onLongPress) {\n this.longPressTimeout = setTimeout(() => {\n this.props.onLongPress?.(\n e,\n gestureState,\n this._getZoomableViewEventObject()\n );\n this.longPressTimeout = null;\n }, this.props.longPressDuration);\n }\n\n this.props.onPanResponderGrant?.(\n e,\n gestureState,\n this._getZoomableViewEventObject()\n );\n\n this.panAnim.stopAnimation();\n this.zoomAnim.stopAnimation();\n this.gestureStarted = true;\n\n this.raisePin();\n };\n\n /**\n * Handles the end of touch events\n *\n * @param e\n * @param gestureState\n *\n * @private\n */\n _handlePanResponderEnd: NonNullable<\n PanResponderCallbacks['onPanResponderEnd']\n > = (e, gestureState) => {\n if (!this.gestureType) {\n this._resolveAndHandleTap(e);\n }\n\n this.setState({ debugPoints: [] });\n\n this.lastGestureCenterPosition = null;\n\n const disableMomentum =\n this.props.disableMomentum ||\n (this.props.panEnabled &&\n this.gestureType === 'shift' &&\n this.props.disablePanOnInitialZoom &&\n this.zoomLevel === this.props.initialZoom);\n\n // Trigger final shift animation unless disablePanOnInitialZoom is set and we're on the initial zoom level\n // or disableMomentum\n if (!disableMomentum) {\n getPanMomentumDecayAnim(this.panAnim, {\n x: gestureState.vx / this.zoomLevel,\n y: gestureState.vy / this.zoomLevel,\n }).start();\n }\n\n if (this.longPressTimeout) {\n clearTimeout(this.longPressTimeout);\n this.longPressTimeout = null;\n }\n\n this.props.onPanResponderEnd?.(\n e,\n gestureState,\n this._getZoomableViewEventObject()\n );\n\n if (this.gestureType === 'pinch') {\n this.props.onZoomEnd?.(\n e,\n gestureState,\n this._getZoomableViewEventObject()\n );\n } else if (this.gestureType === 'shift') {\n this.props.onShiftingEnd?.(\n e,\n gestureState,\n this._getZoomableViewEventObject()\n );\n }\n\n if (this.props.staticPinPosition) {\n this._updateStaticPin();\n }\n\n this.dropPin();\n\n this.gestureType = null;\n this.gestureStarted = false;\n };\n\n /**\n * Handles the actual movement of our pan responder\n *\n * @param e\n * @param gestureState\n *\n * @private\n */\n _handlePanResponderMove = (\n e: GestureResponderEvent,\n gestureState: PanResponderGestureState\n ) => {\n if (this.props.onPanResponderMove) {\n if (\n this.props.onPanResponderMove(\n e,\n gestureState,\n this._getZoomableViewEventObject()\n )\n ) {\n return false;\n }\n }\n\n // Only supports 2 touches and below,\n // any invalid number will cause the gesture to end.\n if (gestureState.numberActiveTouches <= 2) {\n if (!this.gestureStarted) {\n this._handlePanResponderGrant(e, gestureState);\n }\n } else {\n if (this.gestureStarted) {\n this._handlePanResponderEnd(e, gestureState);\n }\n return true;\n }\n\n if (gestureState.numberActiveTouches === 2) {\n if (this.longPressTimeout) {\n clearTimeout(this.longPressTimeout);\n this.longPressTimeout = null;\n }\n\n // change some measurement states when switching gesture to ensure a smooth transition\n if (this.gestureType !== 'pinch') {\n this.lastGestureCenterPosition = calcGestureCenterPoint(\n e,\n gestureState\n );\n this.lastGestureTouchDistance = calcGestureTouchDistance(\n e,\n gestureState\n );\n }\n this.gestureType = 'pinch';\n this._handlePinching(e, gestureState);\n } else if (gestureState.numberActiveTouches === 1) {\n if (\n this.longPressTimeout &&\n (Math.abs(gestureState.dx) > 5 || Math.abs(gestureState.dy) > 5)\n ) {\n clearTimeout(this.longPressTimeout);\n this.longPressTimeout = null;\n }\n // change some measurement states when switching gesture to ensure a smooth transition\n if (this.gestureType !== 'shift') {\n this.lastGestureCenterPosition = calcGestureCenterPoint(\n e,\n gestureState\n );\n }\n\n const { dx, dy } = gestureState;\n const isShiftGesture = Math.abs(dx) > 2 || Math.abs(dy) > 2;\n if (isShiftGesture) {\n this.gestureType = 'shift';\n this._handleShifting(gestureState);\n }\n }\n };\n\n /**\n * Handles the pinch movement and zooming\n *\n * @param e\n * @param gestureState\n *\n * @private\n */\n _handlePinching(\n e: GestureResponderEvent,\n gestureState: PanResponderGestureState\n ) {\n if (!this.props.zoomEnabled) return;\n\n const {\n maxZoom,\n minZoom,\n pinchToZoomInSensitivity,\n pinchToZoomOutSensitivity,\n } = this.props;\n\n const distance = calcGestureTouchDistance(e, gestureState);\n\n if (\n this.props.onZoomBefore &&\n this.props.onZoomBefore(\n e,\n gestureState,\n this._getZoomableViewEventObject()\n )\n ) {\n return;\n }\n\n if (!distance) return;\n if (!this.lastGestureTouchDistance) return;\n\n // define the new zoom level and take zoom level sensitivity into consideration\n const zoomGrowthFromLastGestureState =\n distance / this.lastGestureTouchDistance;\n this.lastGestureTouchDistance = distance;\n\n const pinchToZoomSensitivity =\n zoomGrowthFromLastGestureState < 1\n ? pinchToZoomOutSensitivity\n : pinchToZoomInSensitivity;\n\n if (pinchToZoomSensitivity == null) return;\n const deltaGrowth = zoomGrowthFromLastGestureState - 1;\n // 0 - no resistance\n // 10 - 90% resistance\n const deltaGrowthAdjustedBySensitivity =\n deltaGrowth * (1 - (pinchToZoomSensitivity * 9) / 100);\n\n let newZoomLevel = this.zoomLevel * (1 + deltaGrowthAdjustedBySensitivity);\n\n // make sure max and min zoom levels are respected\n if (maxZoom != null && newZoomLevel > maxZoom) {\n newZoomLevel = maxZoom;\n }\n\n if (minZoom != null && newZoomLevel < minZoom) {\n newZoomLevel = minZoom;\n }\n\n const gestureCenterPoint = calcGestureCenterPoint(e, gestureState);\n\n if (!gestureCenterPoint) return;\n\n let zoomCenter = {\n x: gestureCenterPoint.x - this.state.originalPageX,\n y: gestureCenterPoint.y - this.state.originalPageY,\n };\n\n if (this.props.staticPinPosition) {\n // When we use a static pin position, the zoom centre is the same as that position,\n // otherwise the pin moves around way too much while zooming.\n zoomCenter = {\n x: this.props.staticPinPosition.x,\n y: this.props.staticPinPosition.y,\n };\n }\n\n // Uncomment to debug\n this.props.debug && this._setPinchDebugPoints(e, zoomCenter);\n\n const { originalHeight, originalWidth } = this.state;\n\n const oldOffsetX = this.offsetX;\n const oldOffsetY = this.offsetY;\n const oldScale = this.zoomLevel;\n const newScale = newZoomLevel;\n\n if (!originalHeight || !originalWidth) return;\n\n let offsetY = calcNewScaledOffsetForZoomCentering(\n oldOffsetY,\n originalHeight,\n oldScale,\n newScale,\n zoomCenter.y\n );\n let offsetX = calcNewScaledOffsetForZoomCentering(\n oldOffsetX,\n originalWidth,\n oldScale,\n newScale,\n zoomCenter.x\n );\n\n const offsetShift =\n this._calcOffsetShiftSinceLastGestureState(gestureCenterPoint);\n if (offsetShift) {\n offsetX += offsetShift.x;\n offsetY += offsetShift.y;\n }\n\n this.offsetX = offsetX;\n this.offsetY = offsetY;\n this.zoomLevel = newScale;\n\n this.panAnim.setValue({ x: this.offsetX, y: this.offsetY });\n this.zoomAnim.setValue(this.zoomLevel);\n\n this.props.onZoomAfter?.(\n e,\n gestureState,\n this._getZoomableViewEventObject()\n );\n }\n\n /**\n * Used to debug pinch events\n * @param gestureResponderEvent\n * @param zoomCenter\n * @param points\n */\n _setPinchDebugPoints(\n gestureResponderEvent: GestureResponderEvent,\n zoomCenter: Vec2D,\n ...points: Vec2D[]\n ) {\n const { touches } = gestureResponderEvent.nativeEvent;\n const { originalPageY, originalPageX } = this.state;\n\n this.setState({\n debugPoints: [\n {\n x: touches[0].pageX - originalPageX,\n y: touches[0].pageY - originalPageY,\n },\n {\n x: touches[1].pageX - originalPageX,\n y: touches[1].pageY - originalPageY,\n },\n zoomCenter,\n ...points,\n ],\n });\n }\n\n /**\n * Calculates the amount the offset should shift since the last position during panning\n *\n * @param {Vec2D} gestureCenterPoint\n *\n * @private\n */\n _calcOffsetShiftSinceLastGestureState(gestureCenterPoint: Vec2D) {\n const { movementSensibility } = this.props;\n\n let shift = null;\n\n if (this.lastGestureCenterPosition && movementSensibility) {\n const dx = gestureCenterPoint.x - this.lastGestureCenterPosition.x;\n const dy = gestureCenterPoint.y - this.lastGestureCenterPosition.y;\n\n const shiftX = dx / this.zoomLevel / movementSensibility;\n const shiftY = dy / this.zoomLevel / movementSensibility;\n\n shift = {\n x: shiftX,\n y: shiftY,\n };\n }\n\n this.lastGestureCenterPosition = gestureCenterPoint;\n\n return shift;\n }\n\n /**\n * Handles movement by tap and move\n *\n * @param gestureState\n *\n * @private\n */\n _handleShifting(gestureState: PanResponderGestureState) {\n // Skips shifting if panEnabled is false or disablePanOnInitialZoom is true and we're on the initial zoom level\n if (\n !this.props.panEnabled ||\n (this.props.disablePanOnInitialZoom &&\n this.zoomLevel === this.props.initialZoom)\n ) {\n return;\n }\n const shift = this._calcOffsetShiftSinceLastGestureState({\n x: gestureState.moveX,\n y: gestureState.moveY,\n });\n if (!shift) return;\n\n const offsetX = this.offsetX + shift.x;\n const offsetY = this.offsetY + shift.y;\n\n if (\n this.props.debug &&\n this.state.originalPageX &&\n this.state.originalPageY\n ) {\n const x = gestureState.moveX - this.state.originalPageX;\n const y = gestureState.moveY - this.state.originalPageY;\n this.setState({ debugPoints: [{ x, y }] });\n }\n\n this._setNewOffsetPosition(offsetX, offsetY);\n\n this.raisePin();\n }\n\n /**\n * Set the state to offset moved\n *\n * @param {number} newOffsetX\n * @param {number} newOffsetY\n * @returns\n */\n _setNewOffsetPosition(newOffsetX: number, newOffsetY: number) {\n const { onShiftingBefore, onShiftingAfter } = this.props;\n\n if (onShiftingBefore?.(null, null, this._getZoomableViewEventObject())) {\n return;\n }\n\n this.offsetX = newOffsetX;\n this.offsetY = newOffsetY;\n\n this.panAnim.setValue({ x: this.offsetX, y: this.offsetY });\n this.zoomAnim.setValue(this.zoomLevel);\n\n onShiftingAfter?.(null, null, this._getZoomableViewEventObject());\n }\n\n /**\n * Check whether the press event is double tap\n * or single tap and handle the event accordingly\n *\n * @param e\n *\n * @private\n */\n private _resolveAndHandleTap = (e: GestureResponderEvent) => {\n const now = Date.now();\n if (\n this.doubleTapFirstTapReleaseTimestamp &&\n this.props.doubleTapDelay &&\n now - this.doubleTapFirstTapReleaseTimestamp < this.props.doubleTapDelay\n ) {\n this.doubleTapFirstTap &&\n this._addTouch({\n ...this.doubleTapFirstTap,\n id: now.toString(),\n isSecondTap: true,\n });\n this.singleTapTimeoutId && clearTimeout(this.singleTapTimeoutId);\n delete this.doubleTapFirstTapReleaseTimestamp;\n delete this.singleTapTimeoutId;\n delete this.doubleTapFirstTap;\n this._handleDoubleTap(e);\n } else {\n this.doubleTapFirstTapReleaseTimestamp = now;\n this.doubleTapFirstTap = {\n id: now.toString(),\n x: e.nativeEvent.pageX - this.state.originalPageX,\n y: e.nativeEvent.pageY - this.state.originalPageY,\n };\n this._addTouch(this.doubleTapFirstTap);\n\n // persist event so e.nativeEvent is preserved after a timeout delay\n e.persist();\n this.singleTapTimeoutId = setTimeout(() => {\n delete this.doubleTapFirstTapReleaseTimestamp;\n delete this.singleTapTimeoutId;\n\n // Pan to the tapped location\n if (this.props.staticPinPosition && this.doubleTapFirstTap) {\n const tapX =\n this.props.staticPinPosition.x - this.doubleTapFirstTap.x;\n const tapY =\n this.props.staticPinPosition.y - this.doubleTapFirstTap.y;\n\n Animated.timing(this.panAnim, {\n toValue: {\n x: this.offsetX + tapX / this.zoomLevel,\n y: this.offsetY + tapY / this.zoomLevel,\n },\n useNativeDriver: true,\n duration: 200,\n }).start(() => {\n this._updateStaticPin();\n });\n }\n\n this.props.onSingleTap?.(e, this._getZoomableViewEventObject());\n }, this.props.doubleTapDelay);\n }\n };\n\n moveStaticPinTo = (position: Vec2D, duration?: number) => {\n const { originalWidth, originalHeight } = this.state;\n const { staticPinPosition, contentWidth, contentHeight } = this.props;\n\n if (!staticPinPosition) return;\n if (!originalWidth || !originalHeight) return;\n if (!contentWidth || !contentHeight) return;\n\n // Offset for the static pin\n const pinX = staticPinPosition.x - originalWidth / 2;\n const pinY = staticPinPosition.y - originalHeight / 2;\n\n this.offsetX = contentWidth / 2 - position.x + pinX / this.zoomLevel;\n this.offsetY = contentHeight / 2 - position.y + pinY / this.zoomLevel;\n\n if (duration) {\n Animated.timing(this.panAnim, {\n toValue: { x: this.offsetX, y: this.offsetY },\n useNativeDriver: true,\n duration,\n }).start();\n } else {\n this.panAnim.setValue({ x: this.offsetX, y: this.offsetY });\n }\n };\n\n private _staticPinPosition = () => {\n if (!this.props.staticPinPosition) return;\n if (!this.props.contentWidth || !this.props.contentHeight) return;\n\n return viewportPositionToImagePosition({\n viewportPosition: {\n x: this.props.staticPinPosition.x,\n y: this.props.staticPinPosition.y,\n },\n imageSize: {\n height: this.props.contentHeight,\n width: this.props.contentWidth,\n },\n zoomableEvent: {\n ...this._getZoomableViewEventObject(),\n offsetX: this.offsetX,\n offsetY: this.offsetY,\n zoomLevel: this.zoomLevel,\n },\n });\n };\n\n private _updateStaticPin = () => {\n const position = this._staticPinPosition();\n if (!position) return;\n this.props.onStaticPinPositionChange?.(position);\n };\n\n private _addTouch(touch: TouchPoint) {\n this.touches.push(touch);\n this.setState({ touches: [...this.touches] });\n }\n\n private _removeTouch(touch: TouchPoint) {\n this.touches.splice(this.touches.indexOf(touch), 1);\n this.setState({ touches: [...this.touches] });\n }\n\n /**\n * Handles the double tap event\n *\n * @param e\n *\n * @private\n */\n _handleDoubleTap(e: GestureResponderEvent) {\n const { onDoubleTapBefore, onDoubleTapAfter, doubleTapZoomToCenter } =\n this.props;\n\n onDoubleTapBefore?.(e, this._getZoomableViewEventObject());\n\n const nextZoomStep = this._getNextZoomStep();\n if (nextZoomStep == null) return;\n\n const { originalPageX, originalPageY } = this.state;\n\n // define new zoom position coordinates\n const zoomPositionCoordinates = {\n x: e.nativeEvent.pageX - originalPageX,\n y: e.nativeEvent.pageY - originalPageY,\n };\n\n // if doubleTapZoomToCenter enabled -> always zoom to center instead\n if (doubleTapZoomToCenter) {\n zoomPositionCoordinates.x = 0;\n zoomPositionCoordinates.y = 0;\n }\n\n this.zoomTo(nextZoomStep, zoomPositionCoordinates);\n\n onDoubleTapAfter?.(\n e,\n this._getZoomableViewEventObject({ zoomLevel: nextZoomStep })\n );\n }\n\n /**\n * Returns the next zoom step based on current step and zoomStep property.\n * If we are zoomed all the way in -> return to initialzoom\n *\n * @returns {*}\n */\n _getNextZoomStep() {\n const { zoomStep, maxZoom, initialZoom } = this.props;\n const { zoomLevel } = this;\n\n if (maxZoom == null) return;\n\n if (zoomLevel.toFixed(2) === maxZoom.toFixed(2)) {\n return initialZoom;\n }\n\n if (zoomStep == null) return;\n\n const nextZoomStep = zoomLevel * (1 + zoomStep);\n if (nextZoomStep > maxZoom) {\n return maxZoom;\n }\n\n return nextZoomStep;\n }\n\n /**\n * Zooms to a specific level. A \"zoom center\" can be provided, which specifies\n * the point that will remain in the same position on the screen after the zoom.\n * The coordinates of the zoom center is relative to the zoom subject.\n * { x: 0, y: 0 } is the very center of the zoom subject.\n *\n * @param newZoomLevel\n * @param zoomCenter - If not supplied, the container's center is the zoom center\n */\n zoomTo(newZoomLevel: number, zoomCenter?: Vec2D) {\n if (!this.props.zoomEnabled) return false;\n if (this.props.maxZoom && newZoomLevel > this.props.maxZoom) return false;\n if (this.props.minZoom && newZoomLevel < this.props.minZoom) return false;\n\n this.props.onZoomBefore?.(null, null, this._getZoomableViewEventObject());\n\n // == Perform Pan Animation to preserve the zoom center while zooming ==\n let listenerId = '';\n if (zoomCenter) {\n // Calculates panAnim values based on changes in zoomAnim.\n let prevScale = this.zoomLevel;\n // Since zoomAnim is calculated in native driver,\n // it will jitter panAnim once in a while,\n // because here panAnim is being calculated in js.\n // However the jittering should mostly occur in simulator.\n listenerId = this.zoomAnim.addListener(({ value: newScale }) => {\n this.panAnim.setValue({\n x: calcNewScaledOffsetForZoomCentering(\n this.offsetX,\n this.state.originalWidth,\n prevScale,\n newScale,\n zoomCenter.x\n ),\n y: calcNewScaledOffsetForZoomCentering(\n this.offsetY,\n this.state.originalHeight,\n prevScale,\n newScale,\n zoomCenter.y\n ),\n });\n prevScale = newScale;\n });\n }\n\n // == Perform Zoom Animation ==\n getZoomToAnimation(this.zoomAnim, newZoomLevel).start(() => {\n this.zoomAnim.removeListener(listenerId);\n });\n // == Zoom Animation Ends ==\n\n this.props.onZoomAfter?.(null, null, this._getZoomableViewEventObject());\n return true;\n }\n\n /**\n * Zooms in or out by a specified change level\n * Use a positive number for `zoomLevelChange` to zoom in\n * Use a negative number for `zoomLevelChange` to zoom out\n *\n * Returns a promise if everything was updated and a boolean, whether it could be updated or if it exceeded the min/max zoom limits.\n *\n * @param {number | null} zoomLevelChange\n *\n * @return {bool}\n */\n zoomBy(zoomLevelChange: number) {\n // if no zoom level Change given -> just use zoom step\n zoomLevelChange ||= this.props.zoomStep || 0;\n return this.zoomTo(this.zoomLevel + zoomLevelChange);\n }\n\n /**\n * Moves the zoomed view to a specified position\n * Returns a promise when finished\n *\n * @param {number} newOffsetX the new position we want to move it to (x-axis)\n * @param {number} newOffsetY the new position we want to move it to (y-axis)\n *\n * @return {bool}\n */\n moveTo(newOffsetX: number, newOffsetY: number) {\n const { originalWidth, originalHeight } = this.state;\n if (!originalWidth || !originalHeight) return;\n\n const offsetX = (newOffsetX - originalWidth / 2) / this.zoomLevel;\n const offsetY = (newOffsetY - originalHeight / 2) / this.zoomLevel;\n\n this._setNewOffsetPosition(-offsetX, -offsetY);\n }\n\n /**\n * Moves the zoomed view by a certain amount.\n *\n * Returns a promise when finished\n *\n * @param {number} offsetChangeX the amount we want to move the offset by (x-axis)\n * @param {number} offsetChangeY the amount we want to move the offset by (y-axis)\n *\n * @return {bool}\n */\n moveBy(offsetChangeX: number, offsetChangeY: number) {\n const offsetX =\n (this.offsetX * this.zoomLevel - offsetChangeX) / this.zoomLevel;\n const offsetY =\n (this.offsetY * this.zoomLevel - offsetChangeY) / this.zoomLevel;\n\n this._setNewOffsetPosition(offsetX, offsetY);\n }\n\n render() {\n const {\n staticPinIcon,\n children,\n visualTouchFeedbackEnabled,\n doubleTapDelay,\n staticPinPosition,\n onStaticPinLongPress,\n onStaticPinPress,\n pinProps,\n } = this.props;\n const { pinSize, touches, debugPoints = [] } = this.state;\n\n return (\n {\n this.props.onLayout?.(event);\n this.grabZoomSubjectOriginalMeasurements();\n }}\n >\n \n {children}\n \n\n {visualTouchFeedbackEnabled &&\n touches?.map(\n (touch) =>\n doubleTapDelay && (\n {\n this._removeTouch(touch);\n }}\n />\n )\n )}\n\n {/* For Debugging Only */}\n {debugPoints.map(({ x, y }, index) => {\n return ;\n })}\n\n {staticPinPosition && (\n {\n this.setState({ pinSize: size });\n }}\n pinProps={pinProps}\n />\n )}\n \n );\n }\n}\n\nconst styles = StyleSheet.create({\n container: {\n alignItems: 'center',\n flex: 1,\n justifyContent: 'center',\n overflow: 'hidden',\n position: 'relative',\n },\n zoomSubject: {\n alignItems: 'center',\n flex: 1,\n justifyContent: 'center',\n width: '100%',\n },\n});\n\nexport default ReactNativeZoomableView;\n\nexport { ReactNativeZoomableView };\n"]} \ No newline at end of file +{"version":3,"sources":["ReactNativeZoomableView.tsx"],"names":["React","Component","createRef","Animated","Easing","PanResponder","StyleSheet","View","AnimatedTouchFeedback","DebugTouchPoint","calcGestureCenterPoint","calcGestureTouchDistance","calcNewScaledOffsetForZoomCentering","applyPanBoundariesToOffset","viewportPositionToImagePosition","StaticPin","debounce","getBoundaryCrossedAnim","getPanMomentumDecayAnim","getZoomToAnimation","initialState","originalWidth","originalHeight","originalPageX","originalPageY","pinSize","width","height","ReactNativeZoomableView","gestureStarted","v","_gestureStarted","constructor","props","ValueXY","x","y","Value","value","boundaryCrossedAnimInEffect","position","onStaticPinPositionChange","requestAnimationFrame","setTimeout","zoomSubjectWrapperRef","current","measureInWindow","state","setState","e","gestureState","onStartShouldSetPanResponder","_getZoomableViewEventObject","onLongPress","longPressTimeout","longPressDuration","onPanResponderGrant","panAnim","stopAnimation","zoomAnim","raisePin","gestureType","_resolveAndHandleTap","debugPoints","lastGestureCenterPosition","disableMomentum","panEnabled","disablePanOnInitialZoom","zoomLevel","initialZoom","vx","vy","start","clearTimeout","onPanResponderEnd","onZoomEnd","onShiftingEnd","staticPinPosition","_updateStaticPin","dropPin","onPanResponderMove","numberActiveTouches","_handlePanResponderGrant","_handlePanResponderEnd","lastGestureTouchDistance","_handlePinching","Math","abs","dx","dy","isShiftGesture","_handleShifting","now","Date","doubleTapFirstTapReleaseTimestamp","doubleTapDelay","doubleTapFirstTap","_addTouch","id","toString","isSecondTap","singleTapTimeoutId","_handleDoubleTap","nativeEvent","pageX","pageY","persist","tapX","tapY","timing","toValue","offsetX","offsetY","useNativeDriver","duration","onSingleTap","contentWidth","contentHeight","pinX","pinY","setValue","viewportPosition","imageSize","zoomableEvent","_staticPinPosition","gestureHandlers","create","_handleStartShouldSetPanResponder","_handlePanResponderMove","onPanResponderRelease","onPanResponderTerminate","evt","onPanResponderTerminationRequest","onShouldBlockNativeResponder","onStartShouldSetPanResponderCapture","onMoveShouldSetPanResponderCapture","zoomAnimatedValue","panAnimatedValueXY","initialOffsetX","initialOffsetY","addListener","animatePin","pinAnim","easing","out","ease","__setOffset","__getOffset","axis","offset","offsetState","__offsets","bindToBorders","containerSize","contentSize","boundOffset","panBoundaryPadding","boundariesApplied","toFixed","componentDidUpdate","prevProps","prevState","zoomEnabled","onTransformInvocationInitialized","_invokeOnTransform","successful","currState","originalMeasurementsChanged","staticPinPositionChanged","onLayoutMeasured","componentDidMount","measureZoomSubject","measureZoomSubjectInterval","setInterval","componentWillUnmount","clearInterval","zoomableViewEvent","onTransform","onStaticPinPositionMove","debouncedOnStaticPinPositionChange","overwriteObj","maxZoom","minZoom","pinchToZoomInSensitivity","pinchToZoomOutSensitivity","distance","onZoomBefore","zoomGrowthFromLastGestureState","pinchToZoomSensitivity","deltaGrowth","deltaGrowthAdjustedBySensitivity","newZoomLevel","gestureCenterPoint","zoomCenter","debug","_setPinchDebugPoints","oldOffsetX","oldOffsetY","oldScale","newScale","offsetShift","_calcOffsetShiftSinceLastGestureState","onZoomAfter","gestureResponderEvent","points","touches","movementSensibility","shift","shiftX","shiftY","moveX","moveY","_setNewOffsetPosition","newOffsetX","newOffsetY","onShiftingBefore","onShiftingAfter","touch","push","_removeTouch","splice","indexOf","onDoubleTapBefore","onDoubleTapAfter","doubleTapZoomToCenter","nextZoomStep","_getNextZoomStep","zoomPositionCoordinates","zoomTo","zoomStep","listenerId","prevScale","removeListener","zoomBy","zoomLevelChange","moveTo","moveBy","offsetChangeX","offsetChangeY","render","staticPinIcon","children","visualTouchFeedbackEnabled","onStaticPinLongPress","onStaticPinPress","pinProps","styles","container","panHandlers","zoomSubject","style","transform","scale","getTranslateTransform","map","index","size","undefined","alignItems","flex","justifyContent","overflow"],"mappings":"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","sourcesContent":["import React, { Component, createRef, RefObject } from 'react';\nimport {\n Animated,\n Easing,\n GestureResponderEvent,\n PanResponder,\n PanResponderCallbacks,\n PanResponderGestureState,\n PanResponderInstance,\n StyleSheet,\n View,\n} from 'react-native';\n\nimport {\n Vec2D,\n ReactNativeZoomableViewProps,\n ReactNativeZoomableViewState,\n TouchPoint,\n ZoomableViewEvent,\n Size2D,\n} from './typings';\n\nimport { AnimatedTouchFeedback } from './components';\nimport { DebugTouchPoint } from './debugHelper';\nimport {\n calcGestureCenterPoint,\n calcGestureTouchDistance,\n calcNewScaledOffsetForZoomCentering,\n} from './helper';\nimport { applyPanBoundariesToOffset } from './helper/applyPanBoundariesToOffset';\nimport { viewportPositionToImagePosition } from './helper/coordinateConversion';\nimport { StaticPin } from './components/StaticPin';\nimport { debounce } from 'lodash';\nimport {\n getBoundaryCrossedAnim,\n getPanMomentumDecayAnim,\n getZoomToAnimation,\n} from './animations';\n\nconst initialState: ReactNativeZoomableViewState = {\n originalWidth: 0,\n originalHeight: 0,\n originalPageX: 0,\n originalPageY: 0,\n pinSize: { width: 0, height: 0 },\n};\n\nclass ReactNativeZoomableView extends Component<\n ReactNativeZoomableViewProps,\n ReactNativeZoomableViewState\n> {\n zoomSubjectWrapperRef: RefObject;\n gestureHandlers: PanResponderInstance;\n doubleTapFirstTapReleaseTimestamp: number | undefined;\n\n static defaultProps = {\n zoomEnabled: true,\n panEnabled: true,\n initialZoom: 1,\n initialOffsetX: 0,\n initialOffsetY: 0,\n maxZoom: 1.5,\n minZoom: 0.5,\n pinchToZoomInSensitivity: 1,\n pinchToZoomOutSensitivity: 1,\n movementSensibility: 1,\n doubleTapDelay: 300,\n bindToBorders: true,\n zoomStep: 0.5,\n onLongPress: null,\n longPressDuration: 700,\n contentWidth: undefined,\n contentHeight: undefined,\n panBoundaryPadding: 0,\n visualTouchFeedbackEnabled: true,\n staticPinPosition: undefined,\n staticPinIcon: undefined,\n onStaticPinPositionChange: undefined,\n onStaticPinPositionMove: undefined,\n animatePin: true,\n disablePanOnInitialZoom: false,\n };\n\n private panAnim = new Animated.ValueXY({ x: 0, y: 0 });\n private zoomAnim = new Animated.Value(1);\n private pinAnim = new Animated.ValueXY({ x: 0, y: 0 });\n\n private __offsets = {\n x: {\n value: 0,\n boundaryCrossedAnimInEffect: false,\n },\n y: {\n value: 0,\n boundaryCrossedAnimInEffect: false,\n },\n };\n\n private zoomLevel = 1;\n private lastGestureCenterPosition: { x: number; y: number } | null = null;\n private lastGestureTouchDistance: number | null = null;\n private gestureType: 'pinch' | 'shift' | null;\n\n private _gestureStarted = false;\n private set gestureStarted(v: boolean) {\n this._gestureStarted = v;\n }\n\n public get gestureStarted() {\n return this._gestureStarted;\n }\n\n /**\n * Last press time (used to evaluate whether user double tapped)\n * @type {number}\n */\n private longPressTimeout: NodeJS.Timeout | null = null;\n private onTransformInvocationInitialized: boolean | undefined;\n private singleTapTimeoutId: NodeJS.Timeout | undefined;\n private touches: TouchPoint[] = [];\n private doubleTapFirstTap: TouchPoint | undefined;\n private measureZoomSubjectInterval: NodeJS.Timer | undefined;\n\n constructor(props: ReactNativeZoomableViewProps) {\n super(props);\n // This needs to be done before anything else to initialize the state.\n // Otherwise, the logic below may reference the state when it's undefined,\n // causing runtime errors.\n this.state = { ...initialState };\n\n this.gestureHandlers = PanResponder.create({\n onStartShouldSetPanResponder: this._handleStartShouldSetPanResponder,\n onPanResponderGrant: this._handlePanResponderGrant,\n onPanResponderMove: this._handlePanResponderMove,\n onPanResponderRelease: this._handlePanResponderEnd,\n onPanResponderTerminate: (evt, gestureState) => {\n // We should also call _handlePanResponderEnd\n // to properly perform cleanups when the gesture is terminated\n // (aka gesture handling responsibility is taken over by another component).\n // This also fixes a weird issue where\n // on real device, sometimes onPanResponderRelease is not called when you lift 2 fingers up,\n // but onPanResponderTerminate is called instead for no apparent reason.\n this._handlePanResponderEnd(evt, gestureState);\n this.props.onPanResponderTerminate?.(\n evt,\n gestureState,\n this._getZoomableViewEventObject()\n );\n },\n onPanResponderTerminationRequest: (evt, gestureState) =>\n !!this.props.onPanResponderTerminationRequest?.(\n evt,\n gestureState,\n this._getZoomableViewEventObject()\n ),\n // Defaults to true to prevent parent components, such as React Navigation's tab view, from taking over as responder.\n onShouldBlockNativeResponder: (evt, gestureState) =>\n this.props.onShouldBlockNativeResponder?.(\n evt,\n gestureState,\n this._getZoomableViewEventObject()\n ) ?? true,\n onStartShouldSetPanResponderCapture: (evt, gestureState) =>\n !!this.props.onStartShouldSetPanResponderCapture?.(evt, gestureState),\n onMoveShouldSetPanResponderCapture: (evt, gestureState) =>\n !!this.props.onMoveShouldSetPanResponderCapture?.(evt, gestureState),\n });\n\n this.zoomSubjectWrapperRef = createRef();\n\n if (this.props.zoomAnimatedValue)\n this.zoomAnim = this.props.zoomAnimatedValue;\n if (this.props.panAnimatedValueXY)\n this.panAnim = this.props.panAnimatedValueXY;\n\n if (this.props.initialZoom) this.zoomLevel = this.props.initialZoom;\n if (this.props.initialOffsetX != null)\n this.offsetX = this.props.initialOffsetX;\n if (this.props.initialOffsetY != null)\n this.offsetY = this.props.initialOffsetY;\n\n this.panAnim.setValue({ x: this.offsetX, y: this.offsetY });\n this.zoomAnim.setValue(this.zoomLevel);\n this.panAnim.addListener(({ x, y }) => {\n this.offsetX = x;\n this.offsetY = y;\n });\n this.zoomAnim.addListener(({ value }) => {\n this.zoomLevel = value;\n });\n\n this.lastGestureTouchDistance = 150;\n\n this.gestureType = null;\n }\n\n private raisePin() {\n if (!this.props.animatePin) return;\n Animated.timing(this.pinAnim, {\n toValue: { x: 0, y: -10 },\n useNativeDriver: true,\n easing: Easing.out(Easing.ease),\n duration: 100,\n }).start();\n }\n\n private dropPin() {\n if (!this.props.animatePin) return;\n Animated.timing(this.pinAnim, {\n toValue: { x: 0, y: 0 },\n useNativeDriver: true,\n easing: Easing.out(Easing.ease),\n duration: 100,\n }).start();\n }\n\n private set offsetX(x: number) {\n this.__setOffset('x', x);\n }\n\n private set offsetY(y: number) {\n this.__setOffset('y', y);\n }\n\n private get offsetX() {\n return this.__getOffset('x');\n }\n\n private get offsetY() {\n return this.__getOffset('y');\n }\n\n private __setOffset(axis: 'x' | 'y', offset: number) {\n const offsetState = this.__offsets[axis];\n\n if (this.props.bindToBorders) {\n const containerSize =\n axis === 'x' ? this.state.originalWidth : this.state.originalHeight;\n const contentSize =\n axis === 'x'\n ? this.props.contentWidth || this.state.originalWidth\n : this.props.contentHeight || this.state.originalHeight;\n\n const boundOffset =\n contentSize && containerSize && this.props.panBoundaryPadding != null\n ? applyPanBoundariesToOffset(\n offset,\n containerSize,\n contentSize,\n this.zoomLevel,\n this.props.panBoundaryPadding\n )\n : offset;\n\n if (!this.gestureType && !offsetState.boundaryCrossedAnimInEffect) {\n const boundariesApplied =\n boundOffset !== offset &&\n boundOffset.toFixed(3) !== offset.toFixed(3);\n if (boundariesApplied) {\n offsetState.boundaryCrossedAnimInEffect = true;\n getBoundaryCrossedAnim(this.panAnim[axis], boundOffset).start(() => {\n offsetState.boundaryCrossedAnimInEffect = false;\n });\n return;\n }\n }\n }\n\n offsetState.value = offset;\n }\n\n private __getOffset(axis: 'x' | 'y') {\n return this.__offsets[axis].value;\n }\n\n componentDidUpdate(\n prevProps: ReactNativeZoomableViewProps,\n prevState: ReactNativeZoomableViewState\n ) {\n const { zoomEnabled, initialZoom } = this.props;\n if (prevProps.zoomEnabled && !zoomEnabled && initialZoom) {\n this.zoomLevel = initialZoom;\n this.zoomAnim.setValue(this.zoomLevel);\n }\n if (\n !this.onTransformInvocationInitialized &&\n this._invokeOnTransform().successful\n ) {\n this.panAnim.addListener(() => this._invokeOnTransform());\n this.zoomAnim.addListener(() => this._invokeOnTransform());\n this.onTransformInvocationInitialized = true;\n }\n\n const currState = this.state;\n const originalMeasurementsChanged =\n currState.originalHeight !== prevState.originalHeight ||\n currState.originalWidth !== prevState.originalWidth ||\n currState.originalPageX !== prevState.originalPageX ||\n currState.originalPageY !== prevState.originalPageY;\n\n const staticPinPositionChanged =\n prevProps.staticPinPosition?.x !== this.props.staticPinPosition?.x ||\n prevProps.staticPinPosition?.y !== this.props.staticPinPosition?.y;\n\n // We use a custom `onLayout` event because:\n // a) View's `onLayout` sometimes doesn't get called\n // b) we use `measureInWindow` internally to keep track of layout changes\n // When the client uses this, they can stay in-sync with the internal measurements,\n // thus applying transformations at more accurate timings\n if (originalMeasurementsChanged) {\n this.props.onLayoutMeasured?.({\n width: currState.originalWidth,\n height: currState.originalHeight,\n x: currState.originalPageX,\n y: currState.originalPageY,\n });\n }\n\n if (\n this.onTransformInvocationInitialized &&\n (originalMeasurementsChanged || staticPinPositionChanged)\n ) {\n this._invokeOnTransform();\n }\n }\n\n componentDidMount() {\n this.measureZoomSubject();\n // We've already run `grabZoomSubjectOriginalMeasurements` at various events\n // to make sure the measurements are promptly updated.\n // However, there might be cases we haven't accounted for, especially when\n // native processes are involved. To account for those cases,\n // we'll use an interval here to ensure we're always up-to-date.\n // The `setState` in `grabZoomSubjectOriginalMeasurements` won't trigger a rerender\n // if the values given haven't changed, so we're not running performance risk here.\n this.measureZoomSubjectInterval = setInterval(this.measureZoomSubject, 1e3);\n }\n\n componentWillUnmount() {\n this.measureZoomSubjectInterval &&\n clearInterval(this.measureZoomSubjectInterval);\n }\n\n debouncedOnStaticPinPositionChange = debounce(\n (position: Vec2D) => this.props.onStaticPinPositionChange?.(position),\n 100\n );\n\n /**\n * try to invoke onTransform\n * @private\n */\n _invokeOnTransform() {\n const zoomableViewEvent = this._getZoomableViewEventObject();\n const position = this._staticPinPosition();\n\n if (!zoomableViewEvent.originalWidth || !zoomableViewEvent.originalHeight)\n return { successful: false };\n\n this.props.onTransform?.(zoomableViewEvent);\n\n if (position) {\n this.props.onStaticPinPositionMove?.(position);\n this.debouncedOnStaticPinPositionChange(position);\n }\n\n return { successful: true };\n }\n\n /**\n * Returns additional information about components current state for external event hooks\n *\n * @returns {{}}\n * @private\n */\n _getZoomableViewEventObject(overwriteObj = {}): ZoomableViewEvent {\n return {\n zoomLevel: this.zoomLevel,\n offsetX: this.offsetX,\n offsetY: this.offsetY,\n originalHeight: this.state.originalHeight,\n originalWidth: this.state.originalWidth,\n originalPageX: this.state.originalPageX,\n originalPageY: this.state.originalPageY,\n ...overwriteObj,\n } as ZoomableViewEvent;\n }\n\n /**\n * Get the original box dimensions and save them for later use.\n * (They will be used to calculate boxBorders)\n *\n * @private\n */\n private measureZoomSubject = () => {\n // make sure we measure after animations are complete\n requestAnimationFrame(() => {\n // this setTimeout is here to fix a weird issue on iOS where the measurements are all `0`\n // when navigating back (react-navigation stack) from another view\n // while closing the keyboard at the same time\n setTimeout(() => {\n // In normal conditions, we're supposed to measure zoomSubject instead of its wrapper.\n // However, our zoomSubject may have been transformed by an initial zoomLevel or offset,\n // in which case these measurements will not represent the true \"original\" measurements.\n // We just need to make sure the zoomSubjectWrapper perfectly aligns with the zoomSubject\n // (no border, space, or anything between them)\n const zoomSubjectWrapperRef = this.zoomSubjectWrapperRef;\n // we don't wanna measure when zoomSubjectWrapperRef is not yet available or has been unmounted\n zoomSubjectWrapperRef.current?.measureInWindow(\n (x, y, width, height) => {\n // When the component is off-screen, these become all 0s, so we don't set them\n // to avoid messing up calculations, especially ones that are done right after\n // the component transitions from hidden to visible.\n if (!x && !y && !width && !height) return;\n\n // If these values are all the same, don't re-set them in state\n // this way we don't re-render\n if (\n this.state.originalWidth === width &&\n this.state.originalHeight === height &&\n this.state.originalPageX === x &&\n this.state.originalPageY === y\n ) {\n return;\n }\n\n this.setState({\n originalWidth: width,\n originalHeight: height,\n originalPageX: x,\n originalPageY: y,\n });\n }\n );\n });\n });\n };\n\n /**\n * Handles the start of touch events and checks for taps\n *\n * @param e\n * @param gestureState\n * @returns {boolean}\n *\n * @private\n */\n _handleStartShouldSetPanResponder = (\n e: GestureResponderEvent,\n gestureState: PanResponderGestureState\n ) => {\n if (this.props.onStartShouldSetPanResponder) {\n this.props.onStartShouldSetPanResponder(\n e,\n gestureState,\n this._getZoomableViewEventObject(),\n false\n );\n }\n\n // Always set pan responder on start\n // of gesture so we can handle tap.\n // \"Pan threshold validation\" will be handled\n // in `onPanResponderMove` instead of in `onMoveShouldSetPanResponder`\n return true;\n };\n\n /**\n * Calculates pinch distance\n *\n * @param e\n * @param gestureState\n * @private\n */\n _handlePanResponderGrant: NonNullable<\n PanResponderCallbacks['onPanResponderGrant']\n > = (e, gestureState) => {\n if (this.props.onLongPress) {\n this.longPressTimeout = setTimeout(() => {\n this.props.onLongPress?.(\n e,\n gestureState,\n this._getZoomableViewEventObject()\n );\n this.longPressTimeout = null;\n }, this.props.longPressDuration);\n }\n\n this.props.onPanResponderGrant?.(\n e,\n gestureState,\n this._getZoomableViewEventObject()\n );\n\n this.panAnim.stopAnimation();\n this.zoomAnim.stopAnimation();\n this.gestureStarted = true;\n\n this.raisePin();\n };\n\n /**\n * Handles the end of touch events\n *\n * @param e\n * @param gestureState\n *\n * @private\n */\n _handlePanResponderEnd: NonNullable<\n PanResponderCallbacks['onPanResponderEnd']\n > = (e, gestureState) => {\n if (!this.gestureType) {\n this._resolveAndHandleTap(e);\n }\n\n this.setState({ debugPoints: [] });\n\n this.lastGestureCenterPosition = null;\n\n const disableMomentum =\n this.props.disableMomentum ||\n (this.props.panEnabled &&\n this.gestureType === 'shift' &&\n this.props.disablePanOnInitialZoom &&\n this.zoomLevel === this.props.initialZoom);\n\n // Trigger final shift animation unless disablePanOnInitialZoom is set and we're on the initial zoom level\n // or disableMomentum\n if (!disableMomentum) {\n getPanMomentumDecayAnim(this.panAnim, {\n x: gestureState.vx / this.zoomLevel,\n y: gestureState.vy / this.zoomLevel,\n }).start();\n }\n\n if (this.longPressTimeout) {\n clearTimeout(this.longPressTimeout);\n this.longPressTimeout = null;\n }\n\n this.props.onPanResponderEnd?.(\n e,\n gestureState,\n this._getZoomableViewEventObject()\n );\n\n if (this.gestureType === 'pinch') {\n this.props.onZoomEnd?.(\n e,\n gestureState,\n this._getZoomableViewEventObject()\n );\n } else if (this.gestureType === 'shift') {\n this.props.onShiftingEnd?.(\n e,\n gestureState,\n this._getZoomableViewEventObject()\n );\n }\n\n if (this.props.staticPinPosition) {\n this._updateStaticPin();\n }\n\n this.dropPin();\n\n this.gestureType = null;\n this.gestureStarted = false;\n };\n\n /**\n * Handles the actual movement of our pan responder\n *\n * @param e\n * @param gestureState\n *\n * @private\n */\n _handlePanResponderMove = (\n e: GestureResponderEvent,\n gestureState: PanResponderGestureState\n ) => {\n if (this.props.onPanResponderMove) {\n if (\n this.props.onPanResponderMove(\n e,\n gestureState,\n this._getZoomableViewEventObject()\n )\n ) {\n return false;\n }\n }\n\n // Only supports 2 touches and below,\n // any invalid number will cause the gesture to end.\n if (gestureState.numberActiveTouches <= 2) {\n if (!this.gestureStarted) {\n this._handlePanResponderGrant(e, gestureState);\n }\n } else {\n if (this.gestureStarted) {\n this._handlePanResponderEnd(e, gestureState);\n }\n return true;\n }\n\n if (gestureState.numberActiveTouches === 2) {\n if (this.longPressTimeout) {\n clearTimeout(this.longPressTimeout);\n this.longPressTimeout = null;\n }\n\n // change some measurement states when switching gesture to ensure a smooth transition\n if (this.gestureType !== 'pinch') {\n this.lastGestureCenterPosition = calcGestureCenterPoint(\n e,\n gestureState\n );\n this.lastGestureTouchDistance = calcGestureTouchDistance(\n e,\n gestureState\n );\n }\n this.gestureType = 'pinch';\n this._handlePinching(e, gestureState);\n } else if (gestureState.numberActiveTouches === 1) {\n if (\n this.longPressTimeout &&\n (Math.abs(gestureState.dx) > 5 || Math.abs(gestureState.dy) > 5)\n ) {\n clearTimeout(this.longPressTimeout);\n this.longPressTimeout = null;\n }\n // change some measurement states when switching gesture to ensure a smooth transition\n if (this.gestureType !== 'shift') {\n this.lastGestureCenterPosition = calcGestureCenterPoint(\n e,\n gestureState\n );\n }\n\n const { dx, dy } = gestureState;\n const isShiftGesture = Math.abs(dx) > 2 || Math.abs(dy) > 2;\n if (isShiftGesture) {\n this.gestureType = 'shift';\n this._handleShifting(gestureState);\n }\n }\n };\n\n /**\n * Handles the pinch movement and zooming\n *\n * @param e\n * @param gestureState\n *\n * @private\n */\n _handlePinching(\n e: GestureResponderEvent,\n gestureState: PanResponderGestureState\n ) {\n if (!this.props.zoomEnabled) return;\n\n const {\n maxZoom,\n minZoom,\n pinchToZoomInSensitivity,\n pinchToZoomOutSensitivity,\n } = this.props;\n\n const distance = calcGestureTouchDistance(e, gestureState);\n\n if (\n this.props.onZoomBefore &&\n this.props.onZoomBefore(\n e,\n gestureState,\n this._getZoomableViewEventObject()\n )\n ) {\n return;\n }\n\n if (!distance) return;\n if (!this.lastGestureTouchDistance) return;\n\n // define the new zoom level and take zoom level sensitivity into consideration\n const zoomGrowthFromLastGestureState =\n distance / this.lastGestureTouchDistance;\n this.lastGestureTouchDistance = distance;\n\n const pinchToZoomSensitivity =\n zoomGrowthFromLastGestureState < 1\n ? pinchToZoomOutSensitivity\n : pinchToZoomInSensitivity;\n\n if (pinchToZoomSensitivity == null) return;\n const deltaGrowth = zoomGrowthFromLastGestureState - 1;\n // 0 - no resistance\n // 10 - 90% resistance\n const deltaGrowthAdjustedBySensitivity =\n deltaGrowth * (1 - (pinchToZoomSensitivity * 9) / 100);\n\n let newZoomLevel = this.zoomLevel * (1 + deltaGrowthAdjustedBySensitivity);\n\n // make sure max and min zoom levels are respected\n if (maxZoom != null && newZoomLevel > maxZoom) {\n newZoomLevel = maxZoom;\n }\n\n if (minZoom != null && newZoomLevel < minZoom) {\n newZoomLevel = minZoom;\n }\n\n const gestureCenterPoint = calcGestureCenterPoint(e, gestureState);\n\n if (!gestureCenterPoint) return;\n\n let zoomCenter = {\n x: gestureCenterPoint.x - this.state.originalPageX,\n y: gestureCenterPoint.y - this.state.originalPageY,\n };\n\n if (this.props.staticPinPosition) {\n // When we use a static pin position, the zoom centre is the same as that position,\n // otherwise the pin moves around way too much while zooming.\n zoomCenter = {\n x: this.props.staticPinPosition.x,\n y: this.props.staticPinPosition.y,\n };\n }\n\n // Uncomment to debug\n this.props.debug && this._setPinchDebugPoints(e, zoomCenter);\n\n const { originalHeight, originalWidth } = this.state;\n\n const oldOffsetX = this.offsetX;\n const oldOffsetY = this.offsetY;\n const oldScale = this.zoomLevel;\n const newScale = newZoomLevel;\n\n if (!originalHeight || !originalWidth) return;\n\n let offsetY = calcNewScaledOffsetForZoomCentering(\n oldOffsetY,\n originalHeight,\n oldScale,\n newScale,\n zoomCenter.y\n );\n let offsetX = calcNewScaledOffsetForZoomCentering(\n oldOffsetX,\n originalWidth,\n oldScale,\n newScale,\n zoomCenter.x\n );\n\n const offsetShift =\n this._calcOffsetShiftSinceLastGestureState(gestureCenterPoint);\n if (offsetShift) {\n offsetX += offsetShift.x;\n offsetY += offsetShift.y;\n }\n\n this.offsetX = offsetX;\n this.offsetY = offsetY;\n this.zoomLevel = newScale;\n\n this.panAnim.setValue({ x: this.offsetX, y: this.offsetY });\n this.zoomAnim.setValue(this.zoomLevel);\n\n this.props.onZoomAfter?.(\n e,\n gestureState,\n this._getZoomableViewEventObject()\n );\n }\n\n /**\n * Used to debug pinch events\n * @param gestureResponderEvent\n * @param zoomCenter\n * @param points\n */\n _setPinchDebugPoints(\n gestureResponderEvent: GestureResponderEvent,\n zoomCenter: Vec2D,\n ...points: Vec2D[]\n ) {\n const { touches } = gestureResponderEvent.nativeEvent;\n const { originalPageY, originalPageX } = this.state;\n\n this.setState({\n debugPoints: [\n {\n x: touches[0].pageX - originalPageX,\n y: touches[0].pageY - originalPageY,\n },\n {\n x: touches[1].pageX - originalPageX,\n y: touches[1].pageY - originalPageY,\n },\n zoomCenter,\n ...points,\n ],\n });\n }\n\n /**\n * Calculates the amount the offset should shift since the last position during panning\n *\n * @param {Vec2D} gestureCenterPoint\n *\n * @private\n */\n _calcOffsetShiftSinceLastGestureState(gestureCenterPoint: Vec2D) {\n const { movementSensibility } = this.props;\n\n let shift = null;\n\n if (this.lastGestureCenterPosition && movementSensibility) {\n const dx = gestureCenterPoint.x - this.lastGestureCenterPosition.x;\n const dy = gestureCenterPoint.y - this.lastGestureCenterPosition.y;\n\n const shiftX = dx / this.zoomLevel / movementSensibility;\n const shiftY = dy / this.zoomLevel / movementSensibility;\n\n shift = {\n x: shiftX,\n y: shiftY,\n };\n }\n\n this.lastGestureCenterPosition = gestureCenterPoint;\n\n return shift;\n }\n\n /**\n * Handles movement by tap and move\n *\n * @param gestureState\n *\n * @private\n */\n _handleShifting(gestureState: PanResponderGestureState) {\n // Skips shifting if panEnabled is false or disablePanOnInitialZoom is true and we're on the initial zoom level\n if (\n !this.props.panEnabled ||\n (this.props.disablePanOnInitialZoom &&\n this.zoomLevel === this.props.initialZoom)\n ) {\n return;\n }\n const shift = this._calcOffsetShiftSinceLastGestureState({\n x: gestureState.moveX,\n y: gestureState.moveY,\n });\n if (!shift) return;\n\n const offsetX = this.offsetX + shift.x;\n const offsetY = this.offsetY + shift.y;\n\n if (\n this.props.debug &&\n this.state.originalPageX &&\n this.state.originalPageY\n ) {\n const x = gestureState.moveX - this.state.originalPageX;\n const y = gestureState.moveY - this.state.originalPageY;\n this.setState({ debugPoints: [{ x, y }] });\n }\n\n this._setNewOffsetPosition(offsetX, offsetY);\n\n this.raisePin();\n }\n\n /**\n * Set the state to offset moved\n *\n * @param {number} newOffsetX\n * @param {number} newOffsetY\n * @returns\n */\n _setNewOffsetPosition(newOffsetX: number, newOffsetY: number) {\n const { onShiftingBefore, onShiftingAfter } = this.props;\n\n if (onShiftingBefore?.(null, null, this._getZoomableViewEventObject())) {\n return;\n }\n\n this.offsetX = newOffsetX;\n this.offsetY = newOffsetY;\n\n this.panAnim.setValue({ x: this.offsetX, y: this.offsetY });\n this.zoomAnim.setValue(this.zoomLevel);\n\n onShiftingAfter?.(null, null, this._getZoomableViewEventObject());\n }\n\n /**\n * Check whether the press event is double tap\n * or single tap and handle the event accordingly\n *\n * @param e\n *\n * @private\n */\n private _resolveAndHandleTap = (e: GestureResponderEvent) => {\n const now = Date.now();\n if (\n this.doubleTapFirstTapReleaseTimestamp &&\n this.props.doubleTapDelay &&\n now - this.doubleTapFirstTapReleaseTimestamp < this.props.doubleTapDelay\n ) {\n this.doubleTapFirstTap &&\n this._addTouch({\n ...this.doubleTapFirstTap,\n id: now.toString(),\n isSecondTap: true,\n });\n this.singleTapTimeoutId && clearTimeout(this.singleTapTimeoutId);\n delete this.doubleTapFirstTapReleaseTimestamp;\n delete this.singleTapTimeoutId;\n delete this.doubleTapFirstTap;\n this._handleDoubleTap(e);\n } else {\n this.doubleTapFirstTapReleaseTimestamp = now;\n this.doubleTapFirstTap = {\n id: now.toString(),\n x: e.nativeEvent.pageX - this.state.originalPageX,\n y: e.nativeEvent.pageY - this.state.originalPageY,\n };\n this._addTouch(this.doubleTapFirstTap);\n\n // persist event so e.nativeEvent is preserved after a timeout delay\n e.persist();\n this.singleTapTimeoutId = setTimeout(() => {\n delete this.doubleTapFirstTapReleaseTimestamp;\n delete this.singleTapTimeoutId;\n\n // Pan to the tapped location\n if (this.props.staticPinPosition && this.doubleTapFirstTap) {\n const tapX =\n this.props.staticPinPosition.x - this.doubleTapFirstTap.x;\n const tapY =\n this.props.staticPinPosition.y - this.doubleTapFirstTap.y;\n\n Animated.timing(this.panAnim, {\n toValue: {\n x: this.offsetX + tapX / this.zoomLevel,\n y: this.offsetY + tapY / this.zoomLevel,\n },\n useNativeDriver: true,\n duration: 200,\n }).start(() => {\n this._updateStaticPin();\n });\n }\n\n this.props.onSingleTap?.(e, this._getZoomableViewEventObject());\n }, this.props.doubleTapDelay);\n }\n };\n\n moveStaticPinTo = (position: Vec2D, duration?: number) => {\n const { originalWidth, originalHeight } = this.state;\n const { staticPinPosition, contentWidth, contentHeight } = this.props;\n\n if (!staticPinPosition) return;\n if (!originalWidth || !originalHeight) return;\n if (!contentWidth || !contentHeight) return;\n\n // Offset for the static pin\n const pinX = staticPinPosition.x - originalWidth / 2;\n const pinY = staticPinPosition.y - originalHeight / 2;\n\n this.offsetX = contentWidth / 2 - position.x + pinX / this.zoomLevel;\n this.offsetY = contentHeight / 2 - position.y + pinY / this.zoomLevel;\n\n if (duration) {\n Animated.timing(this.panAnim, {\n toValue: { x: this.offsetX, y: this.offsetY },\n useNativeDriver: true,\n duration,\n }).start();\n } else {\n this.panAnim.setValue({ x: this.offsetX, y: this.offsetY });\n }\n };\n\n private _staticPinPosition = () => {\n if (!this.props.staticPinPosition) return;\n if (!this.props.contentWidth || !this.props.contentHeight) return;\n\n return viewportPositionToImagePosition({\n viewportPosition: {\n x: this.props.staticPinPosition.x,\n y: this.props.staticPinPosition.y,\n },\n imageSize: {\n height: this.props.contentHeight,\n width: this.props.contentWidth,\n },\n zoomableEvent: {\n ...this._getZoomableViewEventObject(),\n offsetX: this.offsetX,\n offsetY: this.offsetY,\n zoomLevel: this.zoomLevel,\n },\n });\n };\n\n private _updateStaticPin = () => {\n const position = this._staticPinPosition();\n if (!position) return;\n this.props.onStaticPinPositionChange?.(position);\n };\n\n private _addTouch(touch: TouchPoint) {\n this.touches.push(touch);\n this.setState({ touches: [...this.touches] });\n }\n\n private _removeTouch(touch: TouchPoint) {\n this.touches.splice(this.touches.indexOf(touch), 1);\n this.setState({ touches: [...this.touches] });\n }\n\n /**\n * Handles the double tap event\n *\n * @param e\n *\n * @private\n */\n _handleDoubleTap(e: GestureResponderEvent) {\n const { onDoubleTapBefore, onDoubleTapAfter, doubleTapZoomToCenter } =\n this.props;\n\n onDoubleTapBefore?.(e, this._getZoomableViewEventObject());\n\n const nextZoomStep = this._getNextZoomStep();\n if (nextZoomStep == null) return;\n\n const { originalPageX, originalPageY } = this.state;\n\n // define new zoom position coordinates\n const zoomPositionCoordinates = {\n x: e.nativeEvent.pageX - originalPageX,\n y: e.nativeEvent.pageY - originalPageY,\n };\n\n // if doubleTapZoomToCenter enabled -> always zoom to center instead\n if (doubleTapZoomToCenter) {\n zoomPositionCoordinates.x = 0;\n zoomPositionCoordinates.y = 0;\n }\n\n this.zoomTo(nextZoomStep, zoomPositionCoordinates);\n\n onDoubleTapAfter?.(\n e,\n this._getZoomableViewEventObject({ zoomLevel: nextZoomStep })\n );\n }\n\n /**\n * Returns the next zoom step based on current step and zoomStep property.\n * If we are zoomed all the way in -> return to initialzoom\n *\n * @returns {*}\n */\n _getNextZoomStep() {\n const { zoomStep, maxZoom, initialZoom } = this.props;\n const { zoomLevel } = this;\n\n if (maxZoom == null) return;\n\n if (zoomLevel.toFixed(2) === maxZoom.toFixed(2)) {\n return initialZoom;\n }\n\n if (zoomStep == null) return;\n\n const nextZoomStep = zoomLevel * (1 + zoomStep);\n if (nextZoomStep > maxZoom) {\n return maxZoom;\n }\n\n return nextZoomStep;\n }\n\n /**\n * Zooms to a specific level. A \"zoom center\" can be provided, which specifies\n * the point that will remain in the same position on the screen after the zoom.\n * The coordinates of the zoom center is relative to the zoom subject.\n * { x: 0, y: 0 } is the very center of the zoom subject.\n *\n * @param newZoomLevel\n * @param zoomCenter - If not supplied, the container's center is the zoom center\n */\n zoomTo(newZoomLevel: number, zoomCenter?: Vec2D) {\n if (!this.props.zoomEnabled) return false;\n if (this.props.maxZoom && newZoomLevel > this.props.maxZoom) return false;\n if (this.props.minZoom && newZoomLevel < this.props.minZoom) return false;\n\n this.props.onZoomBefore?.(null, null, this._getZoomableViewEventObject());\n\n // == Perform Pan Animation to preserve the zoom center while zooming ==\n let listenerId = '';\n if (zoomCenter) {\n // Calculates panAnim values based on changes in zoomAnim.\n let prevScale = this.zoomLevel;\n // Since zoomAnim is calculated in native driver,\n // it will jitter panAnim once in a while,\n // because here panAnim is being calculated in js.\n // However the jittering should mostly occur in simulator.\n listenerId = this.zoomAnim.addListener(({ value: newScale }) => {\n this.panAnim.setValue({\n x: calcNewScaledOffsetForZoomCentering(\n this.offsetX,\n this.state.originalWidth,\n prevScale,\n newScale,\n zoomCenter.x\n ),\n y: calcNewScaledOffsetForZoomCentering(\n this.offsetY,\n this.state.originalHeight,\n prevScale,\n newScale,\n zoomCenter.y\n ),\n });\n prevScale = newScale;\n });\n }\n\n // == Perform Zoom Animation ==\n getZoomToAnimation(this.zoomAnim, newZoomLevel).start(() => {\n this.zoomAnim.removeListener(listenerId);\n });\n // == Zoom Animation Ends ==\n\n this.props.onZoomAfter?.(null, null, this._getZoomableViewEventObject());\n return true;\n }\n\n /**\n * Zooms in or out by a specified change level\n * Use a positive number for `zoomLevelChange` to zoom in\n * Use a negative number for `zoomLevelChange` to zoom out\n *\n * Returns a promise if everything was updated and a boolean, whether it could be updated or if it exceeded the min/max zoom limits.\n *\n * @param {number | null} zoomLevelChange\n *\n * @return {bool}\n */\n zoomBy(zoomLevelChange: number) {\n // if no zoom level Change given -> just use zoom step\n zoomLevelChange ||= this.props.zoomStep || 0;\n return this.zoomTo(this.zoomLevel + zoomLevelChange);\n }\n\n /**\n * Moves the zoomed view to a specified position\n * Returns a promise when finished\n *\n * @param {number} newOffsetX the new position we want to move it to (x-axis)\n * @param {number} newOffsetY the new position we want to move it to (y-axis)\n *\n * @return {bool}\n */\n moveTo(newOffsetX: number, newOffsetY: number) {\n const { originalWidth, originalHeight } = this.state;\n if (!originalWidth || !originalHeight) return;\n\n const offsetX = (newOffsetX - originalWidth / 2) / this.zoomLevel;\n const offsetY = (newOffsetY - originalHeight / 2) / this.zoomLevel;\n\n this._setNewOffsetPosition(-offsetX, -offsetY);\n }\n\n /**\n * Moves the zoomed view by a certain amount.\n *\n * Returns a promise when finished\n *\n * @param {number} offsetChangeX the amount we want to move the offset by (x-axis)\n * @param {number} offsetChangeY the amount we want to move the offset by (y-axis)\n *\n * @return {bool}\n */\n moveBy(offsetChangeX: number, offsetChangeY: number) {\n const offsetX =\n (this.offsetX * this.zoomLevel - offsetChangeX) / this.zoomLevel;\n const offsetY =\n (this.offsetY * this.zoomLevel - offsetChangeY) / this.zoomLevel;\n\n this._setNewOffsetPosition(offsetX, offsetY);\n }\n\n render() {\n const {\n staticPinIcon,\n children,\n visualTouchFeedbackEnabled,\n doubleTapDelay,\n staticPinPosition,\n onStaticPinLongPress,\n onStaticPinPress,\n pinProps,\n } = this.props;\n const { pinSize, touches, debugPoints = [] } = this.state;\n\n return (\n \n \n {children}\n \n\n {visualTouchFeedbackEnabled &&\n touches?.map(\n (touch) =>\n doubleTapDelay && (\n {\n this._removeTouch(touch);\n }}\n />\n )\n )}\n\n {/* For Debugging Only */}\n {debugPoints.map(({ x, y }, index) => {\n return ;\n })}\n\n {staticPinPosition && (\n {\n this.setState({ pinSize: size });\n }}\n pinProps={pinProps}\n />\n )}\n \n );\n }\n}\n\nconst styles = StyleSheet.create({\n container: {\n alignItems: 'center',\n flex: 1,\n justifyContent: 'center',\n overflow: 'hidden',\n position: 'relative',\n },\n zoomSubject: {\n alignItems: 'center',\n flex: 1,\n justifyContent: 'center',\n width: '100%',\n },\n});\n\nexport default ReactNativeZoomableView;\n\nexport { ReactNativeZoomableView };\n"]} \ No newline at end of file diff --git a/lib/module/typings/index.js.map b/lib/module/typings/index.js.map index 8ced74e..97617cf 100644 --- a/lib/module/typings/index.js.map +++ b/lib/module/typings/index.js.map @@ -1 +1 @@ -{"version":3,"sources":["index.ts"],"names":["SwipeDirection"],"mappings":"AAOA,WAAYA,cAAZ;;WAAYA,c;AAAAA,EAAAA,c;AAAAA,EAAAA,c;AAAAA,EAAAA,c;AAAAA,EAAAA,c;GAAAA,c,KAAAA,c","sourcesContent":["import {\n Animated,\n GestureResponderEvent,\n PanResponderGestureState,\n ViewProps,\n} from 'react-native';\n\nexport enum SwipeDirection {\n SWIPE_UP = 'SWIPE_UP',\n SWIPE_DOWN = 'SWIPE_DOWN',\n SWIPE_LEFT = 'SWIPE_LEFT',\n SWIPE_RIGHT = 'SWIPE_RIGHT',\n}\n\nexport interface ZoomableViewEvent {\n zoomLevel: number;\n offsetX: number;\n offsetY: number;\n originalHeight: number;\n originalWidth: number;\n originalPageX: number;\n originalPageY: number;\n}\n\nexport interface ReactNativeZoomableViewProps extends ViewProps {\n // options\n zoomEnabled?: boolean;\n panEnabled?: boolean;\n initialZoom?: number;\n initialOffsetX?: number;\n initialOffsetY?: number;\n contentWidth?: number;\n contentHeight?: number;\n panBoundaryPadding?: number;\n maxZoom?: number;\n minZoom?: number;\n doubleTapDelay?: number;\n doubleTapZoomToCenter?: boolean;\n bindToBorders?: boolean;\n zoomStep?: number;\n pinchToZoomInSensitivity?: number;\n pinchToZoomOutSensitivity?: number;\n movementSensibility?: number;\n longPressDuration?: number;\n visualTouchFeedbackEnabled?: boolean;\n disablePanOnInitialZoom?: boolean;\n\n // Zoom animated value ref\n zoomAnimatedValue?: Animated.Value;\n panAnimatedValueXY?: Animated.ValueXY;\n\n // debug\n debug?: boolean;\n\n // callbacks\n onTransform?: (zoomableViewEventObject: ZoomableViewEvent) => void;\n onSingleTap?: (\n event: GestureResponderEvent,\n zoomableViewEventObject: ZoomableViewEvent\n ) => void;\n onDoubleTapBefore?: (\n event: GestureResponderEvent,\n zoomableViewEventObject: ZoomableViewEvent\n ) => void;\n onDoubleTapAfter?: (\n event: GestureResponderEvent,\n zoomableViewEventObject: ZoomableViewEvent\n ) => void;\n onShiftingBefore?: (\n event: GestureResponderEvent | null,\n gestureState: PanResponderGestureState | null,\n zoomableViewEventObject: ZoomableViewEvent\n ) => boolean;\n onShiftingAfter?: (\n event: GestureResponderEvent | null,\n gestureState: PanResponderGestureState | null,\n zoomableViewEventObject: ZoomableViewEvent\n ) => boolean;\n onShiftingEnd?: (\n event: GestureResponderEvent,\n gestureState: PanResponderGestureState,\n zoomableViewEventObject: ZoomableViewEvent\n ) => void;\n onZoomBefore?: (\n event: GestureResponderEvent | null,\n gestureState: PanResponderGestureState | null,\n zoomableViewEventObject: ZoomableViewEvent\n ) => boolean | undefined;\n onZoomAfter?: (\n event: GestureResponderEvent | null,\n gestureState: PanResponderGestureState | null,\n zoomableViewEventObject: ZoomableViewEvent\n ) => void;\n onZoomEnd?: (\n event: GestureResponderEvent,\n gestureState: PanResponderGestureState,\n zoomableViewEventObject: ZoomableViewEvent\n ) => void;\n onLongPress?: (\n event: GestureResponderEvent,\n gestureState: PanResponderGestureState,\n zoomableViewEventObject: ZoomableViewEvent\n ) => void;\n onStartShouldSetPanResponder?: (\n event: GestureResponderEvent,\n gestureState: PanResponderGestureState,\n zoomableViewEventObject: ZoomableViewEvent,\n baseComponentResult: boolean\n ) => boolean;\n onPanResponderGrant?: (\n event: GestureResponderEvent,\n gestureState: PanResponderGestureState,\n zoomableViewEventObject: ZoomableViewEvent\n ) => void;\n onPanResponderEnd?: (\n event: GestureResponderEvent,\n gestureState: PanResponderGestureState,\n zoomableViewEventObject: ZoomableViewEvent\n ) => void;\n onPanResponderMove?: (\n event: GestureResponderEvent,\n gestureState: PanResponderGestureState,\n zoomableViewEventObject: ZoomableViewEvent\n ) => boolean;\n onPanResponderTerminate?: (\n event: GestureResponderEvent,\n gestureState: PanResponderGestureState,\n zoomableViewEventObject: ZoomableViewEvent\n ) => void;\n onPanResponderTerminationRequest?: (\n event: GestureResponderEvent,\n gestureState: PanResponderGestureState,\n zoomableViewEventObject: ZoomableViewEvent\n ) => boolean;\n onShouldBlockNativeResponder?: (\n event: GestureResponderEvent,\n gestureState: PanResponderGestureState,\n zoomableViewEventObject: ZoomableViewEvent\n ) => boolean;\n onStartShouldSetPanResponderCapture?: (\n event: GestureResponderEvent,\n gestureState: PanResponderGestureState\n ) => boolean;\n onMoveShouldSetPanResponderCapture?: (\n event: GestureResponderEvent,\n gestureState: PanResponderGestureState\n ) => boolean;\n onStaticPinPress?: (event: GestureResponderEvent) => void;\n onStaticPinLongPress?: (event: GestureResponderEvent) => void;\n staticPinPosition?: Vec2D;\n staticPinIcon?: React.ReactElement;\n onStaticPinPositionChange?: (position: Vec2D) => void;\n onStaticPinPositionMove?: (position: Vec2D) => void;\n animatePin: boolean;\n pinProps?: ViewProps;\n disableMomentum?: boolean;\n}\n\nexport interface Vec2D {\n x: number;\n y: number;\n}\n\nexport interface Size2D {\n width: number;\n height: number;\n}\n\nexport interface TouchPoint extends Vec2D {\n id: string;\n isSecondTap?: boolean;\n}\n\nexport interface ReactNativeZoomableViewState {\n touches?: TouchPoint[];\n originalWidth: number;\n originalHeight: number;\n originalPageX: number;\n originalPageY: number;\n debugPoints?: undefined | Vec2D[];\n pinSize: Size2D;\n}\n\nexport interface ReactNativeZoomableViewWithGesturesProps\n extends ReactNativeZoomableViewProps {\n swipeLengthThreshold?: number;\n swipeVelocityThreshold?: number;\n swipeDirectionalThreshold?: number;\n swipeMinZoom?: number;\n swipeMaxZoom?: number;\n swipeDisabled?: boolean;\n onSwipe?: (\n swipeDirection: SwipeDirection,\n gestureState: PanResponderGestureState\n ) => void;\n onSwipeUp?: (gestureState: PanResponderGestureState) => void;\n onSwipeDown?: (gestureState: PanResponderGestureState) => void;\n onSwipeLeft?: (gestureState: PanResponderGestureState) => void;\n onSwipeRight?: (gestureState: PanResponderGestureState) => void;\n}\n"]} \ No newline at end of file +{"version":3,"sources":["index.ts"],"names":["SwipeDirection"],"mappings":"AAQA,WAAYA,cAAZ;;WAAYA,c;AAAAA,EAAAA,c;AAAAA,EAAAA,c;AAAAA,EAAAA,c;AAAAA,EAAAA,c;GAAAA,c,KAAAA,c","sourcesContent":["import {\n Animated,\n GestureResponderEvent,\n PanResponderGestureState,\n ViewProps,\n} from 'react-native';\nimport { ReactNode } from 'react';\n\nexport enum SwipeDirection {\n SWIPE_UP = 'SWIPE_UP',\n SWIPE_DOWN = 'SWIPE_DOWN',\n SWIPE_LEFT = 'SWIPE_LEFT',\n SWIPE_RIGHT = 'SWIPE_RIGHT',\n}\n\nexport interface ZoomableViewEvent {\n zoomLevel: number;\n offsetX: number;\n offsetY: number;\n originalHeight: number;\n originalWidth: number;\n originalPageX: number;\n originalPageY: number;\n}\n\nexport interface ReactNativeZoomableViewProps {\n // options\n style?: ViewProps['style'];\n children?: ReactNode;\n zoomEnabled?: boolean;\n panEnabled?: boolean;\n initialZoom?: number;\n initialOffsetX?: number;\n initialOffsetY?: number;\n contentWidth?: number;\n contentHeight?: number;\n panBoundaryPadding?: number;\n maxZoom?: number;\n minZoom?: number;\n doubleTapDelay?: number;\n doubleTapZoomToCenter?: boolean;\n bindToBorders?: boolean;\n zoomStep?: number;\n pinchToZoomInSensitivity?: number;\n pinchToZoomOutSensitivity?: number;\n movementSensibility?: number;\n longPressDuration?: number;\n visualTouchFeedbackEnabled?: boolean;\n disablePanOnInitialZoom?: boolean;\n\n // Zoom animated value ref\n zoomAnimatedValue?: Animated.Value;\n panAnimatedValueXY?: Animated.ValueXY;\n\n // debug\n debug?: boolean;\n\n // callbacks\n onLayoutMeasured?: (size: Size2D & Vec2D) => void;\n onTransform?: (zoomableViewEventObject: ZoomableViewEvent) => void;\n onSingleTap?: (\n event: GestureResponderEvent,\n zoomableViewEventObject: ZoomableViewEvent\n ) => void;\n onDoubleTapBefore?: (\n event: GestureResponderEvent,\n zoomableViewEventObject: ZoomableViewEvent\n ) => void;\n onDoubleTapAfter?: (\n event: GestureResponderEvent,\n zoomableViewEventObject: ZoomableViewEvent\n ) => void;\n onShiftingBefore?: (\n event: GestureResponderEvent | null,\n gestureState: PanResponderGestureState | null,\n zoomableViewEventObject: ZoomableViewEvent\n ) => boolean;\n onShiftingAfter?: (\n event: GestureResponderEvent | null,\n gestureState: PanResponderGestureState | null,\n zoomableViewEventObject: ZoomableViewEvent\n ) => boolean;\n onShiftingEnd?: (\n event: GestureResponderEvent,\n gestureState: PanResponderGestureState,\n zoomableViewEventObject: ZoomableViewEvent\n ) => void;\n onZoomBefore?: (\n event: GestureResponderEvent | null,\n gestureState: PanResponderGestureState | null,\n zoomableViewEventObject: ZoomableViewEvent\n ) => boolean | undefined;\n onZoomAfter?: (\n event: GestureResponderEvent | null,\n gestureState: PanResponderGestureState | null,\n zoomableViewEventObject: ZoomableViewEvent\n ) => void;\n onZoomEnd?: (\n event: GestureResponderEvent,\n gestureState: PanResponderGestureState,\n zoomableViewEventObject: ZoomableViewEvent\n ) => void;\n onLongPress?: (\n event: GestureResponderEvent,\n gestureState: PanResponderGestureState,\n zoomableViewEventObject: ZoomableViewEvent\n ) => void;\n onStartShouldSetPanResponder?: (\n event: GestureResponderEvent,\n gestureState: PanResponderGestureState,\n zoomableViewEventObject: ZoomableViewEvent,\n baseComponentResult: boolean\n ) => boolean;\n onPanResponderGrant?: (\n event: GestureResponderEvent,\n gestureState: PanResponderGestureState,\n zoomableViewEventObject: ZoomableViewEvent\n ) => void;\n onPanResponderEnd?: (\n event: GestureResponderEvent,\n gestureState: PanResponderGestureState,\n zoomableViewEventObject: ZoomableViewEvent\n ) => void;\n onPanResponderMove?: (\n event: GestureResponderEvent,\n gestureState: PanResponderGestureState,\n zoomableViewEventObject: ZoomableViewEvent\n ) => boolean;\n onPanResponderTerminate?: (\n event: GestureResponderEvent,\n gestureState: PanResponderGestureState,\n zoomableViewEventObject: ZoomableViewEvent\n ) => void;\n onPanResponderTerminationRequest?: (\n event: GestureResponderEvent,\n gestureState: PanResponderGestureState,\n zoomableViewEventObject: ZoomableViewEvent\n ) => boolean;\n onShouldBlockNativeResponder?: (\n event: GestureResponderEvent,\n gestureState: PanResponderGestureState,\n zoomableViewEventObject: ZoomableViewEvent\n ) => boolean;\n onStartShouldSetPanResponderCapture?: (\n event: GestureResponderEvent,\n gestureState: PanResponderGestureState\n ) => boolean;\n onMoveShouldSetPanResponderCapture?: (\n event: GestureResponderEvent,\n gestureState: PanResponderGestureState\n ) => boolean;\n onStaticPinPress?: (event: GestureResponderEvent) => void;\n onStaticPinLongPress?: (event: GestureResponderEvent) => void;\n staticPinPosition?: Vec2D;\n staticPinIcon?: React.ReactElement;\n onStaticPinPositionChange?: (position: Vec2D) => void;\n onStaticPinPositionMove?: (position: Vec2D) => void;\n animatePin: boolean;\n pinProps?: ViewProps;\n disableMomentum?: boolean;\n}\n\nexport interface Vec2D {\n x: number;\n y: number;\n}\n\nexport interface Size2D {\n width: number;\n height: number;\n}\n\nexport interface TouchPoint extends Vec2D {\n id: string;\n isSecondTap?: boolean;\n}\n\nexport interface ReactNativeZoomableViewState {\n touches?: TouchPoint[];\n originalWidth: number;\n originalHeight: number;\n originalPageX: number;\n originalPageY: number;\n debugPoints?: undefined | Vec2D[];\n pinSize: Size2D;\n}\n\nexport interface ReactNativeZoomableViewWithGesturesProps\n extends ReactNativeZoomableViewProps {\n swipeLengthThreshold?: number;\n swipeVelocityThreshold?: number;\n swipeDirectionalThreshold?: number;\n swipeMinZoom?: number;\n swipeMaxZoom?: number;\n swipeDisabled?: boolean;\n onSwipe?: (\n swipeDirection: SwipeDirection,\n gestureState: PanResponderGestureState\n ) => void;\n onSwipeUp?: (gestureState: PanResponderGestureState) => void;\n onSwipeDown?: (gestureState: PanResponderGestureState) => void;\n onSwipeLeft?: (gestureState: PanResponderGestureState) => void;\n onSwipeRight?: (gestureState: PanResponderGestureState) => void;\n}\n"]} \ No newline at end of file diff --git a/lib/typescript/ReactNativeZoomableView.d.ts b/lib/typescript/ReactNativeZoomableView.d.ts index 418ead4..37b8b33 100644 --- a/lib/typescript/ReactNativeZoomableView.d.ts +++ b/lib/typescript/ReactNativeZoomableView.d.ts @@ -87,7 +87,7 @@ declare class ReactNativeZoomableView extends Component import { Animated, GestureResponderEvent, PanResponderGestureState, ViewProps } from 'react-native'; +import { ReactNode } from 'react'; export declare enum SwipeDirection { SWIPE_UP = "SWIPE_UP", SWIPE_DOWN = "SWIPE_DOWN", @@ -15,7 +15,9 @@ export interface ZoomableViewEvent { originalPageX: number; originalPageY: number; } -export interface ReactNativeZoomableViewProps extends ViewProps { +export interface ReactNativeZoomableViewProps { + style?: ViewProps['style']; + children?: ReactNode; zoomEnabled?: boolean; panEnabled?: boolean; initialZoom?: number; @@ -39,6 +41,7 @@ export interface ReactNativeZoomableViewProps extends ViewProps { zoomAnimatedValue?: Animated.Value; panAnimatedValueXY?: Animated.ValueXY; debug?: boolean; + onLayoutMeasured?: (size: Size2D & Vec2D) => void; onTransform?: (zoomableViewEventObject: ZoomableViewEvent) => void; onSingleTap?: (event: GestureResponderEvent, zoomableViewEventObject: ZoomableViewEvent) => void; onDoubleTapBefore?: (event: GestureResponderEvent, zoomableViewEventObject: ZoomableViewEvent) => void; diff --git a/package.json b/package.json index a4cf8c7..bda83a7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@openspacelabs/react-native-zoomable-view", - "version": "2.3.2", + "version": "2.4.0", "description": "A view component for react-native with pinch to zoom, tap to move and double tap to zoom capability.", "main": "lib/commonjs/index", "module": "lib/module/index", diff --git a/src/ReactNativeZoomableView.tsx b/src/ReactNativeZoomableView.tsx index 6291149..d333c36 100644 --- a/src/ReactNativeZoomableView.tsx +++ b/src/ReactNativeZoomableView.tsx @@ -302,6 +302,20 @@ class ReactNativeZoomableView extends Component< prevProps.staticPinPosition?.x !== this.props.staticPinPosition?.x || prevProps.staticPinPosition?.y !== this.props.staticPinPosition?.y; + // We use a custom `onLayout` event because: + // a) View's `onLayout` sometimes doesn't get called + // b) we use `measureInWindow` internally to keep track of layout changes + // When the client uses this, they can stay in-sync with the internal measurements, + // thus applying transformations at more accurate timings + if (originalMeasurementsChanged) { + this.props.onLayoutMeasured?.({ + width: currState.originalWidth, + height: currState.originalHeight, + x: currState.originalPageX, + y: currState.originalPageY, + }); + } + if ( this.onTransformInvocationInitialized && (originalMeasurementsChanged || staticPinPositionChanged) @@ -311,7 +325,7 @@ class ReactNativeZoomableView extends Component< } componentDidMount() { - this.grabZoomSubjectOriginalMeasurements(); + this.measureZoomSubject(); // We've already run `grabZoomSubjectOriginalMeasurements` at various events // to make sure the measurements are promptly updated. // However, there might be cases we haven't accounted for, especially when @@ -319,10 +333,7 @@ class ReactNativeZoomableView extends Component< // we'll use an interval here to ensure we're always up-to-date. // The `setState` in `grabZoomSubjectOriginalMeasurements` won't trigger a rerender // if the values given haven't changed, so we're not running performance risk here. - this.measureZoomSubjectInterval = setInterval( - this.grabZoomSubjectOriginalMeasurements, - 1e3 - ); + this.measureZoomSubjectInterval = setInterval(this.measureZoomSubject, 1e3); } componentWillUnmount() { @@ -381,7 +392,7 @@ class ReactNativeZoomableView extends Component< * * @private */ - private grabZoomSubjectOriginalMeasurements = () => { + private measureZoomSubject = () => { // make sure we measure after animations are complete requestAnimationFrame(() => { // this setTimeout is here to fix a weird issue on iOS where the measurements are all `0` @@ -1215,10 +1226,7 @@ class ReactNativeZoomableView extends Component< style={styles.container} {...this.gestureHandlers.panHandlers} ref={this.zoomSubjectWrapperRef} - onLayout={(event) => { - this.props.onLayout?.(event); - this.grabZoomSubjectOriginalMeasurements(); - }} + onLayout={this.measureZoomSubject} > void; onTransform?: (zoomableViewEventObject: ZoomableViewEvent) => void; onSingleTap?: ( event: GestureResponderEvent,