snapsvg.zpd.extended
Version:
A zoom/pan/drag plugin for Snap.svg
891 lines (699 loc) • 34.2 kB
JavaScript
/* globals Snap, document, navigator */
/**
* snapsvg-zpd.js: A zoom/pan/drag plugin for Snap.svg
* ==================================================
*
* Usage
* =======
* var paper = Snap();
* var bigCircle = paper.circle(150, 150, 100);
* paper.zpd();
*
* // or settings and callback
* paper.zpd({ zoom: false }), function (err, paper) { });
*
* // or callback
* paper.zpd(function (err, paper) { });
*
* // destroy
* paper.zpd('destroy');
*
* // save
* paper.zpd('save');
*
* // load
* // paper.zpd({ load: SVGMatrix {} });
*
* // origin
* paper.zpd('origin');
*
* // zoomTo
* paper.zoomTo(1);
*
* // panTo
* paper.panTo(0, 0); // original location
* paper.panTo('+10', 0); // move right
*
* // rotate
* paper.rotate(15); // rotate 15 deg
*
* Notice
* ========
* This usually use on present view only. Not for Storing, modifying the paper.
*
* Reason:
* Usually <pan> <zoom> => <svg transform="matrix(a,b,c,d,e,f)"></svg>
*
* But if you need to store the <drag> location, (for storing)
* we have to use <circle cx="x" cy="y"></circle> not <circle tranform="matrix(a,b,c,d,e,f)"></circle>
*
* License
* =========
* This code is licensed under the following BSD license:
*
* Copyright 2014 Huei Tan <huei90@gmail.com> (Snap.svg integration). All rights reserved.
* Copyright 2009-2010 Andrea Leofreddi <a.leofreddi@itcharm.com> (original author). All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY Andrea Leofreddi ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Andrea Leofreddi OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of Andrea Leofreddi.
*/
SVGElement.prototype.getTransformToElement = SVGElement.prototype.getTransformToElement || function(elem) {
return elem.getScreenCTM().inverse().multiply(this.getScreenCTM());
};
(function (Snap) {
Snap.plugin(function (Snap, Element, Paper, glob, Fragment) {
/**
* Global variable for snap.svg.zpd plugin
*/
var snapsvgzpd = {
uniqueIdPrefix: 'snapsvg-zpd-', // prefix for the unique ids created for zpd
dataStore: {}, // "global" storage for all our zpd elements
enable: true // By default, snapsvgzpd should enable, zpd('toggle') to toggle enable or disable
};
/**
* Global variable to store root of the svg element
*/
var rootSvgObject;
/**
* remove node parent but keep children
*/
var _removeNodeKeepChildren = function removeNodeKeepChildren(node) {
if (!node.parentNode) {
return;
}
while (node.firstChild) {
node.parentNode.insertBefore(node.firstChild, node);
}
node.parentNode.removeChild(node);
};
/**
* Detect is +1 -1 or 1
* increase decrease or just number
*/
var _increaseDecreaseOrNumber = function increaseDecreaseOrNumber(defaultValue, input) {
if (input === undefined) {
return parseInt(defaultValue);
} else if (input[0] == '+') {
return defaultValue + parseInt(input.split('+')[1]);
} else if (input[0] == '-') {
return defaultValue - parseInt(input.split('-')[1]);
} else {
return parseInt(input);
}
};
/**
* Sets the current transform matrix of an element.
*/
var _setCTM = function setCTM(zpdElement, element, matrix, threshold) {
if (threshold && typeof threshold === 'object') { // array [0.5,2]
var oldMatrix = Snap(element).transform().globalMatrix;
if (matrix.a < oldMatrix.a && matrix.a < threshold[0]) {
return;
} else if (matrix.a > oldMatrix.a && matrix.a > threshold[1]) {
return;
}
if (matrix.d < oldMatrix.d && matrix.d < threshold[0]) {
return;
} else if (matrix.d > oldMatrix.d && matrix.d > threshold[1]) {
return;
}
}
/**
* boundaries for drag and pan
* to avoid draggin out of the
* viewport
*/
if(zpdElement && zpdElement.options.jailToViewport) {
var pointX = matrix.e;
var pointY = matrix.f;
if(zpdElement.data.root.clientWidth - zpdElement.element.node.getBoundingClientRect().width < 0) {
if(pointX >= 0) {
matrix.e = 0
}
if(pointX <= -Math.abs(parseFloat(zpdElement.element.node.getBoundingClientRect().width - zpdElement.data.root.clientWidth))) {
matrix.e = -Math.abs(parseFloat(zpdElement.element.node.getBoundingClientRect().width - zpdElement.data.root.clientWidth))
}
} else {
// center map if its smaller than the container
if(pointX >= (zpdElement.data.root.clientWidth - zpdElement.element.node.getBoundingClientRect().width) / 2) {
matrix.e = (zpdElement.data.root.clientWidth - zpdElement.element.node.getBoundingClientRect().width) / 2
}
if(pointX <= (zpdElement.data.root.clientWidth - parseFloat(zpdElement.element.node.getBoundingClientRect().width)) / 2) {
matrix.e = (zpdElement.data.root.clientWidth - parseFloat(zpdElement.element.node.getBoundingClientRect().width)) / 2
}
}
if(zpdElement.data.root.clientHeight - zpdElement.element.node.getBoundingClientRect().height < 0) {
if(pointY >= 0) {
matrix.f = 0
}
if(pointY <= -Math.abs(parseFloat(zpdElement.element.node.getBoundingClientRect().height - zpdElement.data.root.clientHeight))) {
matrix.f = -Math.abs(parseFloat(zpdElement.element.node.getBoundingClientRect().height - zpdElement.data.root.clientHeight))
}
} else {
// center map if its smaller than the container
if(pointY >= (zpdElement.data.root.clientHeight - zpdElement.element.node.getBoundingClientRect().height) / 2) {
matrix.f = (zpdElement.data.root.clientHeight - zpdElement.element.node.getBoundingClientRect().height) / 2
}
if(pointY <= (zpdElement.data.root.clientHeight - parseFloat(zpdElement.element.node.getBoundingClientRect().height)) / 2) {
matrix.f = (parseFloat(zpdElement.data.root.clientHeight) - parseFloat(zpdElement.element.node.getBoundingClientRect().height)) / 2
}
}
}
var s = "matrix(" + matrix.a + "," + matrix.b + "," + matrix.c + "," + matrix.d + "," + matrix.e + "," + matrix.f + ")";
element.setAttribute("transform", s);
};
/**
* Dumps a matrix to a string (useful for debug).
*/
var _dumpMatrix = function dumpMatrix(matrix) {
var s = "[ " + matrix.a + ", " + matrix.c + ", " + matrix.e + "\n " + matrix.b + ", " + matrix.d + ", " + matrix.f + "\n 0, 0, 1 ]";
return s;
};
/**
* Instance an SVGPoint object with given event coordinates.
*/
var _findPos = function findPos(obj) {
var curleft = curtop = 0;
if (obj.offsetParent) {
do {
curleft += obj.offsetLeft;
curtop += obj.offsetTop;
} while(obj = obj.offsetParent);
}
return [curleft,curtop];
};
var _getEventPoint = function getEventPoint(event, svgNode) {
var p = svgNode.node.createSVGPoint(),
svgPos = _findPos(svgNode.node);
p.x = event.clientX - svgPos[0];
p.y = event.clientY - svgPos[1];
return p;
};
/**
* Get an svg transformation matrix as string representation
*/
var _getSvgMatrixAsString = function _getMatrixAsString (matrix) {
return 'matrix(' + matrix.a + ',' + matrix.b + ',' + matrix.c + ',' + matrix.d + ',' + matrix.e + ',' + matrix.f + ')';
};
/**
* add a new <g> element to the paper
* add paper nodes into <g> element (Snapsvg Element)
* and give the nodes an unique id like 'snapsvg-zpd-12345'
* and let this <g> Element to global snapsvgzpd.dataStore['snapsvg-zpd-12345']
* and
* <svg>
* <def>something</def>
* <circle cx="10" cy="10" r="100"></circle>
* </svg>
*
* transform to =>
*
* <svg>
* <g id="snapsvg-zpd-12345">
* <def>something</def>
* <circle cx="10" cy="10" r="100"></circle>
* </g>
* </svg>
*/
var _initZpdElement = function initAndGetZpdElement (svgObject, options) {
// get root of svg object
rootSvgObject = svgObject.node;
// get all child nodes in our svg element
var rootChildNodes = svgObject.node.childNodes;
// create a new graphics element in our svg element
var gElement = svgObject.g();
var gNode = gElement.node;
// add our unique id to the element
gNode.id = snapsvgzpd.uniqueIdPrefix + svgObject.id;
// check if a matrix has been supplied to initialize the drawing
if (options.load && typeof options.load === 'object') {
var matrix = options.load;
// create a matrix string from our supplied matrix
var matrixString = "matrix(" + matrix.a + "," + matrix.b + "," + matrix.c + "," + matrix.d + "," + matrix.e + "," + matrix.f + ")";
// load <g> transform matrix
gElement.transform(matrixString);
} else {
// initial set <g transform="matrix(1,0,0,1,0,0)">
gElement.transform('matrix');
}
// initialize our index counter for child nodes
var index = 0;
// get the number of child nodes in our root node
// substract -1 to exclude our <g> element
var noOfChildNodes = rootChildNodes.length - 1;
// go through all child elements
// (except the last one, which is our <g> element)
while (index < noOfChildNodes) {
gNode.appendChild(rootChildNodes[0]);
index += 1;
}
// define some data to be used in the function internally
var data = {
svg: svgObject,
root: svgObject.node, // get paper svg
state: 'none',
stateTarget: null,
stateOrigin: null,
stateTf: null
};
// create an element with all required properties
var item = {
"element": gElement,
"data": data,
"options": options,
};
// create some mouse event handlers for our item
// store them globally for optional removal later on
item.handlerFunctions = _getHandlerFunctions(item);
// return our element
return item;
};
/**
* create some handler functions for our mouse actions
* we will take advantace of closures to preserve some data
*/
var _getHandlerFunctions = function getHandlerFunctions(zpdElement) {
var handleMouseUp = function handleMouseUp (event) {
if (event.preventDefault) {
event.preventDefault();
}
if (!snapsvgzpd.enable) return;
event.returnValue = false;
if (zpdElement.data.state == 'pan' || zpdElement.data.state == 'drag') {
// quit pan mode
zpdElement.data.state = '';
}
};
var handleMouseDown = function handleMouseDown (event) {
if (event.preventDefault) {
event.preventDefault();
}
if (!snapsvgzpd.enable) return;
event.returnValue = false;
var g = zpdElement.element.node;
if (
event.target.tagName == "svg" || !zpdElement.options.drag // Pan anyway when drag is disabled and the user clicked on an element
) {
// Pan mode
zpdElement.data.state = 'pan';
zpdElement.data.stateTf = g.getCTM().inverse();
zpdElement.data.stateOrigin = _getEventPoint(event, zpdElement.data.svg).matrixTransform(zpdElement.data.stateTf);
} else {
// Drag mode
zpdElement.data.state = 'drag';
zpdElement.data.stateTarget = event.target;
zpdElement.data.stateTf = g.getCTM().inverse();
zpdElement.data.stateOrigin = _getEventPoint(event, zpdElement.data.svg).matrixTransform(zpdElement.data.stateTf);
}
};
var handleMouseMove = function handleMouseMove (event) {
if (event.preventDefault) {
event.preventDefault();
}
if (!snapsvgzpd.enable) return;
if (zpdElement.mouseIsOutside) return;
event.returnValue = false;
var g = zpdElement.element.node;
if (zpdElement.data.state == 'pan' && zpdElement.options.pan) {
// Pan mode
var p = _getEventPoint(event, zpdElement.data.svg).matrixTransform(zpdElement.data.stateTf);
_setCTM(zpdElement, g, zpdElement.data.stateTf.inverse().translate(p.x - zpdElement.data.stateOrigin.x, p.y - zpdElement.data.stateOrigin.y), zpdElement.options.zoomThreshold);
//_seCTM(g, zpdElement.data.stateTf.inverse().translate(pointX, pointY), zpdElement.options.zoomThreshold);
} else if (zpdElement.data.state == 'drag' && zpdElement.options.drag) {
// Drag mode
var dragPoint = _getEventPoint(event, zpdElement.data.svg).matrixTransform(g.getCTM().inverse());
_setCTM(zpdElement,zpdElement.data.stateTarget,
zpdElement.data.root.createSVGMatrix()
.translate(dragPoint.x - zpdElement.data.stateOrigin.x, dragPoint.y - zpdElement.data.stateOrigin.y)
.multiply(g.getCTM().inverse())
.multiply(zpdElement.data.stateTarget.getCTM()),
zpdElement.options.zoomThreshold);
zpdElement.data.stateOrigin = dragPoint;
}
};
var handleMouseLeave = function handleMouseLeave (event) {
console.log("outside!")
zpdElement.data.state = '';
zpdElement.mouseIsOutside = true;
};
var handleMouseEnter = function handleMouseEnter (event) {
zpdElement.mouseIsOutside = false;
};
var handleMouseWheel = function handleMouseWheel (event) {
if (!zpdElement.options.zoom) {
return;
}
if (event.preventDefault) {
event.preventDefault();
}
if (!snapsvgzpd.enable) return;
event.returnValue = false;
var delta = 0;
if (event.wheelDelta) {
delta = event.wheelDelta / 360; // Chrome/Safari
}
else {
delta = event.detail / -9; // Mozilla
}
var z = Math.pow(1 + zpdElement.options.zoomScale, delta);
var g = zpdElement.element.node;
var p = _getEventPoint(event, zpdElement.data.svg);
p = p.matrixTransform(g.getCTM().inverse());
// Compute new scale matrix in current mouse position
var k = zpdElement.data.root.createSVGMatrix().translate(p.x, p.y).scale(z).translate(-p.x, -p.y);
_setCTM(zpdElement, g, g.getCTM().multiply(k), zpdElement.options.zoomThreshold);
if (typeof(stateTf) == 'undefined') {
zpdElement.data.stateTf = g.getCTM().inverse();
}
zpdElement.data.stateTf = zpdElement.data.stateTf.multiply(k.inverse());
};
return {
"mouseUp": handleMouseUp,
"mouseDown": handleMouseDown,
"mouseMove": handleMouseMove,
"mouseWheel": handleMouseWheel,
"mouseLeave": handleMouseLeave,
"mouseEnter": handleMouseEnter,
};
};
/**
* Register handlers
* desktop and mobile (?)
*/
var _setupHandlers = function setupHandlers(svgElement, handlerFunctions) {
// mobile
// (?)
// desktop
if ('onmouseup' in document.documentElement) {
// IE < 9 would need to use the event onmouseup, but they do not support svg anyway..
svgElement.addEventListener('mouseup', handlerFunctions.mouseUp, false);
svgElement.addEventListener('mousedown', handlerFunctions.mouseDown, false);
svgElement.addEventListener('mousemove', handlerFunctions.mouseMove, false);
svgElement.addEventListener('mouseleave', handlerFunctions.mouseLeave, false);
svgElement.addEventListener('mouseenter', handlerFunctions.mouseEnter, false);
if (navigator.userAgent.toLowerCase().indexOf('webkit') >= 0 ||
navigator.userAgent.toLowerCase().indexOf('trident') >= 0) {
svgElement.addEventListener('mousewheel', handlerFunctions.mouseWheel, false); // Chrome/Safari
}
else {
svgElement.addEventListener('DOMMouseScroll', handlerFunctions.mouseWheel, false); // Others
}
}
};
/**
* remove event handlers
*/
var _tearDownHandlers = function tearDownHandlers(svgElement, handlerFunctions) {
svgElement.removeEventListener('mouseup', handlerFunctions.mouseUp, false);
svgElement.removeEventListener('mousedown', handlerFunctions.mouseDown, false);
svgElement.removeEventListener('mousemove', handlerFunctions.mouseMove, false);
svgElement.removeEventListener('mouseleave', handlerFunctions.mouseLeave, false);
svgElement.removeEventListener('mouseenter', handlerFunctions.mouseEnter, false);
if (navigator.userAgent.toLowerCase().indexOf('webkit') >= 0 ||
navigator.userAgent.toLowerCase().indexOf('trident') >= 0) {
svgElement.removeEventListener('mousewheel', handlerFunctions.mouseWheel, false);
}
else {
svgElement.removeEventListener('DOMMouseScroll', handlerFunctions.mouseWheel, false);
}
};
/* our global zpd function */
var zpd = function (options, callbackFunc) {
// get a reference to the current element
var self = this;
// define some custom options
var zpdOptions = {
pan: true, // enable or disable panning (default enabled)
zoom: true, // enable or disable zooming (default enabled)
drag: false, // enable or disable dragging (default disabled)
zoomScale: 0.2, // define zoom sensitivity
zoomThreshold: null, // define zoom threshold
jailToViewport: false, // avoid dragging panning objects outside the viewport
};
// the situation event of zpd, may be init, reinit, destroy, save, origin, toggle
var situation,
situationState = {
init: 'init',
reinit: 'reinit',
destroy: 'destroy',
save: 'save',
origin: 'origin',
callback: 'callback',
toggle: 'toggle'
};
var zpdElement = null;
// it is also possible to only specify a callback function without any options
if (typeof options === 'function') {
callbackFunc = options;
situation = situationState.callback;
}
// check if element was already initialized
if (snapsvgzpd.dataStore.hasOwnProperty(self.id)) {
// return existing element
zpdElement = snapsvgzpd.dataStore[self.id];
// adapt the stored options, with the options passed in
if (typeof options === 'object') {
for (var prop in options) {
zpdElement.options[prop] = options[prop];
}
situation = situationState.reinit;
} else if (typeof options === 'string') {
situation = options;
}
}
else {
// adapt the default options
if (typeof options === 'object') {
for (var prop2 in options) {
zpdOptions[prop2] = options[prop2];
}
situation = situationState.init;
} else if (typeof options === 'string') {
situation = options;
}
// initialize a new element and save it to our global storage
zpdElement = _initZpdElement(self, zpdOptions);
// setup the handlers for our svg-canvas
_setupHandlers(self.node, zpdElement.handlerFunctions);
snapsvgzpd.dataStore[self.id] = zpdElement;
}
switch (situation) {
case situationState.init:
case situationState.reinit:
case situationState.callback:
// callback
if (callbackFunc) {
callbackFunc(null, zpdElement);
}
return;
case situationState.destroy:
// remove event handlers
_tearDownHandlers(self.node, zpdElement.handlerFunctions);
// remove our custom <g> element
_removeNodeKeepChildren(self.node.firstChild);
// remove the object from our internal storage
delete snapsvgzpd.dataStore[self.id];
// callback
if (callbackFunc) {
callbackFunc(null, zpdElement);
}
return; // exit all
case situationState.save:
var g = document.getElementById(snapsvgzpd.uniqueIdPrefix + self.id);
var returnValue = g.getCTM();
// callback
if (callbackFunc) {
callbackFunc(null, returnValue);
}
return returnValue;
case situationState.origin:
// back to origin location
self.zoomTo(1, 1000);
// callback
if (callbackFunc) {
callbackFunc(null, zpdElement);
}
return;
case situationState.toggle:
// toggle enabled
snapsvgzpd.enable = !snapsvgzpd.enable;
// callback
if (callbackFunc) {
callbackFunc(null, snapsvgzpd.enable);
}
return;
}
};
/**
* zoom element to a certain zoom factor
*/
var zoomTo = function (zoom, interval, ease, callbackFunction) {
if (zoom < 0 || typeof zoom !== 'number') {
console.error('zoomTo(arg) should be a number and greater than 0');
return;
}
if (typeof interval !== 'number') {
interval = 3000;
}
var self = this;
// check if we have this element in our zpd data storage
if (snapsvgzpd.dataStore.hasOwnProperty(self.id)) {
// get a reference to the element
var zpdElement = snapsvgzpd.dataStore[self.id].element;
var currentTransformMatrix = zpdElement.node.getTransformToElement(rootSvgObject);
var currentZoom = currentTransformMatrix.a;
var originX = currentTransformMatrix.e;
var originY = currentTransformMatrix.f;
var boundingBox = zpdElement.getBBox();
var deltaX = parseFloat(boundingBox.width) / 2.0;
var deltaY = parseFloat(boundingBox.height) / 2.0;
Snap.animate(currentZoom, zoom, function (value) {
// calculate difference of zooming value to initial zoom
var deltaZoom = value / currentZoom;
if (value !== currentZoom) {
// calculate new translation
currentTransformMatrix.e = originX - ((deltaX * deltaZoom - deltaX));
currentTransformMatrix.f = originY - ((deltaY * deltaZoom - deltaY));
// add new scaling
currentTransformMatrix.a = value;
currentTransformMatrix.d = value;
// apply transformation to our element
zpdElement.node.setAttribute('transform', _getSvgMatrixAsString(currentTransformMatrix));
}
}, interval, ease, callbackFunction);
}
};
/**
* move the element to a certain position
*/
var panTo = function (x, y, interval, ease, cb) {
// get a reference to the current element
var self = this;
// check if we have this element in our zpd data storage
if (snapsvgzpd.dataStore.hasOwnProperty(self.id)) {
var zpdElement = snapsvgzpd.dataStore[self.id].element;
var gMatrix = zpdElement.node.getCTM(),
matrixX = _increaseDecreaseOrNumber(gMatrix.e, x),
matrixY = _increaseDecreaseOrNumber(gMatrix.f, y),
matrixString = "matrix(" + gMatrix.a + "," + gMatrix.b + "," + gMatrix.c + "," + gMatrix.d + "," + matrixX + "," + matrixY + ")";
// dataStore[me.id].transform(matrixString); // load <g> transform matrix
zpdElement.animate({ transform: matrixString }, interval || 10, ease || null, function () {
if (cb) {
cb(null, zpdElement);
}
});
}
};
/**
* moves the element to the center
* of the canvas
*/
var panToCenter = function(interval, ease, cb) {
// get a reference to the current element
var self = this;
// check if we have this element in our zpd data storage
if (snapsvgzpd.dataStore.hasOwnProperty(self.id)) {
var zpdElement = snapsvgzpd.dataStore[self.id].element;
var zpdContainer = snapsvgzpd.dataStore[self.id];
var x = zpdContainer.data.root.clientWidth / 2 - zpdElement.node.getBoundingClientRect().width / 2;
var y = zpdContainer.data.root.clientHeight / 2 - zpdElement.node.getBoundingClientRect().height / 2;
var gMatrix = zpdElement.node.getCTM(),
matrixX = _increaseDecreaseOrNumber(gMatrix.e, x),
matrixY = _increaseDecreaseOrNumber(gMatrix.f, y),
matrixString = "matrix(" + gMatrix.a + "," + gMatrix.b + "," + gMatrix.c + "," + gMatrix.d + "," + matrixX + "," + matrixY + ")";
// dataStore[me.id].transform(matrixString); // load <g> transform matrix
zpdElement.animate({ transform: matrixString }, interval || 10, ease || null, function () {
if (cb) {
cb(null, zpdElement);
}
});
}
};
/**
* zooms the element to fit the
* canvas viewport
*/
var zoomToFitViewport = function(margin = 0, interval, ease, callbackFunction) {
// get a reference to the current element
var self = this;
// check if we have this element in our zpd data storage
if (snapsvgzpd.dataStore.hasOwnProperty(self.id)) {
var zpdElement = snapsvgzpd.dataStore[self.id].element;
var zpdContainer = snapsvgzpd.dataStore[self.id];
var includeMargin = parseInt(margin) * 2;
var currentTransformMatrix = zpdElement.node.getTransformToElement(rootSvgObject);
var currentZoom = currentTransformMatrix.a;
if(zpdContainer.data.root.clientWidth > zpdElement.node.getBoundingClientRect().width) {
var orignalSizeViewPortFactor = (parseInt(zpdContainer.data.root.clientWidth) - includeMargin)
/ parseInt(zpdElement.node.getBoundingClientRect().width);
} else {
var orignalSizeViewPortFactor = (parseInt(zpdContainer.data.root.clientHeight) - includeMargin)
/ parseInt(zpdElement.node.getBoundingClientRect().height);
}
// add new scaling
currentTransformMatrix.a = orignalSizeViewPortFactor;
currentTransformMatrix.d = orignalSizeViewPortFactor;
// apply transformation to our element
zpdElement.node.setAttribute('transform', _getSvgMatrixAsString(currentTransformMatrix));
return {
minZoom: orignalSizeViewPortFactor,
maxZoom: orignalSizeViewPortFactor * 4,
currentZoom: orignalSizeViewPortFactor
}
}
};
/**
* rotate the element to a certain rotation
*/
var rotate = function (a, x, y, interval, ease, cb) {
// get a reference to the current element
var self = this;
// check if we have this element in our zpd data storage
if (snapsvgzpd.dataStore.hasOwnProperty(self.id)) {
var zpdElement = snapsvgzpd.dataStore[self.id].element;
var gMatrix = zpdElement.node.getCTM(),
matrixString = "matrix(" + gMatrix.a + "," + gMatrix.b + "," + gMatrix.c + "," + gMatrix.d + "," + gMatrix.e + "," + gMatrix.f + ")";
if (!x || typeof x !== 'number') {
x = self.node.offsetWidth / 2;
}
if (!y || typeof y !== 'number') {
y = self.node.offsetHeight / 2;
}
// dataStore[me.id].transform(matrixString); // load <g> transform matrix
zpdElement.animate({ transform: new Snap.Matrix(gMatrix).rotate(a, x, y) }, interval || 10, ease || null, function () {
if (cb) {
cb(null, zpdElement);
}
});
}
};
Paper.prototype.zpd = zpd;
Paper.prototype.zoomTo = zoomTo;
Paper.prototype.panTo = panTo;
Paper.prototype.panToCenter = panToCenter;
Paper.prototype.rotate = rotate;
Paper.prototype.zoomToFitViewport = zoomToFitViewport;
/** UI for zpdr **/
});
})(Snap);