Skip to content

Commit

Permalink
version 1.0.0
Browse files Browse the repository at this point in the history
  • Loading branch information
dotnetCarpenter committed Jun 7, 2017
1 parent b033a97 commit 59d2f3c
Show file tree
Hide file tree
Showing 8 changed files with 396 additions and 51 deletions.
7 changes: 6 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
.DS_Store
.idea
node_modules/
.vscode/
**/.*
node_modules
bower_components
test
tests
package-lock.json
5 changes: 4 additions & 1 deletion bower.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,8 @@
"bower_components",
"test",
"tests"
]
],
"dependencies": {
"svg.js": "^2.6.2"
}
}
192 changes: 192 additions & 0 deletions dist/svg.panzoom.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
/*!
* svg.panzoom.js - A plugin for svg.js that enables panzoom for viewport elements
* @version 1.0.0
* https://github.com/svgdotjs/svg.panzoom.js#readme
*
* @copyright Ulrich-Matthias Schäfer
* @license MIT
*/;
;(function() {
"use strict";

var normalizeEvent = function(ev) {
if(!ev.touches) {
ev.touches = [{clientX: ev.clientX, clientY: ev.clientY}]
}

return ev.touches
}

SVG.extend(SVG.Doc, SVG.Nested, {

panZoom: function(options) {
options = options || {}
var zoomFactor = options.zoomFactor || 0.03

var lastP, lastTouches, zoomInProgress = false

var wheelZoom = function(ev) {
ev.preventDefault()

var zoomAmount = this.zoom() - zoomFactor * ev.deltaY/Math.abs(ev.deltaY)
, p = this.point(ev.clientX, ev.clientY)

this.zoom(zoomAmount, p)
}

var pinchZoomStart = function(ev) {
lastTouches = normalizeEvent(ev)

if(lastTouches.length < 2) return
ev.preventDefault()

if(this.fire('pinchZoomStart', {event: ev}).event().defaultPrevented)
return

this.off('touchstart', pinchZoomStart)

zoomInProgress = true
SVG.on(document, 'touchmove', pinchZoom, this, {passive:false})
SVG.on(document, 'touchend', pinchZoomStop, this, {passive:false})
}

var pinchZoomStop = function(ev) {
ev.preventDefault()
zoomInProgress = false

this.fire('pinchZoomEnd', {event: ev})

SVG.off(document,'touchmove', pinchZoom)
SVG.off(document,'touchend', pinchZoomStop)
this.on('touchstart', pinchZoomStart)
}

var pinchZoom = function(ev) {
ev.preventDefault()

var currentTouches = normalizeEvent(ev)

// Distance Formula
var lastDelta = Math.sqrt(
Math.pow(lastTouches[0].clientX - lastTouches[1].clientX, 2) +
Math.pow(lastTouches[0].clientY - lastTouches[1].clientY, 2)
)

var currentDelta = Math.sqrt(
Math.pow(currentTouches[0].clientX - currentTouches[1].clientX, 2) +
Math.pow(currentTouches[0].clientY - currentTouches[1].clientY, 2)
)

var zoomAmount = lastDelta/currentDelta

var currentFocus = {
x: currentTouches[0].clientX + 0.5 * (currentTouches[1].clientX - currentTouches[0].clientX),
y: currentTouches[0].clientY + 0.5 * (currentTouches[1].clientY - currentTouches[0].clientY)
}

var lastFocus = {
x: lastTouches[0].clientX + 0.5 * (lastTouches[1].clientX - lastTouches[0].clientX),
y: lastTouches[0].clientY + 0.5 * (lastTouches[1].clientY - lastTouches[0].clientY)
}

var p = this.point(currentFocus.x, currentFocus.y)
var focusP = this.point(2*currentFocus.x-lastFocus.x, 2*currentFocus.y-lastFocus.y)
var box = new SVG.Box(this.viewbox()).transform(
new SVG.Matrix()
.translate(p.x, p.y)
.scale(zoomAmount, 0, 0)
.translate(-focusP.x, -focusP.y)
)

this.viewbox(box)

lastTouches = currentTouches

this.fire('zoom', {box: box, focus: focusP})
}

var panStart = function(ev) {
ev.preventDefault()

this.off('mousedown', panStart)

lastTouches = normalizeEvent(ev)

if(zoomInProgress) return

this.fire('panStart', {event: ev})

lastP = {x: lastTouches[0].clientX, y: lastTouches[0].clientY }

SVG.on(document, 'mousemove', panning, this, {passive:false})
SVG.on(document, 'mouseup', panStop, this, {passive:false})
}

var panStop = function(ev) {
ev.preventDefault()

this.fire('panEnd', {event: ev})

SVG.off(document,'mousemove', panning)
SVG.off(document,'mouseup', panStop)
this.on('mousedown', panStart)
}

var panning = function(ev) {
ev.preventDefault()

var currentTouches = normalizeEvent(ev)

var currentP = {x: currentTouches[0].clientX, y: currentTouches[0].clientY }
, p1 = this.point(currentP.x, currentP.y)
, p2 = this.point(lastP.x, lastP.y)
, deltaP = [p2.x - p1.x, p2.y - p1.y]
, box = new SVG.Box(this.viewbox()).transform(new SVG.Matrix().translate(deltaP[0], deltaP[1]))

this.viewbox(box)
lastP = currentP
}

this.on('wheel', wheelZoom)
this.on('touchstart', pinchZoomStart, this, {passive:false})
this.on('mousedown', panStart, this)

return this

},

zoom: function(level, point) {
var style = window.getComputedStyle(this.node)
, width = parseFloat(style.getPropertyValue('width'))
, height = parseFloat(style.getPropertyValue('height'))
, v = this.viewbox()
, zoomX = width / v.width
, zoomY = height / v.height
, zoom = Math.min(zoomX, zoomY)

if(level == null) {
return zoom
}

var zoomAmount = (zoom / level)

point = point || new SVG.Point(width/2 / zoomX + v.x, height/2 / zoomY + v.y)

var box = new SVG.Box(v)
.transform(new SVG.Matrix()
.scale(zoomAmount, point.x, point.y)
)

if(this.fire('zoom', {box: box, focus: point}).event().defaultPrevented)
return this

return this.viewbox(box)
}
})

SVG.extend(SVG.FX, {
zoom: function(level, point) {
return this.add('zoom', new SVG.Number(level), point)
}
})
}());
1 change: 1 addition & 0 deletions dist/svg.panzoom.min.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

48 changes: 48 additions & 0 deletions gulpfile.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
var del = require('del')
, gulp = require('gulp')
, header = require('gulp-header')
, iife = require('gulp-iife')
, rename = require('gulp-rename')
, trim = require('gulp-trimlines')
, uglify = require('gulp-uglify')
, pkg = require('./package.json')


var headerLong = ['/*!'
, '* <%= pkg.name %> - <%= pkg.description %>'
, '* @version <%= pkg.version %>'
, '* <%= pkg.homepage %>'
, '*'
, '* @copyright <%= pkg.author %>'
, '* @license <%= pkg.license %>'
, '*/;'
, ''].join('\n')

var headerShort = '/*! <%= pkg.name %> v<%= pkg.version %> <%= pkg.license %>*/;'

gulp.task('clean', function() {
return del([ 'dist/*' ])
})

gulp.task('copy', ['clean'], function() {
return gulp.src('src/svg.panzoom.js')
.pipe(iife())
.pipe(header(headerLong, { pkg: pkg }))
.pipe(trim({ leading: false }))
.pipe(gulp.dest('dist'))
})

/**
‎* uglify the file
* add the license info
*/
gulp.task('minify', ['copy'], function() {
return gulp.src('dist/svg.panzoom.js')
.pipe(uglify())
.pipe(rename({ suffix:'.min' }))
.pipe(header(headerShort, { pkg: pkg }))
.pipe(gulp.dest('dist'))
})


gulp.task('default', ['clean', 'copy', 'minify'])
18 changes: 15 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
{
"name": "svg.panzoom.js",
"version": "0.0.1",
"version": "1.0.0",
"description": "A plugin for svg.js that enables panzoom for viewport elements",
"main": "svg.panzoom.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
"test": "echo \"Error: no test specified\" && exit 1",
"build": "gulp"
},
"repository": {
"type": "git",
Expand All @@ -21,6 +22,17 @@
},
"homepage": "https://github.com/svgdotjs/svg.panzoom.js#readme",
"dependencies": {
"svg.js": "^2.5.3"
"svg.js": "^2.6.2"
},
"devDependencies": {
"del": "^2.2.2",
"gulp": "^3.9.1",
"gulp-header": "^1.8.8",
"gulp-iife": "^0.3.0",
"gulp-rename": "^1.2.2",
"gulp-standard": "^10.0.0",
"gulp-trimlines": "^1.0.1",
"gulp-uglify": "^2.1.2",
"gulp-wrap-iife": "0.0.1"
}
}
67 changes: 64 additions & 3 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
> A plugin for [svg.js](ttps://github.com/svgdotjs/svg.js) that enables panzoom for viewport elements

## Get started
## Getting started

```
npm install svg.panzoom.js
Expand All @@ -13,5 +13,66 @@ npm install svg.panzoom.js
var draw = SVG('id').size(1000,1000).panZoom()
```

Thats it - no magic involved.
This plugin also works on mobile devices (at least on Android) when used with svg.js v2.6 and above
The SVG element now support panning via mouse-down/mouse-move
and zooming via the mouse wheel. On touch devices, pinch-zoom
support allow you to pan and zoom in one gesture.

You can also animate zooming:

```js
draw.zoom(1) // uses center of viewport by default
.animate()
.zoom(2, {x:100, y:100}) // zoom into specified point
```


## API

`svg.panzoom.js` adds the `.zoom()` method to the element `.panZoom()` is called on.

This comment has been minimized.

Copy link
@Fuzzyma

Fuzzyma Jun 7, 2017

Member

zoom is available on all viewport elements and not only elements you called panzoom on

This comment has been minimized.

Copy link
@dotnetCarpenter

dotnetCarpenter Jun 7, 2017

Author Member

You're right


- `zoom()` - returns current zoom level
- `zoom(Number)` - will zoom in or out depending if the Number is greater or less than the current zoom level
- `zoom(Number, {x,y})` - will zoom with the x/y coordinate as center point
- `zoom(Number, new SVG.Point(x,y))` - will zoom with the x/y coordinate as center point

| Method | Return Value |
| ---------------------------------- | ------------ |
| `zoom()` | Number |
| `zoom(Number)` | element |
| `zoom(Number, {x,y})` | element |
| `zoom(Number, new SVG.Point(x,y))` | element |


## Events

Multiple events are fired doing different actions. This allow you to respond
to actions and in some cases stop an action via `preventDefault()`.

`zoom` is fired when a mouse wheel event or programmable `zoom()` triggers
a zoom. This usually doesn't happen on mobile devices, in which case
`pinchZoomStart` is fired when a zoom happens.

Events fired from SVG.js are [`CustomEvent`s](http://devdocs.io/dom/customevent),
so the arguments passed from svg.panzoom.js are in in the `.detail` property.

| Event Name | Argument Value | preventDefault support |
| -------------- | ---------------- | ---------------------- |
| zoom | `{ box, focus }` | YES |
| panStart | `{ event }` | NO |
| panEnd | `{ event }` | NO |
| pinchZoomStart | `{ event }` | YES |
| pinchZoomEnd | `{ event }` | NO |

Where [`box`](http://svgjs.com/geometry/#svg-box) is the new viewport,
[`focus`](http://svgjs.com/classes/#svg-point) is point of zoom
and event is the event that triggered the action.

An example of stopping a pan-zoom action:

```js
var draw = SVG('id').size(1000,1000).panZoom()
draw.on('pinchZoomStart', function(ev) {
ev.preventDefault()
...
})
```
Loading

0 comments on commit 59d2f3c

Please sign in to comment.