Skip to content
This repository has been archived by the owner on Nov 30, 2022. It is now read-only.

Commit

Permalink
Merge pull request #6 from DuDigital/improve-pinch-to-zoom
Browse files Browse the repository at this point in the history
improved pinch2zoom and added pinch and movement sensitivity
  • Loading branch information
Simon Auer authored Oct 12, 2018
2 parents 134c39f + d82db93 commit 57c65b8
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 11 deletions.
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,10 @@ These options can be used to limit and change the zoom behavior.
| doubleTapDelay | number | How much delay will still be recognized as double press (ms) | 300 |
| bindToBorders | boolean | If true, it makes sure the object stays within box borders | true |
| zoomStep | number | How much zoom should be applied on double tap | 0.5 |

| pinchToZoomInSensitivity | number | the level of resistance (sensitivity) to zoom in (0 - 10) - higher is less sensitive | 3 |
| pinchToZoomOutSensitivity | number | the level of resistance (sensitivity) to zoom out (0 - 10) - higher is less sensitive | 1 |
| zoomCenteringLevelDistance | number | the (zoom level - 0 - maxZoom) distance for pinch to zoom actions until they are shifted on new pinch to zoom center - higher means it centeres slower | 0.5 |
| movementSensibility | number | how resistant should shifting the view around be? (0.5 - 5) - higher is less sensitive | 1.9 |

#### Events

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@dudigital/react-native-zoomable-view",
"version": "1.0.9",
"version": "1.0.10",
"description": "A view component for react-native with pinch to zoom, tap to move and double tap to zoom capability.",
"main": "index.js",
"scripts": {
Expand Down
54 changes: 45 additions & 9 deletions src/ReactNativeZoomableView.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,12 @@ class ReactNativeZoomableView extends Component {
});
}

/**
* Current position of zoom center
* @type { x: number, y: number }
*/
pinchZoomPosition = null;

/**
* Returns additional information about components current state for external event hooks
*
Expand Down Expand Up @@ -155,6 +161,7 @@ class ReactNativeZoomableView extends Component {

if (this.gestureType === 'pinch') {
if (this.props.onZoomEnd) {
this.pinchZoomPosition = null;
this.props.onZoomEnd(e, gestureState, this._getZoomableViewEventObject());
}
} else if (this.gestureType === 'shift') {
Expand Down Expand Up @@ -309,7 +316,7 @@ class ReactNativeZoomableView extends Component {
* @private
*/
_handlePinching = (e, gestureState) => {
const { maxZoom, minZoom } = this.props;
const { maxZoom, minZoom, zoomCenteringLevelDistance, pinchToZoomInSensitivity, pinchToZoomOutSensitivity } = this.props;

let dx = Math.abs(e.nativeEvent.touches[0].pageX - e.nativeEvent.touches[1].pageX);
let dy = Math.abs(e.nativeEvent.touches[0].pageY - e.nativeEvent.touches[1].pageY);
Expand All @@ -321,7 +328,12 @@ class ReactNativeZoomableView extends Component {
}
}

let zoomLevel = distant / this.distance * this.state.lastZoomLevel;
// define the new zoom level and take zoom level sensitivity into consideration
const zoomChangeFromStartOfPinch = (distant / this.distance);
const pinchToZoomSensitivity = (zoomChangeFromStartOfPinch < 1) ? pinchToZoomOutSensitivity : pinchToZoomInSensitivity;
let zoomLevel = ((zoomChangeFromStartOfPinch * this.state.lastZoomLevel) + this.state.lastZoomLevel * pinchToZoomSensitivity) / (pinchToZoomSensitivity + 1);

// make sure max and min zoom levels are respected
if (maxZoom !== null && zoomLevel > maxZoom) {
zoomLevel = maxZoom;
}
Expand All @@ -330,12 +342,26 @@ class ReactNativeZoomableView extends Component {
zoomLevel = minZoom;
}

// only use the first position we get by pinching, or the screen will "wobble" during zoom action
if (this.pinchZoomPosition === null) {
const pinchToZoomCenterX = Math.min(e.nativeEvent.touches[ 0 ].pageX, e.nativeEvent.touches[ 1 ].pageX) + ( dx / 2 );
const pinchToZoomCenterY = Math.min(e.nativeEvent.touches[ 0 ].pageY, e.nativeEvent.touches[ 1 ].pageY) + ( dy / 2 );

this.pinchZoomPosition = this._getOffsetAdjustedPosition(pinchToZoomCenterX, pinchToZoomCenterY);
}

// make sure we shift the layer slowly during our zoom movement
const zoomStage = Math.abs(zoomLevel - this.state.lastZoomLevel) / zoomCenteringLevelDistance;

const ratioOffsetX = this.state.lastX + zoomStage * this.pinchZoomPosition.x;
const ratioOffsetY = this.state.lastY + zoomStage * this.pinchZoomPosition.y;

// define the changeObject and make sure the offset values are bound to view
const changeStateObj = this._bindOffsetValuesToBorders({
zoomLevel,
lastMovePinch: true,
offsetX: this.state.lastX,
offsetY: this.state.lastY,
offsetX: ratioOffsetX,
offsetY: ratioOffsetY,
}, null);

this.setState(changeStateObj, () => {
Expand All @@ -354,13 +380,15 @@ class ReactNativeZoomableView extends Component {
* @private
*/
_handleMovement = (e, gestureState) => {
if (this.state.lastMovePinch) {
gestureState.dx = 0;
gestureState.dy = 0;
const { movementSensibility } = this.props;

// make sure not to accidentally move after pinch to zoom
if (this.pinchZoomPosition) {
return;
}

let offsetX = this.state.lastX + gestureState.dx / this.state.zoomLevel;
let offsetY = this.state.lastY + gestureState.dy / this.state.zoomLevel;
let offsetX = this.state.lastX + gestureState.dx / this.state.zoomLevel / movementSensibility;
let offsetY = this.state.lastY + gestureState.dy / this.state.zoomLevel / movementSensibility;

if (this.props.onShiftingBefore) {
if (this.props.onShiftingBefore(e, gestureState, this._getZoomableViewEventObject())) {
Expand Down Expand Up @@ -546,6 +574,10 @@ ReactNativeZoomableView.propTypes = {
initialZoom: PropTypes.number,
maxZoom: PropTypes.number,
minZoom: PropTypes.number,
pinchToZoomInSensitivity: PropTypes.number, // the level of resistance (sensitivity) to zoom in (0 - 10) - higher is less sensitive - default: 3
pinchToZoomOutSensitivity: PropTypes.number, // the level of resistance (sensitivity) to zoom out (0 - 10) - higher is less sensitive default: 1
zoomCenteringLevelDistance: PropTypes.number, // the (zoom level - 0 - maxZoom) distance for pinch to zoom actions until they are shifted on new pinch to zoom center - higher means it centeres slower - default 0.5
movementSensibility: PropTypes.number, // how resistant should shifting the view around be? (0.5 - 5) - higher is less sensitive - default: 1.9
doubleTapDelay: PropTypes.number, // how much delay will still be recognized as double press
bindToBorders: PropTypes.bool, // makes sure that the object stays within box borders
zoomStep: PropTypes.number, // how much zoom should be applied on double tap
Expand All @@ -569,6 +601,10 @@ ReactNativeZoomableView.defaultProps = {
initialZoom: 1,
maxZoom: 1.5,
minZoom: 0.5,
pinchToZoomInSensitivity: 3,
pinchToZoomOutSensitivity: 1,
zoomCenteringLevelDistance: 0.5,
movementSensibility: 1.9,
doubleTapDelay: 300,
bindToBorders: true,
zoomStep: 0.5,
Expand Down

0 comments on commit 57c65b8

Please sign in to comment.