Git Product home page Git Product logo

angular-pan-zoom's Introduction

angular-pan-zoom

AngularJS directive for implementing pan and zoom on any DOM element

Build Status

NOTE: Angular2 version has been released!

TL;DR: If you're looking for pan/zoom with Angular2 support, I highly recommend that you have a look at ng-panzoom2.

A bit longer explanation: This directive was written for Angular1 and I have not made any effort to migrate it to Angular2. I am very grateful that Tim Underhay has stepped in to correct this omission. What he did was basically salvage the good parts from angular-pan-zoom and make it work in Angular2, fixing the design along the way. I feel honored that someone with which I have no personal affiliation would go through this trouble to pull my somewhat dated code into 2018. I consider ng-panzoom2 to be the natural sucessor to angular-pan-zoom.

My original angular-pan-zoom project will not go away but I expect it to become increasingly forgotten as the world moves away from Angular1. I haven't done any active development for years nor have I received any pull requests for some time. It has been fun to create a project that, though never huge, did make a small splash and was used by people around the world. I expect most of the world to have moved on by now.

We now return to the original broadcast.

Getting it:

Get the code from github. Or simpler yet, use bower:

bower install angular-pan-zoom

Or NPM:

npm install angular-pan-zoom --save

Features:

  • Zoom using mouse wheel, double click, or control widget
  • Pan using click and drag. When releasing mouse button while panning, the pan will come to a gradual stop.
  • AngularJS integrated. Models are used as APIs for communicating
  • Widget with zoom controls provided. Use this or design your own controls if you so prefer.

Requirements:

  • AngularJS (obviously)
  • jQuery (used for managing timing loops)
  • Hamster.JS (for mouse wheel support)
  • angular-mousewheel (which integrates HamsterJS with angular)

For convenience, these requirements are checked in as part of the project. They are also described by the bower.json file.

Demo:

Click here for an online demo of the functionality.

Usage:

Simplest working example

When declaring your module:

angular.module('your_module', ['panzoom', ..])

In your controller:

$scope.config = {}; // use defaults
$scope.model = {}; // always pass empty object

In your markup:

<body>
  ..
  <!-- create panzoom, passing models from controller -->
  <panzoom config="config" model="model" style="width:800px; height: 600px">
    <!-- your content here -->
  </panzoom>
  ..
  <!-- include scripts -->
  <script src="bower_components/jQuery/dist/jQuery.js"></script>
  <script src="bower_components/hamsterjs/hamster.js"></script>
  <script src="bower_components/angular/angular.min.js"></script>
  <script src="bower_components/angular-mousewheel/mousewheel.js"></script>
  <script src="release/panzoom.js"></script>
</body>

This will provide zoom and pan functionality using default settings. It will, however, not provide any widget to control the zoom and pan.

Using the provided zoom pan widget

To use the bundled <panzoomwidget>, you need to

  • include release/panzoomwidget.css on your page
  • make your AngularJS module depend upon the panzoomwidget module
  • declare an id attribute on your <panzoom> tag
  • use a <panzoomwidget> directive in the markup, specifying its panzoom-id attribute to be the same value as the id of the <panzoom> tag You will probably also want to position the widget above the zoomed contents be means of CSS. Check ./test.html for a working example.

Implementing your own external controls

Refer to panzoomwidget.js for an example of how this may be done. Whether or not you create it as a directive is up to you. To access the API of a panzoom directive, you need to look it up using the getAPI() method on the bundled PanZoomService, passing the id of the <panzoom> widget. The method will return a promise.

Example usage:

// assuming the PanZoomService to be a dependency and panzoomId to be the ID of the <panzoom> directive ...
PanZoomService.getAPI(panzoomId).then(function (api) {
    // you can now invoke the api
}

The API

The API object contains the following properties:

Method Description
model the model object which was passed to the panzoom directive
config the config object which was passed to the panzoom directive
changeZoomLevel(newZoomLevel [,clickPoint]) change zoom level to a new value using a quick animation
zoomIn() shorthand for increasing zoom level by one
zoomOut() shorthand for decreasing zoom level by one
zoomToFit(rectangle) zoom to display a part of the contents. Example rectangle: { "x": 0, "y": 100, "width": 100, "height": 100 }
getViewPosition(modelPosition) takes a argument a {x:.., y:..} in the original, untransformed contents. Returns the current pixel position of this point.
getModelPosition(viewPosition) the reverse operation of getViewPosition()

The config object:

May be used to pass configuration options to the panzoom directive. The directive will fill in any "blanks" with default values.

The config object is not intended to be modified once initialized.

The following config object attributes are supported:

Name Type Default Description
zoomLevels number 5 Number of discrete zoom levels, each one representing a scale.
neutralZoomLevel number 2 The zoom level at which the centents render at 1:1 scale
scalePerZoomLevel number 2.0 The difference in actual scale between two adjacent zoom levels.
initialZoomLevel number neutralZoomLevel The initially selected zoom level
initialPanX number 0 The initial pan in the horizontal direction
initialPanY number 0 The initial pan in the vertical direction
zoomToFitZoomLevelFactor number 0.95 A number to indicate how closely zoom to fit will work. 1.0 is perfect fit, lowering the number will reveal a bit of the surrounding contents
zoomOnDoubleClick boolean true Enable or disable zoom in on double click
zoomButtonIncrement number 1.0 The amount of zoom levels to zoom on double click
zoomStepDuration number 0.2 Amount of seconds to animate between two adjacent zoom levels
disableZoomAnimation boolean false Set to true to disable the animation while zooming. It will be more chunky but will consule less CPU resources.
zoomOnMouseWheel boolean true Enable or disable zoom in/out on mouse wheel
invertMouseWheel boolean false Invert the behaviour of the mouse wheel (or two finger trackpad gesture)
friction number 10.0 Constant which controls the friction when dragging and then letting go. The higher the number, the more quickly the animation will come to a stop.
haltSpeed number 100.0 Constant which controls when the pan animation has slowed down enough to be terminated. The lower the number, the longer time it will run.
panOnClickDrag boolean true Enable or disable pan on clicking and dragging the mouse
modelChangedCallback function undefined Pass a function to receive events when the model changes. The model will be passed to the function.
useHardwareAcceleration boolean false Use translate3d for panning instead of using standard CSS styles 'left' and 'top'. This is intended to trigger hardware acceleration and may increase the speed greatly. In future versions, this may be set to true as default.
chromeUseTransform boolean false Cause Chrome to use CSS transform instead of CSS zoom. Enable if you use nested SVG and see performance problems in Chrome.
initialZoomToFit rectangle undefined When defined, will initially zoom to fit the given rectangle (see API for explanation of zoom to fit). This overrides the initialZoomLevel, initialPanX, and initialPanY values.
keepInBounds boolean false When true, it will not be possible to pan the contents off the screen -- it will snap back when trying to do so -- and it will not be possible to zoom further out than the neutral zoom level.
keepInBoundsRestoreForce number 0.5 Constant to control how quickly the contents snap back in place after attempting to pan off bounds.
keepInBoundsDragPullback number 0.7 Constant to control the perceived force preventing dragging the contents off limits.

The model object:

When initializing, you should pass an empty object. The directive will initialize the object. You can read the current zoom and pan state at any time from this object.

Contributing to the project:

Any code contributions to the project will be appreciated. A few guidelines follow.

Npm is used for building stuff. Use npm install to fetch dependencies (including the bower ones). Use npm start to launch a development server using browsersync. Use 'npm run build' to perform a build as verified by uni tests and lint. For the complete list of npm scripts, see package.json.

angular-pan-zoom's People

Contributors

clementvidal avatar deepinsand avatar equus71 avatar lmonson avatar mikkeltandersen avatar mvindahl avatar nrs-theonetruematt avatar warpdesign 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

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

angular-pan-zoom's Issues

Throws an error on disableZoomAnimation

Here is an error.
disableZoomAnimation is not obligatory for $scope.config ?

even if I added this property, still throws an exception.

`angular.js:13550 TypeError: Cannot read property 'disableZoomAnimation' of undefined

at new controller (panzoom.min.js:6)
at Object.invoke (angular.js:4665)
at $controllerInit (angular.js:10115)
at nodeLinkFn (angular.js:9033)
at compositeLinkFn (angular.js:8397)
at compositeLinkFn (angular.js:8400)
at nodeLinkFn (angular.js:9088)
at compositeLinkFn (angular.js:8397)
at nodeLinkFn (angular.js:9088)
at compositeLinkFn (angular.js:8397)(anonymous function) @ angular.js:13550(anonymous function) @ angular.js:10225processQueue @ angular.js:15969(anonymous function) @ angular.js:15977$eval @ angular.js:17229$digest @ angular.js:17045(anonymous function) @ angular.js:17268completeOutstandingRequest @ angular.js:5869(anonymous function) @ angular.js:6145`

Portrait photos are rotated 90 degrees

It seems that when I try to load a picture with an aspect ratio such that it is taller than it is wide, the picture is rotated 90 degrees. As far as I can tell, there is no way to prevent this behavior in the config. Is this a bug? Or is there some type of configuration I'm missing?

Right now, I'm essentially using the exact same code from the demo, only with different widths.

CLOSED: Nevermind, I'm an idiot.

api to reset zoom and pan

Is it possible to have an api, or at least a workaround, to reset zoom and pan to initial values?

Add to npm

NPM and Browserify seem to be eating client side dependency management these days.

Find out how to add angular-panzoom to npm registry. We should use require() internally to obtain our dependencies but we shouldn't break the bower installation. I suppose that a Browserify compliant wrapper file might do the trick.

Versioning and bower hosting

Hi,

I thought I would "take a stab" at creating a binary release site, to allow for acquiring the pan-zoom directives through bower.

We do however need a versioning convention (i suggest using semver). Let's call the current "bleeding edge"-version 0.9, since it's usable, and is (from my perspective) very close to being something than can be considered stable.

When the release (and a tag) is made available, I'll created the binary repo and register the package with bower.

Sounds good?

Zooming is a bit bumpy

When zooming across several zoom levels there is an impression of "bumpiness". This is caused by the zooming coming to a temporary stop until it receives a new mouse wheel event. This should be fixable by detecting mouse wheel events during the final phase when zooming from one level to another, and if they are of a certain magnitude, just continue zooming once the destination has been reached.

Or figure out an alternative solution.

How do I simply zoom to fit the contents?

I cant seem to find a simple way to automatically zoom to fit the contents of the component when it first loads. I have tried zoomToFit but it requires me to tell it the size of the content to fit, and it doesn't seem to work as I would expect. I was hoping just calling zoomToFit without any parameters would work, but it fails. I dont want to resort to having to measure things or do math just to have it fit its content to the viewport.

keepInBounds Not Working in my App

Your demo keepInBounds seems to work when set to true, but does not allow me to pan in my app. The viewportHeight and viewportWidth are 0 for me. Do you have any suggestions?

KeepInBound issue when viewport size is smaller than the content size

When the viewport size is smaller than the content size, few issues presented:

  • When loaded, the viewport will point to the upper-left corner instead of specified rect
  • Panning to somepoint is stuck, you need to further zoom in to further pan.
  • There is a drifting behaviour of zooming when zooming out.

<!DOCTYPE html> prevents pan to function at all

Hello, I was loading your script on my project and could zoom on images but only in the x=0 y=0 coordinates, panning and dragging the image was impossible.
zoom-no-drag1
zoom-no-drag2

After several hours of testing and loading the exact same code in my index.html from the demo, I came to the conclusion that the tag was preventing the drag and pan directive to work at all, removing it seemed to fix the problem.

I don't know if this is a known bug or this limitation is on purpose since I couldn't find info about it anywhere.

Thanks for your time.

Directive does not unregister API when leaving the page

As of v1.0, the panzoom directive registers an API with the PanzoomService when it it created. This API makes it possible to publish functionality of the directive.

However, it fails to unregister the API as it is leaving the page (i.e. as its scope is destroyed). It should do that.

Failure to unregister animation tick

As reported by @equus71, the directive fails to unregister its animation tick from jQuery.fx when the directive is moved off the page. This has very real implications when using ngRoute since angular routing does just that ...

This issue is serious enough to justify a new bower release once it has been fixed.

Bower 'bin' folder possible renaming

I was looking to use this library for a production-level webapp, but we have strict filtering in place to not allow "bin" folders for security. We are using grunt to automate building and compiling external libraries through bower, and because of these constraints are having problems with this library. It is definitely possible for us to create a workaround in our Gruntfile as to rename the directory ourselves, but I thought I would suggest it as a fix in general because I have not come across other libraries in bower that use the bin directory for the final code. It seems to be more common that 'src', or 'release' is used.

I can understand not wanting to implement something like this so that it will not break anything for other users of the repository, just thought I would suggest it and see if it might be worth doing to keep consistent with other libraries distributed through bower.

Print the panzoom

Hi, there is a way to print the panzoom element? the thing is i have an ng-repeat inside the panzoom, then when I try to print, everithing became a mess, the div doesn't contain correctly the inside images

thanks

Version number in build artefact

We should build both a minified and an unminified file. Both should have version numbers as part of their name. We should also have a descriptive header in the files.

Option to turn off mouse activity?

I'm using panzoom in a project where, on one screen, the zoom effect is to be controlled exclusively by external controls and not by mouse activity (e.g. scroll wheel).

Would you be interested in a pull request that implements the option to turn off some of the mouse activity in panzoom ?

two finger touch on mac trackpad causes zoom out

When I place my two fingers on the mac trackpad and prepare to start scrolling, a zoom out occurs.

I debugged the issue and noticed the wheel event is triggered when I place my fingers on the trackpad. A sign variable is calculated to NaN (var sign = $deltaY / Math.abs($deltaY);) since the deltaY is 0. We need to ensure we only zoom out if sign is a positive number. NaN should not trigger a zoom.

Reset to initial zoom and position

I am having trouble using the api to "reset" the zoom. I am hoping to have a button that zooms out and re-centers the image like it does for me on load.

Panning is not working at all.

Hello, I am using this module in my project and could zoom on images but only in the x=0 y=0 coordinates, panning and dragging the image was impossible.

Going through previous issues, I removed DOCTYPE from my index.html but still issue persists.

I am not able to find the issue.

Libraries:
Angular: 1.3.10
angular-pan-zoom: 1.0.18
hamsterjs: 1.1.2
angular-mousewheel: 1.0.5
jquery: 1.11.3

Thanks for your time.

NPM version of angular-pan-zoom needs bower

I was trying to install the angular-pan-zoom directive via npm but it failed with "bower is not installed" does the npm version of angular-pan-zoom depends on bower? My project is not using bower and I would hate to install it just to use the directive. :(

Chrome: when nesting SVG, text becomes jagged and performance seems degraded

Not sure which versions of Chrome that this applies to but we see this in our project. Even for small amounts of SVG, the text becomes jagged and non-antialiased. For larger amounts of SVG, rendering sometimes stops in mid air and leaves blank areas on the screen.

We don't see it in Safari so it doesn't seem to be a webkit thing.

Kill and resurrect the animation tick

We run the animation tick at all times but we could be more intelligent and thus less wasteful with resources. We could make the function return false when no longer needed, making jQuery.fx purge it from its list. Conversely, we should be able to revive it when needed.

Too many things assigned to $scope

In panzoom.js, we are assigning too many things to the scope and we are dotting all the way through these far too often. As a result the code becomes difficult to minify. Replace $scope variables with local (i.e. private) var declarations whenever it makes sense.

Pan stops working after mousewheel zoom

In your demo, I can pan around just fine, but once I use the mousewheel to zoom in and out, the pan stops working. I will be able to pan again if I click one of the specified zoom buttons, but it will again stop working if I mousewheel zoom again.

Isolate scope design issue

Working with angular pan zoom is pretty painless, when panning or zooming on a static image.

However....

When panning and zooming on a Canvas or SVG document (linked with a Controller in the parent scope) - it's not the case. It becomes very difficult (well, unintuitive at least) to access an ng-model from the controller in the parent scope.

Here's a suggestion for a solution to the issue:

Remove the isolate scope from the panzoom-directive, and use the $parse-service to read the config- and model-objects from the link-function of the directives attr-attribute. Then put those objects on the scope on a`$panzoom``-property (the name is just a suggestion) to avoid colliding with the parent controller.

Wrong API id if id contains an angular expression

When using an Angular expression into the panzoom element's id, the raw (not parsed) expression will be used as elementId:

scope.elementId = element.attr('id');

Ending up with a wrong index in API when calling PanZoomService.registerAPI:

So if you have something like

<panzoom ... id="{{expression}}"></panzoom>

scope.elementId === '{{expression}}'

I think parsing the angular expression would fix the problem.

Provide methods to pan w/out changing zoom level

I'm trying to implement my own pan controls from outside the directive. It doesn't appear that the directive exposes direct methods to pan -- the logic for a "pure pan" is embedded in mouse move event handler.

I would be very happy to provide a pull request -- but wanted to ensure I hadn't missed anything beforehand. I would augment as follows:

changeZoomLevel(newZoomLevel, clickPoint)
zoomIn(clickPoint)
zoomOut(clickPoint)
getViewPosition(modelPosition)
getModelPosition(viewPosition)
** panView(delta) // delta.x and/or delta.y

Option to disable pan/zoom functionality

Is there an easy way to disable the pan/zoom functionality? (i.e. I want an "edit mode" button that toggles editMode between true and false, and only want the pan/zoom functionality enabled when editMode is true.

(awesome directive btw!)

Elements within the <panzoom> with <Draggable>

Hi I worked for the elements within the PanZoom with draggable, and the change made ​​in the branch testing-drag-drop.

I have a problem adding draggable the items I can not prevent the Panzoom move when selected, how could I do to move the item is independent of PanZoom but still within.

Need unit tests

We don't have any right now. This could surely be improved.

ng-transclude orphan when dynamically adding content to the panzoom container.

Hi, thank you for sharing this directive, it is very useful!

what's the correct way to add content to the panzoom container after it has linked?
I have a ng-repeat div inside the panzoom container and any change to the ng-repeat's array will break the panzoom directive. Angular complains about ng-transclude being specified in the template without having transclude=true specified in the directive...

Don't export methods from panzoom directive by means of the model

The directive currently exposes functionality by attaching methods to the model object that it receives. The five methods are:

changeZoomLevel(newZoomLevel, clickPoint)
zoomIn(clickPoint)
zoomOut(clickPoint)
getViewPosition(modelPosition)
getModelPosition(viewPosition)

The surrounding controller can then use these methods as a handy way to manipulate the model and to perform calculations. Also, the panzoomwidget directive uses them. All of the methods rely upon complex calculations which there is no reason that the surrounding controller should deal with.

From an angular perspective it seems like a hack to publish an API in this manner. However, it's also a very simple way to do so. Investigate if angular offers an equally simple way of exposing an API without offending the angular gods.

Namespacing of directives

To avoid having directives name-clash with application (other) directives, we should prefixing our directives with a namespace.

To be clear, angular's "core" directives are prefixed with ng, eg.:

ng-repeat="foo in bar"

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.