GithubHelp home page GithubHelp logo

mnogueron / react-easy-panzoom Goto Github PK

View Code? Open in Web Editor NEW
78.0 2.0 17.0 11.67 MB

Wrapper to enable pan and zoom features for any React component

License: MIT License

JavaScript 95.74% HTML 4.16% CSS 0.09%
react panzoom reactcomponents reactjs pan zoom

react-easy-panzoom's Introduction

react-easy-panzoom

Code Code npm Code Code

react-easy-panzoom-demo

React components that enables pan and zoom features for any component. Try out the live demo here

Installation

react-panzoom requires React 16 or later.

Using npm:

npm install --save react-easy-panzoom

Using yarn:

yarn add react-easy-panzoom

Usage

import { PanZoom } from 'react-easy-panzoom'

// ...
render() {
  return (
    <PanZoom>
      { 'This content can be panned and zoomed' }
    </PanZoom>
  )
}

Key mapping

PanZoom component natively supports keyboard interactions with arrow keys and - / + keys. This mapping can be extends using the keyMapping prop.

e.g. Mapping w, a, s, d:

import { PanZoom } from 'react-easy-panzoom'

// ...
render() {
  return (
    <PanZoom
      keyMapping={{
        '87': { x: 0, y: -1, z: 0 },
        '83': { x: 0, y: 1, z: 0 },
        '65': { x: -1, y: 0, z: 0 },
        '68': { x: 1, y: 0, z: 0 },
      }}
    >
      { 'This content can be panned and zoomed' }
    </PanZoom>
  )
}

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

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>
  )
}

Boundaries

PanZoom supports the enableBoundingBox prop to restrict panning. The box is calculated based on the width and height of the inner content. A ratio is applied so that the bounding box allows panning up to a specific percentage of the inner content. By default this ratio is 0.8 but can be modified with boundaryRatioVertical and boundaryRatioHorizontal. In this case the pan content will be able to pan outside the parent container up to 80% of its size (the 20% remaining will always be visible).

A negative ratio will create a padding, but combined with zooming it can produce strange behaviour. A ratio above 1 will allow the pan content to pan outside the parent container more than its size.

To use the bounding box:

import { PanZoom } from 'react-easy-panzoom'

// ...
render() {
  return (
    <PanZoom
      boundaryRatioVertical={0.8} 
      boundaryRatioHorizontal={0.8} 
      enableBoundingBox
    >
      <div>{ 'This content can be panned and zoomed' }</div>
    </PanZoom>
  )
}

Properties

Name Type Default Description
autoCenter bool false Auto-center the view when mounting
autoCenterZoomLevel number Specify the initial zoom level for auto-center
zoomSpeed number 1 Sets the zoom speed
doubleZoomSpeed number 1.75 Sets the zoom speed for double click
disabled bool false Disable pan and zoom
disableKeyInteraction bool false Disable keyboard interaction
disableDoubleClickZoom bool false Disable zoom when performing a double click
disableScrollZoom bool false Disable zoom when performing a scroll
realPinch bool false Enable real pinch interaction for touch events
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
enableBoundingBox boolean false Enable bounding box for the panzoom element. The bounding box will contain the element based on a ratio of its size
boundaryRatioVertical number 0.8 Vertical ratio for the bounding box
boundaryRatioHorizontal number 0.8 Horizontal ratio for the bounding box
noStateUpdate bool true Disable state update for each new x, y, z transform value while panning. Enabling it drastically increases the performances
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
onStateChange func Called after the state of the component has changed

You can also pass in every other props you would pass to a div element. Those will be passed through to the container component. This is helpful for adding custom event handlers.

Methods

By using ref, methods from PanZoom can be accessed and called to trigger manipulation functions.

Available methods are listed below:

Name Parameters Description
zoomIn (zoomSpeed?: number) Zoom in from the center of the PanZoom container
zoomOut (zoomSpeed?: number) Zoom out from the center of the PanZoom container
autoCenter (zoom: number, animate?: boolean = true) Center and resize the view to fit the PanZoom container
reset Reset the view to it's original state (will not auto center if autoCenter is enabled)
moveByRatio (x: number, y: number, moveSpeedRatio?: number) Move the view along x or/and y axis
rotate (angle: number | (prevAngle) => newAngle) Rotate the view by the specified angle

Thanks

This react library is based on the awesome panzoom by @anvaka.

License

The files included in this repository are licensed under the MIT license.

react-easy-panzoom's People

Contributors

dependabot-preview[bot] avatar emilyzhong avatar mnogueron avatar n1ru4l avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

react-easy-panzoom's Issues

Transform matrix endpoint

Hi! Would it be possible to have a method to get the current transform matrix? (Something like getMatrixTransformString, except instead of taking in arguments and formatting it into a string returning the css transform value?

Thanks in advance :)

Explicitly set the scale?

Hello, I was wondering if there was a way to explicitly set the scale in the state from outside. I am attempting to create a menu button that will Zoom to 75%, which can be kind tricky using the zoomOut / zoomIn methods. Something like panZoom.current.setScale(0.75)? Apologies if this is documented somewhere already ๐Ÿ™Š

TypeScript typings

First of all, thanks for this awesome library!

I'm using it for the electronic diagram viewer in my Arduino simulator project, and it works like a charm :-)

I'm working with TypeScript, so I created a simple type definition file for the library.
I created it manually based on the documentation in the README, so it may not
be completely accurate, but it does the trick for me.

I'm sharing it below for anyone who might need to use the library with TypeScript
in the future:

declare module 'react-easy-panzoom' {
  interface PanZoom extends React.ReactElement {
    zoomIn(zoomSpeed?: number): void;
    zoomOut(zoomSpeed?: number): void;
    autoCenter(zoom: number, animate?: boolean = true): void;
    reset(): void;
    moveByRatio(x: number, y: number, moveSpeedRatio?: number): void;
    rotate(angle: number | ((prevAngle: number) => number)): void;
  }

  export interface OnStateChangeData {
    x: number;
    y: number;
    scale: number;
    angle: number;
  }

  function PanZoom(props: {
    autoCenter?: boolean;
    autoCenterZoomLevel?: number;
    zoomSpeed?: number;
    doubleZoomSpeed?: number;
    disabled?: boolean;
    disableKeyInteraction?: boolean;
    disableDoubleClickZoom?: boolean;
    disableScrollZoom?: boolean;
    realPinch?: boolean;
    minZoom?: number;
    keyMapping?: { [key: string]: { x: number; y: number; z: number } };
    maxZoom?: number;
    enableBoundingBox?: boolean;
    boundaryRatioVertical?: number;
    boundaryRatioHorizontal?: number;
    noStateUpdate?: boolean;
    onPanStart?: (event: React.MouseEvent) => void;
    onPan?: (event: React.MouseEvent) => void;
    onPanEnd?: (event: React.MouseEvent) => void;
    preventPan?: (event: React.MouseEvent, x: number, y: number) => boolean;
    style?: React.StyleHTMLAttributes;
    onStateChange?: (data: OnStateChangeData) => void;
    children: React.ReactNode;
  }): React.ReactElement;
}

Also, if you are interested, I can create pull request and integrate this type information into the library (it will be a separate file, so it doesn't change the existing source code of the library in any way), so that people who install the package via npm will be able to take advantage of it automatically.

And if not, that's fine too, at least people will be able to refer to this issue and find the type definitions here.

Thanks again for creating and maintaining react-easy-panzoom ๐Ÿ‘

Add option to disable zoom on scroll

Hi! Would it be possible to disable zoom on scroll while still having panning enabled? For reference, I'm trying to create a feature that includes zoom-like features, but still allows the user to scroll regularly if needed.

Reset zoom on end

I would like to zoom only when I have the pinch motion and after that I would like to zoom out. Like in Instagram.

I tried using the onPanEnd method and there I usedzoomTo (0, 0, 0)and alsoreset ()

How could I solve this?

Reset zoom when done

<PanZoom autoCenter ref={panZoom} 
    onPanEnd={() => {
        console.log(panZoom);
        panZoom.current.zoomTo(0, 0, 0);
        panZoom.current.reset(); 
    }}
>
     <img src={image.url} alt="imagem slider" />
</PanZoom>

Zoom bug when boundingBox enabled with small boundaryRatios

Hey,

first, thanks a lot for this cool library!
Unfortunately I encountered an issue, when I try to set the boundaryRatios to 0, or already when the value gets close to it, approximately smaller than 0.3. Then the zoom doesn't work properly anymore and fidgets around weirdly. Does anyone have a solution?
Thanks a lot!

Anton

Is it possible to have rotate feature?

I am looking for a way to have to zoom in out feature as well as rotate feature. but all the library i see doesn't have rotate feature. Can you please guide me an way to add this?

Zoom feature produces preventDefault errors and jerky animations in Chrome 73

Description

Since v73, Chrome is setting mousewheel event listeners to be passive by default. This is breaking the zoom feature as PanZoom make use of onWheel event listener from React that doesn't force the listener to be passive and rely on Chrome implementation.

To fix it we need to use this.container.addEventListener('mousewheel', this.onWheel, { passive: false }) instead of React onWheel listener.

For more details about Chrome's decision: https://developers.google.com/web/updates/2019/02/scrolling-intervention

PanZoom with react-designer component

Hi,

I'm developing a tool for a software where i needed to made a version of react-designer(https://github.com/react-designer/react-designer) combined with panZoom, in the 'draw container' i put a background image to guide the user where they have to draw some shapes to highlight some areas of bakground, and it's works very well but, when zooming the draw container, the reference of points 'x' and 'y' of mouseClick got offset, resulting in a shape drawed in another position relation to background, i suppose that is necessary consider zoom in the transform matrix but i'm not sure how to, so could you explain to me the calculations you made on the transform matrix? After this i can work on implementation of this calculus that consider the relative position of the mouse pointer in the zoomed image. Or if exist some way to do that with some feature that PanZoom already have.
If you need more information about this case, i'm glad to provide to you everithing you need to solve this situation.
Thanks

Zoom in / Zoom out method scale amounts

Hello! Is it possible to have a parameter to the zoomIn and zoomOut methods so they can scale a certain amount? I dug through the code a little and currently it scales by this.props.zoomSpeed * some multiplier, but it would be great to be able to determine a zoom speed separately for these methods :)

Prevent re-renders of children

Hi, I'm using Panzoom to create a zoomable/pannable canvas that includes draggable elements that can move around the canvas.

I'm having an issue where panning and zooming re-renders all children of <Panzoom>, creating huge performance bottlenecks, especially when there is a large quantity of children.

Is there a way to prevent this? Perhaps wrapping the Panzoom component in a React.memo?

Limit drag inside container

Hey. Thanks for the solution. Is it possible to limit the drag of an element inside a container so that there are no empty indents between the container and the contents?
Now it is possible to drag the contents outside the container so that it will not be visible.
See an example to understand what I mean
https://z3ut.github.io/mouse-wheel-zoom/

Controlled PanZoom

Hi there! I'm incorporating PanZoom in an application and I have a use case where it would be useful to have a controlled PanZoom component. I would like to be able to absolutely set the position and the scale when some props are updated. It seems to me like this feature could be useful for many use cases.

One way to achieve it right now is to use the zoomAbs method that is actually not documented in the readme (is this on purpose?) and also never used in the PanZoom component itself.

It works fine with this method but I would have expected one of the following:

  1. Document the zoomAbs method in the readme.
  2. Add some props to achieve this. Something like initialPosition and initialScale.

EDIT: You cannot absolutely set the position using zoomAbs. You can only set the zoom. So I don't see any way to control the position except using ref.setState({x: 10, y: 10}) but this seems like a terrible pattern to me.

movement via arrow keys is not persisted in state

Reproduction:

  1. Use arrow keys for moving the content
  2. Drag content and move it slightly (without releasing)
  3. The content jumps back to the initial position (before the arrow key shiftings were applied)

Possible Solution:

It seems like there must be a setState call upon releasing the arrow keys (onKeyUp).

Default zoom

Is there a way to set the default zoom level?

svg wrong scale after zoom change and window resize

Hello, thank you for this library I have enjoyed using it but I am unsure where I need to go to fix this issue I'm having.

I am using react-easy-panzoom as a wrapper component around react-archer elements to be able to pan and zoom around a large flow chart.

At PanZoom zoom level of "1" I can click->drag and pan around the chart and resize the containing window and everything works fine.

The issue is that if I zoom out with the mouse wheel using the PanZoom functionality the react-archer arrows scale properly and I can pan without issue, but then after resizing the window while zoomed out the react-archer arrows seem to rerender at the wrong scale. The further I zoom out and then resize the window the smaller the arrows will scale down to.

https://codesandbox.io/s/react-easy-panzoom-svg-scaling-behavior-g8vcn?fontsize=14

        <div>
          <ArcherContainer strokeColor="red">
            <div style={gridWrapper}>
              <ArcherElement
                id="source"
                relations={[
                  {
                    targetId: "target",
                    targetAnchor: "left",
                    sourceAnchor: "right"
                  }
                ]}
              >
                <div style={boxStyle}>Root</div>
              </ArcherElement>
              <ArcherElement id="target" relations={[]}>
                <div style={boxStyle}>Root</div>
              </ArcherElement>
            </div>
          </ArcherContainer>
        </div>
      </PanZoom>

PanZoom zoom level 1 https://i.imgur.com/xr9RRQr.jpg

zoom out https://i.imgur.com/UjHUJ1m.jpg

resize after zoom out https://i.imgur.com/QcGzQWj.jpg

Zoom to element

First of all, thank you for the awesome library. I would like to ask if there is any function that gives the ability to zoom to the target.
for instance, I give the target node (document.getElementById('target')) to the function and it zoom in to that node. Thanks in advance

Change default border color

Is there a way to change the default blue border whenever you pan? I'd like to hide it or at least be able to change that color. Right now if even if I set the border color to a different color, it still turns blue when panning.

Add option to disable zoom for double click

There is currently no option available to disable the zoom on a doubleClick.

Furthermore, it would be very helpful to have a callback that is called after any pan/zoom aka interaction has happened.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.