Skip to content

Commit

Permalink
Support doubleTapBehavior
Browse files Browse the repository at this point in the history
  • Loading branch information
bradstiff committed Feb 2, 2019
1 parent 650abb7 commit cda9bc8
Show file tree
Hide file tree
Showing 6 changed files with 37 additions and 12 deletions.
1 change: 1 addition & 0 deletions .npmignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ examples
.gitignore
.prettierignore
.vs
.vscode
webpack.config.js
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2018 Markus Englund
Copyright (c) 2018 - Present Brad Stiff

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,11 @@ Prop | Type | Default | Description
------------|-----------|-----------|--------------------------------------------------------------------------------------------------------------------
initialTop | number | 0 | The initial top coordinate of the image with respect to the container.
initialLeft | number | 0 | The initial left coordinate of the image wiht respect to the container.
initialScale| number | auto | The initial scale of the image. When `auto`, the image will be proportionally 'autofit' to the container.
minScale | number | auto | The minimum scale to which the image can be zoomed out. When `auto`, the minimum scale is the 'autofit' scale.
initialScale| number | 'auto' | The initial scale of the image. When `auto`, the image will be proportionally 'autofit' to the container.
minScale | number | 'auto' | The minimum scale to which the image can be zoomed out. When `auto`, the minimum scale is the 'autofit' scale.
maxScale | number | 1 | The maximum scale to which the image can be zoomed in.
zoomButtons | bool | true | Render plus (+) and minus (-) buttons on top of the image as another way to access the zoom feature.
doubleTapBehavior | 'reset' or 'zoom' | 'reset' | Whether to zoom in or reset to initial scale on double-click / double-tap.

## Development

Expand Down
2 changes: 1 addition & 1 deletion examples/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ const ExplicitContainerView = ({menu}) => (
<div>
<nav>{menu}</nav>
<main style={{ width: '500px', height: '500px' }}>
<PinchZoomPan>
<PinchZoomPan doubleTapBehavior='zoom'>
<img alt='Demo Image' src='http://picsum.photos/1000/1000?random' />
</PinchZoomPan>
</main>
Expand Down
37 changes: 30 additions & 7 deletions src/PinchZoomPan.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ export default class PinchZoomPan extends React.Component {

handleTouchEnd = (event) => {
if (event.touches && event.touches.length > 0) return null;
this.cancelAnimation();

//We allow transient +/-5% over-pinching.
//Animate the bounce back to constraints if applicable.
Expand All @@ -83,6 +84,7 @@ export default class PinchZoomPan extends React.Component {
}

handleMouseUp = (event) => {
this.cancelAnimation();
this.pointerUp(event.timeStamp);
if (this.mouseDown) {
this.mouseDown = false;
Expand Down Expand Up @@ -116,9 +118,17 @@ export default class PinchZoomPan extends React.Component {
}
}

handleZoomInClick = () => {
this.cancelAnimation();
this.zoomIn();
}

handleZoomOutClick = () => {
this.cancelAnimation();
this.zoomOut();
}

handleWindowResize = () => this.maybeHandleDimensionsChanged();
handleZoomInClick = () => this.zoomIn();
handleZoomOutClick = () => this.zoomOut();
suppressEvent = event => event.preventDefault();

handleRefImage = ref => {
Expand Down Expand Up @@ -164,13 +174,21 @@ export default class PinchZoomPan extends React.Component {

pointerUp(timeStamp) {
if (this.lastPointerUpTimeStamp && this.lastPointerUpTimeStamp + DOUBLE_TAP_THRESHOLD > timeStamp) {
//reset
this.applyInitialTransform(ANIMATION_SPEED);
this.doubleTap(this.lastPanPointerPosition);
}

this.lastPointerUpTimeStamp = timeStamp;
}

doubleTap(pointerPosition) {
if (String(this.props.doubleTapBehavior).toLowerCase() === 'zoom' && this.state.scale * (1 + OVERZOOM_TOLERANCE) < this.props.maxScale) {
this.zoomIn(pointerPosition, ANIMATION_SPEED, 0.3);
} else {
//reset
this.applyInitialTransform(ANIMATION_SPEED);
}
}

move(top, left, tolerance, speed = 0) {
if (!this.isTransformInitialized) {
return;
Expand All @@ -193,12 +211,12 @@ export default class PinchZoomPan extends React.Component {
this.lastPinchLength = length;
}

zoomIn(midpoint) {
zoomIn(midpoint, speed = 0, factor = 0.05) {
midpoint = midpoint || {
x: this.state.containerDimensions.width / 2,
y: this.state.containerDimensions.height / 2
};
this.zoom(this.state.scale * 1.05, midpoint, 0);
this.zoom(this.state.scale * (1 + factor), midpoint, 0, speed);
}

zoomOut(midpoint) {
Expand Down Expand Up @@ -293,7 +311,10 @@ export default class PinchZoomPan extends React.Component {
scale: snapToTarget(this.state.scale + (speed * translateScale), scale, SNAP_TOLERANCE),
};

this.setState(nextTransform, () => this.animation = requestAnimationFrame(frame));
//animation runs until we reach the target
if (!isEqualTransform(nextTransform, this.state)) {
this.setState(nextTransform, () => this.animation = requestAnimationFrame(frame));
}
};
this.animation = requestAnimationFrame(frame);
} else {
Expand Down Expand Up @@ -458,6 +479,7 @@ PinchZoomPan.defaultProps = {
minScale: 'auto',
maxScale: 1,
zoomButtons: true,
doubleTapBehavior: 'reset'
};

PinchZoomPan.propTypes = {
Expand All @@ -474,4 +496,5 @@ PinchZoomPan.propTypes = {
]),
maxScale: PropTypes.number,
zoomButtons: PropTypes.bool,
doubleTapBehavior: PropTypes.oneOf(['reset', 'zoom']),
};
2 changes: 1 addition & 1 deletion src/Utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ export const getMinScale = createSelector(
state => state.imageDimensions,
(state, props) => props.minScale,
(containerDimensions, imageDimensions, minScaleProp) =>
minScaleProp === 'auto'
String(minScaleProp).toLowerCase() === 'auto'
? calculateAutofitScale(containerDimensions, imageDimensions)
: minScaleProp || 1
)
Expand Down

0 comments on commit cda9bc8

Please sign in to comment.