react-easy-panzoom
Advanced tools
Comparing version 0.1.1 to 0.2.0
@@ -36,3 +36,2 @@ "use strict"; | ||
// TODO support minZoom, maxZoom | ||
var PanZoom = | ||
@@ -85,2 +84,4 @@ /*#__PURE__*/ | ||
_defineProperty(_assertThisInitialized(_this), "onMouseDown", function (e) { | ||
var preventPan = _this.props.preventPan; | ||
if (_this.props.disabled) { | ||
@@ -103,6 +104,9 @@ return; | ||
_this.panning = true; | ||
var offset = _this.getOffset(e); // check if there is nothing preventing the pan | ||
var offset = _this.getOffset(e); | ||
if (preventPan(e, offset.x, offset.y)) { | ||
return; | ||
} | ||
_this.mousePos = { | ||
@@ -112,2 +116,3 @@ x: offset.x, | ||
}; | ||
_this.panning = true; | ||
@@ -232,4 +237,4 @@ _this.setMouseListeners(); // Prevent text selection | ||
if (mappedCoords) { | ||
var x = mappedCoords.x, | ||
y = mappedCoords.y, | ||
var _x = mappedCoords.x, | ||
_y = mappedCoords.y, | ||
z = mappedCoords.z; | ||
@@ -239,3 +244,3 @@ e.preventDefault(); | ||
if (x || y) { | ||
if (_x || _y) { | ||
var containerRect = _this.container.getBoundingClientRect(); | ||
@@ -245,4 +250,4 @@ | ||
var moveSpeedRatio = 0.05; | ||
var dx = offset * moveSpeedRatio * x; | ||
var dy = offset * moveSpeedRatio * y; | ||
var dx = offset * moveSpeedRatio * _x; | ||
var dy = offset * moveSpeedRatio * _y; | ||
@@ -253,7 +258,3 @@ _this.moveBy(dx, dy); | ||
if (z) { | ||
var scaleMultiplier = _this.getScaleMultiplier(z); | ||
var _containerRect = _this.container.getBoundingClientRect(); | ||
_this.zoomTo(_containerRect.width / 2, _containerRect.height / 2, scaleMultiplier); | ||
_this.centeredZoom(z); | ||
} | ||
@@ -468,2 +469,5 @@ } | ||
_defineProperty(_assertThisInitialized(_this), "zoomTo", function (x, y, ratio) { | ||
var _this$props2 = _this.props, | ||
minZoom = _this$props2.minZoom, | ||
maxZoom = _this$props2.maxZoom; | ||
var _this$state = _this.state, | ||
@@ -474,2 +478,19 @@ transformX = _this$state.x, | ||
var newScale = scale * ratio; | ||
if (newScale < minZoom) { | ||
if (scale === minZoom) { | ||
return; | ||
} | ||
ratio = minZoom / scale; | ||
newScale = minZoom; | ||
} else if (newScale > maxZoom) { | ||
if (scale === maxZoom) { | ||
return; | ||
} | ||
ratio = maxZoom / scale; | ||
newScale = maxZoom; | ||
} | ||
var newX = x - ratio * (x - transformX); | ||
@@ -485,2 +506,18 @@ var newY = y - ratio * (y - transformY); | ||
_defineProperty(_assertThisInitialized(_this), "centeredZoom", function (delta) { | ||
var scaleMultiplier = _this.getScaleMultiplier(delta); | ||
var containerRect = _this.container.getBoundingClientRect(); | ||
_this.zoomTo(containerRect.width / 2, containerRect.height / 2, scaleMultiplier); | ||
}); | ||
_defineProperty(_assertThisInitialized(_this), "zoomIn", function () { | ||
_this.centeredZoom(-1); | ||
}); | ||
_defineProperty(_assertThisInitialized(_this), "zoomOut", function () { | ||
_this.centeredZoom(1); | ||
}); | ||
_defineProperty(_assertThisInitialized(_this), "getOffset", function (e) { | ||
@@ -503,6 +540,12 @@ var containerRect = _this.container.getBoundingClientRect(); | ||
value: function componentDidMount() { | ||
var _this$props2 = this.props, | ||
autoCenter = _this$props2.autoCenter, | ||
autoCenterZoomLevel = _this$props2.autoCenterZoomLevel; | ||
var _this$props3 = this.props, | ||
autoCenter = _this$props3.autoCenter, | ||
autoCenterZoomLevel = _this$props3.autoCenterZoomLevel, | ||
minZoom = _this$props3.minZoom, | ||
maxZoom = _this$props3.maxZoom; | ||
if (maxZoom < minZoom) { | ||
throw new Error('[PanZoom]: maxZoom props cannot be inferior to minZoom'); | ||
} | ||
if (autoCenter) { | ||
@@ -531,7 +574,7 @@ this.autoCenter(autoCenterZoomLevel); | ||
var _this$props3 = this.props, | ||
children = _this$props3.children, | ||
style = _this$props3.style, | ||
disabled = _this$props3.disabled, | ||
disableKeyInteraction = _this$props3.disableKeyInteraction; | ||
var _this$props4 = this.props, | ||
children = _this$props4.children, | ||
style = _this$props4.style, | ||
disabled = _this$props4.disabled, | ||
disableKeyInteraction = _this$props4.disableKeyInteraction; | ||
var _this$state2 = this.state, | ||
@@ -575,5 +618,10 @@ x = _this$state2.x, | ||
zoomSpeed: 1, | ||
doubleZoomSpeed: 1.75 | ||
doubleZoomSpeed: 1.75, | ||
minZoom: 0, | ||
maxZoom: Infinity, | ||
preventPan: function preventPan() { | ||
return false; | ||
} | ||
}; | ||
var _default = PanZoom; | ||
exports.default = _default; |
{ | ||
"name": "react-easy-panzoom", | ||
"version": "0.1.1", | ||
"version": "0.2.0", | ||
"description": "Wrapper to enable pan and zoom for any React component", | ||
@@ -30,3 +30,5 @@ "main": "./lib/index.js", | ||
"zoom", | ||
"panzoom" | ||
"panzoom", | ||
"auto center", | ||
"keyboard zoom" | ||
], | ||
@@ -33,0 +35,0 @@ "peerDependencies": { |
# react-easy-panzoom | ||
__🚧 Please be advised that this library is currently under construction and might change quickly 🚧__ | ||
Wrapper to enable pan and zoom features for any React component | ||
React components that enables pan and zoom features for any component. | ||
@@ -35,3 +34,3 @@ ## Installation | ||
### Key mapping | ||
`PanZoom` component natively supports keyboard interactions with arrow keys and `-` / `+` keys. This mapping can be extends using `keyMapping` props. | ||
`PanZoom` component natively supports keyboard interactions with arrow keys and `-` / `+` keys. This mapping can be extends using the `keyMapping` prop. | ||
@@ -59,2 +58,43 @@ e.g. Mapping `w`, `a`, `s`, `d`: | ||
### Prevent pan | ||
Sometimes it can be useful to prevent the view from panning, for example if the pan start is done on a clickable element. | ||
`PanZoom` provides the `preventPan` prop that let you define a function to prevent panning. | ||
e.g. prevent panning when starting the pan on a specific `div` | ||
```js | ||
content = null | ||
// preventPan gives access to the event, as well as the | ||
// mouse coordinates in the coordinate system of the PanZoom container | ||
preventPan = (event, x, y) => { | ||
// if the target is the content container then prevent panning | ||
if (e.target === content) { | ||
return true | ||
} | ||
// in the case the target is not the content container | ||
// use the coordinates to determine if the click happened | ||
// on the content container | ||
const contentRect = content.getBoundingClientRect() | ||
const x1 = contentRect.left | ||
const x2 = contentRect.right | ||
const y1 = contentRect.top | ||
const y2 = contentRect.bottom | ||
return (x >= x1 && x <= x2) && (y >= y1 && y <= y2) | ||
} | ||
render() { | ||
return ( | ||
<PanZoom | ||
preventPan={this.preventPan} | ||
> | ||
<div>{ 'This content can be panned and zoomed' }</div> | ||
<div ref={ref => this.content = ref}>{ 'This content can be panned and zoomed only outside of its container' }</div> | ||
</PanZoom> | ||
) | ||
} | ||
``` | ||
## Properties | ||
@@ -71,5 +111,8 @@ |Name|Type|Default|Description| | ||
|keyMapping|`object`|false|Define specific key mapping for keyboard interaction (e.g. `{ '<keyCode>': { x: 0, y: 1, z: 0 } }`, with `<keyCode>` being the key code to map)| | ||
|minZoom|`number`| |Sets the minimum zoom value| | ||
|maxZoom|`number`| |Sets the maximum zoom value| | ||
|onPanStart|`func`| |Fired on pan start| | ||
|onPan|`func`| |Fired on pan| | ||
|onPanEnd|`func`| |Fired on pan end| | ||
|preventPan|`func`| |Defines a function to prevent pan| | ||
|style|`object`| |Override the inline-styles of the root element| | ||
@@ -76,0 +119,0 @@ |
@@ -13,2 +13,5 @@ // @flow | ||
keyMapping?: { [string]: { x: number, y: number, z: number }}, | ||
minZoom?: number, | ||
maxZoom?: number, | ||
preventPan?: (event: SyntheticEvent, x: number, y: number) => boolean, | ||
@@ -20,3 +23,2 @@ onPanStart?: (any) => void, | ||
// TODO support minZoom, maxZoom | ||
class PanZoom extends React.Component<Props> { | ||
@@ -41,3 +43,6 @@ | ||
componentDidMount(): void { | ||
const { autoCenter, autoCenterZoomLevel } = this.props | ||
const { autoCenter, autoCenterZoomLevel, minZoom, maxZoom } = this.props | ||
if (maxZoom < minZoom) { | ||
throw new Error('[PanZoom]: maxZoom props cannot be inferior to minZoom') | ||
} | ||
if (autoCenter) { | ||
@@ -68,2 +73,3 @@ this.autoCenter(autoCenterZoomLevel) | ||
onMouseDown = (e) => { | ||
const { preventPan } = this.props | ||
if (this.props.disabled) { | ||
@@ -85,5 +91,9 @@ return | ||
this.panning = true | ||
const offset = this.getOffset(e) | ||
const offset = this.getOffset(e) | ||
// check if there is nothing preventing the pan | ||
if (preventPan(e, offset.x, offset.y)) { | ||
return | ||
} | ||
this.mousePos = { | ||
@@ -94,2 +104,4 @@ x: offset.x, | ||
this.panning = true | ||
this.setMouseListeners() | ||
@@ -182,5 +194,3 @@ | ||
if (z) { | ||
const scaleMultiplier = this.getScaleMultiplier(z) | ||
const containerRect = this.container.getBoundingClientRect() | ||
this.zoomTo(containerRect.width / 2, containerRect.height / 2, scaleMultiplier) | ||
this.centeredZoom(z) | ||
} | ||
@@ -366,4 +376,21 @@ } | ||
zoomTo = (x, y, ratio) => { | ||
const { minZoom, maxZoom } = this.props | ||
const { x: transformX, y: transformY, scale } = this.state | ||
const newScale = scale * ratio | ||
let newScale = scale * ratio | ||
if (newScale < minZoom) { | ||
if (scale === minZoom) { | ||
return | ||
} | ||
ratio = minZoom / scale | ||
newScale = minZoom | ||
} | ||
else if (newScale > maxZoom) { | ||
if (scale === maxZoom) { | ||
return | ||
} | ||
ratio = maxZoom / scale | ||
newScale = maxZoom | ||
} | ||
const newX = x - ratio * (x - transformX) | ||
@@ -374,2 +401,16 @@ const newY = y - ratio * (y - transformY) | ||
centeredZoom = (delta) => { | ||
const scaleMultiplier = this.getScaleMultiplier(delta) | ||
const containerRect = this.container.getBoundingClientRect() | ||
this.zoomTo(containerRect.width / 2, containerRect.height / 2, scaleMultiplier) | ||
} | ||
zoomIn = () => { | ||
this.centeredZoom(-1) | ||
} | ||
zoomOut = () => { | ||
this.centeredZoom(1) | ||
} | ||
getOffset = (e) => { | ||
@@ -418,4 +459,8 @@ const containerRect = this.container.getBoundingClientRect() | ||
doubleZoomSpeed: 1.75, | ||
minZoom: 0, | ||
maxZoom: Infinity, | ||
preventPan: () => false, | ||
} | ||
export default PanZoom |
38235
880
125