vectorizer.min.js 11 KB

123456789
  1. // Vectorizer.
  2. // -----------
  3. // A tiny library for making your live easier when dealing with SVG.
  4. // Licensed under the MPL v2 license.
  5. // Copyright © 2012 - 2014 client IO (http://client.io)
  6. (function(root,factory){if(typeof define==="function"&&define.amd){define([],factory)}else{root.Vectorizer=root.V=factory()}})(this,function(){var SVGsupported=!!(window.SVGAngle||document.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure","1.1"));var ns={xmlns:"http://www.w3.org/2000/svg",xlink:"http://www.w3.org/1999/xlink"};var SVGversion="1.1";var idCounter=0;function uniqueId(){var id=++idCounter+"";return"v-"+id}function createElement(el,attrs,children){if(!el)return undefined;if(typeof el==="object"){return new VElement(el)}attrs=attrs||{};if(el.toLowerCase()==="svg"){attrs.xmlns=ns.xmlns;attrs["xmlns:xlink"]=ns.xlink;attrs.version=SVGversion}else if(el[0]==="<"){var svg='<svg xmlns="'+ns.xmlns+'" xmlns:xlink="'+ns.xlink+'" version="'+SVGversion+'">'+el+"</svg>";var parser=new DOMParser;parser.async=false;var svgDoc=parser.parseFromString(svg,"text/xml").documentElement;if(svgDoc.childNodes.length>1){var ret=[];for(var i=0,len=svgDoc.childNodes.length;i<len;i++){var childNode=svgDoc.childNodes[i];ret.push(new VElement(document.importNode(childNode,true)))}return ret}return new VElement(document.importNode(svgDoc.firstChild,true))}el=document.createElementNS(ns.xmlns,el);for(var key in attrs){setAttribute(el,key,attrs[key])}if(Object.prototype.toString.call(children)!="[object Array]")children=[children];var i=0,len=children[0]&&children.length||0,child;for(;i<len;i++){child=children[i];el.appendChild(child instanceof VElement?child.node:child)}return new VElement(el)}function setAttribute(el,name,value){if(name.indexOf(":")>-1){var combinedKey=name.split(":");el.setAttributeNS(ns[combinedKey[0]],combinedKey[1],value)}else if(name==="id"){el.id=value}else{el.setAttribute(name,value)}}function parseTransformString(transform){var translate,rotate,scale;if(transform){var translateMatch=transform.match(/translate\((.*)\)/);if(translateMatch){translate=translateMatch[1].split(",")}var rotateMatch=transform.match(/rotate\((.*)\)/);if(rotateMatch){rotate=rotateMatch[1].split(",")}var scaleMatch=transform.match(/scale\((.*)\)/);if(scaleMatch){scale=scaleMatch[1].split(",")}}var sx=scale&&scale[0]?parseFloat(scale[0]):1;return{translate:{tx:translate&&translate[0]?parseInt(translate[0],10):0,ty:translate&&translate[1]?parseInt(translate[1],10):0},rotate:{angle:rotate&&rotate[0]?parseInt(rotate[0],10):0,cx:rotate&&rotate[1]?parseInt(rotate[1],10):undefined,cy:rotate&&rotate[2]?parseInt(rotate[2],10):undefined},scale:{sx:sx,sy:scale&&scale[1]?parseFloat(scale[1]):sx}}}function deltaTransformPoint(matrix,point){var dx=point.x*matrix.a+point.y*matrix.c+0;var dy=point.x*matrix.b+point.y*matrix.d+0;return{x:dx,y:dy}}function decomposeMatrix(matrix){var px=deltaTransformPoint(matrix,{x:0,y:1});var py=deltaTransformPoint(matrix,{x:1,y:0});var skewX=180/Math.PI*Math.atan2(px.y,px.x)-90;var skewY=180/Math.PI*Math.atan2(py.y,py.x);return{translateX:matrix.e,translateY:matrix.f,scaleX:Math.sqrt(matrix.a*matrix.a+matrix.b*matrix.b),scaleY:Math.sqrt(matrix.c*matrix.c+matrix.d*matrix.d),skewX:skewX,skewY:skewY,rotation:skewX}}function VElement(el){this.node=el;if(!this.node.id){this.node.id=uniqueId()}}VElement.prototype={translate:function(tx,ty){ty=ty||0;var transformAttr=this.attr("transform")||"",transform=parseTransformString(transformAttr);if(typeof tx==="undefined"){return transform.translate}transformAttr=transformAttr.replace(/translate\([^\)]*\)/g,"").trim();var newTx=transform.translate.tx+tx,newTy=transform.translate.ty+ty;this.attr("transform","translate("+newTx+","+newTy+") "+transformAttr);return this},rotate:function(angle,cx,cy){var transformAttr=this.attr("transform")||"",transform=parseTransformString(transformAttr);if(typeof angle==="undefined"){return transform.rotate}transformAttr=transformAttr.replace(/rotate\([^\)]*\)/g,"").trim();var newAngle=transform.rotate.angle+angle%360,newOrigin=cx!==undefined&&cy!==undefined?","+cx+","+cy:"";this.attr("transform",transformAttr+" rotate("+newAngle+newOrigin+")");return this},scale:function(sx,sy){sy=typeof sy==="undefined"?sx:sy;var transformAttr=this.attr("transform")||"",transform=parseTransformString(transformAttr);if(typeof sx==="undefined"){return transform.scale}transformAttr=transformAttr.replace(/scale\([^\)]*\)/g,"").trim();this.attr("transform",transformAttr+" scale("+sx+","+sy+")");return this},bbox:function(withoutTransformations,target){if(!this.node.ownerSVGElement)return{x:0,y:0,width:0,height:0};var box;try{box=this.node.getBBox();box={x:box.x|0,y:box.y|0,width:box.width|0,height:box.height|0}}catch(e){box={x:this.node.clientLeft,y:this.node.clientTop,width:this.node.clientWidth,height:this.node.clientHeight}}if(withoutTransformations){return box}var matrix=this.node.getTransformToElement(target||this.node.ownerSVGElement);var corners=[];var point=this.node.ownerSVGElement.createSVGPoint();point.x=box.x;point.y=box.y;corners.push(point.matrixTransform(matrix));point.x=box.x+box.width;point.y=box.y;corners.push(point.matrixTransform(matrix));point.x=box.x+box.width;point.y=box.y+box.height;corners.push(point.matrixTransform(matrix));point.x=box.x;point.y=box.y+box.height;corners.push(point.matrixTransform(matrix));var minX=corners[0].x;var maxX=minX;var minY=corners[0].y;var maxY=minY;for(var i=1,len=corners.length;i<len;i++){var x=corners[i].x;var y=corners[i].y;if(x<minX){minX=x}else if(x>maxX){maxX=x}if(y<minY){minY=y}else if(y>maxY){maxY=y}}return{x:minX,y:minY,width:maxX-minX,height:maxY-minY}},text:function(content){var lines=content.split("\n"),i=0,tspan;this.attr("y","0.8em");this.attr("display",content?null:"none");if(lines.length===1){this.node.textContent=content;return this}this.node.textContent="";for(;i<lines.length;i++){tspan=V("tspan",{dy:i==0?"0em":"1em",x:this.attr("x")||0});tspan.node.textContent=lines[i];this.append(tspan)}return this},attr:function(name,value){if(typeof name==="string"&&typeof value==="undefined"){return this.node.getAttribute(name)}if(typeof name==="object"){for(var attrName in name){if(name.hasOwnProperty(attrName)){setAttribute(this.node,attrName,name[attrName])}}}else{setAttribute(this.node,name,value)}return this},remove:function(){if(this.node.parentNode){this.node.parentNode.removeChild(this.node)}},append:function(el){var els=el;if(Object.prototype.toString.call(el)!=="[object Array]"){els=[el]}for(var i=0,len=els.length;i<len;i++){el=els[i];this.node.appendChild(el instanceof VElement?el.node:el)}return this},prepend:function(el){this.node.insertBefore(el instanceof VElement?el.node:el,this.node.firstChild)},svg:function(){return this.node instanceof window.SVGSVGElement?this:V(this.node.ownerSVGElement)},defs:function(){var defs=this.svg().node.getElementsByTagName("defs");return defs&&defs.length?V(defs[0]):undefined},clone:function(){var clone=V(this.node.cloneNode(true));clone.node.id=uniqueId();return clone},findOne:function(selector){var found=this.node.querySelector(selector);return found?V(found):undefined},find:function(selector){var nodes=this.node.querySelectorAll(selector);for(var i=0,len=nodes.length;i<len;i++){nodes[i]=V(nodes[i])}return nodes},toLocalPoint:function(x,y){var svg=this.svg().node;var p=svg.createSVGPoint();p.x=x;p.y=y;try{var globalPoint=p.matrixTransform(svg.getScreenCTM().inverse());var globalToLocalMatrix=this.node.getTransformToElement(svg).inverse()}catch(e){return p}return globalPoint.matrixTransform(globalToLocalMatrix)},translateCenterToPoint:function(p){var bbox=this.bbox();var center=g.rect(bbox).center();this.translate(p.x-center.x,p.y-center.y)},translateAndAutoOrient:function(position,reference,target){var s=this.scale();this.attr("transform","");this.scale(s.sx,s.sy);var svg=this.svg().node;var bbox=this.bbox(false,target);var translateToOrigin=svg.createSVGTransform();translateToOrigin.setTranslate(-bbox.x-bbox.width/2,-bbox.y-bbox.height/2);var rotateAroundOrigin=svg.createSVGTransform();var angle=g.point(position).changeInAngle(position.x-reference.x,position.y-reference.y,reference);rotateAroundOrigin.setRotate(angle,0,0);var translateFinal=svg.createSVGTransform();var finalPosition=g.point(position).move(reference,bbox.width/2);translateFinal.setTranslate(position.x+(position.x-finalPosition.x),position.y+(position.y-finalPosition.y));var ctm=this.node.getTransformToElement(target);var transform=svg.createSVGTransform();transform.setMatrix(translateFinal.matrix.multiply(rotateAroundOrigin.matrix.multiply(translateToOrigin.matrix.multiply(ctm))));var decomposition=decomposeMatrix(transform.matrix);this.translate(decomposition.translateX,decomposition.translateY);this.rotate(decomposition.rotation);return this},animateAlongPath:function(attrs,path){var animateMotion=V("animateMotion",attrs);var mpath=V("mpath",{"xlink:href":"#"+V(path).node.id});animateMotion.append(mpath);this.append(animateMotion);try{animateMotion.node.beginElement()}catch(e){if(document.documentElement.getAttribute("smiling")==="fake"){var animation=animateMotion.node;animation.animators=[];var animationID=animation.getAttribute("id");if(animationID)id2anim[animationID]=animation;var targets=getTargets(animation);for(var i=0,len=targets.length;i<len;i++){var target=targets[i];var animator=new Animator(animation,target,i);animators.push(animator);animation.animators[i]=animator;animator.register()}}}},hasClass:function(className){return new RegExp("(\\s|^)"+className+"(\\s|$)").test(this.node.getAttribute("class"))},addClass:function(className){if(!this.hasClass(className)){this.node.setAttribute("class",this.node.getAttribute("class")+" "+className)}return this},removeClass:function(className){var removedClass=this.node.getAttribute("class").replace(new RegExp("(\\s|^)"+className+"(\\s|$)","g"),"$2");if(this.hasClass(className)){this.node.setAttribute("class",removedClass)}return this},toggleClass:function(className,toAdd){var toRemove=typeof toAdd==="undefined"?this.hasClass(className):!toAdd;if(toRemove){this.removeClass(className)}else{this.addClass(className)}return this}};function rectToPath(r){var topRx=r.rx||r["top-rx"]||0;var bottomRx=r.rx||r["bottom-rx"]||0;var topRy=r.ry||r["top-ry"]||0;var bottomRy=r.ry||r["bottom-ry"]||0;return["M",r.x,r.y+topRy,"v",r.height-topRy-bottomRy,"a",bottomRx,bottomRy,0,0,0,bottomRx,bottomRy,"h",r.width-2*bottomRx,"a",bottomRx,bottomRy,0,0,0,bottomRx,-bottomRy,"v",-(r.height-bottomRy-topRy),"a",topRx,topRy,0,0,0,-topRx,-topRy,"h",-(r.width-2*topRx),"a",topRx,topRy,0,0,0,-topRx,topRy].join(" ")}var V=createElement;V.decomposeMatrix=decomposeMatrix;V.rectToPath=rectToPath;var svgDocument=V("svg").node;V.createSVGMatrix=function(m){var svgMatrix=svgDocument.createSVGMatrix();for(var component in m){svgMatrix[component]=m[component]}return svgMatrix};V.createSVGTransform=function(){return svgDocument.createSVGTransform()};V.createSVGPoint=function(x,y){var p=svgDocument.createSVGPoint();p.x=x;p.y=y;return p};return V});