From e740edf4cf898ccd0971c3bac859e064f316289e Mon Sep 17 00:00:00 2001 From: Miguel Araujo Perez Date: Wed, 31 Aug 2016 10:15:28 +0200 Subject: [PATCH 1/6] Added feature enableLimits Activating this prop, the view cannot be moved out of viewport. This is the typical default behavior in any native photoview library. --- library/transform/ViewTransformer.js | 80 ++++++++++++++++++++++++++-- 1 file changed, 77 insertions(+), 3 deletions(-) diff --git a/library/transform/ViewTransformer.js b/library/transform/ViewTransformer.js index 9c4e738..a6292cc 100644 --- a/library/transform/ViewTransformer.js +++ b/library/transform/ViewTransformer.js @@ -138,6 +138,10 @@ export default class ViewTransformer extends React.Component { } this.measureLayout(); + if (this.props.enableLimits) { + setTimeout(() => this.animateBounce(), 1); + } + this.props.onLayout && this.props.onLayout(e); } @@ -167,7 +171,12 @@ export default class ViewTransformer extends React.Component { let dx = gestureState.moveX - gestureState.previousMoveX; let dy = gestureState.moveY - gestureState.previousMoveY; - if (this.props.enableResistance) { + + if (this.props.enableLimits) { + let d = this.applyLimits(dx, dy); + dx = d.dx; + dy = d.dy; + } else if (this.props.enableResistance) { let d = this.applyResistance(dx, dy); dx = d.dx; dy = d.dy; @@ -334,6 +343,69 @@ export default class ViewTransformer extends React.Component { } } + applyLimits(dx, dy) { + let availablePanDistance = availableTranslateSpace( + this.transformedContentRect(), + this.viewPortRect() + ); + + // Calculate until where can the view be moved + // This depends if the view is bigger / smaller than the viewport + if (this.transformedContentRect().width() < this.viewPortRect().width()) { + if ( + dx < 0 && + this.transformedContentRect().left + dx < this.viewPortRect().left + ) { + dx = availablePanDistance.left; + } else if ( + dx > 0 && + this.transformedContentRect().right + dx > this.viewPortRect().right + ) { + dx = -availablePanDistance.right; + } + } else { + if ( + dx < 0 && + this.transformedContentRect().right + dx < this.viewPortRect().right + ) { + dx = -availablePanDistance.right; + } else if ( + dx > 0 && + this.transformedContentRect().left + dx > this.viewPortRect().left + ) { + dx = availablePanDistance.left; + } + } + + if (this.transformedContentRect().height() < this.viewPortRect().height()) { + if ( + dy > 0 && + this.transformedContentRect().bottom + dy > this.viewPortRect().bottom + ) { + dy = -availablePanDistance.bottom; + } else if ( + dy < 0 && + this.transformedContentRect().top + dy < this.viewPortRect().top + ) { + dy = availablePanDistance.top; + } + } else { + if ( + dy > 0 && + this.transformedContentRect().top + dy > this.viewPortRect().top + ) { + dy = availablePanDistance.top; + } else if ( + dy < 0 && + this.transformedContentRect().bottom + dy < this.viewPortRect().bottom + ) { + dy = -availablePanDistance.bottom; + } + } + + return { dx, dy } + } + cancelAnimation() { this.state.animator.stopAnimation(); } @@ -442,6 +514,7 @@ ViewTransformer.propTypes = { * Use true to enable resistance effect on over pulling. Default is false. */ enableResistance: React.PropTypes.bool, + enableLimits: React.PropTypes.bool, onViewTransformed: React.PropTypes.func, @@ -453,5 +526,6 @@ ViewTransformer.defaultProps = { enableTranslate: true, enableTransform: true, maxScale: 1, - enableResistance: false -}; \ No newline at end of file + enableResistance: false, + enableLimits: false, +}; From 6aeb862d7d1473ce17a15f565f1e95463ec527ce Mon Sep 17 00:00:00 2001 From: Miguel Araujo Perez Date: Wed, 31 Aug 2016 10:22:03 +0200 Subject: [PATCH 2/6] Adjusted README for enableLimits --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 7046396..9dd32a2 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,8 @@ This component accepts following props: * `enableScale` : false to disable scale. Default is true. * `enableTranslate` : false to disable translateX/Y. Default is true. * `maxScale` : a number. Default is 1. -* `enableResistance` : true to resist over pan. Defaul is false. +* `enableResistance` : true to resist over pan. Default is false. +* `enableLimits` : true so that the view cannot be moved out of its viewport. Default is false. * `maxOverScrollDistance` : a number used to determine final scroll position triggered by fling. Default is 20. * `onViewTransformed` : a callback called when transform changed, receiving current transform object, {scale: xxx, translateX: xxx, translateY: xxx}. * `onTransformGestureReleased` : a callback called when the transform gesture is released, receiving current transform object, {scale: xxx, translateX: xxx, translateY: xxx}. Return true to abort further animations like bounce back. From 42f448118ebc920272f97a66ed5729fe684c5e33 Mon Sep 17 00:00:00 2001 From: Miguel Araujo Perez Date: Wed, 31 Aug 2016 10:48:50 +0200 Subject: [PATCH 3/6] Added initialScale prop Sets the initial scale to be used, and allow cover mode to work in react-native-transformable-image https://github.com/ldn0x7dc/react-native-transformable-image/pull/11 --- library/transform/ViewTransformer.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/library/transform/ViewTransformer.js b/library/transform/ViewTransformer.js index a6292cc..899751e 100644 --- a/library/transform/ViewTransformer.js +++ b/library/transform/ViewTransformer.js @@ -19,9 +19,10 @@ export default class ViewTransformer extends React.Component { constructor(props) { super(props); + this.state = { //transform state - scale: 1, + scale: props.initialScale, translateX: 0, translateY: 0, @@ -507,6 +508,7 @@ ViewTransformer.propTypes = { */ maxOverScrollDistance: React.PropTypes.number, + initialScale: React.PropTypes.number, maxScale: React.PropTypes.number, contentAspectRatio: React.PropTypes.number, @@ -525,6 +527,7 @@ ViewTransformer.defaultProps = { enableScale: true, enableTranslate: true, enableTransform: true, + initialScale: 1, maxScale: 1, enableResistance: false, enableLimits: false, From 6bcc35df8fc3cf0190cdd0182390ca49a5c2f60a Mon Sep 17 00:00:00 2001 From: Miguel Araujo Perez Date: Thu, 8 Sep 2016 13:10:13 +0200 Subject: [PATCH 4/6] Remove animateBounce and some coding style changes --- library/transform/ViewTransformer.js | 24 +++++++----------------- 1 file changed, 7 insertions(+), 17 deletions(-) diff --git a/library/transform/ViewTransformer.js b/library/transform/ViewTransformer.js index 899751e..1b24a55 100644 --- a/library/transform/ViewTransformer.js +++ b/library/transform/ViewTransformer.js @@ -134,15 +134,11 @@ export default class ViewTransformer extends React.Component { onLayout(e) { const {width, height} = e.nativeEvent.layout; - if(width !== this.state.width || height !== this.state.height) { + if (width !== this.state.width || height !== this.state.height) { this.setState({width, height}); } this.measureLayout(); - if (this.props.enableLimits) { - setTimeout(() => this.animateBounce(), 1); - } - this.props.onLayout && this.props.onLayout(e); } @@ -194,13 +190,12 @@ export default class ViewTransformer extends React.Component { let pivotY = gestureState.moveY - this.state.pageY; - let rect = transformedRect(transformedRect(this.contentRect(), this.currentTransform()), new Transform( - scaleBy, dx, dy, - { - x: pivotX, - y: pivotY - } - )); + let rect = transformedRect( + transformedRect(this.contentRect(), this.currentTransform()), + new Transform( + scaleBy, dx, dy, { x: pivotX, y: pivotY } + ) + ); transform = getTransform(this.contentRect(), rect); } else { if (Math.abs(dx) > 2 * Math.abs(dy)) { @@ -251,11 +246,6 @@ export default class ViewTransformer extends React.Component { } } - - - - - performFling(vx, vy) { let startX = 0; let startY = 0; From 2b04269f6a1aab37d44662909c0ab0691708e927 Mon Sep 17 00:00:00 2001 From: Miguel Araujo Perez Date: Wed, 28 Sep 2016 14:50:18 +0200 Subject: [PATCH 5/6] initialScale can change now --- library/transform/ViewTransformer.js | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/library/transform/ViewTransformer.js b/library/transform/ViewTransformer.js index 1b24a55..b392a9e 100644 --- a/library/transform/ViewTransformer.js +++ b/library/transform/ViewTransformer.js @@ -55,6 +55,12 @@ export default class ViewTransformer extends React.Component { }); } + componentWillReceiveProps(nextProps) { + if (this.props.initialScale != nextProps.initialScale) { + this.updateTransform({ scale: nextProps.initialScale }) + } + } + viewPortRect() { this._viewPortRect.set(0, 0, this.state.width, this.state.height); return this._viewPortRect; @@ -116,16 +122,18 @@ export default class ViewTransformer extends React.Component { {...this.props} {...gestureResponder} ref={'innerViewRef'} - onLayout={this.onLayout.bind(this)}> + onLayout={this.onLayout.bind(this)} + > + {scale: this.state.scale}, + {translateX: this.state.translateX}, + {translateY: this.state.translateY}, + ] + }} + > {this.props.children} From 755dfcd09ea01d75244728e69c63d9c89ef69a5c Mon Sep 17 00:00:00 2001 From: Miguel Araujo Perez Date: Mon, 12 Feb 2018 18:10:52 +0100 Subject: [PATCH 6/6] Use separate prop-types --- library/transform/ViewTransformer.js | 48 +++++++++++++--------------- 1 file changed, 22 insertions(+), 26 deletions(-) diff --git a/library/transform/ViewTransformer.js b/library/transform/ViewTransformer.js index b392a9e..b4d9ea7 100644 --- a/library/transform/ViewTransformer.js +++ b/library/transform/ViewTransformer.js @@ -1,6 +1,7 @@ 'use strict'; import React from 'react'; +import PropTypes from 'prop-types'; import ReactNative, { View, Animated, @@ -55,12 +56,6 @@ export default class ViewTransformer extends React.Component { }); } - componentWillReceiveProps(nextProps) { - if (this.props.initialScale != nextProps.initialScale) { - this.updateTransform({ scale: nextProps.initialScale }) - } - } - viewPortRect() { this._viewPortRect.set(0, 0, this.state.width, this.state.height); return this._viewPortRect; @@ -95,7 +90,10 @@ export default class ViewTransformer extends React.Component { onResponderGrant: this.onResponderGrant.bind(this), onResponderRelease: this.onResponderRelease.bind(this), onResponderTerminate: this.onResponderRelease.bind(this), - onResponderTerminationRequest: (evt, gestureState) => false //Do not allow parent view to intercept gesture + onResponderTerminationRequest: (evt, gestureState) => false, //Do not allow parent view to intercept gesture + onResponderSingleTapConfirmed: (evt, gestureState) => { + this.props.onSingleTapConfirmed && this.props.onSingleTapConfirmed(); + } }); } @@ -122,18 +120,16 @@ export default class ViewTransformer extends React.Component { {...this.props} {...gestureResponder} ref={'innerViewRef'} - onLayout={this.onLayout.bind(this)} - > + onLayout={this.onLayout.bind(this)}> + {scale: this.state.scale}, + {translateX: this.state.translateX}, + {translateY: this.state.translateY} + ] + }}> {this.props.children} @@ -489,36 +485,36 @@ ViewTransformer.propTypes = { /** * Use false to disable transform. Default is true. */ - enableTransform: React.PropTypes.bool, + enableTransform: PropTypes.bool, /** * Use false to disable scaling. Default is true. */ - enableScale: React.PropTypes.bool, + enableScale: PropTypes.bool, /** * Use false to disable translateX/translateY. Default is true. */ - enableTranslate: React.PropTypes.bool, + enableTranslate: PropTypes.bool, /** * Default is 20 */ - maxOverScrollDistance: React.PropTypes.number, + maxOverScrollDistance: PropTypes.number, - initialScale: React.PropTypes.number, - maxScale: React.PropTypes.number, - contentAspectRatio: React.PropTypes.number, + initialScale: PropTypes.number, + maxScale: PropTypes.number, + contentAspectRatio: PropTypes.number, /** * Use true to enable resistance effect on over pulling. Default is false. */ - enableResistance: React.PropTypes.bool, - enableLimits: React.PropTypes.bool, + enableResistance: PropTypes.bool, + enableLimits: PropTypes.bool, - onViewTransformed: React.PropTypes.func, + onViewTransformed: PropTypes.func, - onTransformGestureReleased: React.PropTypes.func + onTransformGestureReleased: PropTypes.func }; ViewTransformer.defaultProps = { maxOverScrollDistance: 20,