bettertyped / react-zoom-pan-pinch Goto Github PK
View Code? Open in Web Editor NEW🖼 React library to support easy zoom, pan, pinch on various html dom elements like <img> and <div>
License: MIT License
🖼 React library to support easy zoom, pan, pinch on various html dom elements like <img> and <div>
License: MIT License
Purpose:
Double-click image zoom in
Single-click image zoom out / reset
So if I load a big image (like 2000x2000) into TransformWrapper
it doesn't work as expected. Slow zoom, incorrect pan. I tried use minScale
or put it into overflow: auto
and it doesn't help. Any ideas?
Sometimes when using zoomIn/zoomOut/resetTransform app crashes. Noticed it when updating version 1.4.5 to 1.5.5
TypeError: Failed to execute 'requestAnimationFrame' on 'Window': The callback provided as parameter 1 is not a function.
this.animation = () => {
if (!this.animation || !this.mounted) return;
const frameTime = new Date().getTime() - startTime;
const animationProgress = frameTime / animationTime;
const animationType = availableAnimations[animationName];
const step = animationType(animationProgress);
if (frameTime >= animationTime) {
callback(lastStep);
this.animation = null;
} else {
callback(step);
requestAnimationFrame(this.animation); << CRASHES HERE
}
};
I am working on a project where I would like to provide zooming and panning for images that could be of any size. I have set a size on a div inside of the TransformWrapper
to restrict the zooming and panning area to within the width and height of the screen. However, sometimes the images inside the TransformComponent
can be larger than the screen. In this scenario, it seems to center the images within the larger element rather than the smaller one, causing parts of the image to not be reachable within the zooming area.
It is important for me to initially show the user the image at the original size so scaling them down is not really an option.
Below is an example using divs that reproduces the error. See the issue in code sandbox
import React from 'react';
import { TransformWrapper, TransformComponent } from "react-zoom-pan-pinch";
export default function Example(){
return (
<TransformWrapper
defaultScale={0.3}
options={{
minScale: 0.1,
// false for centerContent does not seem to work except at initial render?
// centerContent: false
// true seems to center it with the TransformComponent-module_container__XXX
// which causes it to be off-center
centerContent: true
}}>
{({ zoomIn, zoomOut, resetTransform, ...rest }) => (
<React.Fragment>
<div style={{textAlign: 'left'}}>
<div>Orange = Zooming Area; Blue = Object being zoomed</div>
<button onClick={zoomIn}>+</button>
<button onClick={zoomOut}>-</button>
<button onClick={resetTransform}>x</button>
</div>
{/* Set zooming area size. Tried with sizing div outside/inside/inside and outside of TransformComponent */}
<div style={{height: 510, width: 510, backgroundColor: 'orange', border: '10px solid green'}}>
<TransformComponent>
{/* Thing I am actualy trying to zoom. Potentially bigger than TransformComponent parent */}
<div style={{height: 1000, width: 1000, backgroundColor: 'blue', border: '50px solid'}} />
</TransformComponent>
</div>
</React.Fragment>
)}
</TransformWrapper>
);
}
Changing the height/width properties for TransformComponent-module_container__XXX
in the browser from fit-content
to 100%
seems to make the issue a little better, but it is still not perfectly centered and I'm not sure of the implications of this.
Here is what is rendered after zooming out some.
After setting the TransformComponent-module_container__XXX
div to have a 100% size:
After upgrading from version 1.0.0 to 1.6.1 I get the following error:
TypeError: Cannot read property 'offsetWidth' of null
getComponentsSizes
node_modules/react-zoom-pan-pinch/dist/index.es.js:484
481 | }
482 |
483 | function getComponentsSizes(wrapperComponent, contentComponent, newScale) {
> 484 | var wrapperWidth = wrapperComponent.offsetWidth;
485 | var wrapperHeight = wrapperComponent.offsetHeight;
486 | var contentWidth = contentComponent.offsetWidth;
487 | var contentHeight = contentComponent.offsetHeight;
just using the basic setup from the GitHub example.
I've stubled upon a very interesting bug. If you have the react-zoom-pan-pinch component anywhere rendered on the screen, all input html elements of type range would no longer be slide-able. You can click on them to change their value, but sliding (click and drag) them does nothing.
Here is sample code of slider that would no longer work if you have used the component:
import React, { Component } from 'react';
class GeneralOpt extends Component {
constructor(props) {
super(props);
this.state = {
to: -39
};
this.handlePoseChange = this.handlePoseChange.bind(this);
}
handlePoseChange(event) {
let state = {to: event.target.value};
this.setState(state);
}
render() {
return (
<div id="sidebar-container">
<input
id="to"
type="range"
min="-100"
max="100"
value={this.state.to}
onChange={this.handlePoseChange}/>
</div>
);
}
}
export default GeneralOpt;
Text selection (click and drag on a text) also seems to not work. I guess the component is tapping into the sliding event of the whole page somehow. It would be nice if the sliding worked as expected everywhere except over the react-zoom-pan-pinch component.
Thank you for the nice tool
Hey! Are there any return functions from onZoomChange?
I can only see data about the zoom, but I want to say 'when the zoom hits a scale of 8, reset/zoomOut' and can't seem to find anything
Hi, npm/yarn version1.5.5 is different from github.
i.e. TransformWrapper.d.ts import { TransformWrapperProps } from "../store/interfaces/transformWrapperInterface";
. But transformWrapperInterface is not exist.
I'm just a little confused
Getting an error after i navigate to a new route using 'react-router-dom' history.push method.
Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in the componentWillUnmount method.
after i removed the use of TransformWrapper the error is gone.
I submitted a question about this on stackoverflow here and the answer i got was to submit an issue here.
After panning and my mouse is no longer clicked, the wrapper still continues to animate. I tried setting enableVelocity
to false
but that behavior still happens. Is there a way that i can remove the extra animations after panning?
Thanks!
Nice work! Really useful widget.
It would be useful if the feature could somehow return the position of the clicked pixel as a relative value (values between 0 and 1. Coordinate (0,0) being top left, (1,1) being bottom right corner).
PositionX and PositionY make no difference on component mounting with nested image
Quick demo :
https://codesandbox.io/s/empty-wind-shhik?fontsize=14&hidenavigation=1&theme=dark
Trying to use the pan: { disableOnTarget } gives a typescript error not assignable to type
If I add disableOnTarget?: string[];
to the pan
in .d.ts
the feature works fine however
Hi! Is it possible to support React 15.6? 😃
Is it possible to make this function also take into account the animation time, such as reset?
because right now it just instantly changes transform without animation
Is it possible to support a non-scaling stroke width for zooming SVGs?
It would be nice to add a fullscreen option.
The mousewheel event is deprecated and doesn't work in Firefox. The wheel event might be a better option as a replacement.
If i set the defaultScale
to 2 the scale
is still set to 1 on initial render and on component update the scale remains at the position it was at before the update. If i set the scale
to 2 then every time my component updates the scale is set back to 2. How can i have the scale set to 2 on initial render and not have it jump back to 2 on a component update?
I get this error when i use the onZoomChange to store the current zoom level in my components state.
this is an extract of my code, if i comment out the setZoom()
statement below it works fine again.
....
const [zoom, setZoom] = useState<number>();
const zoomChange = ({ scale }) => {
console.log('zoom', scale);
setZoom(scale);
};
return (
<SelectionProvider>
<TransformWrapper {...opts} onZoomChange={zoomChange}>
{({ zoomIn, zoomOut, resetTransform }) => (
<>
<TransformComponent>
<div className="graphView__container">
<Graph
graph={graph}
bounds={graphBounds}
zoom={zoom || 1}
/>
</div>
</TransformComponent>
<ToolButtons
zoomIn={zoomIn}
zoomOut={zoomOut}
resetTransform={resetTransform}
/>
</>
)}
</TransformWrapper>
);
TypeError: Failed to execute 'requestAnimationFrame' on 'Window': The callback provided as parameter 1 is not a function.
animation
src/store/animations/index.ts:35
32 | this.animation = null;
33 | } else {
34 | callback(step);
> 35 | requestAnimationFrame(this.animation);
36 | ^ }
37 | };
38 |
In case of the scale below 1 with no bounds limit content seems to be positioned randomly while using zoomIn and zoomOut functions.
Configuration:
const options = { minScale: 0.1, maxScale: 3, limitToBounds: false, };
Everything seems to be fine while limitToBounds is set to true.
Hello. I have a simple interactive SVG map, I would like to have dragging callbacks to toggle pointer-events: none
, to prevent clicking to buttons in during of dragging. That is, I need to know when I click and move the mouse. onPanningStart
works when clicked only without waiting for mouse movement
I'm currently using
<button
type='button'
onClick={(e) => this.onZoomIn(e, scale, zoomIn)} >
+
</button>
and inside of
onZoomIn = (e, scale, zoomIn) => {
zoomIn(e);
console.log(e, scale);
}
This works fine except the scale that is returned is the old scale value. Is there a way that i can get the updated scale value after zooming in or out?
or
Is there by chance an onChange event or something similar where i can always get updated values when ever any change is made? Currently there is onPanning
, onWheel
, etc but there is nothing for onZoom
.
Thanks
Bug:
defaultPositionX
and defaultPositionY
are immediately overwritten by dynamic values when the components render.
Expected behaviour:
I would expect the defaultPosition (X, Y) values to be applied on initial rendering. For defaultScale
this already works correctly.
From what i can see this library is meant for images with a width of 100% of the container. Using an image with a fixed width and height doesn't fully pan since its calculating for an image that is meant to be 100% of the container. I can fix this by setting limitToBounds
to false so that i can pan it but then by doing this you can pan the content off the screen. Is there a way to use an image with a fixed width and height while sticking to the limit bounds?
Thanks.
Hi,
There is a problem with Type on TransformComponent component in TS context (class component)
error :
Type 'TransformComponent' is missing the following properties from type 'ElementClass': context, setState, forceUpdate, props, and 2 more.ts(2605)
https://codesandbox.io/s/boring-firefly-u35d3
Do you have an idea of the problem ?
Thanks.
Currently defaultScale: >1
with centerContent:true
doesn't put the scaled svg at the center.
A simple usage of the library does not work.
<TransformWrapper>
<TransformComponent>
<img src={xxx} />
</TransformComponent>
</TransformWrapper>
MacOS v10.11.6
node: v10.8.0
"react": "^16.3.2"
"react-zoom-pan-pinch": "^1.6.1"
None of the "AnimationSpeed" props seem to work. Can someone help me zoom faster or slower?
Also, I noticed the within the source code, the animation speed props are set to PropTypes,bool instead of PropTypes.number could that be the issue? I did not trace the code any further.
how can I stop moving?
And is it possible to support RTL?
im using zoom-pan-pinch to zoom an svg element.
Panning works great. but zooming is incredibly slow, setting options.wheel.step does not change anything.
I am trying to attach a slider component to trigger zoom in & out, I use it to update the scale value however when that happens it zooms into (0,0) (top, left) corner of the image. Is there an easy way to have this automatically zoom to the center of the image?
In the TransformComponent
file you use double quotes in the react-transform-component
classname and I'm not sure it is suppose to be there. That class is for the developer to style the outer div and, since double quotes are not used in the react-transform-element
which is a direct child of the outer div and have the same purpose, I think removing the double quotes would be the best approach to maintain consistency across the code.
The snippet of what I'm talking about:
<div ref={wrapperRef} className={`"react-transform-component" `${styles.container}`}>`
^^^ ^^^
<div ref={contentRef} className={`react-transform-element ${styles.content}`} style={style}>
{children}
</div>
</div>
ios safari bug: animation scaling, if new scale again,scale forever invalid:
not working without "options" object, plz fix this src/components/TransformWrapper.tsx:25
I know the click event is right in the div demo, but when I have a image component in the TransformComponent and set onClick in the image or have a map and some areas attrs, the click event did not work.
<img
src={require('./images/map.jpg')}
useMap="#image-map"
onClick={() => alert(1)} // <---- not work
/>
<map name="image-map">
<area
coords="751,538,846,640"
shape="rect"
onClick={() => alert(1)} // <----- not work either
/>
There is white space which extends past the react webpage boundary. From my testing, this is because the componets within the TransformComponet are technically larger than the page boundary. The screenshot is of the TransformComponet scaled somewhere close to 0.3.
I would like the whitespace to not exist while maintaining the functionality of this wonderful react-zoom-pan-pinch component. Is there a strategy that I can employ while retaining the original structure of my components within the TransformComponent?
want to support typescript
I've noticed since the last update that OnWheel is not always triggered and the component does not scale. I have to drag the component a little then i'm able to zoom again. If i revert back to the older version of the code then it works fine.
In StateContext
file, in the componentDidMount, you return the removeEventListener for: mousedown, mousemove and mouseup events.
This removeEventListeners never executes, and the listeners keep working when you change page, creating a strange behavior when you try to select any text.
componentDidMount() {
const passiveOption = makePassiveEventOption(false);
// Panning on window to allow panning when mouse is out of wrapper
window.addEventListener("mousedown", this.handleStartPanning, passiveOption);
window.addEventListener("mousemove", this.handlePanning, passiveOption);
window.addEventListener("mouseup", this.handleStopPanning, passiveOption);
return () => {
window.removeEventListener("mousedown", this.handleStartPanning, passiveOption);
window.removeEventListener("mousemove", this.handlePanning, passiveOption);
window.removeEventListener("mouseup", this.handleStopPanning, passiveOption);
};
}
If you add the componentWillUnmount lifecycle with the removeEventListeners, it works as expected when you unmount the component.
componentDidMount() {
const passiveOption = makePassiveEventOption(false);
// Panning on window to allow panning when mouse is out of wrapper
window.addEventListener("mousedown", this.handleStartPanning, passiveOption);
window.addEventListener("mousemove", this.handlePanning, passiveOption);
window.addEventListener("mouseup", this.handleStopPanning, passiveOption);
}
componentWillUnmount() {
const passiveOption = makePassiveEventOption(false);
window.removeEventListener("mousedown", this.handleStartPanning, passiveOption);
window.removeEventListener("mousemove", this.handlePanning, passiveOption);
window.removeEventListener("mouseup", this.handleStopPanning, passiveOption);
}
Hi,
Is this module due for a major version bump? Got an update and the complete interface changed from 1.1.2 to now.
Before update to 1.1.1 it's worked nice. Now, after click on button that call resetTransform nothing happen. In DevTools no errors, no DOM changes.
React & React-dom - 16.9.0
I got this error message every time when I click on the page:
Uncaught TypeError: Cannot read property 'getBoundingClientRect' of null
at getComponentsSizes (index.es.js:348)
at StateProvider.handleCalculateBounds (index.es.js:380)
at StateProvider._this.handleStartPanning (index.es.js:941)
getComponentsSizes @ index.es.js:348
handleCalculateBounds @ index.es.js:380
StateProvider._this.handleStartPanning @ index.es.js:941
15:33:48.257
When I tried to debug I added:
console.log("setWrapperComponent", wrapperComponent);
to StateContext.js
and my console show:
setWrapperComponent <div>…</div>
and few seconds later:
setWrapperComponent null
I think when TransformWrapper
added with array map and we change the array that can cause an issue. I can't reproduce the issue outside of our codebase.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.