From 4f40f37a3f8c61a90be2e648f6fef89c47d57f02 Mon Sep 17 00:00:00 2001 From: Timmy Willison Date: Thu, 25 Jul 2013 14:12:10 -0400 Subject: [PATCH] Add dValue option to zoom(). Trigger zoom and pan events on resetZoom/resetPan. --- README.md | 34 ++-- bower.json | 2 +- dist/jquery.panzoom.js | 78 +++++---- dist/jquery.panzoom.min.js | 6 +- jquery.panzoom.js | 74 +++++---- package.json | 2 +- panzoom.jquery.json | 2 +- test/bdd/test.js | 317 ++++++++++++++++++++++--------------- 8 files changed, 303 insertions(+), 212 deletions(-) diff --git a/README.md b/README.md index 4151b217..25f5bcbe 100644 --- a/README.md +++ b/README.md @@ -6,8 +6,8 @@ And although IE<=8 is not supported, this plugin is future-proof. jquery.panzoom.min.js (8.7kb/3.3kb gzip), included in this repo, is compressed with [uglifyjs](https://github.com/mishoo/UglifyJS). -[Download version 1.3.8](https://raw.github.com/timmywil/jquery.panzoom/v1.3.8/dist/jquery.panzoom.min.js) -[Development version](https://raw.github.com/timmywil/jquery.panzoom/v1.3.8/dist/jquery.panzoom.js) +[Download version 1.4.0](https://raw.github.com/timmywil/jquery.panzoom/v1.4.0/dist/jquery.panzoom.min.js) +[Development version](https://raw.github.com/timmywil/jquery.panzoom/v1.4.0/dist/jquery.panzoom.js) ## Mobile support @@ -148,40 +148,54 @@ $elem.panzoom("option", { Any option can be changed. See the defaults above for a list. -### `reset( [animate] )` +### `reset( [options] )` __Arguments__ - 1. `animate` _{Boolean}_: Whether to animate the reset (default: true) + 1. `options` _{Object|Boolean}_: If a boolean is passed, animate the reset (default: true). If an options object is passed, simply pass that along to setMatrix. + 2. `options.silent` _{Boolean}_: Silence the reset event (as well as the change event as the same options are passed to setMatrix) ```js $elem.panzoom("reset"); +$elem.panzoom("reset", false); +$elem.panzoom("reset", { + animate: false, + contain: false +}); ``` Reset the transform matrix to its original value. All panning and zooming is reset. -### `resetZoom( [animate] )` +### `resetZoom( [options] )` __Arguments__ - 1. `animate` _{Boolean}_: Whether to animate the reset (default: true) + 1. `options` _{Object|Boolean}_: If a boolean is passed, animate the reset (default: true). If an options object is passed, simply pass that along to zoom. ```js $elem.panzoom("resetZoom"); $elem.panzoom("resetZoom", false); +$elem.panzoom("resetZoom", { + animate: false, + silent: true +}); ``` -Reset the scale to its original value. +Reset the scale to its original value (resets both scale values in the matrix to their original values). -### `resetPan( [animate] )` +### `resetPan( [options] )` __Arguments__ - 1. `animate` _{Boolean}_: Whether to animate the reset (default: true) + 1. `options` _{Object|Boolean}_: If a boolean is passed, animate the reset (default: true). If an options object is passed, simply pass that along to pan. ```js $elem.panzoom("resetPan"); $elem.panzoom("resetPan", false); +$elem.panzoom("resetPan", { + animate: false, + silent: true +}); ``` Reset the pan to its original value. @@ -310,7 +324,7 @@ __Arguments__ $elem.panzoom("setMatrix", [ 1, 0, 0, -1, 0, 0 ]); ``` -Sets the transform matrix of the panzoom element. It accepts the matrix as an array. The return value is `undefined`. +Sets the transform matrix of the panzoom element. It accepts the matrix as an array. Returns the newly-set matrix as an _Array_. ### `transition( [off] )` diff --git a/bower.json b/bower.json index 325999dd..e5871642 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "jquery.panzoom", - "version": "1.3.8", + "version": "1.4.0", "main": "dist/jquery.panzoom.js", "ignore": [ "**/.*", diff --git a/dist/jquery.panzoom.js b/dist/jquery.panzoom.js index 8a384ce7..a56bce7c 100644 --- a/dist/jquery.panzoom.js +++ b/dist/jquery.panzoom.js @@ -1,6 +1,6 @@ /** - * @license jquery.panzoom.js v1.3.8 - * Updated: Thu Jul 18 2013 + * @license jquery.panzoom.js v1.4.0 + * Updated: Thu Jul 25 2013 * Add pan and zoom functionality to any element * Copyright (c) 2013 timmy willison * Released under the MIT license @@ -56,6 +56,21 @@ floating + '\\)$' ); + /** + * Creates the options object for reset functions + * @param {Boolean|Object} opts See reset methods + * @returns {Object} Returns the newly-created options object + */ + function createResetOptions( opts ) { + var options = { range: true, animate: true }; + if ( typeof opts === 'boolean' ) { + options.animate = opts; + } else { + $.extend( options, opts ); + } + return options; + } + /** * Create a Panzoom object for a given element * @constructor @@ -216,32 +231,36 @@ /** * Return the element to it's original transform matrix - * @param {Boolean} [animate] Whether to animate the reset (default: true) + * @param {Boolean} [options] If a boolean is passed, animate the reset (default: true). If an options object is passed, simply pass that along to setMatrix. + * @param {Boolean} [options.silent] Silence the reset event */ - reset: function( animate ) { + reset: function( options ) { + options = createResetOptions( options ); // Reset the transform to its original value - var matrix = this.setMatrix( this._origTransform, { - animate: typeof animate !== 'boolean' || animate, - // Set zoomRange value - range: true - }); - this._trigger( 'reset', matrix ); + var matrix = this.setMatrix( this._origTransform, options ); + if ( !options.silent ) { + this._trigger( 'reset', matrix ); + } }, /** * Only resets zoom level - * @param {Boolean} [animate] Whether to animate the reset (default: true) + * @param {Boolean|Object} [options] Whether to animate the reset (default: true) or an object of options to pass to zoom() */ - resetZoom: function( animate ) { - this._resetParts( [ 0, 3 ], animate ); + resetZoom: function( options ) { + options = createResetOptions( options ); + var origMatrix = this.getMatrix( this._origTransform ); + options.dValue = origMatrix[ 3 ]; + this.zoom( origMatrix[0], options ); }, /** * Only reset panning - * @param {Boolean} [animate] Whether to animate the reset (default: true) + * @param {Boolean|Object} [options] Whether to animate the reset (default: true) or an object of options to pass to pan() */ - resetPan: function( animate ) { - this._resetParts( [ 4, 5 ], animate ); + resetPan: function( options ) { + var origMatrix = this.getMatrix( this._origTransform ); + this.pan( origMatrix[4], origMatrix[5], createResetOptions(options) ); }, /** @@ -288,7 +307,7 @@ * @param {Boolean} [options.contain] Override the global contain option * @param {Boolean} [options.range] If true, $zoomRange's value will be updated. * @param {Boolean} [options.silent] If true, the change event will not be triggered - * @returns {Array} Returns the matrix that was set + * @returns {Array} Returns the newly-set matrix */ setMatrix: function( matrix, options ) { if ( this.disabled ) { return; } @@ -328,6 +347,7 @@ if ( !options.silent ) { this._trigger( 'change', matrix ); } + return matrix; }, @@ -385,6 +405,10 @@ * @param {Object} [opts.middle] Specify a middle point towards which to gravitate when zooming * @param {Boolean} [opts.animate] Whether to animate the zoom (defaults to true if scale is not a number, false otherwise) * @param {Boolean} [opts.silent] Silence the zoom event + * @param {Number} [opts.dValue] Think of a transform matrix as four values a, b, c, d (where a/d are the horizontal/vertical scale values and b/c are the skew values) (5 and 6 of matrix array are the tx/ty transform values). + * Normally, the scale is set to both the a and d values of the matrix. + * This option allows you to specify a different d value for the zoom. For instance, to flip vertically, you could set -1 as the dValue. + * @returns {Array} Returns the newly-set matrix */ zoom: function( scale, opts ) { var animate = false; @@ -420,7 +444,8 @@ } // Set the scale - matrix[0] = matrix[3] = scale; + matrix[0] = scale; + matrix[3] = typeof opts.dValue === 'number' ? opts.dValue : scale; this.setMatrix( matrix, { animate: typeof opts.animate === 'boolean' ? opts.animate : animate, // Set the zoomRange value @@ -705,23 +730,6 @@ } }, - /** - * Reset certain parts of the transform - */ - _resetParts: function( indices, animate ) { - var origMatrix = this.getMatrix( this._origTransform ); - var cur = this.getMatrix(); - var i = indices.length; - while( i-- ) { - cur[ indices[i] ] = origMatrix[ indices[i] ]; - } - this.setMatrix(cur, { - animate: typeof animate !== 'boolean' || animate, - // Set zoomRange value - range: true - }); - }, - /** * Calculates the distance between two touch points * Remember pythagorean? diff --git a/dist/jquery.panzoom.min.js b/dist/jquery.panzoom.min.js index fbef8d0e..eaf80559 100644 --- a/dist/jquery.panzoom.min.js +++ b/dist/jquery.panzoom.min.js @@ -1,9 +1,9 @@ /** - * @license jquery.panzoom.js v1.3.8 - * Updated: Thu Jul 18 2013 + * @license jquery.panzoom.js v1.4.0 + * Updated: Thu Jul 25 2013 * Add pan and zoom functionality to any element * Copyright (c) 2013 timmy willison * Released under the MIT license * https://github.com/timmywil/jquery.panzoom/blob/master/MIT-License.txt */ -(function(t,e){"function"==typeof define&&define.amd?define(["jquery"],e):e(t.jQuery)})(this,function(t){"use strict";var e={props:["touches","pageX","pageY"],filter:function(t,e){var n;return!e.pageX&&e.touches&&(n=e.touches[0])&&(t.pageX=n.pageX,t.pageY=n.pageY),t}};t.each(["touchstart","touchmove","touchend"],function(n,i){t.event.fixHooks[i]=e});var n="__pz__",i=Array.prototype.slice,a=/([A-Z])/g,s=/^http:[\w\.\/]+svg$/,o="(\\-?[\\d\\.e]+)",r="\\,?\\s*",h=RegExp("^matrix\\("+o+r+o+r+o+r+o+r+o+r+o+"\\)$"),c=function(e,i){1!==e.nodeType&&t.error("Panzoom called on non-Element node"),t.contains(document,e)||t.error("Panzoom element must be attached to the document");var o=t.data(e,n);if(o)return o;if(!(this instanceof c))return new c(e,i);this.options=i=t.extend({},c.defaults,i),this.elem=e;var r=this.$elem=t(e);this.$parent=r.parent(),this.isSVG=s.test(e.namespaceURI)&&"svg"!==e.nodeName.toLowerCase(),this.panning=!1,this._buildTransform(),this._transform=t.cssProps.transform.replace(a,"-$1").toLowerCase(),this._buildTransition(),this._buildContain();var h=t(),m=this;return t.each(["$zoomIn","$zoomOut","$zoomRange","$reset"],function(t,e){m[e]=i[e]||h}),this.enable(),t.data(e,n,this),this};return c.rmatrix=h,c.defaults={eventNamespace:".panzoom",transition:!0,cursor:"move",disablePan:!1,disableZoom:!1,increment:.3,minScale:.4,maxScale:5,duration:200,easing:"ease-in-out",contain:!1},c.prototype={constructor:c,instance:function(){return this},enable:function(){this._unbind(),this._initStyle(),this._bind(),this.disabled=!1},disable:function(){this.disabled=!0,this._resetStyle(),this._unbind()},isDisabled:function(){return this.disabled},destroy:function(){this.disable(),t.removeData(this.elem,n)},reset:function(t){var e=this.setMatrix(this._origTransform,{animate:"boolean"!=typeof t||t,range:!0});this._trigger("reset",e)},resetZoom:function(t){this._resetParts([0,3],t)},resetPan:function(t){this._resetParts([4,5],t)},getTransform:function(){var e=this.elem,n=t.style(e,"transform");return this.isSVG&&!n?n=t.attr(e,"transform"):"none"===n||h.test(n)||(n=t.style(e,"transform",t.css(e,"transform"))),n||"none"},getMatrix:function(t){var e=h.exec(t||this.getTransform());return e&&e.shift(),e||[1,0,0,1,0,0]},setMatrix:function(e,n){if(!this.disabled){n||(n={}),"string"==typeof e&&(e=this.getMatrix(e));var i,a,s,o,r,h=+e[0];return(i=n.contain!==void 0?n.contain:this.options.contain)&&(a="invert"===i,s=this.container,o=this.dimensions,r=(o.width*h-s.width)/2,e[4]=Math[a?"max":"min"](Math[a?"min":"max"](e[4],r-o.left),-r-o.left),r=(o.height*h-s.height)/2,e[5]=Math[a?"max":"min"](Math[a?"min":"max"](e[5],r-o.top),-r-o.top)),"skip"!==n.animate&&this.transition(!n.animate),n.range&&this.$zoomRange.val(h),t[this.isSVG?"attr":"style"](this.elem,"transform","matrix("+e.join(",")+")"),n.silent||this._trigger("change",e),e}},isPanning:function(){return this.panning},transition:function(e){var n=e||!this.options.transition?"none":this._transition;t.style(this.elem,"transition",n)},pan:function(t,e,n){n||(n={});var i=n.matrix;i||(i=this.getMatrix()),n.relative?(i[4]=+i[4]+t,i[5]=+i[5]+e):(i[4]=t,i[5]=e),this.setMatrix(i,n),n.silent||this._trigger("pan",t,e)},zoom:function(t,e){var n=!1,i=this.options;if(!i.disableZoom){"object"==typeof t?(e=t,t=null):e||(e={});var a=this.getMatrix(),s=e.middle;s&&(a[4]=+a[4]+(s.pageX===a[4]?0:s.pageX>a[4]?1:-1),a[5]=+a[5]+(s.pageY===a[5]?0:s.pageY>a[5]?1:-1)),"number"!=typeof t&&(t=+a[0]+i.increment*(t?-1:1),n=!0),t>i.maxScale?t=i.maxScale:i.minScale>t&&(t=i.minScale),a[0]=a[3]=t,this.setMatrix(a,{animate:"boolean"==typeof e.animate?e.animate:n,range:!e.noSetRange}),e.silent||this._trigger("zoom",t,e)}},option:function(e,n){var i;if(!e)return t.extend({},this.options);if("string"==typeof e){if(1===arguments.length)return this.options[e];i={},i[e]=n}else i=e;this._setOptions(i)},_setOptions:function(e){var n=this;t.each(e,function(e,i){switch(e){case"disablePan":n._resetStyle();case"disableZoom":case"$zoomIn":case"$zoomOut":case"$zoomRange":case"$reset":case"onStart":case"onChange":case"onZoom":case"onPan":case"onEnd":case"onReset":case"eventNamespace":n._unbind()}switch(n.options[e]=i,e){case"disablePan":n._initStyle();case"disableZoom":case"$zoomIn":case"$zoomOut":case"$zoomRange":case"$reset":case"onStart":case"onChange":case"onZoom":case"onPan":case"onEnd":case"onReset":case"eventNamespace":n._bind();break;case"cursor":t.style(n.elem,"cursor",i);break;case"minScale":n.$zoomRange.attr("min",i);break;case"maxScale":n.$zoomRange.attr("max",i);break;case"contain":n._buildContain();break;case"startTransform":n._buildTransform();break;case"duration":case"easing":n._buildTransition();case"transition":n.transition()}})},_initStyle:function(){this.options.disablePan||this.$elem.css("cursor",this.options.cursor);var e=this.$parent;if(e.length&&!t.nodeName(e[0],"body")){var n={overflow:"hidden"};"static"===e.css("position")&&(n.position="relative"),e.css(n)}},_resetStyle:function(){this.$elem.css({cursor:"",transition:""}),this.$parent.css({overflow:"",position:""})},_bind:function(){var e=this,n=this.options,i=n.eventNamespace,a="touchstart"+i+" mousedown"+i,s="touchend"+i+" click"+i,o={};if(t.each(["Start","Change","Zoom","Pan","End","Reset"],function(){var e=n["on"+this];t.isFunction(e)&&(o["panzoom"+this.toLowerCase()+i]=e)}),n.disablePan&&n.disableZoom||(o[a]=function(t){var i;("mousedown"===t.type?n.disablePan||1!==t.which:!(i=t.touches)||(1!==i.length||n.disablePan)&&2!==i.length)||(t.preventDefault(),t.stopPropagation(),e._startMove(t,i))}),this.$elem.on(o),!n.disableZoom){var r=this.$zoomIn,h=this.$zoomOut,c=this.$zoomRange,m=this.$reset;r.length&&h.length&&(r.on(s,function(t){t.preventDefault(),e.zoom()}),h.on(s,function(t){t.preventDefault(),e.zoom(!0)})),c.length&&(c.attr({min:n.minScale,max:n.maxScale,step:.05}).prop({value:this.getMatrix()[0]}),o={},o.mousedown=function(){e.transition(!0)},o["change"+i]=function(){e.zoom(+this.value,{noSetRange:!0})},c.on(o)),m.length&&m.on(s,function(t){t.preventDefault(),e.reset()})}},_unbind:function(){this.$elem.add(this.$zoomIn).add(this.$zoomOut).add(this.$reset).off(this.options.eventNamespace)},_buildTransform:function(){this._origTransform=this.options.startTransform||this.getTransform()},_buildTransition:function(){var t=this.options;this._transform&&(this._transition=this._transform+" "+t.duration+"ms "+t.easing)},_buildContain:function(){if(this.options.contain){var e=this.$parent;this.container={width:e.width(),height:e.height()};var n=this.elem,i=this.$elem;this.dimensions=this.isSVG?{left:n.getAttribute("x")||0,top:n.getAttribute("y")||0,width:n.getAttribute("width")||i.width(),height:n.getAttribute("height")||i.height()}:{left:t.css(n,"left",!0)||0,top:t.css(n,"top",!0)||0,width:i.width(),height:i.height()}}},_resetParts:function(t,e){for(var n=this.getMatrix(this._origTransform),i=this.getMatrix(),a=t.length;a--;)i[t[a]]=n[t[a]];this.setMatrix(i,{animate:"boolean"!=typeof e||e,range:!0})},_getDistance:function(t){var e=t[0],n=t[1];return Math.sqrt(Math.pow(Math.abs(n.pageX-e.pageX),2)+Math.pow(Math.abs(n.pageY-e.pageY),2))},_getMiddle:function(t){var e=t[0],n=t[1];return{pageX:(n.pageX-e.pageX)/2+e.pageX,pageY:(n.pageY-e.pageY)/2+e.pageY}},_trigger:function(t){this.$elem.triggerHandler("panzoom"+t,[this].concat(i.call(arguments,1)))},_startMove:function(e,n){var i,a,s,o,r,h,c=this,m=this.options,u="touchstart"===e.type,g=m.eventNamespace,l=(u?"touchmove":"mousemove")+g,p=(u?"touchend":"mouseup")+g,f=this.getMatrix(),d={matrix:f,animate:"skip"},v=f.slice(0),b=+v[4],_=+v[5];this.transition(!0),this.panning=!0,this._trigger("start",e,n),n&&2===n.length?(a=this._getDistance(n),s=+f[0],o=this._getMiddle(n),i=function(t){t.preventDefault();var e=c._getMiddle(n=t.touches);c.pan(b+e.pageX-o.pageX,_+e.pageY-o.pageY,d);var i=c._getDistance(n)-a;c.zoom(i/300+s,{middle:e})}):(r=e.pageX,h=e.pageY,i=function(t){t.preventDefault(),c.pan(b+t.pageX-r,_+t.pageY-h,d)}),t(document).off(g).on(l,i).on(p,function(e){e.preventDefault(),t(this).off(g),c.panning=!1,c._trigger("end",f,!!t(v).not(f).length)})}},t.fn.panzoom=function(e){var a,s,o,r;return"string"==typeof e?(r=[],s=i.call(arguments,1),this.each(function(){a=t.data(this,n),a?"_"!==e.charAt(0)&&"function"==typeof(o=a[e])&&void 0!==(o=o.apply(a,s))&&r.push(o):r.push(void 0)}),r.length?1===r.length?r[0]:r:this):this.each(function(){new c(this,e)})},c}); \ No newline at end of file +(function(t,e){"function"==typeof define&&define.amd?define(["jquery"],e):e(t.jQuery)})(this,function(t){"use strict";function e(e){var n={range:!0,animate:!0};return"boolean"==typeof e?n.animate=e:t.extend(n,e),n}var n={props:["touches","pageX","pageY"],filter:function(t,e){var n;return!e.pageX&&e.touches&&(n=e.touches[0])&&(t.pageX=n.pageX,t.pageY=n.pageY),t}};t.each(["touchstart","touchmove","touchend"],function(e,i){t.event.fixHooks[i]=n});var i="__pz__",a=Array.prototype.slice,s=/([A-Z])/g,o=/^http:[\w\.\/]+svg$/,r="(\\-?[\\d\\.e]+)",h="\\,?\\s*",c=RegExp("^matrix\\("+r+h+r+h+r+h+r+h+r+h+r+"\\)$"),u=function(e,n){1!==e.nodeType&&t.error("Panzoom called on non-Element node"),t.contains(document,e)||t.error("Panzoom element must be attached to the document");var a=t.data(e,i);if(a)return a;if(!(this instanceof u))return new u(e,n);this.options=n=t.extend({},u.defaults,n),this.elem=e;var r=this.$elem=t(e);this.$parent=r.parent(),this.isSVG=o.test(e.namespaceURI)&&"svg"!==e.nodeName.toLowerCase(),this.panning=!1,this._buildTransform(),this._transform=t.cssProps.transform.replace(s,"-$1").toLowerCase(),this._buildTransition(),this._buildContain();var h=t(),c=this;return t.each(["$zoomIn","$zoomOut","$zoomRange","$reset"],function(t,e){c[e]=n[e]||h}),this.enable(),t.data(e,i,this),this};return u.rmatrix=c,u.defaults={eventNamespace:".panzoom",transition:!0,cursor:"move",disablePan:!1,disableZoom:!1,increment:.3,minScale:.4,maxScale:5,duration:200,easing:"ease-in-out",contain:!1},u.prototype={constructor:u,instance:function(){return this},enable:function(){this._unbind(),this._initStyle(),this._bind(),this.disabled=!1},disable:function(){this.disabled=!0,this._resetStyle(),this._unbind()},isDisabled:function(){return this.disabled},destroy:function(){this.disable(),t.removeData(this.elem,i)},reset:function(t){t=e(t);var n=this.setMatrix(this._origTransform,t);t.silent||this._trigger("reset",n)},resetZoom:function(t){t=e(t);var n=this.getMatrix(this._origTransform);t.dValue=n[3],this.zoom(n[0],t)},resetPan:function(t){var n=this.getMatrix(this._origTransform);this.pan(n[4],n[5],e(t))},getTransform:function(){var e=this.elem,n=t.style(e,"transform");return this.isSVG&&!n?n=t.attr(e,"transform"):"none"===n||c.test(n)||(n=t.style(e,"transform",t.css(e,"transform"))),n||"none"},getMatrix:function(t){var e=c.exec(t||this.getTransform());return e&&e.shift(),e||[1,0,0,1,0,0]},setMatrix:function(e,n){if(!this.disabled){n||(n={}),"string"==typeof e&&(e=this.getMatrix(e));var i,a,s,o,r,h=+e[0];return(i=n.contain!==void 0?n.contain:this.options.contain)&&(a="invert"===i,s=this.container,o=this.dimensions,r=(o.width*h-s.width)/2,e[4]=Math[a?"max":"min"](Math[a?"min":"max"](e[4],r-o.left),-r-o.left),r=(o.height*h-s.height)/2,e[5]=Math[a?"max":"min"](Math[a?"min":"max"](e[5],r-o.top),-r-o.top)),"skip"!==n.animate&&this.transition(!n.animate),n.range&&this.$zoomRange.val(h),t[this.isSVG?"attr":"style"](this.elem,"transform","matrix("+e.join(",")+")"),n.silent||this._trigger("change",e),e}},isPanning:function(){return this.panning},transition:function(e){var n=e||!this.options.transition?"none":this._transition;t.style(this.elem,"transition",n)},pan:function(t,e,n){n||(n={});var i=n.matrix;i||(i=this.getMatrix()),n.relative?(i[4]=+i[4]+t,i[5]=+i[5]+e):(i[4]=t,i[5]=e),this.setMatrix(i,n),n.silent||this._trigger("pan",t,e)},zoom:function(t,e){var n=!1,i=this.options;if(!i.disableZoom){"object"==typeof t?(e=t,t=null):e||(e={});var a=this.getMatrix(),s=e.middle;s&&(a[4]=+a[4]+(s.pageX===a[4]?0:s.pageX>a[4]?1:-1),a[5]=+a[5]+(s.pageY===a[5]?0:s.pageY>a[5]?1:-1)),"number"!=typeof t&&(t=+a[0]+i.increment*(t?-1:1),n=!0),t>i.maxScale?t=i.maxScale:i.minScale>t&&(t=i.minScale),a[0]=t,a[3]="number"==typeof e.dValue?e.dValue:t,this.setMatrix(a,{animate:"boolean"==typeof e.animate?e.animate:n,range:!e.noSetRange}),e.silent||this._trigger("zoom",t,e)}},option:function(e,n){var i;if(!e)return t.extend({},this.options);if("string"==typeof e){if(1===arguments.length)return this.options[e];i={},i[e]=n}else i=e;this._setOptions(i)},_setOptions:function(e){var n=this;t.each(e,function(e,i){switch(e){case"disablePan":n._resetStyle();case"disableZoom":case"$zoomIn":case"$zoomOut":case"$zoomRange":case"$reset":case"onStart":case"onChange":case"onZoom":case"onPan":case"onEnd":case"onReset":case"eventNamespace":n._unbind()}switch(n.options[e]=i,e){case"disablePan":n._initStyle();case"disableZoom":case"$zoomIn":case"$zoomOut":case"$zoomRange":case"$reset":case"onStart":case"onChange":case"onZoom":case"onPan":case"onEnd":case"onReset":case"eventNamespace":n._bind();break;case"cursor":t.style(n.elem,"cursor",i);break;case"minScale":n.$zoomRange.attr("min",i);break;case"maxScale":n.$zoomRange.attr("max",i);break;case"contain":n._buildContain();break;case"startTransform":n._buildTransform();break;case"duration":case"easing":n._buildTransition();case"transition":n.transition()}})},_initStyle:function(){this.options.disablePan||this.$elem.css("cursor",this.options.cursor);var e=this.$parent;if(e.length&&!t.nodeName(e[0],"body")){var n={overflow:"hidden"};"static"===e.css("position")&&(n.position="relative"),e.css(n)}},_resetStyle:function(){this.$elem.css({cursor:"",transition:""}),this.$parent.css({overflow:"",position:""})},_bind:function(){var e=this,n=this.options,i=n.eventNamespace,a="touchstart"+i+" mousedown"+i,s="touchend"+i+" click"+i,o={};if(t.each(["Start","Change","Zoom","Pan","End","Reset"],function(){var e=n["on"+this];t.isFunction(e)&&(o["panzoom"+this.toLowerCase()+i]=e)}),n.disablePan&&n.disableZoom||(o[a]=function(t){var i;("mousedown"===t.type?n.disablePan||1!==t.which:!(i=t.touches)||(1!==i.length||n.disablePan)&&2!==i.length)||(t.preventDefault(),t.stopPropagation(),e._startMove(t,i))}),this.$elem.on(o),!n.disableZoom){var r=this.$zoomIn,h=this.$zoomOut,c=this.$zoomRange,u=this.$reset;r.length&&h.length&&(r.on(s,function(t){t.preventDefault(),e.zoom()}),h.on(s,function(t){t.preventDefault(),e.zoom(!0)})),c.length&&(c.attr({min:n.minScale,max:n.maxScale,step:.05}).prop({value:this.getMatrix()[0]}),o={},o.mousedown=function(){e.transition(!0)},o["change"+i]=function(){e.zoom(+this.value,{noSetRange:!0})},c.on(o)),u.length&&u.on(s,function(t){t.preventDefault(),e.reset()})}},_unbind:function(){this.$elem.add(this.$zoomIn).add(this.$zoomOut).add(this.$reset).off(this.options.eventNamespace)},_buildTransform:function(){this._origTransform=this.options.startTransform||this.getTransform()},_buildTransition:function(){var t=this.options;this._transform&&(this._transition=this._transform+" "+t.duration+"ms "+t.easing)},_buildContain:function(){if(this.options.contain){var e=this.$parent;this.container={width:e.width(),height:e.height()};var n=this.elem,i=this.$elem;this.dimensions=this.isSVG?{left:n.getAttribute("x")||0,top:n.getAttribute("y")||0,width:n.getAttribute("width")||i.width(),height:n.getAttribute("height")||i.height()}:{left:t.css(n,"left",!0)||0,top:t.css(n,"top",!0)||0,width:i.width(),height:i.height()}}},_getDistance:function(t){var e=t[0],n=t[1];return Math.sqrt(Math.pow(Math.abs(n.pageX-e.pageX),2)+Math.pow(Math.abs(n.pageY-e.pageY),2))},_getMiddle:function(t){var e=t[0],n=t[1];return{pageX:(n.pageX-e.pageX)/2+e.pageX,pageY:(n.pageY-e.pageY)/2+e.pageY}},_trigger:function(t){this.$elem.triggerHandler("panzoom"+t,[this].concat(a.call(arguments,1)))},_startMove:function(e,n){var i,a,s,o,r,h,c=this,u=this.options,m="touchstart"===e.type,l=u.eventNamespace,g=(m?"touchmove":"mousemove")+l,p=(m?"touchend":"mouseup")+l,f=this.getMatrix(),d={matrix:f,animate:"skip"},v=f.slice(0),b=+v[4],_=+v[5];this.transition(!0),this.panning=!0,this._trigger("start",e,n),n&&2===n.length?(a=this._getDistance(n),s=+f[0],o=this._getMiddle(n),i=function(t){t.preventDefault();var e=c._getMiddle(n=t.touches);c.pan(b+e.pageX-o.pageX,_+e.pageY-o.pageY,d);var i=c._getDistance(n)-a;c.zoom(i/300+s,{middle:e})}):(r=e.pageX,h=e.pageY,i=function(t){t.preventDefault(),c.pan(b+t.pageX-r,_+t.pageY-h,d)}),t(document).off(l).on(g,i).on(p,function(e){e.preventDefault(),t(this).off(l),c.panning=!1,c._trigger("end",f,!!t(v).not(f).length)})}},t.fn.panzoom=function(e){var n,s,o,r;return"string"==typeof e?(r=[],s=a.call(arguments,1),this.each(function(){n=t.data(this,i),n?"_"!==e.charAt(0)&&"function"==typeof(o=n[e])&&void 0!==(o=o.apply(n,s))&&r.push(o):r.push(void 0)}),r.length?1===r.length?r[0]:r:this):this.each(function(){new u(this,e)})},u}); \ No newline at end of file diff --git a/jquery.panzoom.js b/jquery.panzoom.js index 2b7374ca..277b93cc 100644 --- a/jquery.panzoom.js +++ b/jquery.panzoom.js @@ -56,6 +56,21 @@ floating + '\\)$' ); + /** + * Creates the options object for reset functions + * @param {Boolean|Object} opts See reset methods + * @returns {Object} Returns the newly-created options object + */ + function createResetOptions( opts ) { + var options = { range: true, animate: true }; + if ( typeof opts === 'boolean' ) { + options.animate = opts; + } else { + $.extend( options, opts ); + } + return options; + } + /** * Create a Panzoom object for a given element * @constructor @@ -216,32 +231,36 @@ /** * Return the element to it's original transform matrix - * @param {Boolean} [animate] Whether to animate the reset (default: true) + * @param {Boolean} [options] If a boolean is passed, animate the reset (default: true). If an options object is passed, simply pass that along to setMatrix. + * @param {Boolean} [options.silent] Silence the reset event */ - reset: function( animate ) { + reset: function( options ) { + options = createResetOptions( options ); // Reset the transform to its original value - var matrix = this.setMatrix( this._origTransform, { - animate: typeof animate !== 'boolean' || animate, - // Set zoomRange value - range: true - }); - this._trigger( 'reset', matrix ); + var matrix = this.setMatrix( this._origTransform, options ); + if ( !options.silent ) { + this._trigger( 'reset', matrix ); + } }, /** * Only resets zoom level - * @param {Boolean} [animate] Whether to animate the reset (default: true) + * @param {Boolean|Object} [options] Whether to animate the reset (default: true) or an object of options to pass to zoom() */ - resetZoom: function( animate ) { - this._resetParts( [ 0, 3 ], animate ); + resetZoom: function( options ) { + options = createResetOptions( options ); + var origMatrix = this.getMatrix( this._origTransform ); + options.dValue = origMatrix[ 3 ]; + this.zoom( origMatrix[0], options ); }, /** * Only reset panning - * @param {Boolean} [animate] Whether to animate the reset (default: true) + * @param {Boolean|Object} [options] Whether to animate the reset (default: true) or an object of options to pass to pan() */ - resetPan: function( animate ) { - this._resetParts( [ 4, 5 ], animate ); + resetPan: function( options ) { + var origMatrix = this.getMatrix( this._origTransform ); + this.pan( origMatrix[4], origMatrix[5], createResetOptions(options) ); }, /** @@ -288,7 +307,7 @@ * @param {Boolean} [options.contain] Override the global contain option * @param {Boolean} [options.range] If true, $zoomRange's value will be updated. * @param {Boolean} [options.silent] If true, the change event will not be triggered - * @returns {Array} Returns the matrix that was set + * @returns {Array} Returns the newly-set matrix */ setMatrix: function( matrix, options ) { if ( this.disabled ) { return; } @@ -328,6 +347,7 @@ if ( !options.silent ) { this._trigger( 'change', matrix ); } + return matrix; }, @@ -385,6 +405,10 @@ * @param {Object} [opts.middle] Specify a middle point towards which to gravitate when zooming * @param {Boolean} [opts.animate] Whether to animate the zoom (defaults to true if scale is not a number, false otherwise) * @param {Boolean} [opts.silent] Silence the zoom event + * @param {Number} [opts.dValue] Think of a transform matrix as four values a, b, c, d (where a/d are the horizontal/vertical scale values and b/c are the skew values) (5 and 6 of matrix array are the tx/ty transform values). + * Normally, the scale is set to both the a and d values of the matrix. + * This option allows you to specify a different d value for the zoom. For instance, to flip vertically, you could set -1 as the dValue. + * @returns {Array} Returns the newly-set matrix */ zoom: function( scale, opts ) { var animate = false; @@ -420,7 +444,8 @@ } // Set the scale - matrix[0] = matrix[3] = scale; + matrix[0] = scale; + matrix[3] = typeof opts.dValue === 'number' ? opts.dValue : scale; this.setMatrix( matrix, { animate: typeof opts.animate === 'boolean' ? opts.animate : animate, // Set the zoomRange value @@ -705,23 +730,6 @@ } }, - /** - * Reset certain parts of the transform - */ - _resetParts: function( indices, animate ) { - var origMatrix = this.getMatrix( this._origTransform ); - var cur = this.getMatrix(); - var i = indices.length; - while( i-- ) { - cur[ indices[i] ] = origMatrix[ indices[i] ]; - } - this.setMatrix(cur, { - animate: typeof animate !== 'boolean' || animate, - // Set zoomRange value - range: true - }); - }, - /** * Calculates the distance between two touch points * Remember pythagorean? diff --git a/package.json b/package.json index 7ec2a4fe..bb0df346 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "jquery.panzoom", - "version": "1.3.8", + "version": "1.4.0", "devDependencies": { "grunt": "~0.4.1", "grunt-contrib-jshint": "~0.3.0", diff --git a/panzoom.jquery.json b/panzoom.jquery.json index 403157ec..732b9279 100644 --- a/panzoom.jquery.json +++ b/panzoom.jquery.json @@ -9,7 +9,7 @@ "zoom", "panzoom" ], - "version": "1.3.8", + "version": "1.4.0", "author": { "name": "Timmy Willison", "email": "timmywillisn@gmail.com", diff --git a/test/bdd/test.js b/test/bdd/test.js index 55499e4e..9d01e86a 100644 --- a/test/bdd/test.js +++ b/test/bdd/test.js @@ -11,10 +11,7 @@ describe('Panzoom', function() { var $zoomOut = $('.zoom-out'); var $zoomRange = $('.zoom-range'); var $reset = $('.reset'); - - before(function() { - $elem.panzoom(); - }); + var rnoneMatrix = /^matrix\(1\,?\s*0\,?\s*0\,?\s*1\,?\s*0\,?\s*0\)/; /** * Simulates a start by triggering faux mousedown and touchstart events @@ -52,8 +49,37 @@ describe('Panzoom', function() { $doc.trigger( e ).trigger('mouseup').trigger('touchend'); } - var rnoneMatrix = /^matrix\(1\,?\s*0\,?\s*0\,?\s*1\,?\s*0\,?\s*0\)/; + /** + * Simulates a pinch gesture (even in desktop browsers) starting at the move + * (the move event must already be bound) + * @param {Function} complete + */ + function testPinch( complete ) { + var panzoom = $elem.panzoom('instance'); + var origMatrix = panzoom.getMatrix(); + + // Faux events with touches property + var e = new jQuery.Event('mousemove', { + touches: [ + { pageX: 10, pageY: 10 }, + { pageX: 20, pageY: 20 } + ] + }); + var $doc = $(document).trigger( e ); + e.type = 'touchmove'; + $doc.trigger( e ) + // Kill events + .trigger('touchend').trigger('mouseup'); + + // Run tests + complete(); + // Reset matrix + panzoom.setMatrix( origMatrix ); + } + + /* panzoom creation and options + ---------------------------------------------------------------------- */ it('should have elements available', function() { expect( $elem ).to.have.length( 1 ); expect( $zoomIn ).to.have.length( 1 ); @@ -62,14 +88,12 @@ describe('Panzoom', function() { expect( $reset ).to.have.length( 1 ); }); it('should chain and not create a new instance when called again', function() { + $elem.panzoom(); var orig = $elem.panzoom('instance'); expect( $elem.panzoom().panzoom('instance') ).to.eql( orig ); }); - it('should destroy itself', function() { - $elem.panzoom('destroy'); - expect( $elem.panzoom('instance') ).to.be.undefined; - }); it('should allow different starting values for zoom than 1', function() { + $elem.panzoom('destroy'); $elem.css( 'transform', 'scale(2)' ); var panzoom = $elem.panzoom({ $zoomRange: $zoomRange }).panzoom('instance'); expect( panzoom.getTransform() ).to.contain('matrix'); @@ -148,23 +172,43 @@ describe('Panzoom', function() { clickEvent = events && ( events.click || events.touchend ); expect( clickEvent ).to.not.be.empty; }); - it('should zoom, then reset transform matrix', function() { - var panzoom = $elem.panzoom('instance'); - // Zoom twice - $elem.panzoom('zoom'); - $elem.panzoom('zoom'); - expect( +panzoom.getMatrix()[0] ).to.be.above( 1 ); - $elem.panzoom('reset'); - expect( +panzoom.getMatrix()[0] ).to.equal( 1 ); + /* containment + ---------------------------------------------------------------------- */ + it('should contain the panzoom element within its parent when the contain option is true', function() { + $elem.panzoom( 'option', 'contain', true ); + fauxMove( -2, -2 ); + var matrix = $elem.panzoom('getMatrix'); + expect( +matrix[4] ).to.not.equal( -2 ); + expect( +matrix[5] ).to.not.equal( -2 ); + // Clean up + $elem.panzoom('option', 'contain', false).panzoom( 'reset', false ); }); - it('should set the zoom range input\'s value on zoom', function() { - var cur = $zoomRange.val(); - $elem.panzoom('zoom'); - var val = $zoomRange.val(); - expect( val ).to.not.equal( cur ); - expect( val ).to.equal( $elem.panzoom('getMatrix')[0] ); + it('should invert-contain the panzoom element outside its parent when the contain option is set to "invert"', function() { + var panzoom = $elem.panzoom('instance'); + // Zoom in for moving + $elem.panzoom('zoom', { animate: false }); + // Set contain to 'invert' + $elem.panzoom('option', 'contain', 'invert'); + fauxMove( -2, -2 ); + var matrix = panzoom.getMatrix(); + expect( +matrix[4] ).to.equal( -2 ); + expect( +matrix[5] ).to.equal( -2 ); + fauxMove( 2, 2 ); + matrix = panzoom.getMatrix(); + // Should normalize to 0 + expect( +matrix[4] ).to.equal( 0 ); + expect( +matrix[5] ).to.equal( 0 ); + // Clean up + $elem.panzoom('option', 'contain', false).panzoom( 'reset', false ); + matrix = panzoom.getMatrix(); + expect( +matrix[4] ).to.equal( 0 ); + expect( +matrix[5] ).to.equal( 0 ); }); + + + /* Events + ---------------------------------------------------------------------- */ it('should bind the onStart event', function() { var called = false; var instance = $elem.panzoom('instance'); @@ -182,13 +226,6 @@ describe('Panzoom', function() { $elem.panzoom( 'option', 'onStart', null ); expect( called ).to.be.true; }); - it('should keep panning up-to-date for isPanning()', function() { - fauxStart(); - var panzoom = $elem.panzoom('instance'); - expect( panzoom.isPanning() ).to.be.true; - $(document).trigger('mouseup').trigger('touchend'); - expect( panzoom.isPanning() ).to.be.false; - }); it('should bind the onEnd event', function() { var called = false; var instance = $elem.panzoom('instance'); @@ -259,7 +296,76 @@ describe('Panzoom', function() { fauxMove( 1, 1 ); expect( called ).to.be.true; }); - it('should allow string or arrays when setting the matrix', function() { + it('should silence the pan event when silent is passed', function() { + var called = false; + $elem.on('panzoompan', function() { + called = true; + }); + $elem.panzoom( 'pan', 0, 0, { silent: true } ); + expect( called ).to.be.false; + }); + + /* pan + ---------------------------------------------------------------------- */ + it('should pan relatively when the relative option is passed', function() { + var panzoom = $elem.panzoom('instance'); + var matrix = panzoom.getMatrix().slice(0); + $elem.panzoom( 'pan', 10, -10, { relative: true } ); + var newMatrix = panzoom.getMatrix(); + expect( newMatrix[4] - matrix[4] ).to.equal( 10 ); + expect( newMatrix[5] - matrix[5] ).to.equal( -10 ); + panzoom.reset( false ); + }); + + /* zoom + ---------------------------------------------------------------------- */ + it('should zoom, then reset transform matrix', function() { + var panzoom = $elem.panzoom('instance'); + // Zoom twice + $elem.panzoom('zoom'); + $elem.panzoom('zoom'); + expect( +panzoom.getMatrix()[0] ).to.be.above( 1 ); + + $elem.panzoom('reset'); + expect( +panzoom.getMatrix()[0] ).to.equal( 1 ); + }); + it('should set the zoom range input\'s value on zoom', function() { + var cur = $zoomRange.val(); + $elem.panzoom('zoom'); + var val = $zoomRange.val(); + expect( val ).to.not.equal( cur ); + expect( val ).to.equal( $elem.panzoom('getMatrix')[0] ); + }); + it('should set the dValue if specified', function() { + $elem.panzoom('zoom', 1, { dValue: -1 }); + var matrix = $elem.panzoom('getMatrix'); + expect( +matrix[0] ).to.equal( 1 ); + expect( +matrix[3] ).to.equal( -1 ); + $elem.panzoom('reset', false); + }); + + /* isPanning + ---------------------------------------------------------------------- */ + it('should keep panning up-to-date for isPanning()', function() { + fauxStart(); + var panzoom = $elem.panzoom('instance'); + expect( panzoom.isPanning() ).to.be.true; + $(document).trigger('mouseup').trigger('touchend'); + expect( panzoom.isPanning() ).to.be.false; + }); + + /* destroy + ---------------------------------------------------------------------- */ + it('should destroy itself', function() { + var options = $elem.panzoom('instance').options; + $elem.panzoom('destroy'); + expect( $elem.panzoom('instance') ).to.be.undefined; + $elem.panzoom( options ); + }); + + /* setMatrix + ---------------------------------------------------------------------- */ + it('should allow strings or arrays when setting the matrix', function() { var panzoom = $elem.panzoom('instance'); var _matrix = panzoom.getMatrix(); panzoom.setMatrix('none'); @@ -267,6 +373,9 @@ describe('Panzoom', function() { panzoom.setMatrix( _matrix ); expect( panzoom.getMatrix() ).to.eql( _matrix ); }); + + /* reset + ---------------------------------------------------------------------- */ it('should trigger the reset event on reset', function() { var called = false; function testReset( e, panzoom, matrix ) { @@ -276,7 +385,21 @@ describe('Panzoom', function() { $elem.on('panzoomreset', testReset).panzoom('reset'); expect( called ).to.be.true; }); - it('should reset zoom only on resetZoom', function() { + it('should reset to the specified transform on reset', function() { + var transform = 'matrix(1, 0, 0, -1, 0, 0)'; + // Reset to upside-down + $elem.panzoom( 'option', 'startTransform', transform ); + var panzoom = $elem.panzoom('instance'); + panzoom.reset(); + expect( panzoom.getTransform() ).to.equal( transform ); + $elem.css('transform', 'none'); + $elem.panzoom( 'option', 'startTransform', undefined ); + panzoom.reset(); + }); + + /* resetZoom + ---------------------------------------------------------------------- */ + it('should reset only zoom on resetZoom', function() { var panzoom = $elem.panzoom('instance'); panzoom.setMatrix([ 2, 0, 0, 2, 1, 1 ], false); $elem.panzoom('resetZoom', false); @@ -287,7 +410,18 @@ describe('Panzoom', function() { expect( matrix[5] ).to.equal( '1' ); $elem.panzoom('reset'); }); - it('should reset pan only on resetPan', function() { + it('should fire a zoom event on resetZoom', function() { + var called = false; + $elem.on('panzoomzoom.resetZoom', function() { + called = true; + }); + $elem.panzoom('resetZoom', false).off('.resetZoom'); + expect( called ).to.be.true; + }); + + /* resetPan + ---------------------------------------------------------------------- */ + it('should reset only pan on resetPan', function() { var panzoom = $elem.panzoom('instance'); panzoom.setMatrix([ 2, 0, 0, 2, 1, 1 ], false); $elem.panzoom('resetPan'); @@ -298,17 +432,17 @@ describe('Panzoom', function() { expect( matrix[5] ).to.equal( '0' ); $elem.panzoom('reset'); }); - it('should reset to the specified transform on reset', function() { - var transform = 'matrix(1, 0, 0, -1, 0, 0)'; - // Reset to upside-down - $elem.panzoom( 'option', 'startTransform', transform ); - var panzoom = $elem.panzoom('instance'); - panzoom.reset(); - expect( panzoom.getTransform() ).to.equal( transform ); - $elem.css('transform', 'none'); - $elem.panzoom( 'option', 'startTransform', undefined ); - panzoom.reset(); + it('should fire a pan event on resetPan', function() { + var called = false; + $elem.on('panzoompan.resetPan', function() { + called = true; + }); + $elem.panzoom('resetPan', false).off('.resetPan'); + expect( called ).to.be.true; }); + + /* disable/enable + ---------------------------------------------------------------------- */ it('should disable/enable panzoom when disable/enable is called', function() { // Disable $elem.panzoom('disable'); @@ -328,78 +462,9 @@ describe('Panzoom', function() { expect( $elem.css('transition') ).to.not.contain('transform'); $elem.panzoom('enable').panzoom( 'reset', false ); }); - it('should contain the panzoom element within its parent when the contain option is true', function() { - $elem.panzoom( 'option', 'contain', true ); - fauxMove( -2, -2 ); - var matrix = $elem.panzoom('getMatrix'); - expect( +matrix[4] ).to.not.equal( -2 ); - expect( +matrix[5] ).to.not.equal( -2 ); - // Clean up - $elem.panzoom('option', 'contain', false).panzoom( 'reset', false ); - }); - it('should invert-contain the panzoom element outside its parent when the contain option is set to "invert"', function() { - var panzoom = $elem.panzoom('instance'); - // Zoom in for moving - $elem.panzoom('zoom', { animate: false }); - // Set contain to 'invert' - $elem.panzoom('option', 'contain', 'invert'); - fauxMove( -2, -2 ); - var matrix = panzoom.getMatrix(); - expect( +matrix[4] ).to.equal( -2 ); - expect( +matrix[5] ).to.equal( -2 ); - fauxMove( 2, 2 ); - matrix = panzoom.getMatrix(); - // Should normalize to 0 - expect( +matrix[4] ).to.equal( 0 ); - expect( +matrix[5] ).to.equal( 0 ); - // Clean up - $elem.panzoom('option', 'contain', false).panzoom( 'reset', false ); - matrix = panzoom.getMatrix(); - expect( +matrix[4] ).to.equal( 0 ); - expect( +matrix[5] ).to.equal( 0 ); - }); - - /** - * Simulates a pinch gesture (even in desktop browsers) starting at the move - * (the move event must already be bound) - * @param {Function} complete - */ - function testPinch( complete ) { - var panzoom = $elem.panzoom('instance'); - var origMatrix = panzoom.getMatrix(); - - // Faux events with touches property - var e = new jQuery.Event('mousemove', { - touches: [ - { pageX: 10, pageY: 10 }, - { pageX: 20, pageY: 20 } - ] - }); - var $doc = $(document).trigger( e ); - e.type = 'touchmove'; - $doc.trigger( e ) - // Kill events - .trigger('touchend').trigger('mouseup'); - // Run tests - complete(); - - // Reset matrix - panzoom.setMatrix( origMatrix ); - } - it('should pan on the middle point when zooming (and gravitate towards that point)', function() { - var panzoom = $elem.panzoom('instance'); - var matrix = panzoom.getMatrix(); - panzoom._startMove({ type: 'touchstart' }, [ - { pageX: 0, pageY: 0 }, - { pageX: 10, pageY: 10 } - ]); - testPinch(function() { - var newMatrix = panzoom.getMatrix(); - expect( +newMatrix[4] ).to.equal( +matrix[4] + 11 ); - expect( +newMatrix[5] ).to.equal( +matrix[5] + 11 ); - }); - }); + /* Touch + ---------------------------------------------------------------------- */ it('should pan with 2 fingers even if disableZoom is true', function() { $elem.panzoom( 'option', 'disableZoom', true ); var panzoom = $elem.panzoom('instance'); @@ -422,22 +487,18 @@ describe('Panzoom', function() { // Clean-up $elem.panzoom( 'option', 'disableZoom', false ); }); - it('should pan relatively when the relative option is passed', function() { + it('should pan on the middle point when zooming (and gravitate towards that point)', function() { var panzoom = $elem.panzoom('instance'); - var matrix = panzoom.getMatrix().slice(0); - $elem.panzoom( 'pan', 10, -10, { relative: true } ); - var newMatrix = panzoom.getMatrix(); - expect( newMatrix[4] - matrix[4] ).to.equal( 10 ); - expect( newMatrix[5] - matrix[5] ).to.equal( -10 ); - panzoom.reset( false ); - }); - it('should silence the pan event when silent is passed', function() { - var called = false; - $elem.on('panzoompan', function() { - called = true; + var matrix = panzoom.getMatrix(); + panzoom._startMove({ type: 'touchstart' }, [ + { pageX: 0, pageY: 0 }, + { pageX: 10, pageY: 10 } + ]); + testPinch(function() { + var newMatrix = panzoom.getMatrix(); + expect( +newMatrix[4] ).to.equal( +matrix[4] + 11 ); + expect( +newMatrix[5] ).to.equal( +matrix[5] + 11 ); }); - $elem.panzoom( 'pan', 0, 0, { silent: true } ); - expect( called ).to.be.false; }); it('should continue with a touch event if started with a touch event', function() { var called = false;