/base/000_base/node_modules/highcharts/lib/canvg.js |
@@ -0,0 +1,130 @@ |
/* |
|
canvg.js - Javascript SVG parser and renderer on Canvas |
MIT Licensed |
Gabe Lerner (gabelerner@gmail.com) |
http://code.google.com/p/canvg/ |
|
Requires: rgbcolor.js - http://www.phpied.com/rgb-color-parser-in-javascript/ |
*/ |
(function(x,y){"undefined"!==typeof define&&define.amd?define("canvgModule",["rgbcolor","stackblur"],y):"undefined"!==typeof module&&module.exports&&(module.exports=y(require("rgbcolor"),require("stackblur")));x.canvg=y(x.RGBColor,x.stackBlur)})("undefined"!==typeof window?window:this,function(x,y){function A(h){var a=[0,0,0],l=function(c,b){var e=h.match(c);null!=e&&(a[b]+=e.length,h=h.replace(c," "))};h=h.replace(/:not\(([^\)]*)\)/g," $1 ");h=h.replace(/{[^]*/gm," ");l(B,1);l(C,0);l(D,1);l(E, |
2);l(F,1);l(G,1);h=h.replace(/[\*\s\+>~]/g," ");h=h.replace(/[#\.]/g," ");l(H,2);return a.join("")}function I(h){var a={opts:h,FRAMERATE:30,MAX_VIRTUAL_PIXELS:3E4,log:function(a){}};1==a.opts.log&&"undefined"!=typeof console&&(a.log=function(a){console.log(a)});a.init=function(c){var b=0;a.UniqueId=function(){b++;return"canvg"+b};a.Definitions={};a.Styles={};a.StylesSpecificity={};a.Animations=[];a.Images=[];a.ctx=c;a.ViewPort=new function(){this.viewPorts=[];this.Clear=function(){this.viewPorts= |
[]};this.SetCurrent=function(a,b){this.viewPorts.push({width:a,height:b})};this.RemoveCurrent=function(){this.viewPorts.pop()};this.Current=function(){return this.viewPorts[this.viewPorts.length-1]};this.width=function(){return this.Current().width};this.height=function(){return this.Current().height};this.ComputeSize=function(a){return null!=a&&"number"==typeof a?a:"x"==a?this.width():"y"==a?this.height():Math.sqrt(Math.pow(this.width(),2)+Math.pow(this.height(),2))/Math.sqrt(2)}}};a.init();a.ImagesLoaded= |
function(){for(var c=0;c<a.Images.length;c++)if(!a.Images[c].loaded)return!1;return!0};a.trim=function(a){return a.replace(/^\s+|\s+$/g,"")};a.compressSpaces=function(a){return a.replace(/[\s\r\t\n]+/gm," ")};a.ajax=function(a){var b;b=window.XMLHttpRequest?new XMLHttpRequest:new ActiveXObject("Microsoft.XMLHTTP");b.open("GET",a,!1);b.send(null);return b.responseText};a.parseXml=function(a){if("undefined"!=typeof Windows&&"undefined"!=typeof Windows.Data&&"undefined"!=typeof Windows.Data.Xml){var b= |
new Windows.Data.Xml.Dom.XmlDocument,e=new Windows.Data.Xml.Dom.XmlLoadSettings;e.prohibitDtd=!1;b.loadXml(a,e);return b}if(window.DOMParser)return(new DOMParser).parseFromString(a,"text/xml");a=a.replace(/<!DOCTYPE svg[^>]*>/,"");b=new ActiveXObject("Microsoft.XMLDOM");b.async="false";b.loadXML(a);return b};a.Property=function(a,b){this.name=a;this.value=b};a.Property.prototype.getValue=function(){return this.value};a.Property.prototype.hasValue=function(){return null!=this.value&&""!==this.value}; |
a.Property.prototype.numValue=function(){if(!this.hasValue())return 0;var a=parseFloat(this.value);(this.value+"").match(/%$/)&&(a/=100);return a};a.Property.prototype.valueOrDefault=function(a){return this.hasValue()?this.value:a};a.Property.prototype.numValueOrDefault=function(a){return this.hasValue()?this.numValue():a};a.Property.prototype.addOpacity=function(c){var b=this.value;if(null!=c.value&&""!=c.value&&"string"==typeof this.value){var e=new x(this.value);e.ok&&(b="rgba("+e.r+", "+e.g+", "+ |
e.b+", "+c.numValue()+")")}return new a.Property(this.name,b)};a.Property.prototype.getDefinition=function(){var c=this.value.match(/#([^\)'"]+)/);c&&(c=c[1]);c||(c=this.value);return a.Definitions[c]};a.Property.prototype.isUrlDefinition=function(){return 0==this.value.indexOf("url(")};a.Property.prototype.getFillStyleDefinition=function(c,b){var e=this.getDefinition();if(null!=e&&e.createGradient)return e.createGradient(a.ctx,c,b);if(null!=e&&e.createPattern){if(e.getHrefAttribute().hasValue()){var d= |
e.attribute("patternTransform"),e=e.getHrefAttribute().getDefinition();d.hasValue()&&(e.attribute("patternTransform",!0).value=d.value)}return e.createPattern(a.ctx,c)}return null};a.Property.prototype.getDPI=function(a){return 96};a.Property.prototype.getEM=function(c){var b=12,e=new a.Property("fontSize",a.Font.Parse(a.ctx.font).fontSize);e.hasValue()&&(b=e.toPixels(c));return b};a.Property.prototype.getUnits=function(){return(this.value+"").replace(/[0-9\.\-]/g,"")};a.Property.prototype.toPixels= |
function(c,b){if(!this.hasValue())return 0;var e=this.value+"";if(e.match(/em$/))return this.numValue()*this.getEM(c);if(e.match(/ex$/))return this.numValue()*this.getEM(c)/2;if(e.match(/px$/))return this.numValue();if(e.match(/pt$/))return this.numValue()*this.getDPI(c)*(1/72);if(e.match(/pc$/))return 15*this.numValue();if(e.match(/cm$/))return this.numValue()*this.getDPI(c)/2.54;if(e.match(/mm$/))return this.numValue()*this.getDPI(c)/25.4;if(e.match(/in$/))return this.numValue()*this.getDPI(c); |
if(e.match(/%$/))return this.numValue()*a.ViewPort.ComputeSize(c);e=this.numValue();return b&&1>e?e*a.ViewPort.ComputeSize(c):e};a.Property.prototype.toMilliseconds=function(){if(!this.hasValue())return 0;var a=this.value+"";if(a.match(/s$/))return 1E3*this.numValue();a.match(/ms$/);return this.numValue()};a.Property.prototype.toRadians=function(){if(!this.hasValue())return 0;var a=this.value+"";return a.match(/deg$/)?this.numValue()*(Math.PI/180):a.match(/grad$/)?this.numValue()*(Math.PI/200):a.match(/rad$/)? |
this.numValue():this.numValue()*(Math.PI/180)};var l={baseline:"alphabetic","before-edge":"top","text-before-edge":"top",middle:"middle",central:"middle","after-edge":"bottom","text-after-edge":"bottom",ideographic:"ideographic",alphabetic:"alphabetic",hanging:"hanging",mathematical:"alphabetic"};a.Property.prototype.toTextBaseline=function(){return this.hasValue()?l[this.value]:null};a.Font=new function(){this.Styles="normal|italic|oblique|inherit";this.Variants="normal|small-caps|inherit";this.Weights= |
"normal|bold|bolder|lighter|100|200|300|400|500|600|700|800|900|inherit";this.CreateFont=function(b,e,d,c,f,g){g=null!=g?this.Parse(g):this.CreateFont("","","","","",a.ctx.font);return{fontFamily:f||g.fontFamily,fontSize:c||g.fontSize,fontStyle:b||g.fontStyle,fontWeight:d||g.fontWeight,fontVariant:e||g.fontVariant,toString:function(){return[this.fontStyle,this.fontVariant,this.fontWeight,this.fontSize,this.fontFamily].join(" ")}}};var c=this;this.Parse=function(b){var e={};b=a.trim(a.compressSpaces(b|| |
"")).split(" ");for(var d=!1,k=!1,f=!1,g=!1,m="",n=0;n<b.length;n++)k||-1==c.Styles.indexOf(b[n])?g||-1==c.Variants.indexOf(b[n])?f||-1==c.Weights.indexOf(b[n])?d?"inherit"!=b[n]&&(m+=b[n]):("inherit"!=b[n]&&(e.fontSize=b[n].split("/")[0]),k=g=f=d=!0):("inherit"!=b[n]&&(e.fontWeight=b[n]),k=g=f=!0):("inherit"!=b[n]&&(e.fontVariant=b[n]),k=g=!0):("inherit"!=b[n]&&(e.fontStyle=b[n]),k=!0);""!=m&&(e.fontFamily=m);return e}};a.ToNumberArray=function(c){c=a.trim(a.compressSpaces((c||"").replace(/,/g," "))).split(" "); |
for(var b=0;b<c.length;b++)c[b]=parseFloat(c[b]);return c};a.Point=function(a,b){this.x=a;this.y=b};a.Point.prototype.angleTo=function(a){return Math.atan2(a.y-this.y,a.x-this.x)};a.Point.prototype.applyTransform=function(a){var b=this.x*a[1]+this.y*a[3]+a[5];this.x=this.x*a[0]+this.y*a[2]+a[4];this.y=b};a.CreatePoint=function(c){c=a.ToNumberArray(c);return new a.Point(c[0],c[1])};a.CreatePath=function(c){c=a.ToNumberArray(c);for(var b=[],e=0;e<c.length;e+=2)b.push(new a.Point(c[e],c[e+1]));return b}; |
a.BoundingBox=function(a,b,e,d){this.y2=this.x2=this.y1=this.x1=Number.NaN;this.x=function(){return this.x1};this.y=function(){return this.y1};this.width=function(){return this.x2-this.x1};this.height=function(){return this.y2-this.y1};this.addPoint=function(a,b){if(null!=a){if(isNaN(this.x1)||isNaN(this.x2))this.x2=this.x1=a;a<this.x1&&(this.x1=a);a>this.x2&&(this.x2=a)}if(null!=b){if(isNaN(this.y1)||isNaN(this.y2))this.y2=this.y1=b;b<this.y1&&(this.y1=b);b>this.y2&&(this.y2=b)}};this.addX=function(a){this.addPoint(a, |
null)};this.addY=function(a){this.addPoint(null,a)};this.addBoundingBox=function(a){this.addPoint(a.x1,a.y1);this.addPoint(a.x2,a.y2)};this.addQuadraticCurve=function(a,b,e,d,c,r){e=a+2/3*(e-a);d=b+2/3*(d-b);this.addBezierCurve(a,b,e,e+1/3*(c-a),d,d+1/3*(r-b),c,r)};this.addBezierCurve=function(a,b,e,d,c,r,u,p){var t=[a,b],h=[e,d],q=[c,r],l=[u,p];this.addPoint(t[0],t[1]);this.addPoint(l[0],l[1]);for(i=0;1>=i;i++)a=function(a){return Math.pow(1-a,3)*t[i]+3*Math.pow(1-a,2)*a*h[i]+3*(1-a)*Math.pow(a, |
2)*q[i]+Math.pow(a,3)*l[i]},b=6*t[i]-12*h[i]+6*q[i],e=-3*t[i]+9*h[i]-9*q[i]+3*l[i],d=3*h[i]-3*t[i],0==e?0!=b&&(b=-d/b,0<b&&1>b&&(0==i&&this.addX(a(b)),1==i&&this.addY(a(b)))):(d=Math.pow(b,2)-4*d*e,0>d||(c=(-b+Math.sqrt(d))/(2*e),0<c&&1>c&&(0==i&&this.addX(a(c)),1==i&&this.addY(a(c))),b=(-b-Math.sqrt(d))/(2*e),0<b&&1>b&&(0==i&&this.addX(a(b)),1==i&&this.addY(a(b)))))};this.isPointInBox=function(a,b){return this.x1<=a&&a<=this.x2&&this.y1<=b&&b<=this.y2};this.addPoint(a,b);this.addPoint(e,d)};a.Transform= |
function(c){var b=this;this.Type={};this.Type.translate=function(b){this.p=a.CreatePoint(b);this.apply=function(a){a.translate(this.p.x||0,this.p.y||0)};this.unapply=function(a){a.translate(-1*this.p.x||0,-1*this.p.y||0)};this.applyToPoint=function(a){a.applyTransform([1,0,0,1,this.p.x||0,this.p.y||0])}};this.Type.rotate=function(b){b=a.ToNumberArray(b);this.angle=new a.Property("angle",b[0]);this.cx=b[1]||0;this.cy=b[2]||0;this.apply=function(a){a.translate(this.cx,this.cy);a.rotate(this.angle.toRadians()); |
a.translate(-this.cx,-this.cy)};this.unapply=function(a){a.translate(this.cx,this.cy);a.rotate(-1*this.angle.toRadians());a.translate(-this.cx,-this.cy)};this.applyToPoint=function(a){var b=this.angle.toRadians();a.applyTransform([1,0,0,1,this.p.x||0,this.p.y||0]);a.applyTransform([Math.cos(b),Math.sin(b),-Math.sin(b),Math.cos(b),0,0]);a.applyTransform([1,0,0,1,-this.p.x||0,-this.p.y||0])}};this.Type.scale=function(b){this.p=a.CreatePoint(b);this.apply=function(a){a.scale(this.p.x||1,this.p.y||this.p.x|| |
1)};this.unapply=function(a){a.scale(1/this.p.x||1,1/this.p.y||this.p.x||1)};this.applyToPoint=function(a){a.applyTransform([this.p.x||0,0,0,this.p.y||0,0,0])}};this.Type.matrix=function(b){this.m=a.ToNumberArray(b);this.apply=function(a){a.transform(this.m[0],this.m[1],this.m[2],this.m[3],this.m[4],this.m[5])};this.unapply=function(a){var b=this.m[0],e=this.m[2],d=this.m[4],c=this.m[1],f=this.m[3],k=this.m[5],h=1/(b*(1*f-0*k)-e*(1*c-0*k)+d*(0*c-0*f));a.transform(h*(1*f-0*k),h*(0*k-1*c),h*(0*d-1* |
e),h*(1*b-0*d),h*(e*k-d*f),h*(d*c-b*k))};this.applyToPoint=function(a){a.applyTransform(this.m)}};this.Type.SkewBase=function(e){this.base=b.Type.matrix;this.base(e);this.angle=new a.Property("angle",e)};this.Type.SkewBase.prototype=new this.Type.matrix;this.Type.skewX=function(a){this.base=b.Type.SkewBase;this.base(a);this.m=[1,0,Math.tan(this.angle.toRadians()),1,0,0]};this.Type.skewX.prototype=new this.Type.SkewBase;this.Type.skewY=function(a){this.base=b.Type.SkewBase;this.base(a);this.m=[1,Math.tan(this.angle.toRadians()), |
0,1,0,0]};this.Type.skewY.prototype=new this.Type.SkewBase;this.transforms=[];this.apply=function(a){for(var b=0;b<this.transforms.length;b++)this.transforms[b].apply(a)};this.unapply=function(a){for(var b=this.transforms.length-1;0<=b;b--)this.transforms[b].unapply(a)};this.applyToPoint=function(a){for(var b=0;b<this.transforms.length;b++)this.transforms[b].applyToPoint(a)};c=a.trim(a.compressSpaces(c)).replace(/\)([a-zA-Z])/g,") $1").replace(/\)(\s?,\s?)/g,") ").split(/\s(?=[a-z])/);for(var e=0;e< |
c.length;e++){var d=a.trim(c[e].split("(")[0]),k=c[e].split("(")[1].replace(")",""),k=new this.Type[d](k);k.type=d;this.transforms.push(k)}};a.AspectRatio=function(c,b,e,d,k,f,g,m,n,r){b=a.compressSpaces(b);b=b.replace(/^defer\s/,"");var h=b.split(" ")[0]||"xMidYMid";b=b.split(" ")[1]||"meet";var p=e/d,t=k/f,l=Math.min(p,t),q=Math.max(p,t);"meet"==b&&(d*=l,f*=l);"slice"==b&&(d*=q,f*=q);n=new a.Property("refX",n);r=new a.Property("refY",r);n.hasValue()&&r.hasValue()?c.translate(-l*n.toPixels("x"), |
-l*r.toPixels("y")):(h.match(/^xMid/)&&("meet"==b&&l==t||"slice"==b&&q==t)&&c.translate(e/2-d/2,0),h.match(/YMid$/)&&("meet"==b&&l==p||"slice"==b&&q==p)&&c.translate(0,k/2-f/2),h.match(/^xMax/)&&("meet"==b&&l==t||"slice"==b&&q==t)&&c.translate(e-d,0),h.match(/YMax$/)&&("meet"==b&&l==p||"slice"==b&&q==p)&&c.translate(0,k-f));"none"==h?c.scale(p,t):"meet"==b?c.scale(l,l):"slice"==b&&c.scale(q,q);c.translate(null==g?0:-g,null==m?0:-m)};a.Element={};a.EmptyProperty=new a.Property("EMPTY","");a.Element.ElementBase= |
function(c){this.attributes={};this.styles={};this.stylesSpecificity={};this.children=[];this.attribute=function(b,e){var d=this.attributes[b];if(null!=d)return d;1==e&&(d=new a.Property(b,""),this.attributes[b]=d);return d||a.EmptyProperty};this.getHrefAttribute=function(){for(var b in this.attributes)if("href"==b||b.match(/:href$/))return this.attributes[b];return a.EmptyProperty};this.style=function(b,e,d){var c=this.styles[b];if(null!=c)return c;var k=this.attribute(b);if(null!=k&&k.hasValue())return this.styles[b]= |
k;if(1!=d&&(d=this.parent,null!=d&&(d=d.style(b),null!=d&&d.hasValue())))return d;1==e&&(c=new a.Property(b,""),this.styles[b]=c);return c||a.EmptyProperty};this.render=function(a){if("none"!=this.style("display").value&&"hidden"!=this.style("visibility").value){a.save();if(this.style("mask").hasValue()){var b=this.style("mask").getDefinition();null!=b&&b.apply(a,this)}else this.style("filter").hasValue()?(b=this.style("filter").getDefinition(),null!=b&&b.apply(a,this)):(this.setContext(a),this.renderChildren(a), |
this.clearContext(a));a.restore()}};this.setContext=function(a){};this.clearContext=function(a){};this.renderChildren=function(a){for(var b=0;b<this.children.length;b++)this.children[b].render(a)};this.addChild=function(b,e){var d=b;e&&(d=a.CreateElement(b));d.parent=this;"title"!=d.type&&this.children.push(d)};this.addStylesFromStyleDefinition=function(){for(var b in a.Styles)if("@"!=b[0]&&w(c,b)){var e=a.Styles[b],d=a.StylesSpecificity[b];if(null!=e)for(var k in e){var r=this.stylesSpecificity[k]; |
"undefined"==typeof r&&(r="000");d>r&&(this.styles[k]=e[k],this.stylesSpecificity[k]=d)}}};if(null!=c&&1==c.nodeType){for(var b=0;b<c.attributes.length;b++){var e=c.attributes[b];this.attributes[e.nodeName]=new a.Property(e.nodeName,e.value)}this.addStylesFromStyleDefinition();if(this.attribute("style").hasValue())for(e=this.attribute("style").value.split(";"),b=0;b<e.length;b++)if(""!=a.trim(e[b])){var d=e[b].split(":"),k=a.trim(d[0]),d=a.trim(d[1]);this.styles[k]=new a.Property(k,d)}this.attribute("id").hasValue()&& |
null==a.Definitions[this.attribute("id").value]&&(a.Definitions[this.attribute("id").value]=this);for(b=0;b<c.childNodes.length;b++)e=c.childNodes[b],1==e.nodeType&&this.addChild(e,!0),!this.captureTextNodes||3!=e.nodeType&&4!=e.nodeType||""!=a.compressSpaces(e.value||e.text||e.textContent||"")&&this.addChild(new a.Element.tspan(e),!1)}};a.Element.RenderedElementBase=function(c){this.base=a.Element.ElementBase;this.base(c);this.setContext=function(b){if(this.style("fill").isUrlDefinition()){var e= |
this.style("fill").getFillStyleDefinition(this,this.style("fill-opacity"));null!=e&&(b.fillStyle=e)}else this.style("fill").hasValue()&&(e=this.style("fill"),"currentColor"==e.value&&(e.value=this.style("color").value),"inherit"!=e.value&&(b.fillStyle="none"==e.value?"rgba(0,0,0,0)":e.value));this.style("fill-opacity").hasValue()&&(e=new a.Property("fill",b.fillStyle),e=e.addOpacity(this.style("fill-opacity")),b.fillStyle=e.value);this.style("stroke").isUrlDefinition()?(e=this.style("stroke").getFillStyleDefinition(this, |
this.style("stroke-opacity")),null!=e&&(b.strokeStyle=e)):this.style("stroke").hasValue()&&(e=this.style("stroke"),"currentColor"==e.value&&(e.value=this.style("color").value),"inherit"!=e.value&&(b.strokeStyle="none"==e.value?"rgba(0,0,0,0)":e.value));this.style("stroke-opacity").hasValue()&&(e=new a.Property("stroke",b.strokeStyle),e=e.addOpacity(this.style("stroke-opacity")),b.strokeStyle=e.value);this.style("stroke-width").hasValue()&&(e=this.style("stroke-width").toPixels(),b.lineWidth=0==e? |
.001:e);this.style("stroke-linecap").hasValue()&&(b.lineCap=this.style("stroke-linecap").value);this.style("stroke-linejoin").hasValue()&&(b.lineJoin=this.style("stroke-linejoin").value);this.style("stroke-miterlimit").hasValue()&&(b.miterLimit=this.style("stroke-miterlimit").value);this.style("stroke-dasharray").hasValue()&&"none"!=this.style("stroke-dasharray").value&&(e=a.ToNumberArray(this.style("stroke-dasharray").value),"undefined"!=typeof b.setLineDash?b.setLineDash(e):"undefined"!=typeof b.webkitLineDash? |
b.webkitLineDash=e:"undefined"==typeof b.mozDash||1==e.length&&0==e[0]||(b.mozDash=e),e=this.style("stroke-dashoffset").numValueOrDefault(1),"undefined"!=typeof b.lineDashOffset?b.lineDashOffset=e:"undefined"!=typeof b.webkitLineDashOffset?b.webkitLineDashOffset=e:"undefined"!=typeof b.mozDashOffset&&(b.mozDashOffset=e));"undefined"!=typeof b.font&&(b.font=a.Font.CreateFont(this.style("font-style").value,this.style("font-variant").value,this.style("font-weight").value,this.style("font-size").hasValue()? |
this.style("font-size").toPixels()+"px":"",this.style("font-family").value).toString());this.style("transform",!1,!0).hasValue()&&(new a.Transform(this.style("transform",!1,!0).value)).apply(b);this.style("clip-path",!1,!0).hasValue()&&(e=this.style("clip-path",!1,!0).getDefinition(),null!=e&&e.apply(b));this.style("opacity").hasValue()&&(b.globalAlpha=this.style("opacity").numValue())}};a.Element.RenderedElementBase.prototype=new a.Element.ElementBase;a.Element.PathElementBase=function(c){this.base= |
a.Element.RenderedElementBase;this.base(c);this.path=function(b){null!=b&&b.beginPath();return new a.BoundingBox};this.renderChildren=function(b){this.path(b);a.Mouse.checkPath(this,b);""!=b.fillStyle&&("inherit"!=this.style("fill-rule").valueOrDefault("inherit")?b.fill(this.style("fill-rule").value):b.fill());""!=b.strokeStyle&&b.stroke();var e=this.getMarkers();if(null!=e){if(this.style("marker-start").isUrlDefinition()){var d=this.style("marker-start").getDefinition();d.render(b,e[0][0],e[0][1])}if(this.style("marker-mid").isUrlDefinition())for(var d= |
this.style("marker-mid").getDefinition(),c=1;c<e.length-1;c++)d.render(b,e[c][0],e[c][1]);this.style("marker-end").isUrlDefinition()&&(d=this.style("marker-end").getDefinition(),d.render(b,e[e.length-1][0],e[e.length-1][1]))}};this.getBoundingBox=function(){return this.path()};this.getMarkers=function(){return null}};a.Element.PathElementBase.prototype=new a.Element.RenderedElementBase;a.Element.svg=function(c){this.base=a.Element.RenderedElementBase;this.base(c);this.baseClearContext=this.clearContext; |
this.clearContext=function(b){this.baseClearContext(b);a.ViewPort.RemoveCurrent()};this.baseSetContext=this.setContext;this.setContext=function(b){b.strokeStyle="rgba(0,0,0,0)";b.lineCap="butt";b.lineJoin="miter";b.miterLimit=4;"undefined"!=typeof b.font&&"undefined"!=typeof window.getComputedStyle&&(b.font=window.getComputedStyle(b.canvas).getPropertyValue("font"));this.baseSetContext(b);this.attribute("x").hasValue()||(this.attribute("x",!0).value=0);this.attribute("y").hasValue()||(this.attribute("y", |
!0).value=0);b.translate(this.attribute("x").toPixels("x"),this.attribute("y").toPixels("y"));var e=a.ViewPort.width(),d=a.ViewPort.height();this.attribute("width").hasValue()||(this.attribute("width",!0).value="100%");this.attribute("height").hasValue()||(this.attribute("height",!0).value="100%");if("undefined"==typeof this.root){var e=this.attribute("width").toPixels("x"),d=this.attribute("height").toPixels("y"),c=0,f=0;this.attribute("refX").hasValue()&&this.attribute("refY").hasValue()&&(c=-this.attribute("refX").toPixels("x"), |
f=-this.attribute("refY").toPixels("y"));"visible"!=this.attribute("overflow").valueOrDefault("hidden")&&(b.beginPath(),b.moveTo(c,f),b.lineTo(e,f),b.lineTo(e,d),b.lineTo(c,d),b.closePath(),b.clip())}a.ViewPort.SetCurrent(e,d);if(this.attribute("viewBox").hasValue()){var c=a.ToNumberArray(this.attribute("viewBox").value),f=c[0],g=c[1],e=c[2],d=c[3];a.AspectRatio(b,this.attribute("preserveAspectRatio").value,a.ViewPort.width(),e,a.ViewPort.height(),d,f,g,this.attribute("refX").value,this.attribute("refY").value); |
a.ViewPort.RemoveCurrent();a.ViewPort.SetCurrent(c[2],c[3])}}};a.Element.svg.prototype=new a.Element.RenderedElementBase;a.Element.rect=function(c){this.base=a.Element.PathElementBase;this.base(c);this.path=function(b){var e=this.attribute("x").toPixels("x"),d=this.attribute("y").toPixels("y"),c=this.attribute("width").toPixels("x"),f=this.attribute("height").toPixels("y"),g=this.attribute("rx").toPixels("x"),m=this.attribute("ry").toPixels("y");this.attribute("rx").hasValue()&&!this.attribute("ry").hasValue()&& |
(m=g);this.attribute("ry").hasValue()&&!this.attribute("rx").hasValue()&&(g=m);g=Math.min(g,c/2);m=Math.min(m,f/2);null!=b&&(b.beginPath(),b.moveTo(e+g,d),b.lineTo(e+c-g,d),b.quadraticCurveTo(e+c,d,e+c,d+m),b.lineTo(e+c,d+f-m),b.quadraticCurveTo(e+c,d+f,e+c-g,d+f),b.lineTo(e+g,d+f),b.quadraticCurveTo(e,d+f,e,d+f-m),b.lineTo(e,d+m),b.quadraticCurveTo(e,d,e+g,d),b.closePath());return new a.BoundingBox(e,d,e+c,d+f)}};a.Element.rect.prototype=new a.Element.PathElementBase;a.Element.circle=function(c){this.base= |
a.Element.PathElementBase;this.base(c);this.path=function(b){var e=this.attribute("cx").toPixels("x"),d=this.attribute("cy").toPixels("y"),c=this.attribute("r").toPixels();null!=b&&(b.beginPath(),b.arc(e,d,c,0,2*Math.PI,!0),b.closePath());return new a.BoundingBox(e-c,d-c,e+c,d+c)}};a.Element.circle.prototype=new a.Element.PathElementBase;a.Element.ellipse=function(c){this.base=a.Element.PathElementBase;this.base(c);this.path=function(b){var e=(Math.sqrt(2)-1)/3*4,d=this.attribute("rx").toPixels("x"), |
c=this.attribute("ry").toPixels("y"),f=this.attribute("cx").toPixels("x"),g=this.attribute("cy").toPixels("y");null!=b&&(b.beginPath(),b.moveTo(f,g-c),b.bezierCurveTo(f+e*d,g-c,f+d,g-e*c,f+d,g),b.bezierCurveTo(f+d,g+e*c,f+e*d,g+c,f,g+c),b.bezierCurveTo(f-e*d,g+c,f-d,g+e*c,f-d,g),b.bezierCurveTo(f-d,g-e*c,f-e*d,g-c,f,g-c),b.closePath());return new a.BoundingBox(f-d,g-c,f+d,g+c)}};a.Element.ellipse.prototype=new a.Element.PathElementBase;a.Element.line=function(c){this.base=a.Element.PathElementBase; |
this.base(c);this.getPoints=function(){return[new a.Point(this.attribute("x1").toPixels("x"),this.attribute("y1").toPixels("y")),new a.Point(this.attribute("x2").toPixels("x"),this.attribute("y2").toPixels("y"))]};this.path=function(b){var e=this.getPoints();null!=b&&(b.beginPath(),b.moveTo(e[0].x,e[0].y),b.lineTo(e[1].x,e[1].y));return new a.BoundingBox(e[0].x,e[0].y,e[1].x,e[1].y)};this.getMarkers=function(){var a=this.getPoints(),e=a[0].angleTo(a[1]);return[[a[0],e],[a[1],e]]}};a.Element.line.prototype= |
new a.Element.PathElementBase;a.Element.polyline=function(c){this.base=a.Element.PathElementBase;this.base(c);this.points=a.CreatePath(this.attribute("points").value);this.path=function(b){var e=new a.BoundingBox(this.points[0].x,this.points[0].y);null!=b&&(b.beginPath(),b.moveTo(this.points[0].x,this.points[0].y));for(var d=1;d<this.points.length;d++)e.addPoint(this.points[d].x,this.points[d].y),null!=b&&b.lineTo(this.points[d].x,this.points[d].y);return e};this.getMarkers=function(){for(var a=[], |
e=0;e<this.points.length-1;e++)a.push([this.points[e],this.points[e].angleTo(this.points[e+1])]);a.push([this.points[this.points.length-1],a[a.length-1][1]]);return a}};a.Element.polyline.prototype=new a.Element.PathElementBase;a.Element.polygon=function(c){this.base=a.Element.polyline;this.base(c);this.basePath=this.path;this.path=function(a){var e=this.basePath(a);null!=a&&(a.lineTo(this.points[0].x,this.points[0].y),a.closePath());return e}};a.Element.polygon.prototype=new a.Element.polyline;a.Element.path= |
function(c){this.base=a.Element.PathElementBase;this.base(c);c=this.attribute("d").value;c=c.replace(/,/gm," ");for(var b=0;2>b;b++)c=c.replace(/([MmZzLlHhVvCcSsQqTtAa])([^\s])/gm,"$1 $2");c=c.replace(/([^\s])([MmZzLlHhVvCcSsQqTtAa])/gm,"$1 $2");c=c.replace(/([0-9])([+\-])/gm,"$1 $2");for(b=0;2>b;b++)c=c.replace(/(\.[0-9]*)(\.)/gm,"$1 $2");c=c.replace(/([Aa](\s+[0-9]+){3})\s+([01])\s*([01])/gm,"$1 $3 $4 ");c=a.compressSpaces(c);c=a.trim(c);this.PathParser=new function(b){this.tokens=b.split(" "); |
this.reset=function(){this.i=-1;this.previousCommand=this.command="";this.start=new a.Point(0,0);this.control=new a.Point(0,0);this.current=new a.Point(0,0);this.points=[];this.angles=[]};this.isEnd=function(){return this.i>=this.tokens.length-1};this.isCommandOrEnd=function(){return this.isEnd()?!0:null!=this.tokens[this.i+1].match(/^[A-Za-z]$/)};this.isRelativeCommand=function(){switch(this.command){case "m":case "l":case "h":case "v":case "c":case "s":case "q":case "t":case "a":case "z":return!0}return!1}; |
this.getToken=function(){this.i++;return this.tokens[this.i]};this.getScalar=function(){return parseFloat(this.getToken())};this.nextCommand=function(){this.previousCommand=this.command;this.command=this.getToken()};this.getPoint=function(){var b=new a.Point(this.getScalar(),this.getScalar());return this.makeAbsolute(b)};this.getAsControlPoint=function(){var a=this.getPoint();return this.control=a};this.getAsCurrentPoint=function(){var a=this.getPoint();return this.current=a};this.getReflectedControlPoint= |
function(){return"c"!=this.previousCommand.toLowerCase()&&"s"!=this.previousCommand.toLowerCase()&&"q"!=this.previousCommand.toLowerCase()&&"t"!=this.previousCommand.toLowerCase()?this.current:new a.Point(2*this.current.x-this.control.x,2*this.current.y-this.control.y)};this.makeAbsolute=function(a){this.isRelativeCommand()&&(a.x+=this.current.x,a.y+=this.current.y);return a};this.addMarker=function(a,b,e){null!=e&&0<this.angles.length&&null==this.angles[this.angles.length-1]&&(this.angles[this.angles.length- |
1]=this.points[this.points.length-1].angleTo(e));this.addMarkerAngle(a,null==b?null:b.angleTo(a))};this.addMarkerAngle=function(a,b){this.points.push(a);this.angles.push(b)};this.getMarkerPoints=function(){return this.points};this.getMarkerAngles=function(){for(var a=0;a<this.angles.length;a++)if(null==this.angles[a])for(var b=a+1;b<this.angles.length;b++)if(null!=this.angles[b]){this.angles[a]=this.angles[b];break}return this.angles}}(c);this.path=function(b){var d=this.PathParser;d.reset();var c= |
new a.BoundingBox;for(null!=b&&b.beginPath();!d.isEnd();)switch(d.nextCommand(),d.command){case "M":case "m":var f=d.getAsCurrentPoint();d.addMarker(f);c.addPoint(f.x,f.y);null!=b&&b.moveTo(f.x,f.y);for(d.start=d.current;!d.isCommandOrEnd();)f=d.getAsCurrentPoint(),d.addMarker(f,d.start),c.addPoint(f.x,f.y),null!=b&&b.lineTo(f.x,f.y);break;case "L":case "l":for(;!d.isCommandOrEnd();){var g=d.current,f=d.getAsCurrentPoint();d.addMarker(f,g);c.addPoint(f.x,f.y);null!=b&&b.lineTo(f.x,f.y)}break;case "H":case "h":for(;!d.isCommandOrEnd();)f= |
new a.Point((d.isRelativeCommand()?d.current.x:0)+d.getScalar(),d.current.y),d.addMarker(f,d.current),d.current=f,c.addPoint(d.current.x,d.current.y),null!=b&&b.lineTo(d.current.x,d.current.y);break;case "V":case "v":for(;!d.isCommandOrEnd();)f=new a.Point(d.current.x,(d.isRelativeCommand()?d.current.y:0)+d.getScalar()),d.addMarker(f,d.current),d.current=f,c.addPoint(d.current.x,d.current.y),null!=b&&b.lineTo(d.current.x,d.current.y);break;case "C":case "c":for(;!d.isCommandOrEnd();){var m=d.current, |
g=d.getPoint(),n=d.getAsControlPoint(),f=d.getAsCurrentPoint();d.addMarker(f,n,g);c.addBezierCurve(m.x,m.y,g.x,g.y,n.x,n.y,f.x,f.y);null!=b&&b.bezierCurveTo(g.x,g.y,n.x,n.y,f.x,f.y)}break;case "S":case "s":for(;!d.isCommandOrEnd();)m=d.current,g=d.getReflectedControlPoint(),n=d.getAsControlPoint(),f=d.getAsCurrentPoint(),d.addMarker(f,n,g),c.addBezierCurve(m.x,m.y,g.x,g.y,n.x,n.y,f.x,f.y),null!=b&&b.bezierCurveTo(g.x,g.y,n.x,n.y,f.x,f.y);break;case "Q":case "q":for(;!d.isCommandOrEnd();)m=d.current, |
n=d.getAsControlPoint(),f=d.getAsCurrentPoint(),d.addMarker(f,n,n),c.addQuadraticCurve(m.x,m.y,n.x,n.y,f.x,f.y),null!=b&&b.quadraticCurveTo(n.x,n.y,f.x,f.y);break;case "T":case "t":for(;!d.isCommandOrEnd();)m=d.current,n=d.getReflectedControlPoint(),d.control=n,f=d.getAsCurrentPoint(),d.addMarker(f,n,n),c.addQuadraticCurve(m.x,m.y,n.x,n.y,f.x,f.y),null!=b&&b.quadraticCurveTo(n.x,n.y,f.x,f.y);break;case "A":case "a":for(;!d.isCommandOrEnd();){var m=d.current,r=d.getScalar(),h=d.getScalar(),g=d.getScalar()* |
(Math.PI/180),p=d.getScalar(),n=d.getScalar(),f=d.getAsCurrentPoint(),l=new a.Point(Math.cos(g)*(m.x-f.x)/2+Math.sin(g)*(m.y-f.y)/2,-Math.sin(g)*(m.x-f.x)/2+Math.cos(g)*(m.y-f.y)/2),v=Math.pow(l.x,2)/Math.pow(r,2)+Math.pow(l.y,2)/Math.pow(h,2);1<v&&(r*=Math.sqrt(v),h*=Math.sqrt(v));p=(p==n?-1:1)*Math.sqrt((Math.pow(r,2)*Math.pow(h,2)-Math.pow(r,2)*Math.pow(l.y,2)-Math.pow(h,2)*Math.pow(l.x,2))/(Math.pow(r,2)*Math.pow(l.y,2)+Math.pow(h,2)*Math.pow(l.x,2)));isNaN(p)&&(p=0);var q=new a.Point(p*r*l.y/ |
h,p*-h*l.x/r),m=new a.Point((m.x+f.x)/2+Math.cos(g)*q.x-Math.sin(g)*q.y,(m.y+f.y)/2+Math.sin(g)*q.x+Math.cos(g)*q.y),w=function(a,b){return(a[0]*b[0]+a[1]*b[1])/(Math.sqrt(Math.pow(a[0],2)+Math.pow(a[1],2))*Math.sqrt(Math.pow(b[0],2)+Math.pow(b[1],2)))},x=function(a,b){return(a[0]*b[1]<a[1]*b[0]?-1:1)*Math.acos(w(a,b))},p=x([1,0],[(l.x-q.x)/r,(l.y-q.y)/h]),v=[(l.x-q.x)/r,(l.y-q.y)/h],q=[(-l.x-q.x)/r,(-l.y-q.y)/h],l=x(v,q);-1>=w(v,q)&&(l=Math.PI);1<=w(v,q)&&(l=0);v=1-n?1:-1;q=p+l/2*v;x=new a.Point(m.x+ |
r*Math.cos(q),m.y+h*Math.sin(q));d.addMarkerAngle(x,q-v*Math.PI/2);d.addMarkerAngle(f,q-v*Math.PI);c.addPoint(f.x,f.y);null!=b&&(w=r>h?r:h,f=r>h?1:r/h,r=r>h?h/r:1,b.translate(m.x,m.y),b.rotate(g),b.scale(f,r),b.arc(0,0,w,p,p+l,1-n),b.scale(1/f,1/r),b.rotate(-g),b.translate(-m.x,-m.y))}break;case "Z":case "z":null!=b&&b.closePath(),d.current=d.start}return c};this.getMarkers=function(){for(var a=this.PathParser.getMarkerPoints(),b=this.PathParser.getMarkerAngles(),c=[],f=0;f<a.length;f++)c.push([a[f], |
b[f]]);return c}};a.Element.path.prototype=new a.Element.PathElementBase;a.Element.pattern=function(c){this.base=a.Element.ElementBase;this.base(c);this.createPattern=function(b,e){var d=this.attribute("width").toPixels("x",!0),c=this.attribute("height").toPixels("y",!0),f=new a.Element.svg;f.attributes.viewBox=new a.Property("viewBox",this.attribute("viewBox").value);f.attributes.width=new a.Property("width",d+"px");f.attributes.height=new a.Property("height",c+"px");f.attributes.transform=new a.Property("transform", |
this.attribute("patternTransform").value);f.children=this.children;var g=document.createElement("canvas");g.width=d;g.height=c;d=g.getContext("2d");this.attribute("x").hasValue()&&this.attribute("y").hasValue()&&d.translate(this.attribute("x").toPixels("x",!0),this.attribute("y").toPixels("y",!0));for(c=-1;1>=c;c++)for(var m=-1;1>=m;m++)d.save(),f.attributes.x=new a.Property("x",c*g.width),f.attributes.y=new a.Property("y",m*g.height),f.render(d),d.restore();return b.createPattern(g,"repeat")}};a.Element.pattern.prototype= |
new a.Element.ElementBase;a.Element.marker=function(c){this.base=a.Element.ElementBase;this.base(c);this.baseRender=this.render;this.render=function(b,e,d){b.translate(e.x,e.y);"auto"==this.attribute("orient").valueOrDefault("auto")&&b.rotate(d);"strokeWidth"==this.attribute("markerUnits").valueOrDefault("strokeWidth")&&b.scale(b.lineWidth,b.lineWidth);b.save();var c=new a.Element.svg;c.attributes.viewBox=new a.Property("viewBox",this.attribute("viewBox").value);c.attributes.refX=new a.Property("refX", |
this.attribute("refX").value);c.attributes.refY=new a.Property("refY",this.attribute("refY").value);c.attributes.width=new a.Property("width",this.attribute("markerWidth").value);c.attributes.height=new a.Property("height",this.attribute("markerHeight").value);c.attributes.fill=new a.Property("fill",this.attribute("fill").valueOrDefault("black"));c.attributes.stroke=new a.Property("stroke",this.attribute("stroke").valueOrDefault("none"));c.children=this.children;c.render(b);b.restore();"strokeWidth"== |
this.attribute("markerUnits").valueOrDefault("strokeWidth")&&b.scale(1/b.lineWidth,1/b.lineWidth);"auto"==this.attribute("orient").valueOrDefault("auto")&&b.rotate(-d);b.translate(-e.x,-e.y)}};a.Element.marker.prototype=new a.Element.ElementBase;a.Element.defs=function(c){this.base=a.Element.ElementBase;this.base(c);this.render=function(a){}};a.Element.defs.prototype=new a.Element.ElementBase;a.Element.GradientBase=function(c){this.base=a.Element.ElementBase;this.base(c);this.stops=[];for(c=0;c<this.children.length;c++){var b= |
this.children[c];"stop"==b.type&&this.stops.push(b)}this.getGradient=function(){};this.gradientUnits=function(){return this.attribute("gradientUnits").valueOrDefault("objectBoundingBox")};this.attributesToInherit=["gradientUnits"];this.inheritStopContainer=function(a){for(var b=0;b<this.attributesToInherit.length;b++){var c=this.attributesToInherit[b];!this.attribute(c).hasValue()&&a.attribute(c).hasValue()&&(this.attribute(c,!0).value=a.attribute(c).value)}};this.createGradient=function(b,d,c){var f= |
this;this.getHrefAttribute().hasValue()&&(f=this.getHrefAttribute().getDefinition(),this.inheritStopContainer(f));var g=function(b){return c.hasValue()?(new a.Property("color",b)).addOpacity(c).value:b};b=this.getGradient(b,d);if(null==b)return g(f.stops[f.stops.length-1].color);for(d=0;d<f.stops.length;d++)b.addColorStop(f.stops[d].offset,g(f.stops[d].color));return this.attribute("gradientTransform").hasValue()?(f=a.ViewPort.viewPorts[0],g=new a.Element.rect,g.attributes.x=new a.Property("x",-a.MAX_VIRTUAL_PIXELS/ |
3),g.attributes.y=new a.Property("y",-a.MAX_VIRTUAL_PIXELS/3),g.attributes.width=new a.Property("width",a.MAX_VIRTUAL_PIXELS),g.attributes.height=new a.Property("height",a.MAX_VIRTUAL_PIXELS),d=new a.Element.g,d.attributes.transform=new a.Property("transform",this.attribute("gradientTransform").value),d.children=[g],g=new a.Element.svg,g.attributes.x=new a.Property("x",0),g.attributes.y=new a.Property("y",0),g.attributes.width=new a.Property("width",f.width),g.attributes.height=new a.Property("height", |
f.height),g.children=[d],d=document.createElement("canvas"),d.width=f.width,d.height=f.height,f=d.getContext("2d"),f.fillStyle=b,g.render(f),f.createPattern(d,"no-repeat")):b}};a.Element.GradientBase.prototype=new a.Element.ElementBase;a.Element.linearGradient=function(c){this.base=a.Element.GradientBase;this.base(c);this.attributesToInherit.push("x1");this.attributesToInherit.push("y1");this.attributesToInherit.push("x2");this.attributesToInherit.push("y2");this.getGradient=function(a,e){var c="objectBoundingBox"== |
this.gradientUnits()?e.getBoundingBox():null;this.attribute("x1").hasValue()||this.attribute("y1").hasValue()||this.attribute("x2").hasValue()||this.attribute("y2").hasValue()||(this.attribute("x1",!0).value=0,this.attribute("y1",!0).value=0,this.attribute("x2",!0).value=1,this.attribute("y2",!0).value=0);var k="objectBoundingBox"==this.gradientUnits()?c.x()+c.width()*this.attribute("x1").numValue():this.attribute("x1").toPixels("x"),f="objectBoundingBox"==this.gradientUnits()?c.y()+c.height()*this.attribute("y1").numValue(): |
this.attribute("y1").toPixels("y"),g="objectBoundingBox"==this.gradientUnits()?c.x()+c.width()*this.attribute("x2").numValue():this.attribute("x2").toPixels("x"),c="objectBoundingBox"==this.gradientUnits()?c.y()+c.height()*this.attribute("y2").numValue():this.attribute("y2").toPixels("y");return k==g&&f==c?null:a.createLinearGradient(k,f,g,c)}};a.Element.linearGradient.prototype=new a.Element.GradientBase;a.Element.radialGradient=function(c){this.base=a.Element.GradientBase;this.base(c);this.attributesToInherit.push("cx"); |
this.attributesToInherit.push("cy");this.attributesToInherit.push("r");this.attributesToInherit.push("fx");this.attributesToInherit.push("fy");this.getGradient=function(a,c){var d=c.getBoundingBox();this.attribute("cx").hasValue()||(this.attribute("cx",!0).value="50%");this.attribute("cy").hasValue()||(this.attribute("cy",!0).value="50%");this.attribute("r").hasValue()||(this.attribute("r",!0).value="50%");var k="objectBoundingBox"==this.gradientUnits()?d.x()+d.width()*this.attribute("cx").numValue(): |
this.attribute("cx").toPixels("x"),f="objectBoundingBox"==this.gradientUnits()?d.y()+d.height()*this.attribute("cy").numValue():this.attribute("cy").toPixels("y"),g=k,m=f;this.attribute("fx").hasValue()&&(g="objectBoundingBox"==this.gradientUnits()?d.x()+d.width()*this.attribute("fx").numValue():this.attribute("fx").toPixels("x"));this.attribute("fy").hasValue()&&(m="objectBoundingBox"==this.gradientUnits()?d.y()+d.height()*this.attribute("fy").numValue():this.attribute("fy").toPixels("y"));d="objectBoundingBox"== |
this.gradientUnits()?(d.width()+d.height())/2*this.attribute("r").numValue():this.attribute("r").toPixels();return a.createRadialGradient(g,m,0,k,f,d)}};a.Element.radialGradient.prototype=new a.Element.GradientBase;a.Element.stop=function(c){this.base=a.Element.ElementBase;this.base(c);this.offset=this.attribute("offset").numValue();0>this.offset&&(this.offset=0);1<this.offset&&(this.offset=1);c=this.style("stop-color",!0);""===c.value&&(c.value="#000");this.style("stop-opacity").hasValue()&&(c=c.addOpacity(this.style("stop-opacity"))); |
this.color=c.value};a.Element.stop.prototype=new a.Element.ElementBase;a.Element.AnimateBase=function(c){this.base=a.Element.ElementBase;this.base(c);a.Animations.push(this);this.duration=0;this.begin=this.attribute("begin").toMilliseconds();this.maxDuration=this.begin+this.attribute("dur").toMilliseconds();this.getProperty=function(){var a=this.attribute("attributeType").value,c=this.attribute("attributeName").value;return"CSS"==a?this.parent.style(c,!0):this.parent.attribute(c,!0)};this.initialValue= |
null;this.initialUnits="";this.removed=!1;this.calcValue=function(){return""};this.update=function(a){null==this.initialValue&&(this.initialValue=this.getProperty().value,this.initialUnits=this.getProperty().getUnits());if(this.duration>this.maxDuration){if("indefinite"==this.attribute("repeatCount").value||"indefinite"==this.attribute("repeatDur").value)this.duration=0;else if("freeze"==this.attribute("fill").valueOrDefault("remove")&&!this.frozen)this.frozen=!0,this.parent.animationFrozen=!0,this.parent.animationFrozenValue= |
this.getProperty().value;else if("remove"==this.attribute("fill").valueOrDefault("remove")&&!this.removed)return this.removed=!0,this.getProperty().value=this.parent.animationFrozen?this.parent.animationFrozenValue:this.initialValue,!0;return!1}this.duration+=a;a=!1;this.begin<this.duration&&(a=this.calcValue(),this.attribute("type").hasValue()&&(a=this.attribute("type").value+"("+a+")"),this.getProperty().value=a,a=!0);return a};this.from=this.attribute("from");this.to=this.attribute("to");this.values= |
this.attribute("values");this.values.hasValue()&&(this.values.value=this.values.value.split(";"));this.progress=function(){var b={progress:(this.duration-this.begin)/(this.maxDuration-this.begin)};if(this.values.hasValue()){var c=b.progress*(this.values.value.length-1),d=Math.floor(c),k=Math.ceil(c);b.from=new a.Property("from",parseFloat(this.values.value[d]));b.to=new a.Property("to",parseFloat(this.values.value[k]));b.progress=(c-d)/(k-d)}else b.from=this.from,b.to=this.to;return b}};a.Element.AnimateBase.prototype= |
new a.Element.ElementBase;a.Element.animate=function(c){this.base=a.Element.AnimateBase;this.base(c);this.calcValue=function(){var a=this.progress();return a.from.numValue()+(a.to.numValue()-a.from.numValue())*a.progress+this.initialUnits}};a.Element.animate.prototype=new a.Element.AnimateBase;a.Element.animateColor=function(c){this.base=a.Element.AnimateBase;this.base(c);this.calcValue=function(){var a=this.progress(),c=new x(a.from.value),d=new x(a.to.value);if(c.ok&&d.ok){var k=c.g+(d.g-c.g)*a.progress, |
f=c.b+(d.b-c.b)*a.progress;return"rgb("+parseInt(c.r+(d.r-c.r)*a.progress,10)+","+parseInt(k,10)+","+parseInt(f,10)+")"}return this.attribute("from").value}};a.Element.animateColor.prototype=new a.Element.AnimateBase;a.Element.animateTransform=function(c){this.base=a.Element.AnimateBase;this.base(c);this.calcValue=function(){for(var b=this.progress(),c=a.ToNumberArray(b.from.value),d=a.ToNumberArray(b.to.value),k="",f=0;f<c.length;f++)k+=c[f]+(d[f]-c[f])*b.progress+" ";return k}};a.Element.animateTransform.prototype= |
new a.Element.animate;a.Element.font=function(c){this.base=a.Element.ElementBase;this.base(c);this.horizAdvX=this.attribute("horiz-adv-x").numValue();this.isArabic=this.isRTL=!1;this.missingGlyph=this.fontFace=null;this.glyphs=[];for(c=0;c<this.children.length;c++){var b=this.children[c];"font-face"==b.type?(this.fontFace=b,b.style("font-family").hasValue()&&(a.Definitions[b.style("font-family").value]=this)):"missing-glyph"==b.type?this.missingGlyph=b:"glyph"==b.type&&(""!=b.arabicForm?(this.isArabic= |
this.isRTL=!0,"undefined"==typeof this.glyphs[b.unicode]&&(this.glyphs[b.unicode]=[]),this.glyphs[b.unicode][b.arabicForm]=b):this.glyphs[b.unicode]=b)}};a.Element.font.prototype=new a.Element.ElementBase;a.Element.fontface=function(c){this.base=a.Element.ElementBase;this.base(c);this.ascent=this.attribute("ascent").value;this.descent=this.attribute("descent").value;this.unitsPerEm=this.attribute("units-per-em").numValue()};a.Element.fontface.prototype=new a.Element.ElementBase;a.Element.missingglyph= |
function(c){this.base=a.Element.path;this.base(c);this.horizAdvX=0};a.Element.missingglyph.prototype=new a.Element.path;a.Element.glyph=function(c){this.base=a.Element.path;this.base(c);this.horizAdvX=this.attribute("horiz-adv-x").numValue();this.unicode=this.attribute("unicode").value;this.arabicForm=this.attribute("arabic-form").value};a.Element.glyph.prototype=new a.Element.path;a.Element.text=function(c){this.captureTextNodes=!0;this.base=a.Element.RenderedElementBase;this.base(c);this.baseSetContext= |
this.setContext;this.setContext=function(a){this.baseSetContext(a);var c=this.style("dominant-baseline").toTextBaseline();null==c&&(c=this.style("alignment-baseline").toTextBaseline());null!=c&&(a.textBaseline=c)};this.getBoundingBox=function(){var b=this.attribute("x").toPixels("x"),c=this.attribute("y").toPixels("y"),d=this.parent.style("font-size").numValueOrDefault(a.Font.Parse(a.ctx.font).fontSize);return new a.BoundingBox(b,c-d,b+Math.floor(2*d/3)*this.children[0].getText().length,c)};this.renderChildren= |
function(a){this.x=this.attribute("x").toPixels("x");this.y=this.attribute("y").toPixels("y");this.attribute("dx").hasValue()&&(this.x+=this.attribute("dx").toPixels("x"));this.attribute("dy").hasValue()&&(this.y+=this.attribute("dy").toPixels("y"));this.x+=this.getAnchorDelta(a,this,0);for(var c=0;c<this.children.length;c++)this.renderChild(a,this,c)};this.getAnchorDelta=function(a,c,d){var k=this.style("text-anchor").valueOrDefault("start");if("start"!=k){for(var f=0,g=d;g<c.children.length;g++){var m= |
c.children[g];if(g>d&&m.attribute("x").hasValue())break;f+=m.measureTextRecursive(a)}return-1*("end"==k?f:f/2)}return 0};this.renderChild=function(a,c,d){var k=c.children[d];k.attribute("x").hasValue()?(k.x=k.attribute("x").toPixels("x")+c.getAnchorDelta(a,c,d),k.attribute("dx").hasValue()&&(k.x+=k.attribute("dx").toPixels("x"))):(k.attribute("dx").hasValue()&&(c.x+=k.attribute("dx").toPixels("x")),k.x=c.x);c.x=k.x+k.measureText(a);k.attribute("y").hasValue()?(k.y=k.attribute("y").toPixels("y"),k.attribute("dy").hasValue()&& |
(k.y+=k.attribute("dy").toPixels("y"))):(k.attribute("dy").hasValue()&&(c.y+=k.attribute("dy").toPixels("y")),k.y=c.y);c.y=k.y;k.render(a);for(d=0;d<k.children.length;d++)c.renderChild(a,k,d)}};a.Element.text.prototype=new a.Element.RenderedElementBase;a.Element.TextElementBase=function(c){this.base=a.Element.RenderedElementBase;this.base(c);this.getGlyph=function(a,c,d){var k=c[d],f=null;if(a.isArabic){var g="isolated";(0==d||" "==c[d-1])&&d<c.length-2&&" "!=c[d+1]&&(g="terminal");0<d&&" "!=c[d- |
1]&&d<c.length-2&&" "!=c[d+1]&&(g="medial");0<d&&" "!=c[d-1]&&(d==c.length-1||" "==c[d+1])&&(g="initial");"undefined"!=typeof a.glyphs[k]&&(f=a.glyphs[k][g],null==f&&"glyph"==a.glyphs[k].type&&(f=a.glyphs[k]))}else f=a.glyphs[k];null==f&&(f=a.missingGlyph);return f};this.renderChildren=function(b){var c=this.parent.style("font-family").getDefinition();if(null!=c){var d=this.parent.style("font-size").numValueOrDefault(a.Font.Parse(a.ctx.font).fontSize),k=this.parent.style("font-style").valueOrDefault(a.Font.Parse(a.ctx.font).fontStyle), |
f=this.getText();c.isRTL&&(f=f.split("").reverse().join(""));for(var g=a.ToNumberArray(this.parent.attribute("dx").value),m=0;m<f.length;m++){var n=this.getGlyph(c,f,m),h=d/c.fontFace.unitsPerEm;b.translate(this.x,this.y);b.scale(h,-h);var l=b.lineWidth;b.lineWidth=b.lineWidth*c.fontFace.unitsPerEm/d;"italic"==k&&b.transform(1,0,.4,1,0,0);n.render(b);"italic"==k&&b.transform(1,0,-.4,1,0,0);b.lineWidth=l;b.scale(1/h,-1/h);b.translate(-this.x,-this.y);this.x+=d*(n.horizAdvX||c.horizAdvX)/c.fontFace.unitsPerEm; |
"undefined"==typeof g[m]||isNaN(g[m])||(this.x+=g[m])}}else""!=b.fillStyle&&b.fillText(a.compressSpaces(this.getText()),this.x,this.y),""!=b.strokeStyle&&b.strokeText(a.compressSpaces(this.getText()),this.x,this.y)};this.getText=function(){};this.measureTextRecursive=function(a){for(var c=this.measureText(a),d=0;d<this.children.length;d++)c+=this.children[d].measureTextRecursive(a);return c};this.measureText=function(b){var c=this.parent.style("font-family").getDefinition();if(null!=c){b=this.parent.style("font-size").numValueOrDefault(a.Font.Parse(a.ctx.font).fontSize); |
var d=0,k=this.getText();c.isRTL&&(k=k.split("").reverse().join(""));for(var f=a.ToNumberArray(this.parent.attribute("dx").value),g=0;g<k.length;g++){var m=this.getGlyph(c,k,g),d=d+(m.horizAdvX||c.horizAdvX)*b/c.fontFace.unitsPerEm;"undefined"==typeof f[g]||isNaN(f[g])||(d+=f[g])}return d}c=a.compressSpaces(this.getText());if(!b.measureText)return 10*c.length;b.save();this.setContext(b);c=b.measureText(c).width;b.restore();return c}};a.Element.TextElementBase.prototype=new a.Element.RenderedElementBase; |
a.Element.tspan=function(c){this.captureTextNodes=!0;this.base=a.Element.TextElementBase;this.base(c);this.text=a.compressSpaces(c.value||c.text||c.textContent||"");this.getText=function(){return 0<this.children.length?"":this.text}};a.Element.tspan.prototype=new a.Element.TextElementBase;a.Element.tref=function(c){this.base=a.Element.TextElementBase;this.base(c);this.getText=function(){var a=this.getHrefAttribute().getDefinition();if(null!=a)return a.children[0].getText()}};a.Element.tref.prototype= |
new a.Element.TextElementBase;a.Element.a=function(c){this.base=a.Element.TextElementBase;this.base(c);this.hasText=0<c.childNodes.length;for(var b=0;b<c.childNodes.length;b++)3!=c.childNodes[b].nodeType&&(this.hasText=!1);this.text=this.hasText?c.childNodes[0].value:"";this.getText=function(){return this.text};this.baseRenderChildren=this.renderChildren;this.renderChildren=function(b){if(this.hasText){this.baseRenderChildren(b);var c=new a.Property("fontSize",a.Font.Parse(a.ctx.font).fontSize);a.Mouse.checkBoundingBox(this, |
new a.BoundingBox(this.x,this.y-c.toPixels("y"),this.x+this.measureText(b),this.y))}else 0<this.children.length&&(c=new a.Element.g,c.children=this.children,c.parent=this,c.render(b))};this.onclick=function(){window.open(this.getHrefAttribute().value)};this.onmousemove=function(){a.ctx.canvas.style.cursor="pointer"}};a.Element.a.prototype=new a.Element.TextElementBase;a.Element.image=function(c){this.base=a.Element.RenderedElementBase;this.base(c);var b=this.getHrefAttribute().value;if(""!=b){var e= |
b.match(/\.svg$/);a.Images.push(this);this.loaded=!1;if(e)this.img=a.ajax(b),this.loaded=!0;else{this.img=document.createElement("img");1==a.opts.useCORS&&(this.img.crossOrigin="Anonymous");var d=this;this.img.onload=function(){d.loaded=!0};this.img.onerror=function(){a.log('ERROR: image "'+b+'" not found');d.loaded=!0};this.img.src=b}this.renderChildren=function(b){var c=this.attribute("x").toPixels("x"),d=this.attribute("y").toPixels("y"),m=this.attribute("width").toPixels("x"),n=this.attribute("height").toPixels("y"); |
0!=m&&0!=n&&(b.save(),e?b.drawSvg(this.img,c,d,m,n):(b.translate(c,d),a.AspectRatio(b,this.attribute("preserveAspectRatio").value,m,this.img.width,n,this.img.height,0,0),b.drawImage(this.img,0,0)),b.restore())};this.getBoundingBox=function(){var b=this.attribute("x").toPixels("x"),c=this.attribute("y").toPixels("y"),d=this.attribute("width").toPixels("x"),e=this.attribute("height").toPixels("y");return new a.BoundingBox(b,c,b+d,c+e)}}};a.Element.image.prototype=new a.Element.RenderedElementBase;a.Element.g= |
function(c){this.base=a.Element.RenderedElementBase;this.base(c);this.getBoundingBox=function(){for(var b=new a.BoundingBox,c=0;c<this.children.length;c++)b.addBoundingBox(this.children[c].getBoundingBox());return b}};a.Element.g.prototype=new a.Element.RenderedElementBase;a.Element.symbol=function(c){this.base=a.Element.RenderedElementBase;this.base(c);this.render=function(a){}};a.Element.symbol.prototype=new a.Element.RenderedElementBase;a.Element.style=function(c){this.base=a.Element.ElementBase; |
this.base(c);for(var b="",e=0;e<c.childNodes.length;e++)b+=c.childNodes[e].data;b=b.replace(/(\/\*([^*]|[\r\n]|(\*+([^*\/]|[\r\n])))*\*+\/)|(^[\s]*\/\/.*)/gm,"");b=a.compressSpaces(b);c=b.split("}");for(e=0;e<c.length;e++)if(""!=a.trim(c[e]))for(var d=c[e].split("{"),b=d[0].split(","),d=d[1].split(";"),k=0;k<b.length;k++){var f=a.trim(b[k]);if(""!=f){for(var g=a.Styles[f]||{},m=0;m<d.length;m++){var n=d[m].indexOf(":"),h=d[m].substr(0,n),n=d[m].substr(n+1,d[m].length-n);null!=h&&null!=n&&(g[a.trim(h)]= |
new a.Property(a.trim(h),a.trim(n)))}a.Styles[f]=g;a.StylesSpecificity[f]=A(f);if("@font-face"==f)for(f=g["font-family"].value.replace(/"/g,""),g=g.src.value.split(","),m=0;m<g.length;m++)if(0<g[m].indexOf('format("svg")'))for(h=g[m].indexOf("url"),n=g[m].indexOf(")",h),h=g[m].substr(h+5,n-h-6),h=a.parseXml(a.ajax(h)).getElementsByTagName("font"),n=0;n<h.length;n++){var l=a.CreateElement(h[n]);a.Definitions[f]=l}}}};a.Element.style.prototype=new a.Element.ElementBase;a.Element.use=function(c){this.base= |
a.Element.RenderedElementBase;this.base(c);this.baseSetContext=this.setContext;this.setContext=function(a){this.baseSetContext(a);this.attribute("x").hasValue()&&a.translate(this.attribute("x").toPixels("x"),0);this.attribute("y").hasValue()&&a.translate(0,this.attribute("y").toPixels("y"))};var b=this.getHrefAttribute().getDefinition();this.path=function(a){null!=b&&b.path(a)};this.getBoundingBox=function(){if(null!=b)return b.getBoundingBox()};this.renderChildren=function(c){if(null!=b){var d=b; |
"symbol"==b.type&&(d=new a.Element.svg,d.type="svg",d.attributes.viewBox=new a.Property("viewBox",b.attribute("viewBox").value),d.attributes.preserveAspectRatio=new a.Property("preserveAspectRatio",b.attribute("preserveAspectRatio").value),d.attributes.overflow=new a.Property("overflow",b.attribute("overflow").value),d.children=b.children);"svg"==d.type&&(this.attribute("width").hasValue()&&(d.attributes.width=new a.Property("width",this.attribute("width").value)),this.attribute("height").hasValue()&& |
(d.attributes.height=new a.Property("height",this.attribute("height").value)));var k=d.parent;d.parent=null;d.render(c);d.parent=k}}};a.Element.use.prototype=new a.Element.RenderedElementBase;a.Element.mask=function(c){this.base=a.Element.ElementBase;this.base(c);this.apply=function(b,c){var d=this.attribute("x").toPixels("x"),k=this.attribute("y").toPixels("y"),f=this.attribute("width").toPixels("x"),g=this.attribute("height").toPixels("y");if(0==f&&0==g){g=new a.BoundingBox;for(d=0;d<this.children.length;d++)g.addBoundingBox(this.children[d].getBoundingBox()); |
d=Math.floor(g.x1);k=Math.floor(g.y1);f=Math.floor(g.width());g=Math.floor(g.height())}var m=c.attribute("mask").value;c.attribute("mask").value="";var n=document.createElement("canvas");n.width=d+f;n.height=k+g;var h=n.getContext("2d");this.renderChildren(h);var l=document.createElement("canvas");l.width=d+f;l.height=k+g;var p=l.getContext("2d");c.render(p);p.globalCompositeOperation="destination-in";p.fillStyle=h.createPattern(n,"no-repeat");p.fillRect(0,0,d+f,k+g);b.fillStyle=p.createPattern(l, |
"no-repeat");b.fillRect(0,0,d+f,k+g);c.attribute("mask").value=m};this.render=function(a){}};a.Element.mask.prototype=new a.Element.ElementBase;a.Element.clipPath=function(c){this.base=a.Element.ElementBase;this.base(c);this.apply=function(b){var c=CanvasRenderingContext2D.prototype.beginPath;CanvasRenderingContext2D.prototype.beginPath=function(){};var d=CanvasRenderingContext2D.prototype.closePath;CanvasRenderingContext2D.prototype.closePath=function(){};c.call(b);for(var k=0;k<this.children.length;k++){var f= |
this.children[k];if("undefined"!=typeof f.path){var g=null;f.style("transform",!1,!0).hasValue()&&(g=new a.Transform(f.style("transform",!1,!0).value),g.apply(b));f.path(b);CanvasRenderingContext2D.prototype.closePath=d;g&&g.unapply(b)}}d.call(b);b.clip();CanvasRenderingContext2D.prototype.beginPath=c;CanvasRenderingContext2D.prototype.closePath=d};this.render=function(a){}};a.Element.clipPath.prototype=new a.Element.ElementBase;a.Element.filter=function(c){this.base=a.Element.ElementBase;this.base(c); |
this.apply=function(a,c){var d=c.getBoundingBox(),k=Math.floor(d.x1),f=Math.floor(d.y1),g=Math.floor(d.width()),d=Math.floor(d.height()),m=c.style("filter").value;c.style("filter").value="";for(var h=0,l=0,u=0;u<this.children.length;u++)var p=this.children[u].extraFilterDistance||0,h=Math.max(h,p),l=Math.max(l,p);p=document.createElement("canvas");p.width=g+2*h;p.height=d+2*l;var t=p.getContext("2d");t.translate(-k+h,-f+l);c.render(t);for(u=0;u<this.children.length;u++)"function"===typeof this.children[u].apply&& |
this.children[u].apply(t,0,0,g+2*h,d+2*l);a.drawImage(p,0,0,g+2*h,d+2*l,k-h,f-l,g+2*h,d+2*l);c.style("filter",!0).value=m};this.render=function(a){}};a.Element.filter.prototype=new a.Element.ElementBase;a.Element.feMorphology=function(c){this.base=a.Element.ElementBase;this.base(c);this.apply=function(a,c,d,k,f){}};a.Element.feMorphology.prototype=new a.Element.ElementBase;a.Element.feComposite=function(c){this.base=a.Element.ElementBase;this.base(c);this.apply=function(a,c,d,k,f){}};a.Element.feComposite.prototype= |
new a.Element.ElementBase;a.Element.feColorMatrix=function(c){function b(a,b){var c=e[a];return c*(0>c?b-255:b)}this.base=a.Element.ElementBase;this.base(c);var e=a.ToNumberArray(this.attribute("values").value);switch(this.attribute("type").valueOrDefault("matrix")){case "saturate":c=e[0];e=[.213+.787*c,.715-.715*c,.072-.072*c,0,0,.213-.213*c,.715+.285*c,.072-.072*c,0,0,.213-.213*c,.715-.715*c,.072+.928*c,0,0,0,0,0,1,0,0,0,0,0,1];break;case "hueRotate":var d=e[0]*Math.PI/180;c=function(a,b,c){return a+ |
Math.cos(d)*b+Math.sin(d)*c};e=[c(.213,.787,-.213),c(.715,-.715,-.715),c(.072,-.072,.928),0,0,c(.213,-.213,.143),c(.715,.285,.14),c(.072,-.072,-.283),0,0,c(.213,-.213,-.787),c(.715,-.715,.715),c(.072,.928,.072),0,0,0,0,0,1,0,0,0,0,0,1];break;case "luminanceToAlpha":e=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,.2125,.7154,.0721,0,0,0,0,0,0,1]}this.apply=function(a,c,d,e,h){var l=a.getImageData(0,0,e,h);for(d=0;d<h;d++)for(c=0;c<e;c++){var u=l.data[d*e*4+4*c+0],p=l.data[d*e*4+4*c+1],t=l.data[d*e*4+4*c+2],v=l.data[d* |
e*4+4*c+3],q=b(0,u)+b(1,p)+b(2,t)+b(3,v)+b(4,1);l.data[d*e*4+4*c+0]=q;q=b(5,u)+b(6,p)+b(7,t)+b(8,v)+b(9,1);l.data[d*e*4+4*c+1]=q;q=b(10,u)+b(11,p)+b(12,t)+b(13,v)+b(14,1);l.data[d*e*4+4*c+2]=q;u=b(15,u)+b(16,p)+b(17,t)+b(18,v)+b(19,1);l.data[d*e*4+4*c+3]=u}a.clearRect(0,0,e,h);a.putImageData(l,0,0)}};a.Element.feColorMatrix.prototype=new a.Element.ElementBase;a.Element.feGaussianBlur=function(c){this.base=a.Element.ElementBase;this.base(c);this.extraFilterDistance=this.blurRadius=Math.floor(this.attribute("stdDeviation").numValue()); |
this.apply=function(b,c,d,k,f){"undefined"==typeof y.canvasRGBA?a.log("ERROR: StackBlur.js must be included for blur to work"):(b.canvas.id=a.UniqueId(),b.canvas.style.display="none",document.body.appendChild(b.canvas),y.canvasRGBA(b.canvas.id,c,d,k,f,this.blurRadius),document.body.removeChild(b.canvas))}};a.Element.feGaussianBlur.prototype=new a.Element.ElementBase;a.Element.title=function(a){};a.Element.title.prototype=new a.Element.ElementBase;a.Element.desc=function(a){};a.Element.desc.prototype= |
new a.Element.ElementBase;a.Element.MISSING=function(c){a.log("ERROR: Element '"+c.nodeName+"' not yet implemented.")};a.Element.MISSING.prototype=new a.Element.ElementBase;a.CreateElement=function(c){var b=c.nodeName.replace(/^[^:]+:/,""),b=b.replace(/\-/g,""),b="undefined"!=typeof a.Element[b]?new a.Element[b](c):new a.Element.MISSING(c);b.type=c.nodeName;return b};a.load=function(c,b){a.loadXml(c,a.ajax(b))};a.loadXml=function(c,b){a.loadXmlDoc(c,a.parseXml(b))};a.loadXmlDoc=function(c,b){a.init(c); |
var e=function(a){for(var b=c.canvas;b;)a.x-=b.offsetLeft,a.y-=b.offsetTop,b=b.offsetParent;window.scrollX&&(a.x+=window.scrollX);window.scrollY&&(a.y+=window.scrollY);return a};1!=a.opts.ignoreMouse&&(c.canvas.onclick=function(b){b=e(new a.Point(null!=b?b.clientX:event.clientX,null!=b?b.clientY:event.clientY));a.Mouse.onclick(b.x,b.y)},c.canvas.onmousemove=function(b){b=e(new a.Point(null!=b?b.clientX:event.clientX,null!=b?b.clientY:event.clientY));a.Mouse.onmousemove(b.x,b.y)});var d=a.CreateElement(b.documentElement); |
d.root=!0;d.addStylesFromStyleDefinition();var k=!0,f=function(){a.ViewPort.Clear();c.canvas.parentNode&&a.ViewPort.SetCurrent(c.canvas.parentNode.clientWidth,c.canvas.parentNode.clientHeight);1!=a.opts.ignoreDimensions&&(d.style("width").hasValue()&&(c.canvas.width=d.style("width").toPixels("x"),c.canvas.style.width=c.canvas.width+"px"),d.style("height").hasValue()&&(c.canvas.height=d.style("height").toPixels("y"),c.canvas.style.height=c.canvas.height+"px"));var e=c.canvas.clientWidth||c.canvas.width, |
f=c.canvas.clientHeight||c.canvas.height;1==a.opts.ignoreDimensions&&d.style("width").hasValue()&&d.style("height").hasValue()&&(e=d.style("width").toPixels("x"),f=d.style("height").toPixels("y"));a.ViewPort.SetCurrent(e,f);null!=a.opts.offsetX&&(d.attribute("x",!0).value=a.opts.offsetX);null!=a.opts.offsetY&&(d.attribute("y",!0).value=a.opts.offsetY);if(null!=a.opts.scaleWidth||null!=a.opts.scaleHeight){var g=null,h=null,l=a.ToNumberArray(d.attribute("viewBox").value);null!=a.opts.scaleWidth&&(d.attribute("width").hasValue()? |
g=d.attribute("width").toPixels("x")/a.opts.scaleWidth:isNaN(l[2])||(g=l[2]/a.opts.scaleWidth));null!=a.opts.scaleHeight&&(d.attribute("height").hasValue()?h=d.attribute("height").toPixels("y")/a.opts.scaleHeight:isNaN(l[3])||(h=l[3]/a.opts.scaleHeight));null==g&&(g=h);null==h&&(h=g);d.attribute("width",!0).value=a.opts.scaleWidth;d.attribute("height",!0).value=a.opts.scaleHeight;d.style("transform",!0,!0).value+=" scale("+1/g+","+1/h+")"}1!=a.opts.ignoreClear&&c.clearRect(0,0,e,f);d.render(c);k&& |
(k=!1,"function"==typeof a.opts.renderCallback&&a.opts.renderCallback(b))},g=!0;a.ImagesLoaded()&&(g=!1,f());a.intervalID=setInterval(function(){var b=!1;g&&a.ImagesLoaded()&&(g=!1,b=!0);1!=a.opts.ignoreMouse&&(b|=a.Mouse.hasEvents());if(1!=a.opts.ignoreAnimation)for(var c=0;c<a.Animations.length;c++)b|=a.Animations[c].update(1E3/a.FRAMERATE);"function"==typeof a.opts.forceRedraw&&1==a.opts.forceRedraw()&&(b=!0);b&&(f(),a.Mouse.runEvents())},1E3/a.FRAMERATE)};a.stop=function(){a.intervalID&&clearInterval(a.intervalID)}; |
a.Mouse=new function(){this.events=[];this.hasEvents=function(){return 0!=this.events.length};this.onclick=function(a,b){this.events.push({type:"onclick",x:a,y:b,run:function(a){if(a.onclick)a.onclick()}})};this.onmousemove=function(a,b){this.events.push({type:"onmousemove",x:a,y:b,run:function(a){if(a.onmousemove)a.onmousemove()}})};this.eventElements=[];this.checkPath=function(a,b){for(var e=0;e<this.events.length;e++){var d=this.events[e];b.isPointInPath&&b.isPointInPath(d.x,d.y)&&(this.eventElements[e]= |
a)}};this.checkBoundingBox=function(a,b){for(var e=0;e<this.events.length;e++){var d=this.events[e];b.isPointInBox(d.x,d.y)&&(this.eventElements[e]=a)}};this.runEvents=function(){a.ctx.canvas.style.cursor="";for(var c=0;c<this.events.length;c++)for(var b=this.events[c],e=this.eventElements[c];e;)b.run(e),e=e.parent;this.events=[];this.eventElements=[]}};return a}var z=function(h,a,l){if(null==h&&null==a&&null==l)for(a=document.querySelectorAll("svg"),h=0;h<a.length;h++){l=a[h];var c=document.createElement("canvas"); |
c.width=l.clientWidth;c.height=l.clientHeight;l.parentNode.insertBefore(c,l);l.parentNode.removeChild(l);var b=document.createElement("div");b.appendChild(l);z(c,b.innerHTML)}else{"string"==typeof h&&(h=document.getElementById(h));null!=h.svg&&h.svg.stop();l=I(l||{});if(1!=h.childNodes.length||"OBJECT"!=h.childNodes[0].nodeName)h.svg=l;h=h.getContext("2d");"undefined"!=typeof a.documentElement?l.loadXmlDoc(h,a):"<"==a.substr(0,1)?l.loadXml(h,a):l.load(h,a)}},w;if("undefined"!=typeof Element.prototype.matches)w= |
function(h,a){return h.matches(a)};else if("undefined"!=typeof Element.prototype.webkitMatchesSelector)w=function(h,a){return h.webkitMatchesSelector(a)};else if("undefined"!=typeof Element.prototype.mozMatchesSelector)w=function(h,a){return h.mozMatchesSelector(a)};else if("undefined"!=typeof Element.prototype.msMatchesSelector)w=function(h,a){return h.msMatchesSelector(a)};else if("undefined"!=typeof Element.prototype.oMatchesSelector)w=function(h,a){return h.oMatchesSelector(a)};else{if("function"=== |
typeof jQuery||"function"===typeof Zepto)w=function(h,a){return $(h).is(a)};"undefined"===typeof w&&(w=Sizzle.matchesSelector)}var B=/(\[[^\]]+\])/g,C=/(#[^\s\+>~\.\[:]+)/g,D=/(\.[^\s\+>~\.\[:]+)/g,E=/(::[^\s\+>~\.\[:]+|:first-line|:first-letter|:before|:after)/gi,F=/(:[\w-]+\([^\)]*\))/gi,G=/(:[^\s\+>~\.\[:]+)/g,H=/([^\s\+>~\.\[:]+)/g;"undefined"!=typeof CanvasRenderingContext2D&&(CanvasRenderingContext2D.prototype.drawSvg=function(h,a,l,c,b){z(this.canvas,h,{ignoreMouse:!0,ignoreAnimation:!0,ignoreDimensions:!0, |
ignoreClear:!0,offsetX:a,offsetY:l,scaleWidth:c,scaleHeight:b})});return z}); |
/base/000_base/node_modules/highcharts/lib/canvg.src.js |
@@ -0,0 +1,3073 @@ |
/** @preserve |
* canvg.js - Javascript SVG parser and renderer on Canvas |
* MIT Licensed |
* Gabe Lerner (gabelerner@gmail.com) |
* http://code.google.com/p/canvg/ |
* |
* Requires: rgbcolor.js - http://www.phpied.com/rgb-color-parser-in-javascript/ |
*/ |
(function ( global, factory ) { |
|
'use strict'; |
|
// export as AMD... |
if ( typeof define !== 'undefined' && define.amd ) { |
define('canvgModule', [ 'rgbcolor', 'stackblur' ], factory ); |
} |
|
// ...or as browserify |
else if ( typeof module !== 'undefined' && module.exports ) { |
module.exports = factory( require( 'rgbcolor' ), require( 'stackblur' ) ); |
} |
|
global.canvg = factory( global.RGBColor, global.stackBlur ); |
|
}( typeof window !== 'undefined' ? window : this, function ( RGBColor, stackBlur ) { |
|
// canvg(target, s) |
// empty parameters: replace all 'svg' elements on page with 'canvas' elements |
// target: canvas element or the id of a canvas element |
// s: svg string, url to svg file, or xml document |
// opts: optional hash of options |
// ignoreMouse: true => ignore mouse events |
// ignoreAnimation: true => ignore animations |
// ignoreDimensions: true => does not try to resize canvas |
// ignoreClear: true => does not clear canvas |
// offsetX: int => draws at a x offset |
// offsetY: int => draws at a y offset |
// scaleWidth: int => scales horizontally to width |
// scaleHeight: int => scales vertically to height |
// renderCallback: function => will call the function after the first render is completed |
// forceRedraw: function => will call the function on every frame, if it returns true, will redraw |
var canvg = function (target, s, opts) { |
// no parameters |
if (target == null && s == null && opts == null) { |
var svgTags = document.querySelectorAll('svg'); |
for (var i=0; i<svgTags.length; i++) { |
var svgTag = svgTags[i]; |
var c = document.createElement('canvas'); |
c.width = svgTag.clientWidth; |
c.height = svgTag.clientHeight; |
svgTag.parentNode.insertBefore(c, svgTag); |
svgTag.parentNode.removeChild(svgTag); |
var div = document.createElement('div'); |
div.appendChild(svgTag); |
canvg(c, div.innerHTML); |
} |
return; |
} |
|
if (typeof target == 'string') { |
target = document.getElementById(target); |
} |
|
// store class on canvas |
if (target.svg != null) target.svg.stop(); |
var svg = build(opts || {}); |
// on i.e. 8 for flash canvas, we can't assign the property so check for it |
if (!(target.childNodes.length == 1 && target.childNodes[0].nodeName == 'OBJECT')) target.svg = svg; |
|
var ctx = target.getContext('2d'); |
if (typeof(s.documentElement) != 'undefined') { |
// load from xml doc |
svg.loadXmlDoc(ctx, s); |
} |
else if (s.substr(0,1) == '<') { |
// load from xml string |
svg.loadXml(ctx, s); |
} |
else { |
// load from url |
svg.load(ctx, s); |
} |
} |
|
// see https://developer.mozilla.org/en-US/docs/Web/API/Element.matches |
var matchesSelector; |
if (typeof(Element.prototype.matches) != 'undefined') { |
matchesSelector = function(node, selector) { |
return node.matches(selector); |
}; |
} else if (typeof(Element.prototype.webkitMatchesSelector) != 'undefined') { |
matchesSelector = function(node, selector) { |
return node.webkitMatchesSelector(selector); |
}; |
} else if (typeof(Element.prototype.mozMatchesSelector) != 'undefined') { |
matchesSelector = function(node, selector) { |
return node.mozMatchesSelector(selector); |
}; |
} else if (typeof(Element.prototype.msMatchesSelector) != 'undefined') { |
matchesSelector = function(node, selector) { |
return node.msMatchesSelector(selector); |
}; |
} else if (typeof(Element.prototype.oMatchesSelector) != 'undefined') { |
matchesSelector = function(node, selector) { |
return node.oMatchesSelector(selector); |
}; |
} else { |
// requires Sizzle: https://github.com/jquery/sizzle/wiki/Sizzle-Documentation |
// or jQuery: http://jquery.com/download/ |
// or Zepto: http://zeptojs.com/# |
// without it, this is a ReferenceError |
|
if (typeof jQuery === 'function' || typeof Zepto === 'function') { |
matchesSelector = function (node, selector) { |
return $(node).is(selector); |
}; |
} |
|
if (typeof matchesSelector === 'undefined') { |
matchesSelector = Sizzle.matchesSelector; |
} |
} |
|
// slightly modified version of https://github.com/keeganstreet/specificity/blob/master/specificity.js |
var attributeRegex = /(\[[^\]]+\])/g; |
var idRegex = /(#[^\s\+>~\.\[:]+)/g; |
var classRegex = /(\.[^\s\+>~\.\[:]+)/g; |
var pseudoElementRegex = /(::[^\s\+>~\.\[:]+|:first-line|:first-letter|:before|:after)/gi; |
var pseudoClassWithBracketsRegex = /(:[\w-]+\([^\)]*\))/gi; |
var pseudoClassRegex = /(:[^\s\+>~\.\[:]+)/g; |
var elementRegex = /([^\s\+>~\.\[:]+)/g; |
function getSelectorSpecificity(selector) { |
var typeCount = [0, 0, 0]; |
var findMatch = function(regex, type) { |
var matches = selector.match(regex); |
if (matches == null) { |
return; |
} |
typeCount[type] += matches.length; |
selector = selector.replace(regex, ' '); |
}; |
|
selector = selector.replace(/:not\(([^\)]*)\)/g, ' $1 '); |
selector = selector.replace(/{[^]*/gm, ' '); |
findMatch(attributeRegex, 1); |
findMatch(idRegex, 0); |
findMatch(classRegex, 1); |
findMatch(pseudoElementRegex, 2); |
findMatch(pseudoClassWithBracketsRegex, 1); |
findMatch(pseudoClassRegex, 1); |
selector = selector.replace(/[\*\s\+>~]/g, ' '); |
selector = selector.replace(/[#\.]/g, ' '); |
findMatch(elementRegex, 2); |
return typeCount.join(''); |
} |
|
function build(opts) { |
var svg = { opts: opts }; |
|
svg.FRAMERATE = 30; |
svg.MAX_VIRTUAL_PIXELS = 30000; |
|
svg.log = function(msg) {}; |
if (svg.opts['log'] == true && typeof(console) != 'undefined') { |
svg.log = function(msg) { console.log(msg); }; |
}; |
|
// globals |
svg.init = function(ctx) { |
var uniqueId = 0; |
svg.UniqueId = function () { uniqueId++; return 'canvg' + uniqueId; }; |
svg.Definitions = {}; |
svg.Styles = {}; |
svg.StylesSpecificity = {}; |
svg.Animations = []; |
svg.Images = []; |
svg.ctx = ctx; |
svg.ViewPort = new (function () { |
this.viewPorts = []; |
this.Clear = function() { this.viewPorts = []; } |
this.SetCurrent = function(width, height) { this.viewPorts.push({ width: width, height: height }); } |
this.RemoveCurrent = function() { this.viewPorts.pop(); } |
this.Current = function() { return this.viewPorts[this.viewPorts.length - 1]; } |
this.width = function() { return this.Current().width; } |
this.height = function() { return this.Current().height; } |
this.ComputeSize = function(d) { |
if (d != null && typeof(d) == 'number') return d; |
if (d == 'x') return this.width(); |
if (d == 'y') return this.height(); |
return Math.sqrt(Math.pow(this.width(), 2) + Math.pow(this.height(), 2)) / Math.sqrt(2); |
} |
}); |
} |
svg.init(); |
|
// images loaded |
svg.ImagesLoaded = function() { |
for (var i=0; i<svg.Images.length; i++) { |
if (!svg.Images[i].loaded) return false; |
} |
return true; |
} |
|
// trim |
svg.trim = function(s) { return s.replace(/^\s+|\s+$/g, ''); } |
|
// compress spaces |
svg.compressSpaces = function(s) { return s.replace(/[\s\r\t\n]+/gm,' '); } |
|
// ajax |
svg.ajax = function(url) { |
var AJAX; |
if(window.XMLHttpRequest){AJAX=new XMLHttpRequest();} |
else{AJAX=new ActiveXObject('Microsoft.XMLHTTP');} |
if(AJAX){ |
AJAX.open('GET',url,false); |
AJAX.send(null); |
return AJAX.responseText; |
} |
return null; |
} |
|
// parse xml |
svg.parseXml = function(xml) { |
if (typeof(Windows) != 'undefined' && typeof(Windows.Data) != 'undefined' && typeof(Windows.Data.Xml) != 'undefined') { |
var xmlDoc = new Windows.Data.Xml.Dom.XmlDocument(); |
var settings = new Windows.Data.Xml.Dom.XmlLoadSettings(); |
settings.prohibitDtd = false; |
xmlDoc.loadXml(xml, settings); |
return xmlDoc; |
} |
else if (window.DOMParser) |
{ |
var parser = new DOMParser(); |
return parser.parseFromString(xml, 'text/xml'); |
} |
else |
{ |
xml = xml.replace(/<!DOCTYPE svg[^>]*>/, ''); |
var xmlDoc = new ActiveXObject('Microsoft.XMLDOM'); |
xmlDoc.async = 'false'; |
xmlDoc.loadXML(xml); |
return xmlDoc; |
} |
} |
|
svg.Property = function(name, value) { |
this.name = name; |
this.value = value; |
} |
svg.Property.prototype.getValue = function() { |
return this.value; |
} |
|
svg.Property.prototype.hasValue = function() { |
return (this.value != null && this.value !== ''); |
} |
|
// return the numerical value of the property |
svg.Property.prototype.numValue = function() { |
if (!this.hasValue()) return 0; |
|
var n = parseFloat(this.value); |
if ((this.value + '').match(/%$/)) { |
n = n / 100.0; |
} |
return n; |
} |
|
svg.Property.prototype.valueOrDefault = function(def) { |
if (this.hasValue()) return this.value; |
return def; |
} |
|
svg.Property.prototype.numValueOrDefault = function(def) { |
if (this.hasValue()) return this.numValue(); |
return def; |
} |
|
// color extensions |
// augment the current color value with the opacity |
svg.Property.prototype.addOpacity = function(opacityProp) { |
var newValue = this.value; |
if (opacityProp.value != null && opacityProp.value != '' && typeof(this.value)=='string') { // can only add opacity to colors, not patterns |
var color = new RGBColor(this.value); |
if (color.ok) { |
newValue = 'rgba(' + color.r + ', ' + color.g + ', ' + color.b + ', ' + opacityProp.numValue() + ')'; |
} |
} |
return new svg.Property(this.name, newValue); |
} |
|
// definition extensions |
// get the definition from the definitions table |
svg.Property.prototype.getDefinition = function() { |
var name = this.value.match(/#([^\)'"]+)/); |
if (name) { name = name[1]; } |
if (!name) { name = this.value; } |
return svg.Definitions[name]; |
} |
|
svg.Property.prototype.isUrlDefinition = function() { |
return this.value.indexOf('url(') == 0 |
} |
|
svg.Property.prototype.getFillStyleDefinition = function(e, opacityProp) { |
var def = this.getDefinition(); |
|
// gradient |
if (def != null && def.createGradient) { |
return def.createGradient(svg.ctx, e, opacityProp); |
} |
|
// pattern |
if (def != null && def.createPattern) { |
if (def.getHrefAttribute().hasValue()) { |
var pt = def.attribute('patternTransform'); |
def = def.getHrefAttribute().getDefinition(); |
if (pt.hasValue()) { def.attribute('patternTransform', true).value = pt.value; } |
} |
return def.createPattern(svg.ctx, e); |
} |
|
return null; |
} |
|
// length extensions |
svg.Property.prototype.getDPI = function(viewPort) { |
return 96.0; // TODO: compute? |
} |
|
svg.Property.prototype.getEM = function(viewPort) { |
var em = 12; |
|
var fontSize = new svg.Property('fontSize', svg.Font.Parse(svg.ctx.font).fontSize); |
if (fontSize.hasValue()) em = fontSize.toPixels(viewPort); |
|
return em; |
} |
|
svg.Property.prototype.getUnits = function() { |
var s = this.value+''; |
return s.replace(/[0-9\.\-]/g,''); |
} |
|
// get the length as pixels |
svg.Property.prototype.toPixels = function(viewPort, processPercent) { |
if (!this.hasValue()) return 0; |
var s = this.value+''; |
if (s.match(/em$/)) return this.numValue() * this.getEM(viewPort); |
if (s.match(/ex$/)) return this.numValue() * this.getEM(viewPort) / 2.0; |
if (s.match(/px$/)) return this.numValue(); |
if (s.match(/pt$/)) return this.numValue() * this.getDPI(viewPort) * (1.0 / 72.0); |
if (s.match(/pc$/)) return this.numValue() * 15; |
if (s.match(/cm$/)) return this.numValue() * this.getDPI(viewPort) / 2.54; |
if (s.match(/mm$/)) return this.numValue() * this.getDPI(viewPort) / 25.4; |
if (s.match(/in$/)) return this.numValue() * this.getDPI(viewPort); |
if (s.match(/%$/)) return this.numValue() * svg.ViewPort.ComputeSize(viewPort); |
var n = this.numValue(); |
if (processPercent && n < 1.0) return n * svg.ViewPort.ComputeSize(viewPort); |
return n; |
} |
|
// time extensions |
// get the time as milliseconds |
svg.Property.prototype.toMilliseconds = function() { |
if (!this.hasValue()) return 0; |
var s = this.value+''; |
if (s.match(/s$/)) return this.numValue() * 1000; |
if (s.match(/ms$/)) return this.numValue(); |
return this.numValue(); |
} |
|
// angle extensions |
// get the angle as radians |
svg.Property.prototype.toRadians = function() { |
if (!this.hasValue()) return 0; |
var s = this.value+''; |
if (s.match(/deg$/)) return this.numValue() * (Math.PI / 180.0); |
if (s.match(/grad$/)) return this.numValue() * (Math.PI / 200.0); |
if (s.match(/rad$/)) return this.numValue(); |
return this.numValue() * (Math.PI / 180.0); |
} |
|
// text extensions |
// get the text baseline |
var textBaselineMapping = { |
'baseline': 'alphabetic', |
'before-edge': 'top', |
'text-before-edge': 'top', |
'middle': 'middle', |
'central': 'middle', |
'after-edge': 'bottom', |
'text-after-edge': 'bottom', |
'ideographic': 'ideographic', |
'alphabetic': 'alphabetic', |
'hanging': 'hanging', |
'mathematical': 'alphabetic' |
}; |
svg.Property.prototype.toTextBaseline = function () { |
if (!this.hasValue()) return null; |
return textBaselineMapping[this.value]; |
} |
|
// fonts |
svg.Font = new (function() { |
this.Styles = 'normal|italic|oblique|inherit'; |
this.Variants = 'normal|small-caps|inherit'; |
this.Weights = 'normal|bold|bolder|lighter|100|200|300|400|500|600|700|800|900|inherit'; |
|
this.CreateFont = function(fontStyle, fontVariant, fontWeight, fontSize, fontFamily, inherit) { |
var f = inherit != null ? this.Parse(inherit) : this.CreateFont('', '', '', '', '', svg.ctx.font); |
return { |
fontFamily: fontFamily || f.fontFamily, |
fontSize: fontSize || f.fontSize, |
fontStyle: fontStyle || f.fontStyle, |
fontWeight: fontWeight || f.fontWeight, |
fontVariant: fontVariant || f.fontVariant, |
toString: function () { return [this.fontStyle, this.fontVariant, this.fontWeight, this.fontSize, this.fontFamily].join(' ') } |
} |
} |
|
var that = this; |
this.Parse = function(s) { |
var f = {}; |
var d = svg.trim(svg.compressSpaces(s || '')).split(' '); |
var set = { fontSize: false, fontStyle: false, fontWeight: false, fontVariant: false } |
var ff = ''; |
for (var i=0; i<d.length; i++) { |
if (!set.fontStyle && that.Styles.indexOf(d[i]) != -1) { if (d[i] != 'inherit') f.fontStyle = d[i]; set.fontStyle = true; } |
else if (!set.fontVariant && that.Variants.indexOf(d[i]) != -1) { if (d[i] != 'inherit') f.fontVariant = d[i]; set.fontStyle = set.fontVariant = true; } |
else if (!set.fontWeight && that.Weights.indexOf(d[i]) != -1) { if (d[i] != 'inherit') f.fontWeight = d[i]; set.fontStyle = set.fontVariant = set.fontWeight = true; } |
else if (!set.fontSize) { if (d[i] != 'inherit') f.fontSize = d[i].split('/')[0]; set.fontStyle = set.fontVariant = set.fontWeight = set.fontSize = true; } |
else { if (d[i] != 'inherit') ff += d[i]; } |
} if (ff != '') f.fontFamily = ff; |
return f; |
} |
}); |
|
// points and paths |
svg.ToNumberArray = function(s) { |
var a = svg.trim(svg.compressSpaces((s || '').replace(/,/g, ' '))).split(' '); |
for (var i=0; i<a.length; i++) { |
a[i] = parseFloat(a[i]); |
} |
return a; |
} |
svg.Point = function(x, y) { |
this.x = x; |
this.y = y; |
} |
svg.Point.prototype.angleTo = function(p) { |
return Math.atan2(p.y - this.y, p.x - this.x); |
} |
|
svg.Point.prototype.applyTransform = function(v) { |
var xp = this.x * v[0] + this.y * v[2] + v[4]; |
var yp = this.x * v[1] + this.y * v[3] + v[5]; |
this.x = xp; |
this.y = yp; |
} |
|
svg.CreatePoint = function(s) { |
var a = svg.ToNumberArray(s); |
return new svg.Point(a[0], a[1]); |
} |
svg.CreatePath = function(s) { |
var a = svg.ToNumberArray(s); |
var path = []; |
for (var i=0; i<a.length; i+=2) { |
path.push(new svg.Point(a[i], a[i+1])); |
} |
return path; |
} |
|
// bounding box |
svg.BoundingBox = function(x1, y1, x2, y2) { // pass in initial points if you want |
this.x1 = Number.NaN; |
this.y1 = Number.NaN; |
this.x2 = Number.NaN; |
this.y2 = Number.NaN; |
|
this.x = function() { return this.x1; } |
this.y = function() { return this.y1; } |
this.width = function() { return this.x2 - this.x1; } |
this.height = function() { return this.y2 - this.y1; } |
|
this.addPoint = function(x, y) { |
if (x != null) { |
if (isNaN(this.x1) || isNaN(this.x2)) { |
this.x1 = x; |
this.x2 = x; |
} |
if (x < this.x1) this.x1 = x; |
if (x > this.x2) this.x2 = x; |
} |
|
if (y != null) { |
if (isNaN(this.y1) || isNaN(this.y2)) { |
this.y1 = y; |
this.y2 = y; |
} |
if (y < this.y1) this.y1 = y; |
if (y > this.y2) this.y2 = y; |
} |
} |
this.addX = function(x) { this.addPoint(x, null); } |
this.addY = function(y) { this.addPoint(null, y); } |
|
this.addBoundingBox = function(bb) { |
this.addPoint(bb.x1, bb.y1); |
this.addPoint(bb.x2, bb.y2); |
} |
|
this.addQuadraticCurve = function(p0x, p0y, p1x, p1y, p2x, p2y) { |
var cp1x = p0x + 2/3 * (p1x - p0x); // CP1 = QP0 + 2/3 *(QP1-QP0) |
var cp1y = p0y + 2/3 * (p1y - p0y); // CP1 = QP0 + 2/3 *(QP1-QP0) |
var cp2x = cp1x + 1/3 * (p2x - p0x); // CP2 = CP1 + 1/3 *(QP2-QP0) |
var cp2y = cp1y + 1/3 * (p2y - p0y); // CP2 = CP1 + 1/3 *(QP2-QP0) |
this.addBezierCurve(p0x, p0y, cp1x, cp2x, cp1y, cp2y, p2x, p2y); |
} |
|
this.addBezierCurve = function(p0x, p0y, p1x, p1y, p2x, p2y, p3x, p3y) { |
// from http://blog.hackers-cafe.net/2009/06/how-to-calculate-bezier-curves-bounding.html |
var p0 = [p0x, p0y], p1 = [p1x, p1y], p2 = [p2x, p2y], p3 = [p3x, p3y]; |
this.addPoint(p0[0], p0[1]); |
this.addPoint(p3[0], p3[1]); |
|
for (i=0; i<=1; i++) { |
var f = function(t) { |
return Math.pow(1-t, 3) * p0[i] |
+ 3 * Math.pow(1-t, 2) * t * p1[i] |
+ 3 * (1-t) * Math.pow(t, 2) * p2[i] |
+ Math.pow(t, 3) * p3[i]; |
} |
|
var b = 6 * p0[i] - 12 * p1[i] + 6 * p2[i]; |
var a = -3 * p0[i] + 9 * p1[i] - 9 * p2[i] + 3 * p3[i]; |
var c = 3 * p1[i] - 3 * p0[i]; |
|
if (a == 0) { |
if (b == 0) continue; |
var t = -c / b; |
if (0 < t && t < 1) { |
if (i == 0) this.addX(f(t)); |
if (i == 1) this.addY(f(t)); |
} |
continue; |
} |
|
var b2ac = Math.pow(b, 2) - 4 * c * a; |
if (b2ac < 0) continue; |
var t1 = (-b + Math.sqrt(b2ac)) / (2 * a); |
if (0 < t1 && t1 < 1) { |
if (i == 0) this.addX(f(t1)); |
if (i == 1) this.addY(f(t1)); |
} |
var t2 = (-b - Math.sqrt(b2ac)) / (2 * a); |
if (0 < t2 && t2 < 1) { |
if (i == 0) this.addX(f(t2)); |
if (i == 1) this.addY(f(t2)); |
} |
} |
} |
|
this.isPointInBox = function(x, y) { |
return (this.x1 <= x && x <= this.x2 && this.y1 <= y && y <= this.y2); |
} |
|
this.addPoint(x1, y1); |
this.addPoint(x2, y2); |
} |
|
// transforms |
svg.Transform = function(v) { |
var that = this; |
this.Type = {} |
|
// translate |
this.Type.translate = function(s) { |
this.p = svg.CreatePoint(s); |
this.apply = function(ctx) { |
ctx.translate(this.p.x || 0.0, this.p.y || 0.0); |
} |
this.unapply = function(ctx) { |
ctx.translate(-1.0 * this.p.x || 0.0, -1.0 * this.p.y || 0.0); |
} |
this.applyToPoint = function(p) { |
p.applyTransform([1, 0, 0, 1, this.p.x || 0.0, this.p.y || 0.0]); |
} |
} |
|
// rotate |
this.Type.rotate = function(s) { |
var a = svg.ToNumberArray(s); |
this.angle = new svg.Property('angle', a[0]); |
this.cx = a[1] || 0; |
this.cy = a[2] || 0; |
this.apply = function(ctx) { |
ctx.translate(this.cx, this.cy); |
ctx.rotate(this.angle.toRadians()); |
ctx.translate(-this.cx, -this.cy); |
} |
this.unapply = function(ctx) { |
ctx.translate(this.cx, this.cy); |
ctx.rotate(-1.0 * this.angle.toRadians()); |
ctx.translate(-this.cx, -this.cy); |
} |
this.applyToPoint = function(p) { |
var a = this.angle.toRadians(); |
p.applyTransform([1, 0, 0, 1, this.p.x || 0.0, this.p.y || 0.0]); |
p.applyTransform([Math.cos(a), Math.sin(a), -Math.sin(a), Math.cos(a), 0, 0]); |
p.applyTransform([1, 0, 0, 1, -this.p.x || 0.0, -this.p.y || 0.0]); |
} |
} |
|
this.Type.scale = function(s) { |
this.p = svg.CreatePoint(s); |
this.apply = function(ctx) { |
ctx.scale(this.p.x || 1.0, this.p.y || this.p.x || 1.0); |
} |
this.unapply = function(ctx) { |
ctx.scale(1.0 / this.p.x || 1.0, 1.0 / this.p.y || this.p.x || 1.0); |
} |
this.applyToPoint = function(p) { |
p.applyTransform([this.p.x || 0.0, 0, 0, this.p.y || 0.0, 0, 0]); |
} |
} |
|
this.Type.matrix = function(s) { |
this.m = svg.ToNumberArray(s); |
this.apply = function(ctx) { |
ctx.transform(this.m[0], this.m[1], this.m[2], this.m[3], this.m[4], this.m[5]); |
} |
this.unapply = function(ctx) { |
var a = this.m[0]; |
var b = this.m[2]; |
var c = this.m[4]; |
var d = this.m[1]; |
var e = this.m[3]; |
var f = this.m[5]; |
var g = 0.0; |
var h = 0.0; |
var i = 1.0; |
var det = 1 / (a*(e*i-f*h)-b*(d*i-f*g)+c*(d*h-e*g)); |
ctx.transform( |
det*(e*i-f*h), |
det*(f*g-d*i), |
det*(c*h-b*i), |
det*(a*i-c*g), |
det*(b*f-c*e), |
det*(c*d-a*f) |
); |
} |
this.applyToPoint = function(p) { |
p.applyTransform(this.m); |
} |
} |
|
this.Type.SkewBase = function(s) { |
this.base = that.Type.matrix; |
this.base(s); |
this.angle = new svg.Property('angle', s); |
} |
this.Type.SkewBase.prototype = new this.Type.matrix; |
|
this.Type.skewX = function(s) { |
this.base = that.Type.SkewBase; |
this.base(s); |
this.m = [1, 0, Math.tan(this.angle.toRadians()), 1, 0, 0]; |
} |
this.Type.skewX.prototype = new this.Type.SkewBase; |
|
this.Type.skewY = function(s) { |
this.base = that.Type.SkewBase; |
this.base(s); |
this.m = [1, Math.tan(this.angle.toRadians()), 0, 1, 0, 0]; |
} |
this.Type.skewY.prototype = new this.Type.SkewBase; |
|
this.transforms = []; |
|
this.apply = function(ctx) { |
for (var i=0; i<this.transforms.length; i++) { |
this.transforms[i].apply(ctx); |
} |
} |
|
this.unapply = function(ctx) { |
for (var i=this.transforms.length-1; i>=0; i--) { |
this.transforms[i].unapply(ctx); |
} |
} |
|
this.applyToPoint = function(p) { |
for (var i=0; i<this.transforms.length; i++) { |
this.transforms[i].applyToPoint(p); |
} |
} |
|
var data = svg.trim(svg.compressSpaces(v)).replace(/\)([a-zA-Z])/g, ') $1').replace(/\)(\s?,\s?)/g,') ').split(/\s(?=[a-z])/); |
for (var i=0; i<data.length; i++) { |
var type = svg.trim(data[i].split('(')[0]); |
var s = data[i].split('(')[1].replace(')',''); |
var transform = new this.Type[type](s); |
transform.type = type; |
this.transforms.push(transform); |
} |
} |
|
// aspect ratio |
svg.AspectRatio = function(ctx, aspectRatio, width, desiredWidth, height, desiredHeight, minX, minY, refX, refY) { |
// aspect ratio - http://www.w3.org/TR/SVG/coords.html#PreserveAspectRatioAttribute |
aspectRatio = svg.compressSpaces(aspectRatio); |
aspectRatio = aspectRatio.replace(/^defer\s/,''); // ignore defer |
var align = aspectRatio.split(' ')[0] || 'xMidYMid'; |
var meetOrSlice = aspectRatio.split(' ')[1] || 'meet'; |
|
// calculate scale |
var scaleX = width / desiredWidth; |
var scaleY = height / desiredHeight; |
var scaleMin = Math.min(scaleX, scaleY); |
var scaleMax = Math.max(scaleX, scaleY); |
if (meetOrSlice == 'meet') { desiredWidth *= scaleMin; desiredHeight *= scaleMin; } |
if (meetOrSlice == 'slice') { desiredWidth *= scaleMax; desiredHeight *= scaleMax; } |
|
refX = new svg.Property('refX', refX); |
refY = new svg.Property('refY', refY); |
if (refX.hasValue() && refY.hasValue()) { |
ctx.translate(-scaleMin * refX.toPixels('x'), -scaleMin * refY.toPixels('y')); |
} |
else { |
// align |
if (align.match(/^xMid/) && ((meetOrSlice == 'meet' && scaleMin == scaleY) || (meetOrSlice == 'slice' && scaleMax == scaleY))) ctx.translate(width / 2.0 - desiredWidth / 2.0, 0); |
if (align.match(/YMid$/) && ((meetOrSlice == 'meet' && scaleMin == scaleX) || (meetOrSlice == 'slice' && scaleMax == scaleX))) ctx.translate(0, height / 2.0 - desiredHeight / 2.0); |
if (align.match(/^xMax/) && ((meetOrSlice == 'meet' && scaleMin == scaleY) || (meetOrSlice == 'slice' && scaleMax == scaleY))) ctx.translate(width - desiredWidth, 0); |
if (align.match(/YMax$/) && ((meetOrSlice == 'meet' && scaleMin == scaleX) || (meetOrSlice == 'slice' && scaleMax == scaleX))) ctx.translate(0, height - desiredHeight); |
} |
|
// scale |
if (align == 'none') ctx.scale(scaleX, scaleY); |
else if (meetOrSlice == 'meet') ctx.scale(scaleMin, scaleMin); |
else if (meetOrSlice == 'slice') ctx.scale(scaleMax, scaleMax); |
|
// translate |
ctx.translate(minX == null ? 0 : -minX, minY == null ? 0 : -minY); |
} |
|
// elements |
svg.Element = {} |
|
svg.EmptyProperty = new svg.Property('EMPTY', ''); |
|
svg.Element.ElementBase = function(node) { |
this.attributes = {}; |
this.styles = {}; |
this.stylesSpecificity = {}; |
this.children = []; |
|
// get or create attribute |
this.attribute = function(name, createIfNotExists) { |
var a = this.attributes[name]; |
if (a != null) return a; |
|
if (createIfNotExists == true) { a = new svg.Property(name, ''); this.attributes[name] = a; } |
return a || svg.EmptyProperty; |
} |
|
this.getHrefAttribute = function() { |
for (var a in this.attributes) { |
if (a == 'href' || a.match(/:href$/)) { |
return this.attributes[a]; |
} |
} |
return svg.EmptyProperty; |
} |
|
// get or create style, crawls up node tree |
this.style = function(name, createIfNotExists, skipAncestors) { |
var s = this.styles[name]; |
if (s != null) return s; |
|
var a = this.attribute(name); |
if (a != null && a.hasValue()) { |
this.styles[name] = a; // move up to me to cache |
return a; |
} |
|
if (skipAncestors != true) { |
var p = this.parent; |
if (p != null) { |
var ps = p.style(name); |
if (ps != null && ps.hasValue()) { |
return ps; |
} |
} |
} |
|
if (createIfNotExists == true) { s = new svg.Property(name, ''); this.styles[name] = s; } |
return s || svg.EmptyProperty; |
} |
|
// base render |
this.render = function(ctx) { |
// don't render display=none |
if (this.style('display').value == 'none') return; |
|
// don't render visibility=hidden |
if (this.style('visibility').value == 'hidden') return; |
|
ctx.save(); |
if (this.style('mask').hasValue()) { // mask |
var mask = this.style('mask').getDefinition(); |
if (mask != null) mask.apply(ctx, this); |
} |
else if (this.style('filter').hasValue()) { // filter |
var filter = this.style('filter').getDefinition(); |
if (filter != null) filter.apply(ctx, this); |
} |
else { |
this.setContext(ctx); |
this.renderChildren(ctx); |
this.clearContext(ctx); |
} |
ctx.restore(); |
} |
|
// base set context |
this.setContext = function(ctx) { |
// OVERRIDE ME! |
} |
|
// base clear context |
this.clearContext = function(ctx) { |
// OVERRIDE ME! |
} |
|
// base render children |
this.renderChildren = function(ctx) { |
for (var i=0; i<this.children.length; i++) { |
this.children[i].render(ctx); |
} |
} |
|
this.addChild = function(childNode, create) { |
var child = childNode; |
if (create) child = svg.CreateElement(childNode); |
child.parent = this; |
if (child.type != 'title') { this.children.push(child); } |
} |
|
this.addStylesFromStyleDefinition = function () { |
// add styles |
for (var selector in svg.Styles) { |
if (selector[0] != '@' && matchesSelector(node, selector)) { |
var styles = svg.Styles[selector]; |
var specificity = svg.StylesSpecificity[selector]; |
if (styles != null) { |
for (var name in styles) { |
var existingSpecificity = this.stylesSpecificity[name]; |
if (typeof(existingSpecificity) == 'undefined') { |
existingSpecificity = '000'; |
} |
if (specificity > existingSpecificity) { |
this.styles[name] = styles[name]; |
this.stylesSpecificity[name] = specificity; |
} |
} |
} |
} |
} |
}; |
|
if (node != null && node.nodeType == 1) { //ELEMENT_NODE |
// add attributes |
for (var i=0; i<node.attributes.length; i++) { |
var attribute = node.attributes[i]; |
this.attributes[attribute.nodeName] = new svg.Property(attribute.nodeName, attribute.value); |
} |
|
this.addStylesFromStyleDefinition(); |
|
// add inline styles |
if (this.attribute('style').hasValue()) { |
var styles = this.attribute('style').value.split(';'); |
for (var i=0; i<styles.length; i++) { |
if (svg.trim(styles[i]) != '') { |
var style = styles[i].split(':'); |
var name = svg.trim(style[0]); |
var value = svg.trim(style[1]); |
this.styles[name] = new svg.Property(name, value); |
} |
} |
} |
|
// add id |
if (this.attribute('id').hasValue()) { |
if (svg.Definitions[this.attribute('id').value] == null) { |
svg.Definitions[this.attribute('id').value] = this; |
} |
} |
|
// add children |
for (var i=0; i<node.childNodes.length; i++) { |
var childNode = node.childNodes[i]; |
if (childNode.nodeType == 1) this.addChild(childNode, true); //ELEMENT_NODE |
if (this.captureTextNodes && (childNode.nodeType == 3 || childNode.nodeType == 4)) { |
var text = childNode.value || childNode.text || childNode.textContent || ''; |
if (svg.compressSpaces(text) != '') { |
this.addChild(new svg.Element.tspan(childNode), false); // TEXT_NODE |
} |
} |
} |
} |
} |
|
svg.Element.RenderedElementBase = function(node) { |
this.base = svg.Element.ElementBase; |
this.base(node); |
|
this.setContext = function(ctx) { |
// fill |
if (this.style('fill').isUrlDefinition()) { |
var fs = this.style('fill').getFillStyleDefinition(this, this.style('fill-opacity')); |
if (fs != null) ctx.fillStyle = fs; |
} |
else if (this.style('fill').hasValue()) { |
var fillStyle = this.style('fill'); |
if (fillStyle.value == 'currentColor') fillStyle.value = this.style('color').value; |
if (fillStyle.value != 'inherit') ctx.fillStyle = (fillStyle.value == 'none' ? 'rgba(0,0,0,0)' : fillStyle.value); |
} |
if (this.style('fill-opacity').hasValue()) { |
var fillStyle = new svg.Property('fill', ctx.fillStyle); |
fillStyle = fillStyle.addOpacity(this.style('fill-opacity')); |
ctx.fillStyle = fillStyle.value; |
} |
|
// stroke |
if (this.style('stroke').isUrlDefinition()) { |
var fs = this.style('stroke').getFillStyleDefinition(this, this.style('stroke-opacity')); |
if (fs != null) ctx.strokeStyle = fs; |
} |
else if (this.style('stroke').hasValue()) { |
var strokeStyle = this.style('stroke'); |
if (strokeStyle.value == 'currentColor') strokeStyle.value = this.style('color').value; |
if (strokeStyle.value != 'inherit') ctx.strokeStyle = (strokeStyle.value == 'none' ? 'rgba(0,0,0,0)' : strokeStyle.value); |
} |
if (this.style('stroke-opacity').hasValue()) { |
var strokeStyle = new svg.Property('stroke', ctx.strokeStyle); |
strokeStyle = strokeStyle.addOpacity(this.style('stroke-opacity')); |
ctx.strokeStyle = strokeStyle.value; |
} |
if (this.style('stroke-width').hasValue()) { |
var newLineWidth = this.style('stroke-width').toPixels(); |
ctx.lineWidth = newLineWidth == 0 ? 0.001 : newLineWidth; // browsers don't respect 0 |
} |
if (this.style('stroke-linecap').hasValue()) ctx.lineCap = this.style('stroke-linecap').value; |
if (this.style('stroke-linejoin').hasValue()) ctx.lineJoin = this.style('stroke-linejoin').value; |
if (this.style('stroke-miterlimit').hasValue()) ctx.miterLimit = this.style('stroke-miterlimit').value; |
if (this.style('stroke-dasharray').hasValue() && this.style('stroke-dasharray').value != 'none') { |
var gaps = svg.ToNumberArray(this.style('stroke-dasharray').value); |
if (typeof(ctx.setLineDash) != 'undefined') { ctx.setLineDash(gaps); } |
else if (typeof(ctx.webkitLineDash) != 'undefined') { ctx.webkitLineDash = gaps; } |
else if (typeof(ctx.mozDash) != 'undefined' && !(gaps.length==1 && gaps[0]==0)) { ctx.mozDash = gaps; } |
|
var offset = this.style('stroke-dashoffset').numValueOrDefault(1); |
if (typeof(ctx.lineDashOffset) != 'undefined') { ctx.lineDashOffset = offset; } |
else if (typeof(ctx.webkitLineDashOffset) != 'undefined') { ctx.webkitLineDashOffset = offset; } |
else if (typeof(ctx.mozDashOffset) != 'undefined') { ctx.mozDashOffset = offset; } |
} |
|
// font |
if (typeof(ctx.font) != 'undefined') { |
ctx.font = svg.Font.CreateFont( |
this.style('font-style').value, |
this.style('font-variant').value, |
this.style('font-weight').value, |
this.style('font-size').hasValue() ? this.style('font-size').toPixels() + 'px' : '', |
this.style('font-family').value).toString(); |
} |
|
// transform |
if (this.style('transform', false, true).hasValue()) { |
var transform = new svg.Transform(this.style('transform', false, true).value); |
transform.apply(ctx); |
} |
|
// clip |
if (this.style('clip-path', false, true).hasValue()) { |
var clip = this.style('clip-path', false, true).getDefinition(); |
if (clip != null) clip.apply(ctx); |
} |
|
// opacity |
if (this.style('opacity').hasValue()) { |
ctx.globalAlpha = this.style('opacity').numValue(); |
} |
} |
} |
svg.Element.RenderedElementBase.prototype = new svg.Element.ElementBase; |
|
svg.Element.PathElementBase = function(node) { |
this.base = svg.Element.RenderedElementBase; |
this.base(node); |
|
this.path = function(ctx) { |
if (ctx != null) ctx.beginPath(); |
return new svg.BoundingBox(); |
} |
|
this.renderChildren = function(ctx) { |
this.path(ctx); |
svg.Mouse.checkPath(this, ctx); |
if (ctx.fillStyle != '') { |
if (this.style('fill-rule').valueOrDefault('inherit') != 'inherit') { ctx.fill(this.style('fill-rule').value); } |
else { ctx.fill(); } |
} |
if (ctx.strokeStyle != '') ctx.stroke(); |
|
var markers = this.getMarkers(); |
if (markers != null) { |
if (this.style('marker-start').isUrlDefinition()) { |
var marker = this.style('marker-start').getDefinition(); |
marker.render(ctx, markers[0][0], markers[0][1]); |
} |
if (this.style('marker-mid').isUrlDefinition()) { |
var marker = this.style('marker-mid').getDefinition(); |
for (var i=1;i<markers.length-1;i++) { |
marker.render(ctx, markers[i][0], markers[i][1]); |
} |
} |
if (this.style('marker-end').isUrlDefinition()) { |
var marker = this.style('marker-end').getDefinition(); |
marker.render(ctx, markers[markers.length-1][0], markers[markers.length-1][1]); |
} |
} |
} |
|
this.getBoundingBox = function() { |
return this.path(); |
} |
|
this.getMarkers = function() { |
return null; |
} |
} |
svg.Element.PathElementBase.prototype = new svg.Element.RenderedElementBase; |
|
// svg element |
svg.Element.svg = function(node) { |
this.base = svg.Element.RenderedElementBase; |
this.base(node); |
|
this.baseClearContext = this.clearContext; |
this.clearContext = function(ctx) { |
this.baseClearContext(ctx); |
svg.ViewPort.RemoveCurrent(); |
} |
|
this.baseSetContext = this.setContext; |
this.setContext = function(ctx) { |
// initial values and defaults |
ctx.strokeStyle = 'rgba(0,0,0,0)'; |
ctx.lineCap = 'butt'; |
ctx.lineJoin = 'miter'; |
ctx.miterLimit = 4; |
if (typeof(ctx.font) != 'undefined' && typeof(window.getComputedStyle) != 'undefined') { |
ctx.font = window.getComputedStyle(ctx.canvas).getPropertyValue('font'); |
} |
|
this.baseSetContext(ctx); |
|
// create new view port |
if (!this.attribute('x').hasValue()) this.attribute('x', true).value = 0; |
if (!this.attribute('y').hasValue()) this.attribute('y', true).value = 0; |
ctx.translate(this.attribute('x').toPixels('x'), this.attribute('y').toPixels('y')); |
|
var width = svg.ViewPort.width(); |
var height = svg.ViewPort.height(); |
|
if (!this.attribute('width').hasValue()) this.attribute('width', true).value = '100%'; |
if (!this.attribute('height').hasValue()) this.attribute('height', true).value = '100%'; |
if (typeof(this.root) == 'undefined') { |
width = this.attribute('width').toPixels('x'); |
height = this.attribute('height').toPixels('y'); |
|
var x = 0; |
var y = 0; |
if (this.attribute('refX').hasValue() && this.attribute('refY').hasValue()) { |
x = -this.attribute('refX').toPixels('x'); |
y = -this.attribute('refY').toPixels('y'); |
} |
|
if (this.attribute('overflow').valueOrDefault('hidden') != 'visible') { |
ctx.beginPath(); |
ctx.moveTo(x, y); |
ctx.lineTo(width, y); |
ctx.lineTo(width, height); |
ctx.lineTo(x, height); |
ctx.closePath(); |
ctx.clip(); |
} |
} |
svg.ViewPort.SetCurrent(width, height); |
|
// viewbox |
if (this.attribute('viewBox').hasValue()) { |
var viewBox = svg.ToNumberArray(this.attribute('viewBox').value); |
var minX = viewBox[0]; |
var minY = viewBox[1]; |
width = viewBox[2]; |
height = viewBox[3]; |
|
svg.AspectRatio(ctx, |
this.attribute('preserveAspectRatio').value, |
svg.ViewPort.width(), |
width, |
svg.ViewPort.height(), |
height, |
minX, |
minY, |
this.attribute('refX').value, |
this.attribute('refY').value); |
|
svg.ViewPort.RemoveCurrent(); |
svg.ViewPort.SetCurrent(viewBox[2], viewBox[3]); |
} |
} |
} |
svg.Element.svg.prototype = new svg.Element.RenderedElementBase; |
|
// rect element |
svg.Element.rect = function(node) { |
this.base = svg.Element.PathElementBase; |
this.base(node); |
|
this.path = function(ctx) { |
var x = this.attribute('x').toPixels('x'); |
var y = this.attribute('y').toPixels('y'); |
var width = this.attribute('width').toPixels('x'); |
var height = this.attribute('height').toPixels('y'); |
var rx = this.attribute('rx').toPixels('x'); |
var ry = this.attribute('ry').toPixels('y'); |
if (this.attribute('rx').hasValue() && !this.attribute('ry').hasValue()) ry = rx; |
if (this.attribute('ry').hasValue() && !this.attribute('rx').hasValue()) rx = ry; |
rx = Math.min(rx, width / 2.0); |
ry = Math.min(ry, height / 2.0); |
if (ctx != null) { |
ctx.beginPath(); |
ctx.moveTo(x + rx, y); |
ctx.lineTo(x + width - rx, y); |
ctx.quadraticCurveTo(x + width, y, x + width, y + ry) |
ctx.lineTo(x + width, y + height - ry); |
ctx.quadraticCurveTo(x + width, y + height, x + width - rx, y + height) |
ctx.lineTo(x + rx, y + height); |
ctx.quadraticCurveTo(x, y + height, x, y + height - ry) |
ctx.lineTo(x, y + ry); |
ctx.quadraticCurveTo(x, y, x + rx, y) |
ctx.closePath(); |
} |
|
return new svg.BoundingBox(x, y, x + width, y + height); |
} |
} |
svg.Element.rect.prototype = new svg.Element.PathElementBase; |
|
// circle element |
svg.Element.circle = function(node) { |
this.base = svg.Element.PathElementBase; |
this.base(node); |
|
this.path = function(ctx) { |
var cx = this.attribute('cx').toPixels('x'); |
var cy = this.attribute('cy').toPixels('y'); |
var r = this.attribute('r').toPixels(); |
|
if (ctx != null) { |
ctx.beginPath(); |
ctx.arc(cx, cy, r, 0, Math.PI * 2, true); |
ctx.closePath(); |
} |
|
return new svg.BoundingBox(cx - r, cy - r, cx + r, cy + r); |
} |
} |
svg.Element.circle.prototype = new svg.Element.PathElementBase; |
|
// ellipse element |
svg.Element.ellipse = function(node) { |
this.base = svg.Element.PathElementBase; |
this.base(node); |
|
this.path = function(ctx) { |
var KAPPA = 4 * ((Math.sqrt(2) - 1) / 3); |
var rx = this.attribute('rx').toPixels('x'); |
var ry = this.attribute('ry').toPixels('y'); |
var cx = this.attribute('cx').toPixels('x'); |
var cy = this.attribute('cy').toPixels('y'); |
|
if (ctx != null) { |
ctx.beginPath(); |
ctx.moveTo(cx, cy - ry); |
ctx.bezierCurveTo(cx + (KAPPA * rx), cy - ry, cx + rx, cy - (KAPPA * ry), cx + rx, cy); |
ctx.bezierCurveTo(cx + rx, cy + (KAPPA * ry), cx + (KAPPA * rx), cy + ry, cx, cy + ry); |
ctx.bezierCurveTo(cx - (KAPPA * rx), cy + ry, cx - rx, cy + (KAPPA * ry), cx - rx, cy); |
ctx.bezierCurveTo(cx - rx, cy - (KAPPA * ry), cx - (KAPPA * rx), cy - ry, cx, cy - ry); |
ctx.closePath(); |
} |
|
return new svg.BoundingBox(cx - rx, cy - ry, cx + rx, cy + ry); |
} |
} |
svg.Element.ellipse.prototype = new svg.Element.PathElementBase; |
|
// line element |
svg.Element.line = function(node) { |
this.base = svg.Element.PathElementBase; |
this.base(node); |
|
this.getPoints = function() { |
return [ |
new svg.Point(this.attribute('x1').toPixels('x'), this.attribute('y1').toPixels('y')), |
new svg.Point(this.attribute('x2').toPixels('x'), this.attribute('y2').toPixels('y'))]; |
} |
|
this.path = function(ctx) { |
var points = this.getPoints(); |
|
if (ctx != null) { |
ctx.beginPath(); |
ctx.moveTo(points[0].x, points[0].y); |
ctx.lineTo(points[1].x, points[1].y); |
} |
|
return new svg.BoundingBox(points[0].x, points[0].y, points[1].x, points[1].y); |
} |
|
this.getMarkers = function() { |
var points = this.getPoints(); |
var a = points[0].angleTo(points[1]); |
return [[points[0], a], [points[1], a]]; |
} |
} |
svg.Element.line.prototype = new svg.Element.PathElementBase; |
|
// polyline element |
svg.Element.polyline = function(node) { |
this.base = svg.Element.PathElementBase; |
this.base(node); |
|
this.points = svg.CreatePath(this.attribute('points').value); |
this.path = function(ctx) { |
var bb = new svg.BoundingBox(this.points[0].x, this.points[0].y); |
if (ctx != null) { |
ctx.beginPath(); |
ctx.moveTo(this.points[0].x, this.points[0].y); |
} |
for (var i=1; i<this.points.length; i++) { |
bb.addPoint(this.points[i].x, this.points[i].y); |
if (ctx != null) ctx.lineTo(this.points[i].x, this.points[i].y); |
} |
return bb; |
} |
|
this.getMarkers = function() { |
var markers = []; |
for (var i=0; i<this.points.length - 1; i++) { |
markers.push([this.points[i], this.points[i].angleTo(this.points[i+1])]); |
} |
markers.push([this.points[this.points.length-1], markers[markers.length-1][1]]); |
return markers; |
} |
} |
svg.Element.polyline.prototype = new svg.Element.PathElementBase; |
|
// polygon element |
svg.Element.polygon = function(node) { |
this.base = svg.Element.polyline; |
this.base(node); |
|
this.basePath = this.path; |
this.path = function(ctx) { |
var bb = this.basePath(ctx); |
if (ctx != null) { |
ctx.lineTo(this.points[0].x, this.points[0].y); |
ctx.closePath(); |
} |
return bb; |
} |
} |
svg.Element.polygon.prototype = new svg.Element.polyline; |
|
// path element |
svg.Element.path = function(node) { |
this.base = svg.Element.PathElementBase; |
this.base(node); |
|
var d = this.attribute('d').value; |
// TODO: convert to real lexer based on http://www.w3.org/TR/SVG11/paths.html#PathDataBNF |
d = d.replace(/,/gm,' '); // get rid of all commas |
// As the end of a match can also be the start of the next match, we need to run this replace twice. |
for(var i=0; i<2; i++) |
d = d.replace(/([MmZzLlHhVvCcSsQqTtAa])([^\s])/gm,'$1 $2'); // suffix commands with spaces |
d = d.replace(/([^\s])([MmZzLlHhVvCcSsQqTtAa])/gm,'$1 $2'); // prefix commands with spaces |
d = d.replace(/([0-9])([+\-])/gm,'$1 $2'); // separate digits on +- signs |
// Again, we need to run this twice to find all occurances |
for(var i=0; i<2; i++) |
d = d.replace(/(\.[0-9]*)(\.)/gm,'$1 $2'); // separate digits when they start with a comma |
d = d.replace(/([Aa](\s+[0-9]+){3})\s+([01])\s*([01])/gm,'$1 $3 $4 '); // shorthand elliptical arc path syntax |
d = svg.compressSpaces(d); // compress multiple spaces |
d = svg.trim(d); |
this.PathParser = new (function(d) { |
this.tokens = d.split(' '); |
|
this.reset = function() { |
this.i = -1; |
this.command = ''; |
this.previousCommand = ''; |
this.start = new svg.Point(0, 0); |
this.control = new svg.Point(0, 0); |
this.current = new svg.Point(0, 0); |
this.points = []; |
this.angles = []; |
} |
|
this.isEnd = function() { |
return this.i >= this.tokens.length - 1; |
} |
|
this.isCommandOrEnd = function() { |
if (this.isEnd()) return true; |
return this.tokens[this.i + 1].match(/^[A-Za-z]$/) != null; |
} |
|
this.isRelativeCommand = function() { |
switch(this.command) |
{ |
case 'm': |
case 'l': |
case 'h': |
case 'v': |
case 'c': |
case 's': |
case 'q': |
case 't': |
case 'a': |
case 'z': |
return true; |
break; |
} |
return false; |
} |
|
this.getToken = function() { |
this.i++; |
return this.tokens[this.i]; |
} |
|
this.getScalar = function() { |
return parseFloat(this.getToken()); |
} |
|
this.nextCommand = function() { |
this.previousCommand = this.command; |
this.command = this.getToken(); |
} |
|
this.getPoint = function() { |
var p = new svg.Point(this.getScalar(), this.getScalar()); |
return this.makeAbsolute(p); |
} |
|
this.getAsControlPoint = function() { |
var p = this.getPoint(); |
this.control = p; |
return p; |
} |
|
this.getAsCurrentPoint = function() { |
var p = this.getPoint(); |
this.current = p; |
return p; |
} |
|
this.getReflectedControlPoint = function() { |
if (this.previousCommand.toLowerCase() != 'c' && |
this.previousCommand.toLowerCase() != 's' && |
this.previousCommand.toLowerCase() != 'q' && |
this.previousCommand.toLowerCase() != 't' ){ |
return this.current; |
} |
|
// reflect point |
var p = new svg.Point(2 * this.current.x - this.control.x, 2 * this.current.y - this.control.y); |
return p; |
} |
|
this.makeAbsolute = function(p) { |
if (this.isRelativeCommand()) { |
p.x += this.current.x; |
p.y += this.current.y; |
} |
return p; |
} |
|
this.addMarker = function(p, from, priorTo) { |
// if the last angle isn't filled in because we didn't have this point yet ... |
if (priorTo != null && this.angles.length > 0 && this.angles[this.angles.length-1] == null) { |
this.angles[this.angles.length-1] = this.points[this.points.length-1].angleTo(priorTo); |
} |
this.addMarkerAngle(p, from == null ? null : from.angleTo(p)); |
} |
|
this.addMarkerAngle = function(p, a) { |
this.points.push(p); |
this.angles.push(a); |
} |
|
this.getMarkerPoints = function() { return this.points; } |
this.getMarkerAngles = function() { |
for (var i=0; i<this.angles.length; i++) { |
if (this.angles[i] == null) { |
for (var j=i+1; j<this.angles.length; j++) { |
if (this.angles[j] != null) { |
this.angles[i] = this.angles[j]; |
break; |
} |
} |
} |
} |
return this.angles; |
} |
})(d); |
|
this.path = function(ctx) { |
var pp = this.PathParser; |
pp.reset(); |
|
var bb = new svg.BoundingBox(); |
if (ctx != null) ctx.beginPath(); |
while (!pp.isEnd()) { |
pp.nextCommand(); |
switch (pp.command) { |
case 'M': |
case 'm': |
var p = pp.getAsCurrentPoint(); |
pp.addMarker(p); |
bb.addPoint(p.x, p.y); |
if (ctx != null) ctx.moveTo(p.x, p.y); |
pp.start = pp.current; |
while (!pp.isCommandOrEnd()) { |
var p = pp.getAsCurrentPoint(); |
pp.addMarker(p, pp.start); |
bb.addPoint(p.x, p.y); |
if (ctx != null) ctx.lineTo(p.x, p.y); |
} |
break; |
case 'L': |
case 'l': |
while (!pp.isCommandOrEnd()) { |
var c = pp.current; |
var p = pp.getAsCurrentPoint(); |
pp.addMarker(p, c); |
bb.addPoint(p.x, p.y); |
if (ctx != null) ctx.lineTo(p.x, p.y); |
} |
break; |
case 'H': |
case 'h': |
while (!pp.isCommandOrEnd()) { |
var newP = new svg.Point((pp.isRelativeCommand() ? pp.current.x : 0) + pp.getScalar(), pp.current.y); |
pp.addMarker(newP, pp.current); |
pp.current = newP; |
bb.addPoint(pp.current.x, pp.current.y); |
if (ctx != null) ctx.lineTo(pp.current.x, pp.current.y); |
} |
break; |
case 'V': |
case 'v': |
while (!pp.isCommandOrEnd()) { |
var newP = new svg.Point(pp.current.x, (pp.isRelativeCommand() ? pp.current.y : 0) + pp.getScalar()); |
pp.addMarker(newP, pp.current); |
pp.current = newP; |
bb.addPoint(pp.current.x, pp.current.y); |
if (ctx != null) ctx.lineTo(pp.current.x, pp.current.y); |
} |
break; |
case 'C': |
case 'c': |
while (!pp.isCommandOrEnd()) { |
var curr = pp.current; |
var p1 = pp.getPoint(); |
var cntrl = pp.getAsControlPoint(); |
var cp = pp.getAsCurrentPoint(); |
pp.addMarker(cp, cntrl, p1); |
bb.addBezierCurve(curr.x, curr.y, p1.x, p1.y, cntrl.x, cntrl.y, cp.x, cp.y); |
if (ctx != null) ctx.bezierCurveTo(p1.x, p1.y, cntrl.x, cntrl.y, cp.x, cp.y); |
} |
break; |
case 'S': |
case 's': |
while (!pp.isCommandOrEnd()) { |
var curr = pp.current; |
var p1 = pp.getReflectedControlPoint(); |
var cntrl = pp.getAsControlPoint(); |
var cp = pp.getAsCurrentPoint(); |
pp.addMarker(cp, cntrl, p1); |
bb.addBezierCurve(curr.x, curr.y, p1.x, p1.y, cntrl.x, cntrl.y, cp.x, cp.y); |
if (ctx != null) ctx.bezierCurveTo(p1.x, p1.y, cntrl.x, cntrl.y, cp.x, cp.y); |
} |
break; |
case 'Q': |
case 'q': |
while (!pp.isCommandOrEnd()) { |
var curr = pp.current; |
var cntrl = pp.getAsControlPoint(); |
var cp = pp.getAsCurrentPoint(); |
pp.addMarker(cp, cntrl, cntrl); |
bb.addQuadraticCurve(curr.x, curr.y, cntrl.x, cntrl.y, cp.x, cp.y); |
if (ctx != null) ctx.quadraticCurveTo(cntrl.x, cntrl.y, cp.x, cp.y); |
} |
break; |
case 'T': |
case 't': |
while (!pp.isCommandOrEnd()) { |
var curr = pp.current; |
var cntrl = pp.getReflectedControlPoint(); |
pp.control = cntrl; |
var cp = pp.getAsCurrentPoint(); |
pp.addMarker(cp, cntrl, cntrl); |
bb.addQuadraticCurve(curr.x, curr.y, cntrl.x, cntrl.y, cp.x, cp.y); |
if (ctx != null) ctx.quadraticCurveTo(cntrl.x, cntrl.y, cp.x, cp.y); |
} |
break; |
case 'A': |
case 'a': |
while (!pp.isCommandOrEnd()) { |
var curr = pp.current; |
var rx = pp.getScalar(); |
var ry = pp.getScalar(); |
var xAxisRotation = pp.getScalar() * (Math.PI / 180.0); |
var largeArcFlag = pp.getScalar(); |
var sweepFlag = pp.getScalar(); |
var cp = pp.getAsCurrentPoint(); |
|
// Conversion from endpoint to center parameterization |
// http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes |
// x1', y1' |
var currp = new svg.Point( |
Math.cos(xAxisRotation) * (curr.x - cp.x) / 2.0 + Math.sin(xAxisRotation) * (curr.y - cp.y) / 2.0, |
-Math.sin(xAxisRotation) * (curr.x - cp.x) / 2.0 + Math.cos(xAxisRotation) * (curr.y - cp.y) / 2.0 |
); |
// adjust radii |
var l = Math.pow(currp.x,2)/Math.pow(rx,2)+Math.pow(currp.y,2)/Math.pow(ry,2); |
if (l > 1) { |
rx *= Math.sqrt(l); |
ry *= Math.sqrt(l); |
} |
// cx', cy' |
var s = (largeArcFlag == sweepFlag ? -1 : 1) * Math.sqrt( |
((Math.pow(rx,2)*Math.pow(ry,2))-(Math.pow(rx,2)*Math.pow(currp.y,2))-(Math.pow(ry,2)*Math.pow(currp.x,2))) / |
(Math.pow(rx,2)*Math.pow(currp.y,2)+Math.pow(ry,2)*Math.pow(currp.x,2)) |
); |
if (isNaN(s)) s = 0; |
var cpp = new svg.Point(s * rx * currp.y / ry, s * -ry * currp.x / rx); |
// cx, cy |
var centp = new svg.Point( |
(curr.x + cp.x) / 2.0 + Math.cos(xAxisRotation) * cpp.x - Math.sin(xAxisRotation) * cpp.y, |
(curr.y + cp.y) / 2.0 + Math.sin(xAxisRotation) * cpp.x + Math.cos(xAxisRotation) * cpp.y |
); |
// vector magnitude |
var m = function(v) { return Math.sqrt(Math.pow(v[0],2) + Math.pow(v[1],2)); } |
// ratio between two vectors |
var r = function(u, v) { return (u[0]*v[0]+u[1]*v[1]) / (m(u)*m(v)) } |
// angle between two vectors |
var a = function(u, v) { return (u[0]*v[1] < u[1]*v[0] ? -1 : 1) * Math.acos(r(u,v)); } |
// initial angle |
var a1 = a([1,0], [(currp.x-cpp.x)/rx,(currp.y-cpp.y)/ry]); |
// angle delta |
var u = [(currp.x-cpp.x)/rx,(currp.y-cpp.y)/ry]; |
var v = [(-currp.x-cpp.x)/rx,(-currp.y-cpp.y)/ry]; |
var ad = a(u, v); |
if (r(u,v) <= -1) ad = Math.PI; |
if (r(u,v) >= 1) ad = 0; |
|
// for markers |
var dir = 1 - sweepFlag ? 1.0 : -1.0; |
var ah = a1 + dir * (ad / 2.0); |
var halfWay = new svg.Point( |
centp.x + rx * Math.cos(ah), |
centp.y + ry * Math.sin(ah) |
); |
pp.addMarkerAngle(halfWay, ah - dir * Math.PI / 2); |
pp.addMarkerAngle(cp, ah - dir * Math.PI); |
|
bb.addPoint(cp.x, cp.y); // TODO: this is too naive, make it better |
if (ctx != null) { |
var r = rx > ry ? rx : ry; |
var sx = rx > ry ? 1 : rx / ry; |
var sy = rx > ry ? ry / rx : 1; |
|
ctx.translate(centp.x, centp.y); |
ctx.rotate(xAxisRotation); |
ctx.scale(sx, sy); |
ctx.arc(0, 0, r, a1, a1 + ad, 1 - sweepFlag); |
ctx.scale(1/sx, 1/sy); |
ctx.rotate(-xAxisRotation); |
ctx.translate(-centp.x, -centp.y); |
} |
} |
break; |
case 'Z': |
case 'z': |
if (ctx != null) ctx.closePath(); |
pp.current = pp.start; |
} |
} |
|
return bb; |
} |
|
this.getMarkers = function() { |
var points = this.PathParser.getMarkerPoints(); |
var angles = this.PathParser.getMarkerAngles(); |
|
var markers = []; |
for (var i=0; i<points.length; i++) { |
markers.push([points[i], angles[i]]); |
} |
return markers; |
} |
} |
svg.Element.path.prototype = new svg.Element.PathElementBase; |
|
// pattern element |
svg.Element.pattern = function(node) { |
this.base = svg.Element.ElementBase; |
this.base(node); |
|
this.createPattern = function(ctx, element) { |
var width = this.attribute('width').toPixels('x', true); |
var height = this.attribute('height').toPixels('y', true); |
|
// render me using a temporary svg element |
var tempSvg = new svg.Element.svg(); |
tempSvg.attributes['viewBox'] = new svg.Property('viewBox', this.attribute('viewBox').value); |
tempSvg.attributes['width'] = new svg.Property('width', width + 'px'); |
tempSvg.attributes['height'] = new svg.Property('height', height + 'px'); |
tempSvg.attributes['transform'] = new svg.Property('transform', this.attribute('patternTransform').value); |
tempSvg.children = this.children; |
|
var c = document.createElement('canvas'); |
c.width = width; |
c.height = height; |
var cctx = c.getContext('2d'); |
if (this.attribute('x').hasValue() && this.attribute('y').hasValue()) { |
cctx.translate(this.attribute('x').toPixels('x', true), this.attribute('y').toPixels('y', true)); |
} |
// render 3x3 grid so when we transform there's no white space on edges |
for (var x=-1; x<=1; x++) { |
for (var y=-1; y<=1; y++) { |
cctx.save(); |
tempSvg.attributes['x'] = new svg.Property('x', x * c.width); |
tempSvg.attributes['y'] = new svg.Property('y', y * c.height); |
tempSvg.render(cctx); |
cctx.restore(); |
} |
} |
var pattern = ctx.createPattern(c, 'repeat'); |
return pattern; |
} |
} |
svg.Element.pattern.prototype = new svg.Element.ElementBase; |
|
// marker element |
svg.Element.marker = function(node) { |
this.base = svg.Element.ElementBase; |
this.base(node); |
|
this.baseRender = this.render; |
this.render = function(ctx, point, angle) { |
ctx.translate(point.x, point.y); |
if (this.attribute('orient').valueOrDefault('auto') == 'auto') ctx.rotate(angle); |
if (this.attribute('markerUnits').valueOrDefault('strokeWidth') == 'strokeWidth') ctx.scale(ctx.lineWidth, ctx.lineWidth); |
ctx.save(); |
|
// render me using a temporary svg element |
var tempSvg = new svg.Element.svg(); |
tempSvg.attributes['viewBox'] = new svg.Property('viewBox', this.attribute('viewBox').value); |
tempSvg.attributes['refX'] = new svg.Property('refX', this.attribute('refX').value); |
tempSvg.attributes['refY'] = new svg.Property('refY', this.attribute('refY').value); |
tempSvg.attributes['width'] = new svg.Property('width', this.attribute('markerWidth').value); |
tempSvg.attributes['height'] = new svg.Property('height', this.attribute('markerHeight').value); |
tempSvg.attributes['fill'] = new svg.Property('fill', this.attribute('fill').valueOrDefault('black')); |
tempSvg.attributes['stroke'] = new svg.Property('stroke', this.attribute('stroke').valueOrDefault('none')); |
tempSvg.children = this.children; |
tempSvg.render(ctx); |
|
ctx.restore(); |
if (this.attribute('markerUnits').valueOrDefault('strokeWidth') == 'strokeWidth') ctx.scale(1/ctx.lineWidth, 1/ctx.lineWidth); |
if (this.attribute('orient').valueOrDefault('auto') == 'auto') ctx.rotate(-angle); |
ctx.translate(-point.x, -point.y); |
} |
} |
svg.Element.marker.prototype = new svg.Element.ElementBase; |
|
// definitions element |
svg.Element.defs = function(node) { |
this.base = svg.Element.ElementBase; |
this.base(node); |
|
this.render = function(ctx) { |
// NOOP |
} |
} |
svg.Element.defs.prototype = new svg.Element.ElementBase; |
|
// base for gradients |
svg.Element.GradientBase = function(node) { |
this.base = svg.Element.ElementBase; |
this.base(node); |
|
this.stops = []; |
for (var i=0; i<this.children.length; i++) { |
var child = this.children[i]; |
if (child.type == 'stop') this.stops.push(child); |
} |
|
this.getGradient = function() { |
// OVERRIDE ME! |
} |
|
this.gradientUnits = function () { |
return this.attribute('gradientUnits').valueOrDefault('objectBoundingBox'); |
} |
|
this.attributesToInherit = ['gradientUnits']; |
|
this.inheritStopContainer = function (stopsContainer) { |
for (var i=0; i<this.attributesToInherit.length; i++) { |
var attributeToInherit = this.attributesToInherit[i]; |
if (!this.attribute(attributeToInherit).hasValue() && stopsContainer.attribute(attributeToInherit).hasValue()) { |
this.attribute(attributeToInherit, true).value = stopsContainer.attribute(attributeToInherit).value; |
} |
} |
} |
|
this.createGradient = function(ctx, element, parentOpacityProp) { |
var stopsContainer = this; |
if (this.getHrefAttribute().hasValue()) { |
stopsContainer = this.getHrefAttribute().getDefinition(); |
this.inheritStopContainer(stopsContainer); |
} |
|
var addParentOpacity = function (color) { |
if (parentOpacityProp.hasValue()) { |
var p = new svg.Property('color', color); |
return p.addOpacity(parentOpacityProp).value; |
} |
return color; |
}; |
|
var g = this.getGradient(ctx, element); |
if (g == null) return addParentOpacity(stopsContainer.stops[stopsContainer.stops.length - 1].color); |
for (var i=0; i<stopsContainer.stops.length; i++) { |
g.addColorStop(stopsContainer.stops[i].offset, addParentOpacity(stopsContainer.stops[i].color)); |
} |
|
if (this.attribute('gradientTransform').hasValue()) { |
// render as transformed pattern on temporary canvas |
var rootView = svg.ViewPort.viewPorts[0]; |
|
var rect = new svg.Element.rect(); |
rect.attributes['x'] = new svg.Property('x', -svg.MAX_VIRTUAL_PIXELS/3.0); |
rect.attributes['y'] = new svg.Property('y', -svg.MAX_VIRTUAL_PIXELS/3.0); |
rect.attributes['width'] = new svg.Property('width', svg.MAX_VIRTUAL_PIXELS); |
rect.attributes['height'] = new svg.Property('height', svg.MAX_VIRTUAL_PIXELS); |
|
var group = new svg.Element.g(); |
group.attributes['transform'] = new svg.Property('transform', this.attribute('gradientTransform').value); |
group.children = [ rect ]; |
|
var tempSvg = new svg.Element.svg(); |
tempSvg.attributes['x'] = new svg.Property('x', 0); |
tempSvg.attributes['y'] = new svg.Property('y', 0); |
tempSvg.attributes['width'] = new svg.Property('width', rootView.width); |
tempSvg.attributes['height'] = new svg.Property('height', rootView.height); |
tempSvg.children = [ group ]; |
|
var c = document.createElement('canvas'); |
c.width = rootView.width; |
c.height = rootView.height; |
var tempCtx = c.getContext('2d'); |
tempCtx.fillStyle = g; |
tempSvg.render(tempCtx); |
return tempCtx.createPattern(c, 'no-repeat'); |
} |
|
return g; |
} |
} |
svg.Element.GradientBase.prototype = new svg.Element.ElementBase; |
|
// linear gradient element |
svg.Element.linearGradient = function(node) { |
this.base = svg.Element.GradientBase; |
this.base(node); |
|
this.attributesToInherit.push('x1'); |
this.attributesToInherit.push('y1'); |
this.attributesToInherit.push('x2'); |
this.attributesToInherit.push('y2'); |
|
this.getGradient = function(ctx, element) { |
var bb = this.gradientUnits() == 'objectBoundingBox' ? element.getBoundingBox() : null; |
|
if (!this.attribute('x1').hasValue() |
&& !this.attribute('y1').hasValue() |
&& !this.attribute('x2').hasValue() |
&& !this.attribute('y2').hasValue()) { |
this.attribute('x1', true).value = 0; |
this.attribute('y1', true).value = 0; |
this.attribute('x2', true).value = 1; |
this.attribute('y2', true).value = 0; |
} |
|
var x1 = (this.gradientUnits() == 'objectBoundingBox' |
? bb.x() + bb.width() * this.attribute('x1').numValue() |
: this.attribute('x1').toPixels('x')); |
var y1 = (this.gradientUnits() == 'objectBoundingBox' |
? bb.y() + bb.height() * this.attribute('y1').numValue() |
: this.attribute('y1').toPixels('y')); |
var x2 = (this.gradientUnits() == 'objectBoundingBox' |
? bb.x() + bb.width() * this.attribute('x2').numValue() |
: this.attribute('x2').toPixels('x')); |
var y2 = (this.gradientUnits() == 'objectBoundingBox' |
? bb.y() + bb.height() * this.attribute('y2').numValue() |
: this.attribute('y2').toPixels('y')); |
|
if (x1 == x2 && y1 == y2) return null; |
return ctx.createLinearGradient(x1, y1, x2, y2); |
} |
} |
svg.Element.linearGradient.prototype = new svg.Element.GradientBase; |
|
// radial gradient element |
svg.Element.radialGradient = function(node) { |
this.base = svg.Element.GradientBase; |
this.base(node); |
|
this.attributesToInherit.push('cx'); |
this.attributesToInherit.push('cy'); |
this.attributesToInherit.push('r'); |
this.attributesToInherit.push('fx'); |
this.attributesToInherit.push('fy'); |
|
this.getGradient = function(ctx, element) { |
var bb = element.getBoundingBox(); |
|
if (!this.attribute('cx').hasValue()) this.attribute('cx', true).value = '50%'; |
if (!this.attribute('cy').hasValue()) this.attribute('cy', true).value = '50%'; |
if (!this.attribute('r').hasValue()) this.attribute('r', true).value = '50%'; |
|
var cx = (this.gradientUnits() == 'objectBoundingBox' |
? bb.x() + bb.width() * this.attribute('cx').numValue() |
: this.attribute('cx').toPixels('x')); |
var cy = (this.gradientUnits() == 'objectBoundingBox' |
? bb.y() + bb.height() * this.attribute('cy').numValue() |
: this.attribute('cy').toPixels('y')); |
|
var fx = cx; |
var fy = cy; |
if (this.attribute('fx').hasValue()) { |
fx = (this.gradientUnits() == 'objectBoundingBox' |
? bb.x() + bb.width() * this.attribute('fx').numValue() |
: this.attribute('fx').toPixels('x')); |
} |
if (this.attribute('fy').hasValue()) { |
fy = (this.gradientUnits() == 'objectBoundingBox' |
? bb.y() + bb.height() * this.attribute('fy').numValue() |
: this.attribute('fy').toPixels('y')); |
} |
|
var r = (this.gradientUnits() == 'objectBoundingBox' |
? (bb.width() + bb.height()) / 2.0 * this.attribute('r').numValue() |
: this.attribute('r').toPixels()); |
|
return ctx.createRadialGradient(fx, fy, 0, cx, cy, r); |
} |
} |
svg.Element.radialGradient.prototype = new svg.Element.GradientBase; |
|
// gradient stop element |
svg.Element.stop = function(node) { |
this.base = svg.Element.ElementBase; |
this.base(node); |
|
this.offset = this.attribute('offset').numValue(); |
if (this.offset < 0) this.offset = 0; |
if (this.offset > 1) this.offset = 1; |
|
var stopColor = this.style('stop-color', true); |
if (stopColor.value === '') stopColor.value = '#000'; |
if (this.style('stop-opacity').hasValue()) stopColor = stopColor.addOpacity(this.style('stop-opacity')); |
this.color = stopColor.value; |
} |
svg.Element.stop.prototype = new svg.Element.ElementBase; |
|
// animation base element |
svg.Element.AnimateBase = function(node) { |
this.base = svg.Element.ElementBase; |
this.base(node); |
|
svg.Animations.push(this); |
|
this.duration = 0.0; |
this.begin = this.attribute('begin').toMilliseconds(); |
this.maxDuration = this.begin + this.attribute('dur').toMilliseconds(); |
|
this.getProperty = function() { |
var attributeType = this.attribute('attributeType').value; |
var attributeName = this.attribute('attributeName').value; |
|
if (attributeType == 'CSS') { |
return this.parent.style(attributeName, true); |
} |
return this.parent.attribute(attributeName, true); |
}; |
|
this.initialValue = null; |
this.initialUnits = ''; |
this.removed = false; |
|
this.calcValue = function() { |
// OVERRIDE ME! |
return ''; |
} |
|
this.update = function(delta) { |
// set initial value |
if (this.initialValue == null) { |
this.initialValue = this.getProperty().value; |
this.initialUnits = this.getProperty().getUnits(); |
} |
|
// if we're past the end time |
if (this.duration > this.maxDuration) { |
// loop for indefinitely repeating animations |
if (this.attribute('repeatCount').value == 'indefinite' |
|| this.attribute('repeatDur').value == 'indefinite') { |
this.duration = 0.0 |
} |
else if (this.attribute('fill').valueOrDefault('remove') == 'freeze' && !this.frozen) { |
this.frozen = true; |
this.parent.animationFrozen = true; |
this.parent.animationFrozenValue = this.getProperty().value; |
} |
else if (this.attribute('fill').valueOrDefault('remove') == 'remove' && !this.removed) { |
this.removed = true; |
this.getProperty().value = this.parent.animationFrozen ? this.parent.animationFrozenValue : this.initialValue; |
return true; |
} |
return false; |
} |
this.duration = this.duration + delta; |
|
// if we're past the begin time |
var updated = false; |
if (this.begin < this.duration) { |
var newValue = this.calcValue(); // tween |
|
if (this.attribute('type').hasValue()) { |
// for transform, etc. |
var type = this.attribute('type').value; |
newValue = type + '(' + newValue + ')'; |
} |
|
this.getProperty().value = newValue; |
updated = true; |
} |
|
return updated; |
} |
|
this.from = this.attribute('from'); |
this.to = this.attribute('to'); |
this.values = this.attribute('values'); |
if (this.values.hasValue()) this.values.value = this.values.value.split(';'); |
|
// fraction of duration we've covered |
this.progress = function() { |
var ret = { progress: (this.duration - this.begin) / (this.maxDuration - this.begin) }; |
if (this.values.hasValue()) { |
var p = ret.progress * (this.values.value.length - 1); |
var lb = Math.floor(p), ub = Math.ceil(p); |
ret.from = new svg.Property('from', parseFloat(this.values.value[lb])); |
ret.to = new svg.Property('to', parseFloat(this.values.value[ub])); |
ret.progress = (p - lb) / (ub - lb); |
} |
else { |
ret.from = this.from; |
ret.to = this.to; |
} |
return ret; |
} |
} |
svg.Element.AnimateBase.prototype = new svg.Element.ElementBase; |
|
// animate element |
svg.Element.animate = function(node) { |
this.base = svg.Element.AnimateBase; |
this.base(node); |
|
this.calcValue = function() { |
var p = this.progress(); |
|
// tween value linearly |
var newValue = p.from.numValue() + (p.to.numValue() - p.from.numValue()) * p.progress; |
return newValue + this.initialUnits; |
}; |
} |
svg.Element.animate.prototype = new svg.Element.AnimateBase; |
|
// animate color element |
svg.Element.animateColor = function(node) { |
this.base = svg.Element.AnimateBase; |
this.base(node); |
|
this.calcValue = function() { |
var p = this.progress(); |
var from = new RGBColor(p.from.value); |
var to = new RGBColor(p.to.value); |
|
if (from.ok && to.ok) { |
// tween color linearly |
var r = from.r + (to.r - from.r) * p.progress; |
var g = from.g + (to.g - from.g) * p.progress; |
var b = from.b + (to.b - from.b) * p.progress; |
return 'rgb('+parseInt(r,10)+','+parseInt(g,10)+','+parseInt(b,10)+')'; |
} |
return this.attribute('from').value; |
}; |
} |
svg.Element.animateColor.prototype = new svg.Element.AnimateBase; |
|
// animate transform element |
svg.Element.animateTransform = function(node) { |
this.base = svg.Element.AnimateBase; |
this.base(node); |
|
this.calcValue = function() { |
var p = this.progress(); |
|
// tween value linearly |
var from = svg.ToNumberArray(p.from.value); |
var to = svg.ToNumberArray(p.to.value); |
var newValue = ''; |
for (var i=0; i<from.length; i++) { |
newValue += from[i] + (to[i] - from[i]) * p.progress + ' '; |
} |
return newValue; |
}; |
} |
svg.Element.animateTransform.prototype = new svg.Element.animate; |
|
// font element |
svg.Element.font = function(node) { |
this.base = svg.Element.ElementBase; |
this.base(node); |
|
this.horizAdvX = this.attribute('horiz-adv-x').numValue(); |
|
this.isRTL = false; |
this.isArabic = false; |
this.fontFace = null; |
this.missingGlyph = null; |
this.glyphs = []; |
for (var i=0; i<this.children.length; i++) { |
var child = this.children[i]; |
if (child.type == 'font-face') { |
this.fontFace = child; |
if (child.style('font-family').hasValue()) { |
svg.Definitions[child.style('font-family').value] = this; |
} |
} |
else if (child.type == 'missing-glyph') this.missingGlyph = child; |
else if (child.type == 'glyph') { |
if (child.arabicForm != '') { |
this.isRTL = true; |
this.isArabic = true; |
if (typeof(this.glyphs[child.unicode]) == 'undefined') this.glyphs[child.unicode] = []; |
this.glyphs[child.unicode][child.arabicForm] = child; |
} |
else { |
this.glyphs[child.unicode] = child; |
} |
} |
} |
} |
svg.Element.font.prototype = new svg.Element.ElementBase; |
|
// font-face element |
svg.Element.fontface = function(node) { |
this.base = svg.Element.ElementBase; |
this.base(node); |
|
this.ascent = this.attribute('ascent').value; |
this.descent = this.attribute('descent').value; |
this.unitsPerEm = this.attribute('units-per-em').numValue(); |
} |
svg.Element.fontface.prototype = new svg.Element.ElementBase; |
|
// missing-glyph element |
svg.Element.missingglyph = function(node) { |
this.base = svg.Element.path; |
this.base(node); |
|
this.horizAdvX = 0; |
} |
svg.Element.missingglyph.prototype = new svg.Element.path; |
|
// glyph element |
svg.Element.glyph = function(node) { |
this.base = svg.Element.path; |
this.base(node); |
|
this.horizAdvX = this.attribute('horiz-adv-x').numValue(); |
this.unicode = this.attribute('unicode').value; |
this.arabicForm = this.attribute('arabic-form').value; |
} |
svg.Element.glyph.prototype = new svg.Element.path; |
|
// text element |
svg.Element.text = function(node) { |
this.captureTextNodes = true; |
this.base = svg.Element.RenderedElementBase; |
this.base(node); |
|
this.baseSetContext = this.setContext; |
this.setContext = function(ctx) { |
this.baseSetContext(ctx); |
|
var textBaseline = this.style('dominant-baseline').toTextBaseline(); |
if (textBaseline == null) textBaseline = this.style('alignment-baseline').toTextBaseline(); |
if (textBaseline != null) ctx.textBaseline = textBaseline; |
} |
|
this.getBoundingBox = function () { |
var x = this.attribute('x').toPixels('x'); |
var y = this.attribute('y').toPixels('y'); |
var fontSize = this.parent.style('font-size').numValueOrDefault(svg.Font.Parse(svg.ctx.font).fontSize); |
return new svg.BoundingBox(x, y - fontSize, x + Math.floor(fontSize * 2.0 / 3.0) * this.children[0].getText().length, y); |
} |
|
this.renderChildren = function(ctx) { |
this.x = this.attribute('x').toPixels('x'); |
this.y = this.attribute('y').toPixels('y'); |
if (this.attribute('dx').hasValue()) this.x += this.attribute('dx').toPixels('x'); |
if (this.attribute('dy').hasValue()) this.y += this.attribute('dy').toPixels('y'); |
this.x += this.getAnchorDelta(ctx, this, 0); |
for (var i=0; i<this.children.length; i++) { |
this.renderChild(ctx, this, i); |
} |
} |
|
this.getAnchorDelta = function (ctx, parent, startI) { |
var textAnchor = this.style('text-anchor').valueOrDefault('start'); |
if (textAnchor != 'start') { |
var width = 0; |
for (var i=startI; i<parent.children.length; i++) { |
var child = parent.children[i]; |
if (i > startI && child.attribute('x').hasValue()) break; // new group |
width += child.measureTextRecursive(ctx); |
} |
return -1 * (textAnchor == 'end' ? width : width / 2.0); |
} |
return 0; |
} |
|
this.renderChild = function(ctx, parent, i) { |
var child = parent.children[i]; |
if (child.attribute('x').hasValue()) { |
child.x = child.attribute('x').toPixels('x') + parent.getAnchorDelta(ctx, parent, i); |
if (child.attribute('dx').hasValue()) child.x += child.attribute('dx').toPixels('x'); |
} |
else { |
if (child.attribute('dx').hasValue()) parent.x += child.attribute('dx').toPixels('x'); |
child.x = parent.x; |
} |
parent.x = child.x + child.measureText(ctx); |
|
if (child.attribute('y').hasValue()) { |
child.y = child.attribute('y').toPixels('y'); |
if (child.attribute('dy').hasValue()) child.y += child.attribute('dy').toPixels('y'); |
} |
else { |
if (child.attribute('dy').hasValue()) parent.y += child.attribute('dy').toPixels('y'); |
child.y = parent.y; |
} |
parent.y = child.y; |
|
child.render(ctx); |
|
for (var i=0; i<child.children.length; i++) { |
parent.renderChild(ctx, child, i); |
} |
} |
} |
svg.Element.text.prototype = new svg.Element.RenderedElementBase; |
|
// text base |
svg.Element.TextElementBase = function(node) { |
this.base = svg.Element.RenderedElementBase; |
this.base(node); |
|
this.getGlyph = function(font, text, i) { |
var c = text[i]; |
var glyph = null; |
if (font.isArabic) { |
var arabicForm = 'isolated'; |
if ((i==0 || text[i-1]==' ') && i<text.length-2 && text[i+1]!=' ') arabicForm = 'terminal'; |
if (i>0 && text[i-1]!=' ' && i<text.length-2 && text[i+1]!=' ') arabicForm = 'medial'; |
if (i>0 && text[i-1]!=' ' && (i == text.length-1 || text[i+1]==' ')) arabicForm = 'initial'; |
if (typeof(font.glyphs[c]) != 'undefined') { |
glyph = font.glyphs[c][arabicForm]; |
if (glyph == null && font.glyphs[c].type == 'glyph') glyph = font.glyphs[c]; |
} |
} |
else { |
glyph = font.glyphs[c]; |
} |
if (glyph == null) glyph = font.missingGlyph; |
return glyph; |
} |
|
this.renderChildren = function(ctx) { |
var customFont = this.parent.style('font-family').getDefinition(); |
if (customFont != null) { |
var fontSize = this.parent.style('font-size').numValueOrDefault(svg.Font.Parse(svg.ctx.font).fontSize); |
var fontStyle = this.parent.style('font-style').valueOrDefault(svg.Font.Parse(svg.ctx.font).fontStyle); |
var text = this.getText(); |
if (customFont.isRTL) text = text.split("").reverse().join(""); |
|
var dx = svg.ToNumberArray(this.parent.attribute('dx').value); |
for (var i=0; i<text.length; i++) { |
var glyph = this.getGlyph(customFont, text, i); |
var scale = fontSize / customFont.fontFace.unitsPerEm; |
ctx.translate(this.x, this.y); |
ctx.scale(scale, -scale); |
var lw = ctx.lineWidth; |
ctx.lineWidth = ctx.lineWidth * customFont.fontFace.unitsPerEm / fontSize; |
if (fontStyle == 'italic') ctx.transform(1, 0, .4, 1, 0, 0); |
glyph.render(ctx); |
if (fontStyle == 'italic') ctx.transform(1, 0, -.4, 1, 0, 0); |
ctx.lineWidth = lw; |
ctx.scale(1/scale, -1/scale); |
ctx.translate(-this.x, -this.y); |
|
this.x += fontSize * (glyph.horizAdvX || customFont.horizAdvX) / customFont.fontFace.unitsPerEm; |
if (typeof(dx[i]) != 'undefined' && !isNaN(dx[i])) { |
this.x += dx[i]; |
} |
} |
return; |
} |
|
if (ctx.fillStyle != '') ctx.fillText(svg.compressSpaces(this.getText()), this.x, this.y); |
if (ctx.strokeStyle != '') ctx.strokeText(svg.compressSpaces(this.getText()), this.x, this.y); |
} |
|
this.getText = function() { |
// OVERRIDE ME |
} |
|
this.measureTextRecursive = function(ctx) { |
var width = this.measureText(ctx); |
for (var i=0; i<this.children.length; i++) { |
width += this.children[i].measureTextRecursive(ctx); |
} |
return width; |
} |
|
this.measureText = function(ctx) { |
var customFont = this.parent.style('font-family').getDefinition(); |
if (customFont != null) { |
var fontSize = this.parent.style('font-size').numValueOrDefault(svg.Font.Parse(svg.ctx.font).fontSize); |
var measure = 0; |
var text = this.getText(); |
if (customFont.isRTL) text = text.split("").reverse().join(""); |
var dx = svg.ToNumberArray(this.parent.attribute('dx').value); |
for (var i=0; i<text.length; i++) { |
var glyph = this.getGlyph(customFont, text, i); |
measure += (glyph.horizAdvX || customFont.horizAdvX) * fontSize / customFont.fontFace.unitsPerEm; |
if (typeof(dx[i]) != 'undefined' && !isNaN(dx[i])) { |
measure += dx[i]; |
} |
} |
return measure; |
} |
|
var textToMeasure = svg.compressSpaces(this.getText()); |
if (!ctx.measureText) return textToMeasure.length * 10; |
|
ctx.save(); |
this.setContext(ctx); |
var width = ctx.measureText(textToMeasure).width; |
ctx.restore(); |
return width; |
} |
} |
svg.Element.TextElementBase.prototype = new svg.Element.RenderedElementBase; |
|
// tspan |
svg.Element.tspan = function(node) { |
this.captureTextNodes = true; |
this.base = svg.Element.TextElementBase; |
this.base(node); |
|
this.text = svg.compressSpaces(node.value || node.text || node.textContent || ''); |
this.getText = function() { |
// if this node has children, then they own the text |
if (this.children.length > 0) { return ''; } |
return this.text; |
} |
} |
svg.Element.tspan.prototype = new svg.Element.TextElementBase; |
|
// tref |
svg.Element.tref = function(node) { |
this.base = svg.Element.TextElementBase; |
this.base(node); |
|
this.getText = function() { |
var element = this.getHrefAttribute().getDefinition(); |
if (element != null) return element.children[0].getText(); |
} |
} |
svg.Element.tref.prototype = new svg.Element.TextElementBase; |
|
// a element |
svg.Element.a = function(node) { |
this.base = svg.Element.TextElementBase; |
this.base(node); |
|
this.hasText = node.childNodes.length > 0; |
for (var i=0; i<node.childNodes.length; i++) { |
if (node.childNodes[i].nodeType != 3) this.hasText = false; |
} |
|
// this might contain text |
this.text = this.hasText ? node.childNodes[0].value : ''; |
this.getText = function() { |
return this.text; |
} |
|
this.baseRenderChildren = this.renderChildren; |
this.renderChildren = function(ctx) { |
if (this.hasText) { |
// render as text element |
this.baseRenderChildren(ctx); |
var fontSize = new svg.Property('fontSize', svg.Font.Parse(svg.ctx.font).fontSize); |
svg.Mouse.checkBoundingBox(this, new svg.BoundingBox(this.x, this.y - fontSize.toPixels('y'), this.x + this.measureText(ctx), this.y)); |
} |
else if (this.children.length > 0) { |
// render as temporary group |
var g = new svg.Element.g(); |
g.children = this.children; |
g.parent = this; |
g.render(ctx); |
} |
} |
|
this.onclick = function() { |
window.open(this.getHrefAttribute().value); |
} |
|
this.onmousemove = function() { |
svg.ctx.canvas.style.cursor = 'pointer'; |
} |
} |
svg.Element.a.prototype = new svg.Element.TextElementBase; |
|
// image element |
svg.Element.image = function(node) { |
this.base = svg.Element.RenderedElementBase; |
this.base(node); |
|
var href = this.getHrefAttribute().value; |
if (href == '') { return; } |
var isSvg = href.match(/\.svg$/) |
|
svg.Images.push(this); |
this.loaded = false; |
if (!isSvg) { |
this.img = document.createElement('img'); |
if (svg.opts['useCORS'] == true) { this.img.crossOrigin = 'Anonymous'; } |
var self = this; |
this.img.onload = function() { self.loaded = true; } |
this.img.onerror = function() { svg.log('ERROR: image "' + href + '" not found'); self.loaded = true; } |
this.img.src = href; |
} |
else { |
this.img = svg.ajax(href); |
this.loaded = true; |
} |
|
this.renderChildren = function(ctx) { |
var x = this.attribute('x').toPixels('x'); |
var y = this.attribute('y').toPixels('y'); |
|
var width = this.attribute('width').toPixels('x'); |
var height = this.attribute('height').toPixels('y'); |
if (width == 0 || height == 0) return; |
|
ctx.save(); |
if (isSvg) { |
ctx.drawSvg(this.img, x, y, width, height); |
} |
else { |
ctx.translate(x, y); |
svg.AspectRatio(ctx, |
this.attribute('preserveAspectRatio').value, |
width, |
this.img.width, |
height, |
this.img.height, |
0, |
0); |
ctx.drawImage(this.img, 0, 0); |
} |
ctx.restore(); |
} |
|
this.getBoundingBox = function() { |
var x = this.attribute('x').toPixels('x'); |
var y = this.attribute('y').toPixels('y'); |
var width = this.attribute('width').toPixels('x'); |
var height = this.attribute('height').toPixels('y'); |
return new svg.BoundingBox(x, y, x + width, y + height); |
} |
} |
svg.Element.image.prototype = new svg.Element.RenderedElementBase; |
|
// group element |
svg.Element.g = function(node) { |
this.base = svg.Element.RenderedElementBase; |
this.base(node); |
|
this.getBoundingBox = function() { |
var bb = new svg.BoundingBox(); |
for (var i=0; i<this.children.length; i++) { |
bb.addBoundingBox(this.children[i].getBoundingBox()); |
} |
return bb; |
}; |
} |
svg.Element.g.prototype = new svg.Element.RenderedElementBase; |
|
// symbol element |
svg.Element.symbol = function(node) { |
this.base = svg.Element.RenderedElementBase; |
this.base(node); |
|
this.render = function(ctx) { |
// NO RENDER |
}; |
} |
svg.Element.symbol.prototype = new svg.Element.RenderedElementBase; |
|
// style element |
svg.Element.style = function(node) { |
this.base = svg.Element.ElementBase; |
this.base(node); |
|
// text, or spaces then CDATA |
var css = '' |
for (var i=0; i<node.childNodes.length; i++) { |
css += node.childNodes[i].data; |
} |
css = css.replace(/(\/\*([^*]|[\r\n]|(\*+([^*\/]|[\r\n])))*\*+\/)|(^[\s]*\/\/.*)/gm, ''); // remove comments |
css = svg.compressSpaces(css); // replace whitespace |
var cssDefs = css.split('}'); |
for (var i=0; i<cssDefs.length; i++) { |
if (svg.trim(cssDefs[i]) != '') { |
var cssDef = cssDefs[i].split('{'); |
var cssClasses = cssDef[0].split(','); |
var cssProps = cssDef[1].split(';'); |
for (var j=0; j<cssClasses.length; j++) { |
var cssClass = svg.trim(cssClasses[j]); |
if (cssClass != '') { |
var props = svg.Styles[cssClass] || {}; |
for (var k=0; k<cssProps.length; k++) { |
var prop = cssProps[k].indexOf(':'); |
var name = cssProps[k].substr(0, prop); |
var value = cssProps[k].substr(prop + 1, cssProps[k].length - prop); |
if (name != null && value != null) { |
props[svg.trim(name)] = new svg.Property(svg.trim(name), svg.trim(value)); |
} |
} |
svg.Styles[cssClass] = props; |
svg.StylesSpecificity[cssClass] = getSelectorSpecificity(cssClass); |
if (cssClass == '@font-face') { |
var fontFamily = props['font-family'].value.replace(/"/g,''); |
var srcs = props['src'].value.split(','); |
for (var s=0; s<srcs.length; s++) { |
if (srcs[s].indexOf('format("svg")') > 0) { |
var urlStart = srcs[s].indexOf('url'); |
var urlEnd = srcs[s].indexOf(')', urlStart); |
var url = srcs[s].substr(urlStart + 5, urlEnd - urlStart - 6); |
var doc = svg.parseXml(svg.ajax(url)); |
var fonts = doc.getElementsByTagName('font'); |
for (var f=0; f<fonts.length; f++) { |
var font = svg.CreateElement(fonts[f]); |
svg.Definitions[fontFamily] = font; |
} |
} |
} |
} |
} |
} |
} |
} |
} |
svg.Element.style.prototype = new svg.Element.ElementBase; |
|
// use element |
svg.Element.use = function(node) { |
this.base = svg.Element.RenderedElementBase; |
this.base(node); |
|
this.baseSetContext = this.setContext; |
this.setContext = function(ctx) { |
this.baseSetContext(ctx); |
if (this.attribute('x').hasValue()) ctx.translate(this.attribute('x').toPixels('x'), 0); |
if (this.attribute('y').hasValue()) ctx.translate(0, this.attribute('y').toPixels('y')); |
} |
|
var element = this.getHrefAttribute().getDefinition(); |
|
this.path = function(ctx) { |
if (element != null) element.path(ctx); |
} |
|
this.getBoundingBox = function() { |
if (element != null) return element.getBoundingBox(); |
} |
|
this.renderChildren = function(ctx) { |
if (element != null) { |
var tempSvg = element; |
if (element.type == 'symbol') { |
// render me using a temporary svg element in symbol cases (http://www.w3.org/TR/SVG/struct.html#UseElement) |
tempSvg = new svg.Element.svg(); |
tempSvg.type = 'svg'; |
tempSvg.attributes['viewBox'] = new svg.Property('viewBox', element.attribute('viewBox').value); |
tempSvg.attributes['preserveAspectRatio'] = new svg.Property('preserveAspectRatio', element.attribute('preserveAspectRatio').value); |
tempSvg.attributes['overflow'] = new svg.Property('overflow', element.attribute('overflow').value); |
tempSvg.children = element.children; |
} |
if (tempSvg.type == 'svg') { |
// if symbol or svg, inherit width/height from me |
if (this.attribute('width').hasValue()) tempSvg.attributes['width'] = new svg.Property('width', this.attribute('width').value); |
if (this.attribute('height').hasValue()) tempSvg.attributes['height'] = new svg.Property('height', this.attribute('height').value); |
} |
var oldParent = tempSvg.parent; |
tempSvg.parent = null; |
tempSvg.render(ctx); |
tempSvg.parent = oldParent; |
} |
} |
} |
svg.Element.use.prototype = new svg.Element.RenderedElementBase; |
|
// mask element |
svg.Element.mask = function(node) { |
this.base = svg.Element.ElementBase; |
this.base(node); |
|
this.apply = function(ctx, element) { |
// render as temp svg |
var x = this.attribute('x').toPixels('x'); |
var y = this.attribute('y').toPixels('y'); |
var width = this.attribute('width').toPixels('x'); |
var height = this.attribute('height').toPixels('y'); |
|
if (width == 0 && height == 0) { |
var bb = new svg.BoundingBox(); |
for (var i=0; i<this.children.length; i++) { |
bb.addBoundingBox(this.children[i].getBoundingBox()); |
} |
var x = Math.floor(bb.x1); |
var y = Math.floor(bb.y1); |
var width = Math.floor(bb.width()); |
var height = Math.floor(bb.height()); |
} |
|
// temporarily remove mask to avoid recursion |
var mask = element.attribute('mask').value; |
element.attribute('mask').value = ''; |
|
var cMask = document.createElement('canvas'); |
cMask.width = x + width; |
cMask.height = y + height; |
var maskCtx = cMask.getContext('2d'); |
this.renderChildren(maskCtx); |
|
var c = document.createElement('canvas'); |
c.width = x + width; |
c.height = y + height; |
var tempCtx = c.getContext('2d'); |
element.render(tempCtx); |
tempCtx.globalCompositeOperation = 'destination-in'; |
tempCtx.fillStyle = maskCtx.createPattern(cMask, 'no-repeat'); |
tempCtx.fillRect(0, 0, x + width, y + height); |
|
ctx.fillStyle = tempCtx.createPattern(c, 'no-repeat'); |
ctx.fillRect(0, 0, x + width, y + height); |
|
// reassign mask |
element.attribute('mask').value = mask; |
} |
|
this.render = function(ctx) { |
// NO RENDER |
} |
} |
svg.Element.mask.prototype = new svg.Element.ElementBase; |
|
// clip element |
svg.Element.clipPath = function(node) { |
this.base = svg.Element.ElementBase; |
this.base(node); |
|
this.apply = function(ctx) { |
var oldBeginPath = CanvasRenderingContext2D.prototype.beginPath; |
CanvasRenderingContext2D.prototype.beginPath = function () { }; |
|
var oldClosePath = CanvasRenderingContext2D.prototype.closePath; |
CanvasRenderingContext2D.prototype.closePath = function () { }; |
|
oldBeginPath.call(ctx); |
for (var i=0; i<this.children.length; i++) { |
var child = this.children[i]; |
if (typeof(child.path) != 'undefined') { |
var transform = null; |
if (child.style('transform', false, true).hasValue()) { |
transform = new svg.Transform(child.style('transform', false, true).value); |
transform.apply(ctx); |
} |
child.path(ctx); |
CanvasRenderingContext2D.prototype.closePath = oldClosePath; |
if (transform) { transform.unapply(ctx); } |
} |
} |
oldClosePath.call(ctx); |
ctx.clip(); |
|
CanvasRenderingContext2D.prototype.beginPath = oldBeginPath; |
CanvasRenderingContext2D.prototype.closePath = oldClosePath; |
} |
|
this.render = function(ctx) { |
// NO RENDER |
} |
} |
svg.Element.clipPath.prototype = new svg.Element.ElementBase; |
|
// filters |
svg.Element.filter = function(node) { |
this.base = svg.Element.ElementBase; |
this.base(node); |
|
this.apply = function(ctx, element) { |
// render as temp svg |
var bb = element.getBoundingBox(); |
var x = Math.floor(bb.x1); |
var y = Math.floor(bb.y1); |
var width = Math.floor(bb.width()); |
var height = Math.floor(bb.height()); |
|
// temporarily remove filter to avoid recursion |
var filter = element.style('filter').value; |
element.style('filter').value = ''; |
|
var px = 0, py = 0; |
for (var i=0; i<this.children.length; i++) { |
var efd = this.children[i].extraFilterDistance || 0; |
px = Math.max(px, efd); |
py = Math.max(py, efd); |
} |
|
var c = document.createElement('canvas'); |
c.width = width + 2*px; |
c.height = height + 2*py; |
var tempCtx = c.getContext('2d'); |
tempCtx.translate(-x + px, -y + py); |
element.render(tempCtx); |
|
// apply filters |
for (var i=0; i<this.children.length; i++) { |
if (typeof(this.children[i].apply) === 'function') { |
this.children[i].apply(tempCtx, 0, 0, width + 2*px, height + 2*py); |
} |
} |
|
// render on me |
ctx.drawImage(c, 0, 0, width + 2*px, height + 2*py, x - px, y - py, width + 2*px, height + 2*py); |
|
// reassign filter |
element.style('filter', true).value = filter; |
} |
|
this.render = function(ctx) { |
// NO RENDER |
} |
} |
svg.Element.filter.prototype = new svg.Element.ElementBase; |
|
svg.Element.feMorphology = function(node) { |
this.base = svg.Element.ElementBase; |
this.base(node); |
|
this.apply = function(ctx, x, y, width, height) { |
// TODO: implement |
} |
} |
svg.Element.feMorphology.prototype = new svg.Element.ElementBase; |
|
svg.Element.feComposite = function(node) { |
this.base = svg.Element.ElementBase; |
this.base(node); |
|
this.apply = function(ctx, x, y, width, height) { |
// TODO: implement |
} |
} |
svg.Element.feComposite.prototype = new svg.Element.ElementBase; |
|
svg.Element.feColorMatrix = function(node) { |
this.base = svg.Element.ElementBase; |
this.base(node); |
|
var matrix = svg.ToNumberArray(this.attribute('values').value); |
switch (this.attribute('type').valueOrDefault('matrix')) { // http://www.w3.org/TR/SVG/filters.html#feColorMatrixElement |
case 'saturate': |
var s = matrix[0]; |
matrix = [0.213+0.787*s,0.715-0.715*s,0.072-0.072*s,0,0, |
0.213-0.213*s,0.715+0.285*s,0.072-0.072*s,0,0, |
0.213-0.213*s,0.715-0.715*s,0.072+0.928*s,0,0, |
0,0,0,1,0, |
0,0,0,0,1]; |
break; |
case 'hueRotate': |
var a = matrix[0] * Math.PI / 180.0; |
var c = function (m1,m2,m3) { return m1 + Math.cos(a)*m2 + Math.sin(a)*m3; }; |
matrix = [c(0.213,0.787,-0.213),c(0.715,-0.715,-0.715),c(0.072,-0.072,0.928),0,0, |
c(0.213,-0.213,0.143),c(0.715,0.285,0.140),c(0.072,-0.072,-0.283),0,0, |
c(0.213,-0.213,-0.787),c(0.715,-0.715,0.715),c(0.072,0.928,0.072),0,0, |
0,0,0,1,0, |
0,0,0,0,1]; |
break; |
case 'luminanceToAlpha': |
matrix = [0,0,0,0,0, |
0,0,0,0,0, |
0,0,0,0,0, |
0.2125,0.7154,0.0721,0,0, |
0,0,0,0,1]; |
break; |
} |
|
function imGet(img, x, y, width, height, rgba) { |
return img[y*width*4 + x*4 + rgba]; |
} |
|
function imSet(img, x, y, width, height, rgba, val) { |
img[y*width*4 + x*4 + rgba] = val; |
} |
|
function m(i, v) { |
var mi = matrix[i]; |
return mi * (mi < 0 ? v - 255 : v); |
} |
|
this.apply = function(ctx, x, y, width, height) { |
// assuming x==0 && y==0 for now |
var srcData = ctx.getImageData(0, 0, width, height); |
for (var y = 0; y < height; y++) { |
for (var x = 0; x < width; x++) { |
var r = imGet(srcData.data, x, y, width, height, 0); |
var g = imGet(srcData.data, x, y, width, height, 1); |
var b = imGet(srcData.data, x, y, width, height, 2); |
var a = imGet(srcData.data, x, y, width, height, 3); |
imSet(srcData.data, x, y, width, height, 0, m(0,r)+m(1,g)+m(2,b)+m(3,a)+m(4,1)); |
imSet(srcData.data, x, y, width, height, 1, m(5,r)+m(6,g)+m(7,b)+m(8,a)+m(9,1)); |
imSet(srcData.data, x, y, width, height, 2, m(10,r)+m(11,g)+m(12,b)+m(13,a)+m(14,1)); |
imSet(srcData.data, x, y, width, height, 3, m(15,r)+m(16,g)+m(17,b)+m(18,a)+m(19,1)); |
} |
} |
ctx.clearRect(0, 0, width, height); |
ctx.putImageData(srcData, 0, 0); |
} |
} |
svg.Element.feColorMatrix.prototype = new svg.Element.ElementBase; |
|
svg.Element.feGaussianBlur = function(node) { |
this.base = svg.Element.ElementBase; |
this.base(node); |
|
this.blurRadius = Math.floor(this.attribute('stdDeviation').numValue()); |
this.extraFilterDistance = this.blurRadius; |
|
this.apply = function(ctx, x, y, width, height) { |
if (typeof(stackBlur.canvasRGBA) == 'undefined') { |
svg.log('ERROR: StackBlur.js must be included for blur to work'); |
return; |
} |
|
// StackBlur requires canvas be on document |
ctx.canvas.id = svg.UniqueId(); |
ctx.canvas.style.display = 'none'; |
document.body.appendChild(ctx.canvas); |
stackBlur.canvasRGBA(ctx.canvas.id, x, y, width, height, this.blurRadius); |
document.body.removeChild(ctx.canvas); |
} |
} |
svg.Element.feGaussianBlur.prototype = new svg.Element.ElementBase; |
|
// title element, do nothing |
svg.Element.title = function(node) { |
} |
svg.Element.title.prototype = new svg.Element.ElementBase; |
|
// desc element, do nothing |
svg.Element.desc = function(node) { |
} |
svg.Element.desc.prototype = new svg.Element.ElementBase; |
|
svg.Element.MISSING = function(node) { |
svg.log('ERROR: Element \'' + node.nodeName + '\' not yet implemented.'); |
} |
svg.Element.MISSING.prototype = new svg.Element.ElementBase; |
|
// element factory |
svg.CreateElement = function(node) { |
var className = node.nodeName.replace(/^[^:]+:/,''); // remove namespace |
className = className.replace(/\-/g,''); // remove dashes |
var e = null; |
if (typeof(svg.Element[className]) != 'undefined') { |
e = new svg.Element[className](node); |
} |
else { |
e = new svg.Element.MISSING(node); |
} |
|
e.type = node.nodeName; |
return e; |
} |
|
// load from url |
svg.load = function(ctx, url) { |
svg.loadXml(ctx, svg.ajax(url)); |
} |
|
// load from xml |
svg.loadXml = function(ctx, xml) { |
svg.loadXmlDoc(ctx, svg.parseXml(xml)); |
} |
|
svg.loadXmlDoc = function(ctx, dom) { |
svg.init(ctx); |
|
var mapXY = function(p) { |
var e = ctx.canvas; |
while (e) { |
p.x -= e.offsetLeft; |
p.y -= e.offsetTop; |
e = e.offsetParent; |
} |
if (window.scrollX) p.x += window.scrollX; |
if (window.scrollY) p.y += window.scrollY; |
return p; |
} |
|
// bind mouse |
if (svg.opts['ignoreMouse'] != true) { |
ctx.canvas.onclick = function(e) { |
var p = mapXY(new svg.Point(e != null ? e.clientX : event.clientX, e != null ? e.clientY : event.clientY)); |
svg.Mouse.onclick(p.x, p.y); |
}; |
ctx.canvas.onmousemove = function(e) { |
var p = mapXY(new svg.Point(e != null ? e.clientX : event.clientX, e != null ? e.clientY : event.clientY)); |
svg.Mouse.onmousemove(p.x, p.y); |
}; |
} |
|
var e = svg.CreateElement(dom.documentElement); |
e.root = true; |
e.addStylesFromStyleDefinition(); |
|
// render loop |
var isFirstRender = true; |
var draw = function() { |
svg.ViewPort.Clear(); |
if (ctx.canvas.parentNode) svg.ViewPort.SetCurrent(ctx.canvas.parentNode.clientWidth, ctx.canvas.parentNode.clientHeight); |
|
if (svg.opts['ignoreDimensions'] != true) { |
// set canvas size |
if (e.style('width').hasValue()) { |
ctx.canvas.width = e.style('width').toPixels('x'); |
ctx.canvas.style.width = ctx.canvas.width + 'px'; |
} |
if (e.style('height').hasValue()) { |
ctx.canvas.height = e.style('height').toPixels('y'); |
ctx.canvas.style.height = ctx.canvas.height + 'px'; |
} |
} |
var cWidth = ctx.canvas.clientWidth || ctx.canvas.width; |
var cHeight = ctx.canvas.clientHeight || ctx.canvas.height; |
if (svg.opts['ignoreDimensions'] == true && e.style('width').hasValue() && e.style('height').hasValue()) { |
cWidth = e.style('width').toPixels('x'); |
cHeight = e.style('height').toPixels('y'); |
} |
svg.ViewPort.SetCurrent(cWidth, cHeight); |
|
if (svg.opts['offsetX'] != null) e.attribute('x', true).value = svg.opts['offsetX']; |
if (svg.opts['offsetY'] != null) e.attribute('y', true).value = svg.opts['offsetY']; |
if (svg.opts['scaleWidth'] != null || svg.opts['scaleHeight'] != null) { |
var xRatio = null, yRatio = null, viewBox = svg.ToNumberArray(e.attribute('viewBox').value); |
|
if (svg.opts['scaleWidth'] != null) { |
if (e.attribute('width').hasValue()) xRatio = e.attribute('width').toPixels('x') / svg.opts['scaleWidth']; |
else if (!isNaN(viewBox[2])) xRatio = viewBox[2] / svg.opts['scaleWidth']; |
} |
|
if (svg.opts['scaleHeight'] != null) { |
if (e.attribute('height').hasValue()) yRatio = e.attribute('height').toPixels('y') / svg.opts['scaleHeight']; |
else if (!isNaN(viewBox[3])) yRatio = viewBox[3] / svg.opts['scaleHeight']; |
} |
|
if (xRatio == null) { xRatio = yRatio; } |
if (yRatio == null) { yRatio = xRatio; } |
|
e.attribute('width', true).value = svg.opts['scaleWidth']; |
e.attribute('height', true).value = svg.opts['scaleHeight']; |
e.style('transform', true, true).value += ' scale('+(1.0/xRatio)+','+(1.0/yRatio)+')'; |
} |
|
// clear and render |
if (svg.opts['ignoreClear'] != true) { |
ctx.clearRect(0, 0, cWidth, cHeight); |
} |
e.render(ctx); |
if (isFirstRender) { |
isFirstRender = false; |
if (typeof(svg.opts['renderCallback']) == 'function') svg.opts['renderCallback'](dom); |
} |
} |
|
var waitingForImages = true; |
if (svg.ImagesLoaded()) { |
waitingForImages = false; |
draw(); |
} |
svg.intervalID = setInterval(function() { |
var needUpdate = false; |
|
if (waitingForImages && svg.ImagesLoaded()) { |
waitingForImages = false; |
needUpdate = true; |
} |
|
// need update from mouse events? |
if (svg.opts['ignoreMouse'] != true) { |
needUpdate = needUpdate | svg.Mouse.hasEvents(); |
} |
|
// need update from animations? |
if (svg.opts['ignoreAnimation'] != true) { |
for (var i=0; i<svg.Animations.length; i++) { |
needUpdate = needUpdate | svg.Animations[i].update(1000 / svg.FRAMERATE); |
} |
} |
|
// need update from redraw? |
if (typeof(svg.opts['forceRedraw']) == 'function') { |
if (svg.opts['forceRedraw']() == true) needUpdate = true; |
} |
|
// render if needed |
if (needUpdate) { |
draw(); |
svg.Mouse.runEvents(); // run and clear our events |
} |
}, 1000 / svg.FRAMERATE); |
} |
|
svg.stop = function() { |
if (svg.intervalID) { |
clearInterval(svg.intervalID); |
} |
} |
|
svg.Mouse = new (function() { |
this.events = []; |
this.hasEvents = function() { return this.events.length != 0; } |
|
this.onclick = function(x, y) { |
this.events.push({ type: 'onclick', x: x, y: y, |
run: function(e) { if (e.onclick) e.onclick(); } |
}); |
} |
|
this.onmousemove = function(x, y) { |
this.events.push({ type: 'onmousemove', x: x, y: y, |
run: function(e) { if (e.onmousemove) e.onmousemove(); } |
}); |
} |
|
this.eventElements = []; |
|
this.checkPath = function(element, ctx) { |
for (var i=0; i<this.events.length; i++) { |
var e = this.events[i]; |
if (ctx.isPointInPath && ctx.isPointInPath(e.x, e.y)) this.eventElements[i] = element; |
} |
} |
|
this.checkBoundingBox = function(element, bb) { |
for (var i=0; i<this.events.length; i++) { |
var e = this.events[i]; |
if (bb.isPointInBox(e.x, e.y)) this.eventElements[i] = element; |
} |
} |
|
this.runEvents = function() { |
svg.ctx.canvas.style.cursor = ''; |
|
for (var i=0; i<this.events.length; i++) { |
var e = this.events[i]; |
var element = this.eventElements[i]; |
while (element) { |
e.run(element); |
element = element.parent; |
} |
} |
|
// done running, clear |
this.events = []; |
this.eventElements = []; |
} |
}); |
|
return svg; |
}; |
|
if (typeof(CanvasRenderingContext2D) != 'undefined') { |
CanvasRenderingContext2D.prototype.drawSvg = function(s, dx, dy, dw, dh) { |
canvg(this.canvas, s, { |
ignoreMouse: true, |
ignoreAnimation: true, |
ignoreDimensions: true, |
ignoreClear: true, |
offsetX: dx, |
offsetY: dy, |
scaleWidth: dw, |
scaleHeight: dh |
}); |
} |
} |
|
return canvg; |
|
})); |
/base/000_base/node_modules/highcharts/lib/jspdf.js |
@@ -0,0 +1,94 @@ |
/* |
|
jsPDF - PDF Document creation from JavaScript |
Version ${versionID} |
CommitID ${commitID} |
|
Copyright (c) 2010-2014 James Hall <james@parall.ax>, https://github.com/MrRio/jsPDF |
2010 Aaron Spike, https://github.com/acspike |
2012 Willow Systems Corporation, willow-systems.com |
2012 Pablo Hess, https://github.com/pablohess |
2012 Florian Jenett, https://github.com/fjenett |
2013 Warren Weckesser, https://github.com/warrenweckesser |
2013 Youssef Beddad, https://github.com/lifof |
2013 Lee Driscoll, https://github.com/lsdriscoll |
2013 Stefan Slonevskiy, https://github.com/stefslon |
2013 Jeremy Morel, https://github.com/jmorel |
2013 Christoph Hartmann, https://github.com/chris-rock |
2014 Juan Pablo Gaviria, https://github.com/juanpgaviria |
2014 James Makes, https://github.com/dollaruw |
2014 Diego Casorran, https://github.com/diegocr |
2014 Steven Spungin, https://github.com/Flamenco |
2014 Kenneth Glassey, https://github.com/Gavvers |
|
Permission is hereby granted, free of charge, to any person obtaining |
a copy of this software and associated documentation files (the |
"Software"), to deal in the Software without restriction, including |
without limitation the rights to use, copy, modify, merge, publish, |
distribute, sublicense, and/or sell copies of the Software, and to |
permit persons to whom the Software is furnished to do so, subject to |
the following conditions: |
|
The above copyright notice and this permission notice shall be |
included in all copies or substantial portions of the Software. |
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
|
Contributor(s): |
siefkenj, ahwolf, rickygu, Midnith, saintclair, eaparango, |
kim3er, mfo, alnorth, Flamenco |
*/ |
var jsPDF=function(t){function Pa(q){var A={};this.subscribe=function(F,q,w){if("function"!==typeof q)return!1;A.hasOwnProperty(F)||(A[F]={});var t=Math.random().toString(35);A[F][t]=[q,!!w];return t};this.unsubscribe=function(q){for(var t in A)if(A[t][q])return delete A[t][q],!0;return!1};this.publish=function(F){if(A.hasOwnProperty(F)){var Z=Array.prototype.slice.call(arguments,1),w=[],S;for(S in A[F]){var aa=A[F][S];try{aa[0].apply(q,Z)}catch(ca){t.console&&console.error("jsPDF PubSub Error",ca.message, |
ca)}aa[1]&&w.push(S)}w.length&&w.forEach(this.unsubscribe)}}}function q(V,A,F,Z){var w={};"object"===typeof V&&(w=V,V=w.orientation,A=w.unit||A,F=w.format||F,Z=w.compress||w.compressPdf||Z);A=A||"mm";F=F||"a4";V=(""+(V||"P")).toLowerCase();(""+F).toLowerCase();var S=!!Z&&"function"===typeof Uint8Array,aa=w.textColor||"0 g",ca=w.drawColor||"0 G",L=w.fontSize||16,oa=w.lineHeight||1.15,Qa=w.lineWidth||.200025,C=2,da=!1,N=[],r={},G={},D,Fa=[],u={},pa={},H={},qa={},Ga=null,E,z=0,I,m=[],J=[],B=[],ra=[], |
W=[],sa=0,ta=0,P=0,M={},ea={},fa=[],ga,ha,ia,X,Q,ua,O,ja,T={title:"",subject:"",author:"",keywords:"",creator:""},f={},v=new Pa(f),h=function(a){return a.toFixed(2)},k=function(a){return a.toFixed(3)},U=function(a){return("0"+parseInt(a)).slice(-2)},va=function(a){a="00"+a;return a.substr(a.length-2)},c=function(a){da?m[I].push(a):(P+=a.length+1,ra.push(a))},K=function(){C++;N[C]=P;c(C+" 0 obj");return C},ba=function(a){c("stream");c(a);c("endstream")},Ha=function(){c("/ProcSet [/PDF /Text /ImageB /ImageC /ImageI]"); |
c("/Font <<");for(var a in r)r.hasOwnProperty(a)&&c("/"+a+" "+r[a].objectNumber+" 0 R");c(">>");c("/Shading <<");for(var b in u)u.hasOwnProperty(b)&&u[b]instanceof f.ShadingPattern&&0<=u[b].objectNumber&&c("/"+b+" "+u[b].objectNumber+" 0 R");v.publish("putShadingPatternDict");c(">>");c("/Pattern <<");for(var g in u)u.hasOwnProperty(g)&&u[g]instanceof f.TilingPattern&&0<=u[g].objectNumber&&c("/"+g+" "+u[g].objectNumber+" 0 R");v.publish("putTilingPatternDict");c(">>");c("/ExtGState <<");for(var d in H)H.hasOwnProperty(d)&& |
0<=H[d].objectNumber&&c("/"+d+" "+H[d].objectNumber+" 0 R");v.publish("putGStateDict");c(">>");c("/XObject <<");for(var e in M)M.hasOwnProperty(e)&&0<=M[e].objectNumber&&c("/"+e+" "+M[e].objectNumber+" 0 R");v.publish("putXobjectDict");c(">>")},Ia=function(a,b,g,c){var e="F"+(Object.keys(r).length+1).toString(10);a=r[e]={id:e,PostScriptName:a,fontName:b,fontStyle:g,encoding:c,metadata:{}};G.hasOwnProperty(b)||(G[b]={});G[b][g]=e;v.publish("addFont",a);return e},wa=function(a,b){return new R(a.a*b.a+ |
a.b*b.c,a.a*b.b+a.b*b.d,a.c*b.a+a.d*b.c,a.c*b.b+a.d*b.d,a.e*b.a+a.f*b.c+b.e,a.e*b.b+a.f*b.d+b.f)},R=function(a,b,g,c,e,l){this.a=a;this.b=b;this.c=g;this.d=c;this.e=e;this.f=l};R.prototype={toString:function(){return[k(this.a),k(this.b),k(this.c),k(this.d),k(this.e),k(this.f)].join(" ")}};var ka=new R(1,0,0,1,0,0),la=function(){this.page=z;this.currentPage=I;this.pages=m.slice(0);this.pagedim=B.slice(0);this.pagesContext=J.slice(0);this.x=ga;this.y=ha;this.matrix=ia;this.width=X;this.height=Q;this.id= |
"";this.objectNumber=-1};la.prototype={restore:function(){z=this.page;I=this.currentPage;J=this.pagesContext;B=this.pagedim;m=this.pages;ga=this.x;ha=this.y;ia=this.matrix;X=this.width;Q=this.height}};var xa=function(a,b){if(!pa[a]){var g=(b instanceof f.ShadingPattern?"Sh":"P")+(Object.keys(u).length+1).toString(10);b.id=g;pa[a]=g;u[g]=b;v.publish("addPattern",b)}},Ja=function(a,b){if(!a||!qa[a]){var g=!1,c;for(c in H)if(H.hasOwnProperty(c)&&H[c].equals(b)){g=!0;break}g?b=H[c]:(g="GS"+(Object.keys(H).length+ |
1).toString(10),H[g]=b,b.id=g);a&&(qa[a]=b.id);v.publish("addGState",b);return b}},ya=function(a,b){var g,c,e,l,f,h;b=b||{};g=b.sourceEncoding||"Unicode";e=b.outputEncoding;if((b.autoencode||e)&&r[D].metadata&&r[D].metadata[g]&&r[D].metadata[g].encoding&&(g=r[D].metadata[g].encoding,!e&&r[D].encoding&&(e=r[D].encoding),!e&&g.codePages&&(e=g.codePages[0]),"string"===typeof e&&(e=g[e]),e)){f=!1;l=[];g=0;for(c=a.length;g<c;g++)(h=e[a.charCodeAt(g)])?l.push(String.fromCharCode(h)):l.push(a[g]),l[g].charCodeAt(0)>> |
8&&(f=!0);a=l.join("")}for(g=a.length;void 0===f&&0!==g;)a.charCodeAt(g-1)>>8&&(f=!0),g--;if(f){l=b.noBOM?[]:[254,255];g=0;for(c=a.length;g<c;g++){h=a.charCodeAt(g);f=h>>8;if(f>>8)throw Error("Character at position "+g+" of string '"+a+"' exceeds 16bits. Cannot be encoded into UCS-2 BE");l.push(f);l.push(h-(f<<8))}a=String.fromCharCode.apply(void 0,l)}return a.replace(/\\/g,"\\\\").replace(/\(/g,"\\(").replace(/\)/g,"\\)")},Aa=function(a,b){"string"===typeof b&&b.toLowerCase();if("string"===typeof a){var c= |
a.toLowerCase();za.hasOwnProperty(c)&&(a=za[c][0]/E,b=za[c][1]/E)}Array.isArray(a)&&(b=a[1],a=a[0]);da=!0;m[++z]=[];B[z]={width:Number(a)||X,height:Number(b)||Q};J[z]={};Ka(z)},La=function(){Aa.apply(this,arguments);c(h(Qa)+" w");c(ca);0!==sa&&c(sa+" J");0!==ta&&c(ta+" j");v.publish("addPage",{pageNumber:z})},Ra=function(a){0<a&&a<=z&&(m.splice(a,1),B.splice(a,1),z--,I>z&&(I=z),this.setPage(I))},Ka=function(a){0<a&&a<=z&&(I=a,X=B[a].width,Q=B[a].height)},Ba=function(a,b){var c;a=void 0!==a?a:r[D].fontName; |
b=void 0!==b?b:r[D].fontStyle;void 0!==a&&(a=a.toLowerCase());switch(a){case "sans-serif":case "verdana":case "arial":case "helvetica":a="helvetica";break;case "fixed":case "monospace":case "terminal":case "courier":a="courier";break;default:a="times"}try{c=G[a][b]}catch(d){}c||(c=G.times[b],null==c&&(c=G.times.normal));return c},Da=function(){da=!1;C=2;ra=[];N=[];W=[];c("%PDF-1.3");var a,b,g,d,e;e=t.adler32cs||q.adler32cs;S&&"undefined"===typeof e&&(S=!1);for(a=1;a<=z;a++){K();g=(X=B[a].width)*E; |
b=(Q=B[a].height)*E;c("<</Type /Page");c("/Parent 1 0 R");c("/Resources 2 0 R");c("/MediaBox [0 0 "+h(g)+" "+h(b)+"]");v.publish("putPage",{pageNumber:a,page:m[a]});c("/Contents "+(C+1)+" 0 R");c(">>");c("endobj");b=m[a].join("\n");b=(new R(E,0,0,-E,0,Q)).toString()+" cm\n"+b;K();if(S){g=[];for(d=b.length;d--;)g[d]=b.charCodeAt(d);d=e.from(b);b=new Deflater(6);b.append(new Uint8Array(g));b=b.flush();g=new Uint8Array(b.length+6);g.set(new Uint8Array([120,156]));g.set(b,2);g.set(new Uint8Array([d&255, |
d>>8&255,d>>16&255,d>>24&255]),b.length+2);b=String.fromCharCode.apply(null,g);c("<</Length "+b.length+" /Filter [/FlateDecode]>>")}else c("<</Length "+b.length+">>");ba(b);c("endobj")}N[1]=P;c("1 0 obj");c("<</Type /Pages");a="/Kids [";for(d=0;d<z;d++)a+=3+2*d+" 0 R ";c(a+"]");c("/Count "+z);c(">>");c("endobj");v.publish("postPutPages");v.publish("putAdditionalObjects");for(a=0;a<W.length;a++)e=W[a],N[e.objId]=P,c(e.objId+" 0 obj"),c(e.content),c("endobj");C+=W.length;v.publish("postPutAdditionalObjects"); |
for(var l in r)r.hasOwnProperty(l)&&(a=r[l],a.objectNumber=K(),c("<</BaseFont/"+a.PostScriptName+"/Type/Font"),"string"===typeof a.encoding&&c("/Encoding/"+a.encoding),c("/Subtype/Type1>>"),c("endobj"));for(var y in H)if(H.hasOwnProperty(y)){l=H[y];l.objectNumber=K();c("<<");a=void 0;for(a in l)switch(a){case "opacity":c("/ca "+h(l[a]))}c(">>");c("endobj")}for(var p in M)M.hasOwnProperty(p)&&(y=M[p],y.objectNumber=K(),c("<<"),c("/Type /XObject"),c("/Subtype /Form"),c("/BBox ["+[h(y.x),h(y.y),h(y.x+ |
y.width),h(y.y+y.height)].join(" ")+"]"),c("/Matrix ["+y.matrix.toString()+"]"),y=y.pages[1].join("\n"),c("/Length "+y.length),c(">>"),ba(y),c("endobj"));for(var n in u)if(u.hasOwnProperty(n))if(u[n]instanceof f.ShadingPattern){p=u[n];y=K();l=p.colors;a=[];for(d=0;1>d;d+=.05)a.push(d);a.push(1);0!=l[0].offset&&l.unshift({offset:0,color:l[0].color});1!=l[l.length-1].offset&&l.push({offset:1,color:l[l.length-1].color});e="";for(b=g=0;b<a.length;b++){for(d=a[b];d>l[g+1].offset;)g++;var Y=l[g].offset; |
d=(d-Y)/(l[g+1].offset-Y);var Y=l[g].color,Ca=l[g+1].color;e+=va(Math.round((1-d)*Y[0]+d*Ca[0]).toString(16))+va(Math.round((1-d)*Y[1]+d*Ca[1]).toString(16))+va(Math.round((1-d)*Y[2]+d*Ca[2]).toString(16))}l=e.trim();c("<< /FunctionType 0");c("/Domain [0.0 1.0]");c("/Size [21]");c("/BitsPerSample 8");c("/Range [0.0 1.0 0.0 1.0 0.0 1.0]");c("/Decode [0.0 1.0 0.0 1.0 0.0 1.0]");c("/Length "+l.length);c("/Filter /ASCIIHexDecode");c(">>");ba(l);c("endobj");p.objectNumber=K();c("<< /ShadingType "+p.type); |
c("/ColorSpace /DeviceRGB");l="/Coords ["+k(parseFloat(p.coords[0]))+" "+k(parseFloat(p.coords[1]))+" ";l=2===p.type?l+(k(parseFloat(p.coords[2]))+" "+k(parseFloat(p.coords[3]))):l+(k(parseFloat(p.coords[2]))+" "+k(parseFloat(p.coords[3]))+" "+k(parseFloat(p.coords[4]))+" "+k(parseFloat(p.coords[5])));c(l+"]");p.matrix&&c("/Matrix ["+p.matrix.toString()+"]");c("/Function "+y+" 0 R");c("/Extend [true true]");c(">>");c("endobj")}else u[n]instanceof f.TilingPattern&&(p=u[n],y=K(),c("<<"),Ha(),c(">>"), |
c("endobj"),p.objectNumber=K(),c("<< /Type /Pattern"),c("/PatternType 1"),c("/PaintType 1"),c("/TilingType 1"),c("/BBox ["+p.boundingBox.map(k).join(" ")+"]"),c("/XStep "+k(p.xStep)),c("/YStep "+k(p.yStep)),c("/Length "+p.stream.length),c("/Resources "+y+" 0 R"),p.matrix&&c("/Matrix ["+p.matrix.toString()+"]"),c(">>"),ba(p.stream),c("endobj"));v.publish("putResources");N[2]=P;c("2 0 obj");c("<<");Ha();c(">>");c("endobj");v.publish("postPutResources");K();c("<<");c("/Producer (jsPDF "+q.version+")"); |
for(var x in T)T.hasOwnProperty(x)&&T[x]&&c("/"+x.substr(0,1).toUpperCase()+x.substr(1)+" ("+ya(T[x])+")");n=new Date;x=n.getTimezoneOffset();p=Math.abs(x%60);x=[0>x?"+":"-",U(Math.floor(Math.abs(x/60))),"'",U(p),"'"].join("");c(["/CreationDate (D:",n.getFullYear(),U(n.getMonth()+1),U(n.getDate()),U(n.getHours()),U(n.getMinutes()),U(n.getSeconds()),x,")"].join(""));c(">>");c("endobj");K();c("<<");c("/Type /Catalog");c("/Pages 1 0 R");O||(O="fullwidth");switch(O){case "fullwidth":c("/OpenAction [3 0 R /FitH null]"); |
break;case "fullheight":c("/OpenAction [3 0 R /FitV null]");break;case "fullpage":c("/OpenAction [3 0 R /Fit]");break;case "original":c("/OpenAction [3 0 R /XYZ null null 1]");break;default:n=""+O,"%"===n.substr(n.length-1)&&(O=parseInt(O)/100),"number"===typeof O&&c("/OpenAction [3 0 R /XYZ null null "+h(O)+"]")}ja||(ja="continuous");switch(ja){case "continuous":c("/PageLayout /OneColumn");break;case "single":c("/PageLayout /SinglePage");break;case "two":case "twoleft":c("/PageLayout /TwoColumnLeft"); |
break;case "tworight":c("/PageLayout /TwoColumnRight")}ua&&c("/PageMode /"+ua);v.publish("putCatalog");c(">>");c("endobj");n=P;c("xref");c("0 "+(C+1));c("0000000000 65535 f ");for(x=1;x<=C;x++)"function"===typeof N[x]?c(("0000000000"+N[x]()).slice(-10)+" 00000 n "):c(("0000000000"+N[x]).slice(-10)+" 00000 n ");c("trailer");c("<<");c("/Size "+(C+1));c("/Root "+C+" 0 R");c("/Info "+(C-1)+" 0 R");c(">>");c("startxref");c(n);c("%%EOF");da=!0;return ra.join("\n")},Ma=function(a){var b="n";if("D"===a)b= |
"S";else if("F"===a)b="f";else if("FD"===a||"DF"===a)b="B";else if("f"===a||"f*"===a||"B"===a||"B*"===a)b=a;return b},ma=function(a,b,g){a=Ma(a);if(b){g||(g=ka);var d=pa[b],e=u[d];if(e instanceof f.ShadingPattern)c("q"),c("W "+a),e.gState&&f.setGState(e.gState),c(g.toString()+" cm"),c("/"+d+" sh"),c("Q");else if(e instanceof f.TilingPattern){var l=new R(1,0,0,-1,0,Q);g.matrix&&(l=wa(g.matrix||ka,l),d=e.createClone(b,g.boundingBox,g.xStep,g.yStep,l).id);c("q");c("/Pattern cs");c("/"+d+" scn");e.gState&& |
f.setGState(e.gState);c(a);c("Q")}}else c(a)},Na=function(){for(var a=Da(),b=a.length,c=new ArrayBuffer(b),d=new Uint8Array(c);b--;)d[b]=a.charCodeAt(b);return c},Ea=function(){return new Blob([Na()],{type:"application/pdf"})},Oa=function(a){a.foo=function(){try{return a.apply(this,arguments)}catch(c){var b=c.stack||"";~b.indexOf(" at ")&&(b=b.split(" at ")[1]);b="Error in function "+b.split("\n")[0].split("<")[0]+": "+c.message;if(t.console)t.console.error(b,c),t.alert&&alert(b);else throw Error(b); |
}};a.foo.bar=a;return a.foo}(function(a,b){var c="dataur"===(""+a).substr(0,6)?"data:application/pdf;base64,"+btoa(Da()):0;switch(a){case void 0:return Da();case "save":if(navigator.getUserMedia&&(void 0===t.URL||void 0===t.URL.createObjectURL))return f.output("dataurlnewwindow");saveAs(Ea(),b);"function"===typeof saveAs.unload&&t.setTimeout&&setTimeout(saveAs.unload,911);break;case "arraybuffer":return Na();case "blob":return Ea();case "bloburi":case "bloburl":return t.URL&&t.URL.createObjectURL(Ea())|| |
void 0;case "datauristring":case "dataurlstring":return c;case "dataurlnewwindow":if((a=t.open(c))||"undefined"===typeof safari)return a;case "datauri":case "dataurl":return t.document.location.href=c;default:throw Error('Output type "'+a+'" is not supported.');}});switch(A){case "pt":E=1;break;case "mm":E=72/25.4000508;break;case "cm":E=72/2.54000508;break;case "in":E=72;break;case "px":E=96/72;break;case "pc":E=12;break;case "em":E=12;break;case "ex":E=6;break;default:throw"Invalid unit: "+A;}f.internal= |
{pdfEscape:ya,getStyle:Ma,getFont:function(){return r[Ba.apply(f,arguments)]},getFontSize:function(){return L},getLineHeight:function(){return L*oa},write:function(a){c(1===arguments.length?a:Array.prototype.join.call(arguments," "))},getCoordinateString:function(a){return h(a)},getVerticalCoordinateString:function(a){return h(a)},collections:{},newObject:K,newAdditionalObject:function(){var a=2*m.length+1,a=a+W.length,a={objId:a,content:""};W.push(a);return a},newObjectDeferred:function(){C++;N[C]= |
function(){return P};return C},newObjectDeferredBegin:function(a){N[a]=P},putStream:ba,events:v,scaleFactor:E,pageSize:{get width(){return X},get height(){return Q}},output:function(a,b){return Oa(a,b)},getNumberOfPages:function(){return m.length-1},pages:m,out:c,f2:h,getPageInfo:function(a){return{objId:2*(a-1)+3,pageNumber:a,pageContext:J[a]}},getCurrentPageInfo:function(){return{objId:2*(I-1)+3,pageNumber:I,pageContext:J[I]}},getPDFVersion:function(){return"1.3"}};f.GState=function(a){for(var b in a)a.hasOwnProperty(b)&& |
0<="opacity".indexOf(b)&&(this[b]=a[b]);this.id="";this.objectNumber=-1;this.equals=function(a){if(!a||typeof a!==typeof this)return!1;var b=0,c;for(c in this)if(!(0<="id,objectNumber,equals".indexOf(c))){if(this.hasOwnProperty(c)&&!a.hasOwnProperty(c)||this[c]!==a[c])return!1;b++}for(c in a)a.hasOwnProperty(c)&&0>"id,objectNumber,equals".indexOf(c)&&b--;return 0===b}};f.addGState=function(a,b){Ja(a,b);return this};f.addPage=function(){La.apply(this,arguments);return this};f.setPage=function(){Ka.apply(this, |
arguments);return this};f.insertPage=function(a){this.addPage();this.movePage(I,a);return this};f.movePage=function(a,b){var c,d,e;if(a>b){e=m[a];d=B[a];for(c=J[a];a>b;a--)m[a]=m[a-1],B[a]=B[a-1],J[a]=J[a-1];m[b]=e;B[b]=d;J[b]=c;this.setPage(b)}else if(a<b){e=m[a];d=B[a];for(c=J[a];a<b;a++)m[a]=m[a+1],B[a]=B[a+1],J[a]=J[a+1];m[b]=e;B[b]=d;J[b]=c;this.setPage(b)}return this};f.deletePage=function(){Ra.apply(this,arguments);return this};f.setDisplayMode=function(a,b,c){O=a;ja=b;ua=c;return this};f.saveGraphicsState= |
function(){c("q");Fa.push({key:D,size:L});return this};f.restoreGraphicsState=function(){c("Q");var a=Fa.pop();D=a.key;L=a.size;return this};f.setCurrentTransformationMatrix=function(a){c(a.toString()+" cm");return this};f.beginFormObject=function(a,b,c,d,e){fa.push(new la);z=I=0;m=[];ga=a;ha=b;ia=e;Aa(c,d);return this};f.endFormObject=function(a){if(!ea[a]){var b=new la,c="Xo"+(Object.keys(M).length+1).toString(10);b.id=c;ea[a]=c;M[c]=b;v.publish("addFormObject",b);fa.pop().restore()}return this}; |
f.doFormObject=function(a,b){a=M[ea[a]];c("q");c(b.toString()+" cm");c("/"+a.id+" Do");c("Q");return this};f.getFormObject=function(a){a=M[ea[a]];return{x:a.x,y:a.y,width:a.width,height:a.height,matrix:a.matrix}};f.Matrix=R;f.matrixMult=wa;f.unitMatrix=ka;f.ShadingPattern=function(a,b,c,d,e){this.type="axial"===a?2:3;this.coords=b;this.colors=c;this.gState=d;this.matrix=e;this.id="";this.objectNumber=-1};f.TilingPattern=function(a,b,c,d,e){this.boundingBox=a;this.xStep=b;this.yStep=c;this.stream= |
"";this.cloneIndex=0;this.gState=d;this.matrix=e;this.id="";this.objectNumber=-1};f.TilingPattern.prototype={createClone:function(a,b,c,d,e){b=new f.TilingPattern(b||this.boundingBox,c||this.xStep,d||this.yStep,this.gState,e||this.matrix);b.stream=this.stream;a=a+"$$"+this.cloneIndex++ +"$$";xa(a,b);return b}};f.addShadingPattern=function(a,b){xa(a,b);return this};f.beginTilingPattern=function(a){var b=a.boundingBox[0],c=a.boundingBox[1],d=a.boundingBox[2]-a.boundingBox[0],e=a.boundingBox[3]-a.boundingBox[1]; |
a=a.matrix;fa.push(new la);z=I=0;m=[];ga=b;ha=c;ia=a;Aa(d,e)};f.endTilingPattern=function(a,b){b.stream=m[I].join("\n");xa(a,b);v.publish("endTilingPattern",b);fa.pop().restore()};f.text=function(a,b,g,d,e,l){function f(a){a=a.split("\t").join(Array(w.TabLen||9).join(" "));return ya(a,d)}if("number"===typeof a){var p=g;g=b;b=a;a=p}"string"===typeof a&&(a=a.match(/[\n\r]/)?a.split(/\r\n|\r|\n/g):[a]);"string"===typeof e&&(l=e,e=null);"string"===typeof d&&(l=d,d=null);"number"===typeof d&&(e=d,d=null); |
e&&"number"===typeof e?(e*=Math.PI/180,p=Math.cos(e),e=Math.sin(e),e=new R(p,e,-e,p,0,0)):e||(e=ka);d=d||{};"noBOM"in d||(d.noBOM=!0);"autoencode"in d||(d.autoencode=!0);var p="",n=this.internal.getCurrentPageInfo().pageContext;!0===d.stroke?!0!==n.lastTextWasStroke&&(p="1 Tr\n",n.lastTextWasStroke=!0):(n.lastTextWasStroke&&(p="0 Tr\n"),n.lastTextWasStroke=!1);"undefined"===typeof this._runningPageHeight&&(this._runningPageHeight=0);if("string"===typeof a)a=f(a);else if("[object Array]"===Object.prototype.toString.call(a)){for(var k= |
a.concat(),n=[],q=k.length;q--;)n.push(f(k.shift()));if(l){var x,m,v=L*oa,t=a.map(function(a){return this.getStringUnitWidth(a)*L},this);m=Math.max.apply(Math,t);if("center"===l)k=b-m/2,b-=t[0]/2;else if("right"===l)k=b-m,b-=t[0];else throw Error('Unrecognized alignment option, use "center" or "right".');x=b;a=n[0]+") Tj\n";i=1;for(q=n.length;i<q;i++){var u=m-t[i];"center"===l&&(u/=2);a+=k-x+u+" -"+v+" Td ("+n[i];x=k+u;i<q-1&&(a+=") Tj\n")}}else a=n.join(") Tj\nT* (")}else throw Error('Type of text must be string or Array. "'+ |
a+'" is not recognized.');g=h(g);b=new R(1,0,0,-1,b,g);e=wa(b,e);c("BT\n"+L*oa+" TL\n"+p+(e.toString()+" Tm")+"\n("+a+") Tj\nET");return this};f.lstext=function(a,b,c,d){for(var e=0,l=a.length;e<l;e++,b+=d)this.text(a[e],b,c)};f.line=function(a,b,c,d){return this.lines([[c-a,d-b]],a,b,[1,1],"D")};f.clip=function(){c("W");c("S")};f.lines=function(a,b,g,d,e,l,f,h){var n,q,m,t,u,v,w,r;"number"===typeof a&&(n=g,g=b,b=a,a=n);d=d||[1,1];c(k(b)+" "+k(g)+" m ");n=d[0];d=d[1];q=a.length;r=g;for(g=0;g<q;g++)m= |
a[g],2===m.length?(b=m[0]*n+b,r=m[1]*d+r,c(k(b)+" "+k(r)+" l")):(t=m[0]*n+b,u=m[1]*d+r,v=m[2]*n+b,w=m[3]*d+r,b=m[4]*n+b,r=m[5]*d+r,c(k(t)+" "+k(u)+" "+k(v)+" "+k(w)+" "+k(b)+" "+k(r)+" c"));l&&c("h");ma(e,f,h);return this};f.path=function(a,b,g,d){for(var e=0;e<a.length;e++){var f=a[e],h=f.c;switch(f.op){case "m":c(k(h[0])+" "+k(h[1])+" m");break;case "l":c(k(h[0])+" "+k(h[1])+" l");break;case "c":c([k(h[0]),k(h[1]),k(h[2]),k(h[3]),k(h[4]),k(h[5]),"c"].join(" "));break;case "h":c("h")}}ma(b,g,d); |
return this};f.rect=function(a,b,g,d,e,f,k){c([h(a),h(b),h(g),h(-d),"re"].join(" "));ma(e,f,k);return this};f.triangle=function(a,b,c,d,e,f,h,k,n){this.lines([[c-a,d-b],[e-c,f-d],[a-e,b-f]],a,b,[1,1],h,!0,k,n);return this};f.roundedRect=function(a,b,c,d,e,f,h,k,n){var m=4/3*(Math.SQRT2-1);e=Math.min(e,.5*c);f=Math.min(f,.5*d);this.lines([[c-2*e,0],[e*m,0,e,f-f*m,e,f],[0,d-2*f],[0,f*m,-(e*m),f,-e,f],[-c+2*e,0],[-(e*m),0,-e,-(f*m),-e,-f],[0,-d+2*f],[0,-(f*m),e*m,-f,e,-f]],a+e,b,[1,1],h,!0,k,n);return this}; |
f.ellipse=function(a,b,g,d,e,f,k){var m=4/3*(Math.SQRT2-1)*g,n=4/3*(Math.SQRT2-1)*d;c([h(a+g),h(b),"m",h(a+g),h(b-n),h(a+m),h(b-d),h(a),h(b-d),"c"].join(" "));c([h(a-m),h(b-d),h(a-g),h(b-n),h(a-g),h(b),"c"].join(" "));c([h(a-g),h(b+n),h(a-m),h(b+d),h(a),h(b+d),"c"].join(" "));c([h(a+m),h(b+d),h(a+g),h(b+n),h(a+g),h(b),"c"].join(" "));ma(e,f,k);return this};f.circle=function(a,b,c,d,e,f){return this.ellipse(a,b,c,c,d,e,f)};f.setProperties=function(a){for(var b in T)T.hasOwnProperty(b)&&a[b]&&(T[b]= |
a[b]);return this};f.setFontSize=function(a){L=a;c("/"+D+" "+L+" Tf");return this};f.getFontSize=function(){return L};f.setFont=function(a,b){D=Ba(a,b);c("/"+D+" "+L+" Tf");return this};f.setFontStyle=f.setFontType=function(a){D=Ba(void 0,a);return this};f.getFontList=function(){var a={},b,c,d;for(b in G)if(G.hasOwnProperty(b))for(c in a[b]=d=[],G[b])G[b].hasOwnProperty(c)&&d.push(c);return a};f.addFont=function(a,b,c){Ia(a,b,c,"StandardEncoding")};f.setLineWidth=function(a){c(a.toFixed(2)+" w"); |
return this};f.setDrawColor=function(a,b,g,d){a=void 0===b||void 0===d&&a===b===g?"string"===typeof a?a+" G":h(a/255)+" G":void 0===d?"string"===typeof a?[a,b,g,"RG"].join(" "):[h(a/255),h(b/255),h(g/255),"RG"].join(" "):"string"===typeof a?[a,b,g,d,"K"].join(" "):[h(a),h(b),h(g),h(d),"K"].join(" ");c(a);return this};f.setFillColor=function(a,b,g,d){void 0===b||void 0===d&&a===b===g?a="string"===typeof a?a+" g":h(a/255)+" g":void 0===d||"object"===typeof d?(a="string"===typeof a?[a,b,g,"rg"].join(" "): |
[h(a/255),h(b/255),h(g/255),"rg"].join(" "),d&&0===d.a&&(a="255 255 255 rg")):a="string"===typeof a?[a,b,g,d,"k"].join(" "):[h(a),h(b),h(g),h(d),"k"].join(" ");c(a);return this};f.setTextColor=function(a,b,g){"string"===typeof a&&/^#[0-9A-Fa-f]{6}$/.test(a)&&(g=parseInt(a.substr(1),16),a=g>>16&255,b=g>>8&255,g&=255);aa=0===a&&0===b&&0===g||"undefined"===typeof b?k(a/255)+" g":[k(a/255),k(b/255),k(g/255),"rg"].join(" ");c(aa);return this};f.setGState=function(a){a="string"===typeof a?H[qa[a]]:Ja(null, |
a);a.equals(Ga)||(c("/"+a.id+" gs"),Ga=a)};f.CapJoinStyles={0:0,butt:0,but:0,miter:0,1:1,round:1,rounded:1,circle:1,2:2,projecting:2,project:2,square:2,bevel:2};f.setLineCap=function(a){var b=this.CapJoinStyles[a];if(void 0===b)throw Error("Line cap style of '"+a+"' is not recognized. See or extend .CapJoinStyles property for valid styles");sa=b;c(b+" J");return this};f.setLineJoin=function(a){var b=this.CapJoinStyles[a];if(void 0===b)throw Error("Line join style of '"+a+"' is not recognized. See or extend .CapJoinStyles property for valid styles"); |
ta=b;c(b+" j");return this};f.setLineMiterLimit=function(a){c(h(a)+" M");return this};f.setLineDashPattern=function(a,b){c(["["+(void 0!==a[0]?a[0]:""),(void 0!==a[1]?a[1]:"")+"]",b,"d"].join(" "));return this};f.output=Oa;f.save=function(a){f.output("save",a)};for(var na in q.API)q.API.hasOwnProperty(na)&&("events"===na&&q.API.events.length?function(a,b){var c,d,e;for(e=b.length-1;-1!==e;e--)c=b[e][0],d=b[e][1],a.subscribe.apply(a,[c].concat("function"===typeof d?[d]:d))}(v,q.API.events):f[na]=q.API[na]); |
(function(){for(var a=[["Helvetica","helvetica","normal"],["Helvetica-Bold","helvetica","bold"],["Helvetica-Oblique","helvetica","italic"],["Helvetica-BoldOblique","helvetica","bolditalic"],["Courier","courier","normal"],["Courier-Bold","courier","bold"],["Courier-Oblique","courier","italic"],["Courier-BoldOblique","courier","bolditalic"],["Times-Roman","times","normal"],["Times-Bold","times","bold"],["Times-Italic","times","italic"],["Times-BoldItalic","times","bolditalic"],["ZapfDingbats","zapfdingbats"]], |
b=0,c=a.length;b<c;b++){var d=Ia(a[b][0],a[b][1],a[b][2],"StandardEncoding"),e=a[b][0].split("-"),f=e[0],e=e[1]||"";G.hasOwnProperty(f)||(G[f]={});G[f][e]=d}v.publish("addFonts",{fonts:r,dictionary:G})})();D="F1";La(F,V);v.publish("initialized");return f}var za={a0:[2383.94,3370.39],a1:[1683.78,2383.94],a2:[1190.55,1683.78],a3:[841.89,1190.55],a4:[595.28,841.89],a5:[419.53,595.28],a6:[297.64,419.53],a7:[209.76,297.64],a8:[147.4,209.76],a9:[104.88,147.4],a10:[73.7,104.88],b0:[2834.65,4008.19],b1:[2004.09, |
2834.65],b2:[1417.32,2004.09],b3:[1000.63,1417.32],b4:[708.66,1000.63],b5:[498.9,708.66],b6:[354.33,498.9],b7:[249.45,354.33],b8:[175.75,249.45],b9:[124.72,175.75],b10:[87.87,124.72],c0:[2599.37,3676.54],c1:[1836.85,2599.37],c2:[1298.27,1836.85],c3:[918.43,1298.27],c4:[649.13,918.43],c5:[459.21,649.13],c6:[323.15,459.21],c7:[229.61,323.15],c8:[161.57,229.61],c9:[113.39,161.57],c10:[79.37,113.39],dl:[311.81,623.62],letter:[612,792],"government-letter":[576,756],legal:[612,1008],"junior-legal":[576, |
360],ledger:[1224,792],tabloid:[792,1224],"credit-card":[153,243]};q.API={events:[]};q.version="1.0.0-trunk";"function"===typeof define&&define.amd?define("jsPDF",function(){return q}):"undefined"!==typeof module&&module.exports?module.exports=q:t.jsPDF=q;return q}("undefined"!==typeof self&&self||"undefined"!==typeof window&&window||this); |
/base/000_base/node_modules/highcharts/lib/jspdf.src.js |
@@ -0,0 +1,3031 @@ |
/** @preserve |
* jsPDF - PDF Document creation from JavaScript |
* Version ${versionID} |
* CommitID ${commitID} |
* |
* Copyright (c) 2010-2014 James Hall <james@parall.ax>, https://github.com/MrRio/jsPDF |
* 2010 Aaron Spike, https://github.com/acspike |
* 2012 Willow Systems Corporation, willow-systems.com |
* 2012 Pablo Hess, https://github.com/pablohess |
* 2012 Florian Jenett, https://github.com/fjenett |
* 2013 Warren Weckesser, https://github.com/warrenweckesser |
* 2013 Youssef Beddad, https://github.com/lifof |
* 2013 Lee Driscoll, https://github.com/lsdriscoll |
* 2013 Stefan Slonevskiy, https://github.com/stefslon |
* 2013 Jeremy Morel, https://github.com/jmorel |
* 2013 Christoph Hartmann, https://github.com/chris-rock |
* 2014 Juan Pablo Gaviria, https://github.com/juanpgaviria |
* 2014 James Makes, https://github.com/dollaruw |
* 2014 Diego Casorran, https://github.com/diegocr |
* 2014 Steven Spungin, https://github.com/Flamenco |
* 2014 Kenneth Glassey, https://github.com/Gavvers |
* |
* Permission is hereby granted, free of charge, to any person obtaining |
* a copy of this software and associated documentation files (the |
* "Software"), to deal in the Software without restriction, including |
* without limitation the rights to use, copy, modify, merge, publish, |
* distribute, sublicense, and/or sell copies of the Software, and to |
* permit persons to whom the Software is furnished to do so, subject to |
* the following conditions: |
* |
* The above copyright notice and this permission notice shall be |
* included in all copies or substantial portions of the Software. |
* |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
* |
* Contributor(s): |
* siefkenj, ahwolf, rickygu, Midnith, saintclair, eaparango, |
* kim3er, mfo, alnorth, Flamenco |
*/ |
|
/** |
* Creates new jsPDF document object instance. |
* |
* @class |
* @param orientation One of "portrait" or "landscape" (or shortcuts "p" (Default), "l") |
* @param unit Measurement unit to be used when coordinates are specified. |
* One of "pt" (points), "mm" (Default), "cm", "in" |
* @param format One of 'pageFormats' as shown below, default: a4 |
* @returns {jsPDF} |
* @name jsPDF |
*/ |
var jsPDF = (function(global) { |
'use strict'; |
var pdfVersion = '1.3', |
pageFormats = { // Size in pt of various paper formats |
'a0' : [2383.94, 3370.39], 'a1' : [1683.78, 2383.94], |
'a2' : [1190.55, 1683.78], 'a3' : [ 841.89, 1190.55], |
'a4' : [ 595.28, 841.89], 'a5' : [ 419.53, 595.28], |
'a6' : [ 297.64, 419.53], 'a7' : [ 209.76, 297.64], |
'a8' : [ 147.40, 209.76], 'a9' : [ 104.88, 147.40], |
'a10' : [ 73.70, 104.88], 'b0' : [2834.65, 4008.19], |
'b1' : [2004.09, 2834.65], 'b2' : [1417.32, 2004.09], |
'b3' : [1000.63, 1417.32], 'b4' : [ 708.66, 1000.63], |
'b5' : [ 498.90, 708.66], 'b6' : [ 354.33, 498.90], |
'b7' : [ 249.45, 354.33], 'b8' : [ 175.75, 249.45], |
'b9' : [ 124.72, 175.75], 'b10' : [ 87.87, 124.72], |
'c0' : [2599.37, 3676.54], 'c1' : [1836.85, 2599.37], |
'c2' : [1298.27, 1836.85], 'c3' : [ 918.43, 1298.27], |
'c4' : [ 649.13, 918.43], 'c5' : [ 459.21, 649.13], |
'c6' : [ 323.15, 459.21], 'c7' : [ 229.61, 323.15], |
'c8' : [ 161.57, 229.61], 'c9' : [ 113.39, 161.57], |
'c10' : [ 79.37, 113.39], 'dl' : [ 311.81, 623.62], |
'letter' : [612, 792], |
'government-letter' : [576, 756], |
'legal' : [612, 1008], |
'junior-legal' : [576, 360], |
'ledger' : [1224, 792], |
'tabloid' : [792, 1224], |
'credit-card' : [153, 243] |
}; |
|
/** |
* jsPDF's Internal PubSub Implementation. |
* See mrrio.github.io/jsPDF/doc/symbols/PubSub.html |
* Backward compatible rewritten on 2014 by |
* Diego Casorran, https://github.com/diegocr |
* |
* @class |
* @name PubSub |
*/ |
function PubSub(context) { |
var topics = {}; |
|
this.subscribe = function(topic, callback, once) { |
if(typeof callback !== 'function') { |
return false; |
} |
|
if(!topics.hasOwnProperty(topic)) { |
topics[topic] = {}; |
} |
|
var id = Math.random().toString(35); |
topics[topic][id] = [callback,!!once]; |
|
return id; |
}; |
|
this.unsubscribe = function(token) { |
for(var topic in topics) { |
if(topics[topic][token]) { |
delete topics[topic][token]; |
return true; |
} |
} |
return false; |
}; |
|
this.publish = function(topic) { |
if(topics.hasOwnProperty(topic)) { |
var args = Array.prototype.slice.call(arguments, 1), idr = []; |
|
for(var id in topics[topic]) { |
var sub = topics[topic][id]; |
try { |
sub[0].apply(context, args); |
} catch(ex) { |
if(global.console) { |
console.error('jsPDF PubSub Error', ex.message, ex); |
} |
} |
if(sub[1]) idr.push(id); |
} |
if(idr.length) idr.forEach(this.unsubscribe); |
} |
}; |
} |
|
/** |
* @constructor |
* @private |
*/ |
function jsPDF(orientation, unit, format, compressPdf) { |
var options = {}; |
|
if (typeof orientation === 'object') { |
options = orientation; |
|
orientation = options.orientation; |
unit = options.unit || unit; |
format = options.format || format; |
compressPdf = options.compress || options.compressPdf || compressPdf; |
} |
|
// Default options |
unit = unit || 'mm'; |
format = format || 'a4'; |
orientation = ('' + (orientation || 'P')).toLowerCase(); |
|
var format_as_string = ('' + format).toLowerCase(), |
compress = !!compressPdf && typeof Uint8Array === 'function', |
textColor = options.textColor || '0 g', |
drawColor = options.drawColor || '0 G', |
activeFontSize = options.fontSize || 16, |
lineHeightProportion = options.lineHeight || 1.15, |
lineWidth = options.lineWidth || 0.200025, // 2mm |
objectNumber = 2, // 'n' Current object number |
outToPages = !1, // switches where out() prints. outToPages true = push to pages obj. outToPages false = doc builder content |
offsets = [], // List of offsets. Activated and reset by buildDocument(). Pupulated by various calls buildDocument makes. |
fonts = {}, // collection of font objects, where key is fontKey - a dynamically created label for a given font. |
fontmap = {}, // mapping structure fontName > fontStyle > font key - performance layer. See addFont() |
activeFontKey, // will be string representing the KEY of the font as combination of fontName + fontStyle |
|
fontStateStack = [], // |
|
patterns = {}, // collection of pattern objects |
patternMap = {}, // see fonts |
|
gStates = {}, // collection of graphic state objects |
gStatesMap = {}, // see fonts |
activeGState = null, |
|
k, // Scale factor |
tmp, |
page = 0, |
currentPage, |
pages = [], |
pagesContext = [], // same index as pages and pagedim |
pagedim = [], |
content = [], |
additionalObjects = [], |
lineCapID = 0, |
lineJoinID = 0, |
content_length = 0, |
|
renderTargets = {}, |
renderTargetMap = {}, |
renderTargetStack = [], |
|
pageX, pageY, pageMatrix, // only used for FormObjects |
pageWidth, |
pageHeight, |
pageMode, |
zoomMode, |
layoutMode, |
documentProperties = { |
'title' : '', |
'subject' : '', |
'author' : '', |
'keywords' : '', |
'creator' : '' |
}, |
API = {}, |
events = new PubSub(API), |
|
///////////////////// |
// Private functions |
///////////////////// |
f2 = function(number) { |
return number.toFixed(2); // Ie, %.2f |
}, |
f3 = function(number) { |
return number.toFixed(3); // Ie, %.3f |
}, |
padd2 = function(number) { |
return ('0' + parseInt(number)).slice(-2); |
}, |
padd2Hex = function (hexString) { |
var s = "00" + hexString; |
return s.substr(s.length - 2); |
}, |
out = function(string) { |
if (outToPages) { |
/* set by beginPage */ |
pages[currentPage].push(string); |
} else { |
// +1 for '\n' that will be used to join 'content' |
content_length += string.length + 1; |
content.push(string); |
} |
}, |
newObject = function() { |
// Begin a new object |
objectNumber++; |
offsets[objectNumber] = content_length; |
out(objectNumber + ' 0 obj'); |
return objectNumber; |
}, |
// Does not output the object until after the pages have been output. |
// Returns an object containing the objectId and content. |
// All pages have been added so the object ID can be estimated to start right after. |
// This does not modify the current objectNumber; It must be updated after the newObjects are output. |
newAdditionalObject = function() { |
var objId = pages.length * 2 + 1; |
objId += additionalObjects.length; |
var obj = {objId:objId, content:''}; |
additionalObjects.push(obj); |
return obj; |
}, |
// Does not output the object. The caller must call newObjectDeferredBegin(oid) before outputing any data |
newObjectDeferred = function() { |
objectNumber++; |
offsets[objectNumber] = function(){ |
return content_length; |
}; |
return objectNumber; |
}, |
newObjectDeferredBegin = function(oid) { |
offsets[oid] = content_length; |
}, |
putStream = function(str) { |
out('stream'); |
out(str); |
out('endstream'); |
}, |
putPages = function() { |
var n,p,arr,i,deflater,adler32,adler32cs,wPt,hPt; |
|
adler32cs = global.adler32cs || jsPDF.adler32cs; |
if (compress && typeof adler32cs === 'undefined') { |
compress = false; |
} |
|
// outToPages = false as set in endDocument(). out() writes to content. |
|
for (n = 1; n <= page; n++) { |
newObject(); |
wPt = (pageWidth = pagedim[n].width) * k; |
hPt = (pageHeight = pagedim[n].height) * k; |
out('<</Type /Page'); |
out('/Parent 1 0 R'); |
out('/Resources 2 0 R'); |
out('/MediaBox [0 0 ' + f2(wPt) + ' ' + f2(hPt) + ']'); |
// Added for annotation plugin |
events.publish('putPage', {pageNumber: n, page: pages[n]}); |
out('/Contents ' + (objectNumber + 1) + ' 0 R'); |
out('>>'); |
out('endobj'); |
|
// Page content |
p = pages[n].join('\n'); |
|
// prepend global change of basis matrix |
// (Now, instead of converting every coordinate to the pdf coordinate system, we apply a matrix |
// that does this job for us (however, texts, images and similar objects must be drawn bottom up)) |
p = new Matrix(k, 0, 0, -k, 0, pageHeight).toString() + " cm\n" + p; |
|
newObject(); |
if (compress) { |
arr = []; |
i = p.length; |
while(i--) { |
arr[i] = p.charCodeAt(i); |
} |
adler32 = adler32cs.from(p); |
deflater = new Deflater(6); |
deflater.append(new Uint8Array(arr)); |
p = deflater.flush(); |
arr = new Uint8Array(p.length + 6); |
arr.set(new Uint8Array([120, 156])); |
arr.set(p, 2); |
arr.set(new Uint8Array([adler32 & 0xFF, (adler32 >> 8) & 0xFF, (adler32 >> 16) & 0xFF, (adler32 >> 24) & 0xFF]), p.length+2); |
p = String.fromCharCode.apply(null, arr); |
out('<</Length ' + p.length + ' /Filter [/FlateDecode]>>'); |
} else { |
out('<</Length ' + p.length + '>>'); |
} |
putStream(p); |
out('endobj'); |
} |
offsets[1] = content_length; |
out('1 0 obj'); |
out('<</Type /Pages'); |
var kids = '/Kids ['; |
for (i = 0; i < page; i++) { |
kids += (3 + 2 * i) + ' 0 R '; |
} |
out(kids + ']'); |
out('/Count ' + page); |
out('>>'); |
out('endobj'); |
events.publish('postPutPages'); |
}, |
putFont = function(font) { |
font.objectNumber = newObject(); |
out('<</BaseFont/' + font.PostScriptName + '/Type/Font'); |
if (typeof font.encoding === 'string') { |
out('/Encoding/' + font.encoding); |
} |
out('/Subtype/Type1>>'); |
out('endobj'); |
}, |
putFonts = function() { |
for (var fontKey in fonts) { |
if (fonts.hasOwnProperty(fontKey)) { |
putFont(fonts[fontKey]); |
} |
} |
}, |
putXObject = function (xObject) { |
xObject.objectNumber = newObject(); |
out("<<"); |
out("/Type /XObject"); |
out("/Subtype /Form"); |
out("/BBox [" + [ |
f2(xObject.x), |
f2(xObject.y), |
f2(xObject.x + xObject.width), |
f2(xObject.y + xObject.height) |
].join(" ") + "]"); |
out("/Matrix [" + xObject.matrix.toString() + "]"); |
// TODO: /Resources |
|
var p = xObject.pages[1].join("\n"); |
out("/Length " + p.length); |
|
out(">>"); |
putStream(p); |
out("endobj"); |
}, |
putXObjects = function () { |
for (var xObjectKey in renderTargets) { |
if (renderTargets.hasOwnProperty(xObjectKey)) { |
putXObject(renderTargets[xObjectKey]); |
} |
} |
}, |
|
interpolateAndEncodeRGBStream = function (colors, numberSamples) { |
var tValues = []; |
var t; |
var dT = 1.0 / (numberSamples - 1); |
for (t = 0.0; t < 1.0; t += dT) { |
tValues.push(t); |
} |
tValues.push(1.0); |
|
// add first and last control point if not present |
if (colors[0].offset != 0.0) { |
var c0 = { |
offset: 0.0, |
color: colors[0].color |
}; |
colors.unshift(c0) |
} |
if (colors[colors.length - 1].offset != 1.0) { |
var c1 = { |
offset: 1.0, |
color: colors[colors.length - 1].color |
}; |
colors.push(c1); |
} |
|
var out = ""; |
var index = 0; |
|
for (var i = 0; i < tValues.length; i++) { |
t = tValues[i]; |
|
while (t > colors[index + 1].offset) |
index++; |
|
var a = colors[index].offset; |
var b = colors[index + 1].offset; |
var d = (t - a) / (b - a); |
|
var aColor = colors[index].color; |
var bColor = colors[index + 1].color; |
|
out += padd2Hex((Math.round((1 - d) * aColor[0] + d * bColor[0])).toString(16)) |
+ padd2Hex((Math.round((1 - d) * aColor[1] + d * bColor[1])).toString(16)) |
+ padd2Hex((Math.round((1 - d) * aColor[2] + d * bColor[2])).toString(16)); |
} |
return out.trim(); |
}, |
putShadingPattern = function (pattern, numberSamples) { |
/* |
Axial patterns shade between the two points specified in coords, radial patterns between the inner |
and outer circle. |
|
The user can specify an array (colors) that maps t-Values in [0, 1] to RGB colors. These are now |
interpolated to equidistant samples and written to pdf as a sample (type 0) function. |
*/ |
|
// The number of color samples that should be used to describe the shading. |
// The higher, the more accurate the gradient will be. |
numberSamples || (numberSamples = 21); |
|
var funcObjectNumber = newObject(); |
var stream = interpolateAndEncodeRGBStream(pattern.colors, numberSamples); |
out("<< /FunctionType 0"); |
out("/Domain [0.0 1.0]"); |
out("/Size [" + numberSamples + "]"); |
out("/BitsPerSample 8"); |
out("/Range [0.0 1.0 0.0 1.0 0.0 1.0]"); |
out("/Decode [0.0 1.0 0.0 1.0 0.0 1.0]"); |
out("/Length " + stream.length); |
// The stream is Hex encoded |
out("/Filter /ASCIIHexDecode"); |
out(">>"); |
putStream(stream); |
out("endobj"); |
|
pattern.objectNumber = newObject(); |
out("<< /ShadingType " + pattern.type); |
out("/ColorSpace /DeviceRGB"); |
|
var coords = "/Coords [" |
+ f3(parseFloat(pattern.coords[0])) + " "// x1 |
+ f3(parseFloat(pattern.coords[1])) + " "; // y1 |
if (pattern.type === 2) { |
// axial |
coords += f3(parseFloat(pattern.coords[2])) + " " // x2 |
+ f3(parseFloat(pattern.coords[3])); // y2 |
} else { |
// radial |
coords += f3(parseFloat(pattern.coords[2])) + " "// r1 |
+ f3(parseFloat(pattern.coords[3])) + " " // x2 |
+ f3(parseFloat(pattern.coords[4])) + " " // y2 |
+ f3(parseFloat(pattern.coords[5])); // r2 |
} |
coords += "]"; |
out(coords); |
|
if (pattern.matrix) { |
out("/Matrix [" + pattern.matrix.toString() + "]"); |
} |
|
out("/Function " + funcObjectNumber + " 0 R"); |
out("/Extend [true true]"); |
out(">>"); |
out("endobj"); |
}, |
putTilingPattern = function (pattern) { |
var resourcesObjectNumber = newObject(); |
out("<<"); |
putResourceDictionary(); |
out(">>"); |
out("endobj"); |
|
pattern.objectNumber = newObject(); |
out("<< /Type /Pattern"); |
out("/PatternType 1"); // tiling pattern |
out("/PaintType 1"); // colored tiling pattern |
out("/TilingType 1"); // constant spacing |
out("/BBox [" + pattern.boundingBox.map(f3).join(" ") + "]"); |
out("/XStep " + f3(pattern.xStep)); |
out("/YStep " + f3(pattern.yStep)); |
out("/Length " + pattern.stream.length); |
out("/Resources " + resourcesObjectNumber + " 0 R"); // TODO: resources |
pattern.matrix && out("/Matrix [" + pattern.matrix.toString() + "]"); |
|
out(">>"); |
|
putStream(pattern.stream); |
|
out("endobj"); |
}, |
putPatterns = function () { |
var patternKey; |
for (patternKey in patterns) { |
if (patterns.hasOwnProperty(patternKey)) { |
if (patterns[patternKey] instanceof API.ShadingPattern) { |
putShadingPattern(patterns[patternKey]); |
} else if (patterns[patternKey] instanceof API.TilingPattern) { |
putTilingPattern(patterns[patternKey]); |
} |
} |
} |
}, |
|
putGState = function (gState) { |
gState.objectNumber = newObject(); |
out("<<"); |
for (var p in gState) { |
switch (p) { |
case "opacity": |
out("/ca " + f2(gState[p])); |
break; |
} |
} |
out(">>"); |
out("endobj"); |
}, |
putGStates = function () { |
var gStateKey; |
for (gStateKey in gStates) { |
if (gStates.hasOwnProperty(gStateKey)) { |
putGState(gStates[gStateKey]); |
} |
} |
}, |
|
putXobjectDict = function () { |
for (var xObjectKey in renderTargets) { |
if (renderTargets.hasOwnProperty(xObjectKey) && renderTargets[xObjectKey].objectNumber >= 0) { |
out("/" + xObjectKey + " " + renderTargets[xObjectKey].objectNumber + " 0 R"); |
} |
} |
|
events.publish('putXobjectDict'); |
}, |
|
putShadingPatternDict = function () { |
for (var patternKey in patterns) { |
if (patterns.hasOwnProperty(patternKey) && patterns[patternKey] instanceof API.ShadingPattern && patterns[patternKey].objectNumber >= 0) { |
out("/" + patternKey + " " + patterns[patternKey].objectNumber + " 0 R"); |
} |
} |
|
events.publish("putShadingPatternDict"); |
}, |
|
putTilingPatternDict = function () { |
for (var patternKey in patterns) { |
if (patterns.hasOwnProperty(patternKey) && patterns[patternKey] instanceof API.TilingPattern && patterns[patternKey].objectNumber >= 0) { |
out("/" + patternKey + " " + patterns[patternKey].objectNumber + " 0 R"); |
} |
} |
|
events.publish("putTilingPatternDict"); |
}, |
|
putGStatesDict = function () { |
var gStateKey; |
for (gStateKey in gStates) { |
if (gStates.hasOwnProperty(gStateKey) && gStates[gStateKey].objectNumber >= 0) { |
out("/" + gStateKey + " " + gStates[gStateKey].objectNumber + " 0 R"); |
} |
} |
|
events.publish("putGStateDict"); |
}, |
putResourceDictionary = function() { |
out('/ProcSet [/PDF /Text /ImageB /ImageC /ImageI]'); |
out('/Font <<'); |
// Do this for each font, the '1' bit is the index of the font |
for (var fontKey in fonts) { |
if (fonts.hasOwnProperty(fontKey)) { |
out('/' + fontKey + ' ' + fonts[fontKey].objectNumber + ' 0 R'); |
} |
} |
out('>>'); |
|
out("/Shading <<"); |
putShadingPatternDict(); |
out(">>"); |
|
out("/Pattern <<"); |
putTilingPatternDict(); |
out(">>"); |
|
out("/ExtGState <<"); |
putGStatesDict(); |
out('>>'); |
|
out('/XObject <<'); |
putXobjectDict(); |
out('>>'); |
}, |
putResources = function() { |
putFonts(); |
putGStates(); |
putXObjects(); |
putPatterns(); |
events.publish('putResources'); |
// Resource dictionary |
offsets[2] = content_length; |
out('2 0 obj'); |
out('<<'); |
putResourceDictionary(); |
out('>>'); |
out('endobj'); |
events.publish('postPutResources'); |
}, |
putAdditionalObjects = function() { |
events.publish('putAdditionalObjects'); |
for (var i=0; i<additionalObjects.length; i++){ |
var obj = additionalObjects[i]; |
offsets[obj.objId] = content_length; |
out( obj.objId + ' 0 obj'); |
out(obj.content); |
out('endobj'); |
} |
objectNumber += additionalObjects.length; |
events.publish('postPutAdditionalObjects'); |
}, |
addToFontDictionary = function(fontKey, fontName, fontStyle) { |
// this is mapping structure for quick font key lookup. |
// returns the KEY of the font (ex: "F1") for a given |
// pair of font name and type (ex: "Arial". "Italic") |
if (!fontmap.hasOwnProperty(fontName)) { |
fontmap[fontName] = {}; |
} |
fontmap[fontName][fontStyle] = fontKey; |
}, |
/** |
* FontObject describes a particular font as member of an instnace of jsPDF |
* |
* It's a collection of properties like 'id' (to be used in PDF stream), |
* 'fontName' (font's family name), 'fontStyle' (font's style variant label) |
* |
* @public |
* @property id {String} PDF-document-instance-specific label assinged to the font. |
* @property PostScriptName {String} PDF specification full name for the font |
* @property encoding {Object} Encoding_name-to-Font_metrics_object mapping. |
* @name FontObject |
*/ |
addFont = function(PostScriptName, fontName, fontStyle, encoding) { |
var fontKey = 'F' + (Object.keys(fonts).length + 1).toString(10), |
// This is FontObject |
font = fonts[fontKey] = { |
'id' : fontKey, |
'PostScriptName' : PostScriptName, |
'fontName' : fontName, |
'fontStyle' : fontStyle, |
'encoding' : encoding, |
'metadata' : {} |
}; |
addToFontDictionary(fontKey, fontName, fontStyle); |
events.publish('addFont', font); |
|
return fontKey; |
}, |
addFonts = function() { |
|
var HELVETICA = "helvetica", |
TIMES = "times", |
COURIER = "courier", |
NORMAL = "normal", |
BOLD = "bold", |
ITALIC = "italic", |
BOLD_ITALIC = "bolditalic", |
encoding = 'StandardEncoding', |
ZAPF = "zapfdingbats", |
standardFonts = [ |
['Helvetica', HELVETICA, NORMAL], |
['Helvetica-Bold', HELVETICA, BOLD], |
['Helvetica-Oblique', HELVETICA, ITALIC], |
['Helvetica-BoldOblique', HELVETICA, BOLD_ITALIC], |
['Courier', COURIER, NORMAL], |
['Courier-Bold', COURIER, BOLD], |
['Courier-Oblique', COURIER, ITALIC], |
['Courier-BoldOblique', COURIER, BOLD_ITALIC], |
['Times-Roman', TIMES, NORMAL], |
['Times-Bold', TIMES, BOLD], |
['Times-Italic', TIMES, ITALIC], |
['Times-BoldItalic', TIMES, BOLD_ITALIC], |
['ZapfDingbats',ZAPF ] |
]; |
|
for (var i = 0, l = standardFonts.length; i < l; i++) { |
var fontKey = addFont( |
standardFonts[i][0], |
standardFonts[i][1], |
standardFonts[i][2], |
encoding); |
|
// adding aliases for standard fonts, this time matching the capitalization |
var parts = standardFonts[i][0].split('-'); |
addToFontDictionary(fontKey, parts[0], parts[1] || ''); |
} |
events.publish('addFonts', { fonts : fonts, dictionary : fontmap }); |
}, |
matrixMult = function (m1, m2) { |
return new Matrix( |
m1.a * m2.a + m1.b * m2.c, |
m1.a * m2.b + m1.b * m2.d, |
m1.c * m2.a + m1.d * m2.c, |
m1.c * m2.b + m1.d * m2.d, |
m1.e * m2.a + m1.f * m2.c + m2.e, |
m1.e * m2.b + m1.f * m2.d + m2.f |
); |
}, |
Matrix = function (a, b, c, d, e, f) { |
this.a = a; |
this.b = b; |
this.c = c; |
this.d = d; |
this.e = e; |
this.f = f; |
}; |
|
Matrix.prototype = { |
toString: function () { |
return [ |
f3(this.a), |
f3(this.b), |
f3(this.c), |
f3(this.d), |
f3(this.e), |
f3(this.f) |
].join(" "); |
} |
}; |
|
var unitMatrix = new Matrix(1, 0, 0, 1, 0, 0), |
|
// Used (1) to save the current stream state to the XObjects stack and (2) to save completed form |
// objects in the xObjects map. |
RenderTarget = function () { |
this.page = page; |
this.currentPage = currentPage; |
this.pages = pages.slice(0); |
this.pagedim = pagedim.slice(0); |
this.pagesContext = pagesContext.slice(0); |
this.x = pageX; |
this.y = pageY; |
this.matrix = pageMatrix; |
this.width = pageWidth; |
this.height = pageHeight; |
|
this.id = ""; // set by endFormObject() |
this.objectNumber = -1; // will be set by putXObject() |
}; |
|
RenderTarget.prototype = { |
restore: function () { |
page = this.page; |
currentPage = this.currentPage; |
pagesContext = this.pagesContext; |
pagedim = this.pagedim; |
pages = this.pages; |
pageX = this.x; |
pageY = this.y; |
pageMatrix = this.matrix; |
pageWidth = this.width; |
pageHeight = this.height; |
} |
}; |
|
var beginNewRenderTarget = function (x, y, width, height, matrix) { |
// save current state |
renderTargetStack.push(new RenderTarget()); |
|
// clear pages |
page = currentPage = 0; |
pages = []; |
pageX = x; |
pageY = y; |
|
pageMatrix = matrix; |
|
beginPage(width, height); |
}, |
|
endFormObject = function (key) { |
// only add it if it is not already present (the keys provided by the user must be unique!) |
if (renderTargetMap[key]) |
return; |
|
// save the created xObject |
var newXObject = new RenderTarget(); |
|
var xObjectId = 'Xo' + (Object.keys(renderTargets).length + 1).toString(10); |
newXObject.id = xObjectId; |
|
renderTargetMap[key] = xObjectId; |
renderTargets[xObjectId] = newXObject; |
|
events.publish('addFormObject', newXObject); |
|
// restore state from stack |
renderTargetStack.pop().restore(); |
}, |
|
/** |
* Adds a new pattern for later use. |
* @param {String} key The key by it can be referenced later. The keys must be unique! |
* @param {API.Pattern} pattern The pattern |
*/ |
addPattern = function (key, pattern) { |
// only add it if it is not already present (the keys provided by the user must be unique!) |
if (patternMap[key]) |
return; |
|
var prefix = pattern instanceof API.ShadingPattern ? "Sh" : "P"; |
var patternKey = prefix + (Object.keys(patterns).length + 1).toString(10); |
pattern.id = patternKey; |
|
patternMap[key] = patternKey; |
patterns[patternKey] = pattern; |
|
events.publish('addPattern', pattern); |
}, |
|
/** |
* Adds a new Graphics State. Duplicates are automatically eliminated. |
* @param {String} key Might also be null, if no later reference to this gState is needed |
* @param {Object} gState The gState object |
*/ |
addGState = function (key, gState) { |
// only add it if it is not already present (the keys provided by the user must be unique!) |
if (key && gStatesMap[key]) |
return; |
|
var duplicate = false; |
for (var s in gStates) { |
if (gStates.hasOwnProperty(s)) { |
if (gStates[s].equals(gState)) { |
duplicate = true; |
break; |
} |
} |
} |
|
if (duplicate) { |
gState = gStates[s]; |
} else { |
var gStateKey = 'GS' + (Object.keys(gStates).length + 1).toString(10); |
gStates[gStateKey] = gState; |
gState.id = gStateKey; |
} |
|
// several user keys may point to the same GState object |
key && (gStatesMap[key] = gState.id); |
|
events.publish('addGState', gState); |
|
return gState; |
}, |
SAFE = function __safeCall(fn) { |
fn.foo = function __safeCallWrapper() { |
try { |
return fn.apply(this, arguments); |
} catch (e) { |
var stack = e.stack || ''; |
if(~stack.indexOf(' at ')) stack = stack.split(" at ")[1]; |
var m = "Error in function " + stack.split("\n")[0].split('<')[0] + ": " + e.message; |
if(global.console) { |
global.console.error(m, e); |
if(global.alert) alert(m); |
} else { |
throw new Error(m); |
} |
} |
}; |
fn.foo.bar = fn; |
return fn.foo; |
}, |
to8bitStream = function(text, flags) { |
/** |
* PDF 1.3 spec: |
* "For text strings encoded in Unicode, the first two bytes must be 254 followed by |
* 255, representing the Unicode byte order marker, U+FEFF. (This sequence conflicts |
* with the PDFDocEncoding character sequence thorn ydieresis, which is unlikely |
* to be a meaningful beginning of a word or phrase.) The remainder of the |
* string consists of Unicode character codes, according to the UTF-16 encoding |
* specified in the Unicode standard, version 2.0. Commonly used Unicode values |
* are represented as 2 bytes per character, with the high-order byte appearing first |
* in the string." |
* |
* In other words, if there are chars in a string with char code above 255, we |
* recode the string to UCS2 BE - string doubles in length and BOM is prepended. |
* |
* HOWEVER! |
* Actual *content* (body) text (as opposed to strings used in document properties etc) |
* does NOT expect BOM. There, it is treated as a literal GID (Glyph ID) |
* |
* Because of Adobe's focus on "you subset your fonts!" you are not supposed to have |
* a font that maps directly Unicode (UCS2 / UTF16BE) code to font GID, but you could |
* fudge it with "Identity-H" encoding and custom CIDtoGID map that mimics Unicode |
* code page. There, however, all characters in the stream are treated as GIDs, |
* including BOM, which is the reason we need to skip BOM in content text (i.e. that |
* that is tied to a font). |
* |
* To signal this "special" PDFEscape / to8bitStream handling mode, |
* API.text() function sets (unless you overwrite it with manual values |
* given to API.text(.., flags) ) |
* flags.autoencode = true |
* flags.noBOM = true |
* |
* =================================================================================== |
* `flags` properties relied upon: |
* .sourceEncoding = string with encoding label. |
* "Unicode" by default. = encoding of the incoming text. |
* pass some non-existing encoding name |
* (ex: 'Do not touch my strings! I know what I am doing.') |
* to make encoding code skip the encoding step. |
* .outputEncoding = Either valid PDF encoding name |
* (must be supported by jsPDF font metrics, otherwise no encoding) |
* or a JS object, where key = sourceCharCode, value = outputCharCode |
* missing keys will be treated as: sourceCharCode === outputCharCode |
* .noBOM |
* See comment higher above for explanation for why this is important |
* .autoencode |
* See comment higher above for explanation for why this is important |
*/ |
|
var i,l,sourceEncoding,encodingBlock,outputEncoding,newtext,isUnicode,ch,bch; |
|
flags = flags || {}; |
sourceEncoding = flags.sourceEncoding || 'Unicode'; |
outputEncoding = flags.outputEncoding; |
|
// This 'encoding' section relies on font metrics format |
// attached to font objects by, among others, |
// "Willow Systems' standard_font_metrics plugin" |
// see jspdf.plugin.standard_font_metrics.js for format |
// of the font.metadata.encoding Object. |
// It should be something like |
// .encoding = {'codePages':['WinANSI....'], 'WinANSI...':{code:code, ...}} |
// .widths = {0:width, code:width, ..., 'fof':divisor} |
// .kerning = {code:{previous_char_code:shift, ..., 'fof':-divisor},...} |
if ((flags.autoencode || outputEncoding) && |
fonts[activeFontKey].metadata && |
fonts[activeFontKey].metadata[sourceEncoding] && |
fonts[activeFontKey].metadata[sourceEncoding].encoding) { |
encodingBlock = fonts[activeFontKey].metadata[sourceEncoding].encoding; |
|
// each font has default encoding. Some have it clearly defined. |
if (!outputEncoding && fonts[activeFontKey].encoding) { |
outputEncoding = fonts[activeFontKey].encoding; |
} |
|
// Hmmm, the above did not work? Let's try again, in different place. |
if (!outputEncoding && encodingBlock.codePages) { |
outputEncoding = encodingBlock.codePages[0]; // let's say, first one is the default |
} |
|
if (typeof outputEncoding === 'string') { |
outputEncoding = encodingBlock[outputEncoding]; |
} |
// we want output encoding to be a JS Object, where |
// key = sourceEncoding's character code and |
// value = outputEncoding's character code. |
if (outputEncoding) { |
isUnicode = false; |
newtext = []; |
for (i = 0, l = text.length; i < l; i++) { |
ch = outputEncoding[text.charCodeAt(i)]; |
if (ch) { |
newtext.push( |
String.fromCharCode(ch)); |
} else { |
newtext.push( |
text[i]); |
} |
|
// since we are looping over chars anyway, might as well |
// check for residual unicodeness |
if (newtext[i].charCodeAt(0) >> 8) { |
/* more than 255 */ |
isUnicode = true; |
} |
} |
text = newtext.join(''); |
} |
} |
|
i = text.length; |
// isUnicode may be set to false above. Hence the triple-equal to undefined |
while (isUnicode === undefined && i !== 0) { |
if (text.charCodeAt(i - 1) >> 8) { |
/* more than 255 */ |
isUnicode = true; |
} |
i--; |
} |
if (!isUnicode) { |
return text; |
} |
|
newtext = flags.noBOM ? [] : [254, 255]; |
for (i = 0, l = text.length; i < l; i++) { |
ch = text.charCodeAt(i); |
bch = ch >> 8; // divide by 256 |
if (bch >> 8) { |
/* something left after dividing by 256 second time */ |
throw new Error("Character at position " + i + " of string '" |
+ text + "' exceeds 16bits. Cannot be encoded into UCS-2 BE"); |
} |
newtext.push(bch); |
newtext.push(ch - (bch << 8)); |
} |
return String.fromCharCode.apply(undefined, newtext); |
}, |
pdfEscape = function(text, flags) { |
/** |
* Replace '/', '(', and ')' with pdf-safe versions |
* |
* Doing to8bitStream does NOT make this PDF display unicode text. For that |
* we also need to reference a unicode font and embed it - royal pain in the rear. |
* |
* There is still a benefit to to8bitStream - PDF simply cannot handle 16bit chars, |
* which JavaScript Strings are happy to provide. So, while we still cannot display |
* 2-byte characters property, at least CONDITIONALLY converting (entire string containing) |
* 16bit chars to (USC-2-BE) 2-bytes per char + BOM streams we ensure that entire PDF |
* is still parseable. |
* This will allow immediate support for unicode in document properties strings. |
*/ |
return to8bitStream(text, flags).replace(/\\/g, '\\\\').replace(/\(/g, '\\(').replace(/\)/g, '\\)'); |
}, |
putInfo = function() { |
out('/Producer (jsPDF ' + jsPDF.version + ')'); |
for(var key in documentProperties) { |
if(documentProperties.hasOwnProperty(key) && documentProperties[key]) { |
out('/'+key.substr(0,1).toUpperCase() + key.substr(1) |
+' (' + pdfEscape(documentProperties[key]) + ')'); |
} |
} |
var created = new Date(), |
tzoffset = created.getTimezoneOffset(), |
tzsign = tzoffset < 0 ? '+' : '-', |
tzhour = Math.floor(Math.abs(tzoffset / 60)), |
tzmin = Math.abs(tzoffset % 60), |
tzstr = [tzsign, padd2(tzhour), "'", padd2(tzmin), "'"].join(''); |
out(['/CreationDate (D:', |
created.getFullYear(), |
padd2(created.getMonth() + 1), |
padd2(created.getDate()), |
padd2(created.getHours()), |
padd2(created.getMinutes()), |
padd2(created.getSeconds()), tzstr, ')'].join('')); |
}, |
putCatalog = function() { |
out('/Type /Catalog'); |
out('/Pages 1 0 R'); |
// PDF13ref Section 7.2.1 |
if (!zoomMode) zoomMode = 'fullwidth'; |
switch(zoomMode) { |
case 'fullwidth' : out('/OpenAction [3 0 R /FitH null]'); break; |
case 'fullheight' : out('/OpenAction [3 0 R /FitV null]'); break; |
case 'fullpage' : out('/OpenAction [3 0 R /Fit]'); break; |
case 'original' : out('/OpenAction [3 0 R /XYZ null null 1]'); break; |
default: |
var pcn = '' + zoomMode; |
if (pcn.substr(pcn.length-1) === '%') |
zoomMode = parseInt(zoomMode) / 100; |
if (typeof zoomMode === 'number') { |
out('/OpenAction [3 0 R /XYZ null null '+f2(zoomMode)+']'); |
} |
} |
if (!layoutMode) layoutMode = 'continuous'; |
switch(layoutMode) { |
case 'continuous' : out('/PageLayout /OneColumn'); break; |
case 'single' : out('/PageLayout /SinglePage'); break; |
case 'two': |
case 'twoleft' : out('/PageLayout /TwoColumnLeft'); break; |
case 'tworight' : out('/PageLayout /TwoColumnRight'); break; |
} |
if (pageMode) { |
/** |
* A name object specifying how the document should be displayed when opened: |
* UseNone : Neither document outline nor thumbnail images visible -- DEFAULT |
* UseOutlines : Document outline visible |
* UseThumbs : Thumbnail images visible |
* FullScreen : Full-screen mode, with no menu bar, window controls, or any other window visible |
*/ |
out('/PageMode /' + pageMode); |
} |
events.publish('putCatalog'); |
}, |
putTrailer = function() { |
out('/Size ' + (objectNumber + 1)); |
out('/Root ' + objectNumber + ' 0 R'); |
out('/Info ' + (objectNumber - 1) + ' 0 R'); |
}, |
beginPage = function(width,height) { |
// Dimensions are stored as user units and converted to points on output |
var orientation = typeof height === 'string' && height.toLowerCase(); |
if (typeof width === 'string') { |
var format = width.toLowerCase(); |
if (pageFormats.hasOwnProperty(format)) { |
width = pageFormats[format][0] / k; |
height = pageFormats[format][1] / k; |
} |
} |
if (Array.isArray(width)) { |
height = width[1]; |
width = width[0]; |
} |
//if (orientation) { |
// switch(orientation.substr(0,1)) { |
// case 'l': if (height > width ) orientation = 's'; break; |
// case 'p': if (width > height ) orientation = 's'; break; |
// } |
// TODO: What is the reason for this (for me it only seems to raise bugs)? |
// if (orientation === 's') { tmp = width; width = height; height = tmp; } |
//} |
outToPages = true; |
pages[++page] = []; |
pagedim[page] = { |
width : Number(width) || pageWidth, |
height : Number(height) || pageHeight |
}; |
pagesContext[page] = {}; |
_setPage(page); |
}, |
_addPage = function() { |
beginPage.apply(this, arguments); |
// Set line width |
out(f2(lineWidth) + ' w'); |
// Set draw color |
out(drawColor); |
// resurrecting non-default line caps, joins |
if (lineCapID !== 0) { |
out(lineCapID + ' J'); |
} |
if (lineJoinID !== 0) { |
out(lineJoinID + ' j'); |
} |
events.publish('addPage', { pageNumber : page }); |
}, |
_deletePage = function( n ) { |
if (n > 0 && n <= page) { |
pages.splice(n, 1); |
pagedim.splice(n, 1); |
page--; |
if (currentPage > page){ |
currentPage = page; |
} |
this.setPage(currentPage); |
} |
}, |
_setPage = function(n) { |
if (n > 0 && n <= page) { |
currentPage = n; |
pageWidth = pagedim[n].width; |
pageHeight = pagedim[n].height; |
} |
}, |
/** |
* Returns a document-specific font key - a label assigned to a |
* font name + font type combination at the time the font was added |
* to the font inventory. |
* |
* Font key is used as label for the desired font for a block of text |
* to be added to the PDF document stream. |
* @private |
* @function |
* @param {String} fontName can be undefined on "falthy" to indicate "use current" |
* @param {String} fontStyle can be undefined on "falthy" to indicate "use current" |
* @returns {String} Font key. |
*/ |
getFont = function(fontName, fontStyle) { |
var key; |
|
fontName = fontName !== undefined ? fontName : fonts[activeFontKey].fontName; |
fontStyle = fontStyle !== undefined ? fontStyle : fonts[activeFontKey].fontStyle; |
|
if (fontName !== undefined){ |
fontName = fontName.toLowerCase(); |
} |
switch(fontName){ |
case 'sans-serif': |
case 'verdana': |
case 'arial': |
case 'helvetica': |
fontName = 'helvetica'; |
break; |
case 'fixed': |
case 'monospace': |
case 'terminal': |
case 'courier': |
fontName = 'courier'; |
break; |
case 'serif': |
case 'cursive': |
case 'fantasy': |
default: |
fontName = 'times'; |
break; |
} |
|
try { |
// get a string like 'F3' - the KEY corresponding tot he font + type combination. |
key = fontmap[fontName][fontStyle]; |
} catch (e) {} |
|
if (!key) { |
//throw new Error("Unable to look up font label for font '" + fontName + "', '" |
//+ fontStyle + "'. Refer to getFontList() for available fonts."); |
key = fontmap['times'][fontStyle]; |
if (key == null){ |
key = fontmap['times']['normal']; |
} |
} |
return key; |
}, |
buildDocument = function() { |
|
outToPages = false; // switches out() to content |
objectNumber = 2; |
content = []; |
offsets = []; |
additionalObjects = []; |
|
// putHeader() |
out('%PDF-' + pdfVersion); |
|
putPages(); |
|
// Must happen after putPages |
// Modifies current object Id |
putAdditionalObjects(); |
|
putResources(); |
|
// Info |
newObject(); |
out('<<'); |
putInfo(); |
out('>>'); |
out('endobj'); |
|
// Catalog |
newObject(); |
out('<<'); |
putCatalog(); |
out('>>'); |
out('endobj'); |
|
// Cross-ref |
var o = content_length, i, p = "0000000000"; |
out('xref'); |
out('0 ' + (objectNumber + 1)); |
out(p+' 65535 f '); |
for (i = 1; i <= objectNumber; i++) { |
var offset = offsets[i]; |
if (typeof offset === 'function'){ |
out((p + offsets[i]()).slice(-10) + ' 00000 n '); |
}else{ |
out((p + offsets[i]).slice(-10) + ' 00000 n '); |
} |
} |
// Trailer |
out('trailer'); |
out('<<'); |
putTrailer(); |
out('>>'); |
out('startxref'); |
out(o); |
out('%%EOF'); |
|
outToPages = true; |
|
return content.join('\n'); |
}, |
|
getStyle = function(style) { |
// see path-painting operators in PDF spec |
var op = 'n'; // none |
if (style === "D") { |
op = 'S'; // stroke |
} else if (style === 'F') { |
op = 'f'; // fill |
} else if (style === 'FD' || style === 'DF') { |
op = 'B'; // both |
} else if (style === 'f' || style === 'f*' || style === 'B' || style === 'B*') { |
/* |
Allow direct use of these PDF path-painting operators: |
- f fill using nonzero winding number rule |
- f* fill using even-odd rule |
- B fill then stroke with fill using non-zero winding number rule |
- B* fill then stroke with fill using even-odd rule |
*/ |
op = style; |
} |
return op; |
}, |
// puts the style for the previously drawn path. If a patternKey is provided, the pattern is used to fill |
// the path. Use patternMatrix to transform the pattern to rhe right location. |
putStyle = function (style, patternKey, patternData) { |
style = getStyle(style); |
|
// stroking / filling / both the path |
if (!patternKey) { |
out(style); |
return; |
} |
|
patternData || (patternData = unitMatrix); |
|
var patternId = patternMap[patternKey]; |
var pattern = patterns[patternId]; |
|
if (pattern instanceof API.ShadingPattern) { |
out("q"); |
out("W " + style); |
|
if (pattern.gState) { |
API.setGState(pattern.gState); |
} |
|
out(patternData.toString() + " cm"); |
out("/" + patternId + " sh"); |
out("Q"); |
} else if (pattern instanceof API.TilingPattern) { |
// pdf draws patterns starting at the bottom left corner and they are not affected by the global transformation, |
// so we must flip them |
var matrix = new Matrix(1, 0, 0, -1, 0, pageHeight); |
|
if (patternData.matrix) { |
matrix = matrixMult(patternData.matrix || unitMatrix, matrix); |
|
// we cannot apply a matrix to the pattern on use so we must abuse the pattern matrix and create new instances |
// for each use |
patternId = pattern.createClone(patternKey, patternData.boundingBox, patternData.xStep, patternData.yStep, matrix).id; |
} |
|
out("q"); |
out("/Pattern cs"); |
out("/" + patternId + " scn"); |
|
if (pattern.gState) { |
API.setGState(pattern.gState); |
} |
|
out(style); |
out("Q"); |
} |
}, |
|
getArrayBuffer = function() { |
var data = buildDocument(), len = data.length, |
ab = new ArrayBuffer(len), u8 = new Uint8Array(ab); |
|
while(len--) u8[len] = data.charCodeAt(len); |
return ab; |
}, |
getBlob = function() { |
return new Blob([getArrayBuffer()], { type : "application/pdf" }); |
}, |
/** |
* Generates the PDF document. |
* |
* If `type` argument is undefined, output is raw body of resulting PDF returned as a string. |
* |
* @param {String} type A string identifying one of the possible output types. |
* @param {Object} options An object providing some additional signalling to PDF generator. |
* @function |
* @returns {jsPDF} |
* @methodOf jsPDF# |
* @name output |
*/ |
output = SAFE(function(type, options) { |
var datauri = ('' + type).substr(0,6) === 'dataur' |
? 'data:application/pdf;base64,'+btoa(buildDocument()):0; |
|
switch (type) { |
case undefined: |
return buildDocument(); |
case 'save': |
if (navigator.getUserMedia) { |
if (global.URL === undefined |
|| global.URL.createObjectURL === undefined) { |
return API.output('dataurlnewwindow'); |
} |
} |
saveAs(getBlob(), options); |
if(typeof saveAs.unload === 'function') { |
if(global.setTimeout) { |
setTimeout(saveAs.unload,911); |
} |
} |
break; |
case 'arraybuffer': |
return getArrayBuffer(); |
case 'blob': |
return getBlob(); |
case 'bloburi': |
case 'bloburl': |
// User is responsible of calling revokeObjectURL |
return global.URL && global.URL.createObjectURL(getBlob()) || void 0; |
case 'datauristring': |
case 'dataurlstring': |
return datauri; |
case 'dataurlnewwindow': |
var nW = global.open(datauri); |
if (nW || typeof safari === "undefined") return nW; |
/* pass through */ |
case 'datauri': |
case 'dataurl': |
return global.document.location.href = datauri; |
default: |
throw new Error('Output type "' + type + '" is not supported.'); |
} |
// @TODO: Add different output options |
}); |
|
switch (unit) { |
case 'pt': k = 1; break; |
case 'mm': k = 72 / 25.4000508; break; |
case 'cm': k = 72 / 2.54000508; break; |
case 'in': k = 72; break; |
case 'px': k = 96 / 72; break; |
case 'pc': k = 12; break; |
case 'em': k = 12; break; |
case 'ex': k = 6; break; |
default: |
throw ('Invalid unit: ' + unit); |
} |
|
//--------------------------------------- |
// Public API |
|
/** |
* Object exposing internal API to plugins |
* @public |
*/ |
API.internal = { |
'pdfEscape' : pdfEscape, |
'getStyle' : getStyle, |
/** |
* Returns {FontObject} describing a particular font. |
* @public |
* @function |
* @param {String} fontName (Optional) Font's family name |
* @param {String} fontStyle (Optional) Font's style variation name (Example:"Italic") |
* @returns {FontObject} |
*/ |
'getFont' : function() { |
return fonts[getFont.apply(API, arguments)]; |
}, |
'getFontSize' : function() { |
return activeFontSize; |
}, |
'getLineHeight' : function() { |
return activeFontSize * lineHeightProportion; |
}, |
'write' : function(string1 /*, string2, string3, etc */) { |
out(arguments.length === 1 ? string1 : Array.prototype.join.call(arguments, ' ')); |
}, |
'getCoordinateString' : function(value) { |
return f2(value); |
}, |
'getVerticalCoordinateString' : function(value) { |
return f2(value); |
}, |
'collections' : {}, |
'newObject' : newObject, |
'newAdditionalObject' : newAdditionalObject, |
'newObjectDeferred' : newObjectDeferred, |
'newObjectDeferredBegin' : newObjectDeferredBegin, |
'putStream' : putStream, |
'events' : events, |
// ratio that you use in multiplication of a given "size" number to arrive to 'point' |
// units of measurement. |
// scaleFactor is set at initialization of the document and calculated against the stated |
// default measurement units for the document. |
// If default is "mm", k is the number that will turn number in 'mm' into 'points' number. |
// through multiplication. |
'scaleFactor' : k, |
'pageSize' : { |
get width() { |
return pageWidth |
}, |
get height() { |
return pageHeight |
} |
}, |
'output' : function(type, options) { |
return output(type, options); |
}, |
'getNumberOfPages' : function() { |
return pages.length - 1; |
}, |
'pages' : pages, |
'out' : out, |
'f2' : f2, |
'getPageInfo' : function(pageNumberOneBased){ |
var objId = (pageNumberOneBased - 1) * 2 + 3; |
return {objId:objId, pageNumber:pageNumberOneBased, pageContext:pagesContext[pageNumberOneBased]}; |
}, |
'getCurrentPageInfo' : function(){ |
var objId = (currentPage - 1) * 2 + 3; |
return {objId:objId, pageNumber:currentPage, pageContext:pagesContext[currentPage]}; |
}, |
'getPDFVersion': function () { |
return pdfVersion; |
} |
}; |
|
/** |
* An object representing a pdf graphics state. |
* @param parameters A parameter object that contains all properties this graphics state wants to set. |
* Supported are: opacity |
* @constructor |
*/ |
API.GState = function (parameters) { |
var supported = "opacity"; |
for (var p in parameters) { |
if (parameters.hasOwnProperty(p) && supported.indexOf(p) >= 0) { |
this[p] = parameters[p]; |
} |
} |
this.id = ""; // set by addGState() |
this.objectNumber = -1; // will be set by putGState() |
|
this.equals = function (other) { |
var ignore = "id,objectNumber,equals"; |
if (!other || typeof other !== typeof this) |
return false; |
var count = 0; |
for (var p in this) { |
if (ignore.indexOf(p) >= 0) |
continue; |
if (this.hasOwnProperty(p) && !other.hasOwnProperty(p)) |
return false; |
if (this[p] !== other[p]) |
return false; |
count++; |
} |
for (var p in other) { |
if (other.hasOwnProperty(p) && ignore.indexOf(p) < 0) |
count--; |
} |
return count === 0; |
} |
}; |
|
/** |
* Adds a new {@link GState} for later use {@see setGState}. |
* @param {String} key |
* @param {GState} gState |
* @function |
* @returns {jsPDF} |
* @methodOf jsPDF# |
* @name addGState |
*/ |
API.addGState = function (key, gState) { |
addGState(key, gState); |
return this; |
}; |
|
/** |
* Adds (and transfers the focus to) new page to the PDF document. |
* @function |
* @returns {jsPDF} |
* |
* @methodOf jsPDF# |
* @name addPage |
*/ |
API.addPage = function() { |
_addPage.apply(this, arguments); |
return this; |
}; |
API.setPage = function() { |
_setPage.apply(this, arguments); |
return this; |
}; |
API.insertPage = function(beforePage) { |
this.addPage(); |
this.movePage(currentPage, beforePage); |
return this; |
}; |
API.movePage = function(targetPage, beforePage) { |
var tmpPagesContext, tmpPagedim, tmpPages, i; |
if (targetPage > beforePage){ |
tmpPages = pages[targetPage]; |
tmpPagedim = pagedim[targetPage]; |
tmpPagesContext = pagesContext[targetPage]; |
for (i = targetPage; i > beforePage; i--){ |
pages[i] = pages[i-1]; |
pagedim[i] = pagedim[i-1]; |
pagesContext[i] = pagesContext[i-1]; |
} |
pages[beforePage] = tmpPages; |
pagedim[beforePage] = tmpPagedim; |
pagesContext[beforePage] = tmpPagesContext; |
this.setPage(beforePage); |
} else if (targetPage < beforePage){ |
tmpPages = pages[targetPage]; |
tmpPagedim = pagedim[targetPage]; |
tmpPagesContext = pagesContext[targetPage]; |
for (i = targetPage; i < beforePage; i++){ |
pages[i] = pages[i+1]; |
pagedim[i] = pagedim[i+1]; |
pagesContext[i] = pagesContext[i+1]; |
} |
pages[beforePage] = tmpPages; |
pagedim[beforePage] = tmpPagedim; |
pagesContext[beforePage] = tmpPagesContext; |
this.setPage(beforePage); |
} |
return this; |
}; |
|
API.deletePage = function() { |
_deletePage.apply( this, arguments ); |
return this; |
}; |
API.setDisplayMode = function(zoom, layout, pmode) { |
zoomMode = zoom; |
layoutMode = layout; |
pageMode = pmode; |
return this; |
}; |
|
/** |
* Saves the current graphics state ("pushes it on the stack"). It can be restored by {@link restoreGraphicsState} |
* later. Here, the general pdf graphics state is meant, also including the current transformation matrix, |
* fill and stroke colors etc. |
* @function |
* @returns {jsPDF} |
* @methodOf jsPDF# |
* @name saveGraphicsState |
*/ |
API.saveGraphicsState = function () { |
out("q"); |
// as we cannot set font key and size independently we must keep track of both |
fontStateStack.push({ |
key: activeFontKey, |
size: activeFontSize |
}); |
return this; |
}; |
|
/** |
* Restores a previously saved graphics state saved by {@link saveGraphicsState} ("pops the stack"). |
* @function |
* @returns {jsPDF} |
* @methodOf jsPDF# |
* @name restoreGraphicsState |
*/ |
API.restoreGraphicsState = function () { |
out("Q"); |
|
// restore previous font state |
var fontState = fontStateStack.pop(); |
activeFontKey = fontState.key; |
activeFontSize = fontState.size; |
|
return this; |
}; |
|
/** |
* Appends this matrix to the left of all previously applied matrices. |
* @param {Matrix} matrix |
* @function |
* @returns {jsPDF} |
* @methodOf jsPDF# |
* @name setCurrentTransformationMatrix |
*/ |
API.setCurrentTransformationMatrix = function (matrix) { |
out(matrix.toString() + " cm"); |
return this; |
}; |
|
/** |
* Starts a new pdf form object, which means that all conseequent draw calls target a new independent object |
* until {@link endFormObject} is called. The created object can be referenced and drawn later using |
* {@link doFormObject}. Nested form objects are possible. |
* x, y, width, height set the bounding box that is used to clip the content. |
* @param {number} x |
* @param {number} y |
* @param {number} width |
* @param {number} height |
* @param {Matrix} matrix The matrix that will be applied to convert the form objects coordinate system to |
* the parent's. |
* @function |
* @returns {jsPDF} |
* @methodOf jsPDF# |
*/ |
API.beginFormObject = function (x, y, width, height, matrix) { |
// The user can set the output target to a new form object. Nested form objects are possible. |
// Currently, they use the resource dictionary of the surrounding stream. This should be changed, as |
// the PDF-Spec states: |
// "In PDF 1.2 and later versions, form XObjects may be independent of the content streams in which |
// they appear, and this is strongly recommended although not requiredIn PDF 1.2 and later versions, |
// form XObjects may be independent of the content streams in which they appear, and this is strongly |
// recommended although not required" |
beginNewRenderTarget(x, y, width, height, matrix); |
return this; |
}; |
|
/** |
* Completes and saves the form object. |
* @param {String} key The key by which this form object can be referenced. |
* @function |
* @returns {jsPDF} |
* @methodOf jsPDF# |
* @name endFormObject |
*/ |
API.endFormObject = function (key) { |
endFormObject(key); |
return this; |
}; |
|
/** |
* Draws the specified form object by referencing to the respective pdf XObject created with |
* {@link API.beginFormObject} and {@link endFormObject}. |
* The location is determined by matrix. |
* @param {String} key The key to the form object. |
* @param {Matrix} matrix The matrix applied before drawing the form object. |
* @function |
* @returns {jsPDF} |
* @methodOf jsPDF# |
* @name doFormObject |
*/ |
API.doFormObject = function (key, matrix) { |
var xObject = renderTargets[renderTargetMap[key]]; |
out("q"); |
out(matrix.toString() + " cm"); |
out("/" + xObject.id + " Do"); |
out("Q"); |
return this; |
}; |
|
/** |
* Returns the form object specified by key. |
* @param key {String} |
* @returns {{x: number, y: number, width: number, height: number, matrix: Matrix}} |
* @function |
* @returns {jsPDF} |
* @methodOf jsPDF# |
* @name getFormObject |
*/ |
API.getFormObject = function (key) { |
var xObject = renderTargets[renderTargetMap[key]]; |
return { |
x: xObject.x, |
y: xObject.y, |
width: xObject.width, |
height: xObject.height, |
matrix: xObject.matrix |
}; |
}; |
|
/** |
* A matrix object for 2D homogenous transformations: |
* | a b 0 | |
* | c d 0 | |
* | e f 1 | |
* pdf multiplies matrices righthand: v' = v x m1 x m2 x ... |
* @param {number} a |
* @param {number} b |
* @param {number} c |
* @param {number} d |
* @param {number} e |
* @param {number} f |
* @constructor |
*/ |
API.Matrix = Matrix; |
|
/** |
* Multiplies two matrices. (see {@link Matrix}) |
* @param {Matrix} m1 |
* @param {Matrix} m2 |
*/ |
API.matrixMult = matrixMult; |
|
/** |
* The unit matrix (equal to new Matrix(1, 0, 0, 1, 0, 0). |
* @type {Matrix} |
*/ |
API.unitMatrix = unitMatrix; |
|
var Pattern = function (gState, matrix) { |
this.gState = gState; |
this.matrix = matrix; |
|
this.id = ""; // set by addPattern() |
this.objectNumber = -1; // will be set by putPattern() |
}; |
|
/** |
* A pattern describing a shading pattern. |
* @param {String} type One of "axial" or "radial" |
* @param {Array<Number>} coords Either [x1, y1, x2, y2] for "axial" type describing the two interpolation points |
* or [x1, y1, r, x2, y2, r2] for "radial" describing inner and the outer circle. |
* @param {Array<Object>} colors An array of objects with the fields "offset" and "color". "offset" describes |
* the offset in parameter space [0, 1]. "color" is an array of length 3 describing RGB values in [0, 255]. |
* @param {GState=} gState An additional graphics state that gets applied to the pattern (optional). |
* @param {Matrix=} matrix A matrix that describes the transformation between the pattern coordinate system |
* and the use coordinate system (optional). |
* @constructor |
* @extends API.Pattern |
*/ |
API.ShadingPattern = function (type, coords, colors, gState, matrix) { |
// see putPattern() for information how they are realized |
this.type = type === "axial" ? 2 : 3; |
this.coords = coords; |
this.colors = colors; |
|
Pattern.call(this, gState, matrix); |
}; |
|
/** |
* A PDF Tiling pattern. |
* @param {Array.<Number>} boundingBox The bounding box at which one pattern cell gets clipped. |
* @param {Number} xStep Horizontal spacing between pattern cells. |
* @param {Number} yStep Vertical spacing between pattern cells. |
* @param {API.GState=} gState An additional graphics state that gets applied to the pattern (optional). |
* @param {Matrix=} matrix A matrix that describes the transformation between the pattern coordinate system |
* and the use coordinate system (optional). |
* @constructor |
* @extends API.Pattern |
*/ |
API.TilingPattern = function (boundingBox, xStep, yStep, gState, matrix) { |
this.boundingBox = boundingBox; |
this.xStep = xStep; |
this.yStep = yStep; |
|
this.stream = ""; // set by endTilingPattern(); |
|
this.cloneIndex = 0; |
|
Pattern.call(this, gState, matrix); |
}; |
|
API.TilingPattern.prototype = { |
createClone: function (patternKey, boundingBox, xStep, yStep, matrix) { |
var clone = new API.TilingPattern(boundingBox || this.boundingBox, xStep || this.xStep, yStep || this.yStep, |
this.gState, matrix || this.matrix); |
clone.stream = this.stream; |
var key = patternKey + "$$" + this.cloneIndex++ + "$$"; |
addPattern(key, clone); |
return clone; |
} |
}; |
|
/** |
* Adds a new {@link API.ShadingPattern} for later use. |
* @param {String} key |
* @param {Pattern} pattern |
* @function |
* @returns {jsPDF} |
* @methodOf jsPDF# |
* @name addPattern |
*/ |
API.addShadingPattern = function (key, pattern) { |
addPattern(key, pattern); |
return this; |
}; |
|
/** |
* Begins a new tiling pattern. All subsequent render calls are drawn to this pattern until {@link API.endTilingPattern} |
* gets called. |
* @param {API.Pattern} pattern |
*/ |
API.beginTilingPattern = function (pattern) { |
beginNewRenderTarget(pattern.boundingBox[0], pattern.boundingBox[1], |
pattern.boundingBox[2] - pattern.boundingBox[0], pattern.boundingBox[3] - pattern.boundingBox[1], pattern.matrix); |
}; |
|
/** |
* Ends a tiling pattern and sets the render target to the one active before {@link API.beginTilingPattern} has been called. |
* @param {string} key A unique key that is used to reference this pattern at later use. |
* @param {API.Pattern} pattern The pattern to end. |
*/ |
API.endTilingPattern = function (key, pattern) { |
// retrieve the stream |
pattern.stream = pages[currentPage].join("\n"); |
|
addPattern(key, pattern); |
|
events.publish("endTilingPattern", pattern); |
|
// restore state from stack |
renderTargetStack.pop().restore(); |
}; |
|
/** |
* Adds text to page. Supports adding multiline text when 'text' argument is an Array of Strings. |
* |
* @function |
* @param {String|Array} text String or array of strings to be added to the page. Each line is shifted one line down |
* per font, spacing settings declared before this call. |
* @param {Number} x Coordinate (in units declared at inception of PDF document) against left edge of the page |
* @param {Number} y Coordinate (in units declared at inception of PDF document) against upper edge of the page |
* @param {Object} flags Collection of settings signalling how the text must be encoded. Defaults are sane. If you |
* think you want to pass some flags, you likely can read the source. |
* @param {number|Matrix} transform If transform is a number the text will be rotated by this value. If it is a Matrix, |
* this matrix gets directly applied to the text, which allows shearing effects etc. |
* @param align {string} |
* @returns {jsPDF} |
* @methodOf jsPDF# |
*/ |
API.text = function(text, x, y, flags, transform, align) { |
/** |
* Inserts something like this into PDF |
* BT |
* /F1 16 Tf % Font name + size |
* 16 TL % How many units down for next line in multiline text |
* 0 g % color |
* 28.35 813.54 Td % position |
* (line one) Tj |
* T* (line two) Tj |
* T* (line three) Tj |
* ET |
*/ |
function ESC(s) { |
s = s.split("\t").join(Array(options.TabLen||9).join(" ")); |
return pdfEscape(s, flags); |
} |
|
// Pre-August-2012 the order of arguments was function(x, y, text, flags) |
// in effort to make all calls have similar signature like |
// function(data, coordinates... , miscellaneous) |
// this method had its args flipped. |
// code below allows backward compatibility with old arg order. |
if (typeof text === 'number') { |
var tmp = y; |
y = x; |
x = text; |
text = tmp; |
} |
|
// If there are any newlines in text, we assume |
// the user wanted to print multiple lines, so break the |
// text up into an array. If the text is already an array, |
// we assume the user knows what they are doing. |
// Convert text into an array anyway to simplify |
// later code. |
if (typeof text === 'string') { |
if(text.match(/[\n\r]/)) { |
text = text.split( /\r\n|\r|\n/g); |
} else { |
text = [text]; |
} |
} |
if (typeof transform === 'string') { |
align = transform; |
transform = null; |
} |
if (typeof flags === 'string') { |
align = flags; |
flags = null; |
} |
if (typeof flags === 'number') { |
transform = flags; |
flags = null; |
} |
|
var todo; |
if (transform && typeof transform === "number") { |
transform *= (Math.PI / 180); |
var c = Math.cos(transform), |
s = Math.sin(transform); |
transform = new Matrix(c, s , -s, c, 0, 0); |
} else if (!transform) { |
transform = unitMatrix; |
} |
|
flags = flags || {}; |
if (!('noBOM' in flags)) |
flags.noBOM = true; |
if (!('autoencode' in flags)) |
flags.autoencode = true; |
|
var strokeOption = ''; |
var pageContext = this.internal.getCurrentPageInfo().pageContext; |
if (true === flags.stroke){ |
if (pageContext.lastTextWasStroke !== true){ |
strokeOption = '1 Tr\n'; |
pageContext.lastTextWasStroke = true; |
} |
} |
else{ |
if (pageContext.lastTextWasStroke){ |
strokeOption = '0 Tr\n'; |
} |
pageContext.lastTextWasStroke = false; |
} |
|
if (typeof this._runningPageHeight === 'undefined'){ |
this._runningPageHeight = 0; |
} |
|
if (typeof text === 'string') { |
text = ESC(text); |
} else if (Object.prototype.toString.call(text) === '[object Array]') { |
// we don't want to destroy original text array, so cloning it |
var sa = text.concat(), da = [], len = sa.length; |
// we do array.join('text that must not be PDFescaped") |
// thus, pdfEscape each component separately |
while (len--) { |
da.push(ESC(sa.shift())); |
} |
var linesLeft = Math.ceil((y - this._runningPageHeight) / (activeFontSize * lineHeightProportion)); |
if (0 <= linesLeft && linesLeft < da.length + 1) { |
//todo = da.splice(linesLeft-1); |
} |
|
if( align ) { |
var left, |
prevX, |
maxLineLength, |
leading = activeFontSize * lineHeightProportion, |
lineWidths = text.map( function( v ) { |
return this.getStringUnitWidth( v ) * activeFontSize; |
}, this ); |
maxLineLength = Math.max.apply( Math, lineWidths ); |
// The first line uses the "main" Td setting, |
// and the subsequent lines are offset by the |
// previous line's x coordinate. |
if( align === "center" ) { |
// The passed in x coordinate defines |
// the center point. |
left = x - maxLineLength / 2; |
x -= lineWidths[0] / 2; |
} else if ( align === "right" ) { |
// The passed in x coordinate defines the |
// rightmost point of the text. |
left = x - maxLineLength; |
x -= lineWidths[0]; |
} else { |
throw new Error('Unrecognized alignment option, use "center" or "right".'); |
} |
prevX = x; |
text = da[0] + ") Tj\n"; |
for ( i = 1, len = da.length ; i < len; i++ ) { |
var delta = maxLineLength - lineWidths[i]; |
if( align === "center" ) delta /= 2; |
// T* = x-offset leading Td ( text ) |
text += ( ( left - prevX ) + delta ) + " -" + leading + " Td (" + da[i]; |
prevX = left + delta; |
if( i < len - 1 ) { |
text += ") Tj\n"; |
} |
} |
} else { |
text = da.join(") Tj\nT* ("); |
} |
} else { |
throw new Error('Type of text must be string or Array. "' + text + '" is not recognized.'); |
} |
// Using "'" ("go next line and render text" mark) would save space but would complicate our rendering code, templates |
|
// BT .. ET does NOT have default settings for Tf. You must state that explicitely every time for BT .. ET |
// if you want text transformation matrix (+ multiline) to work reliably (which reads sizes of things from font declarations) |
// Thus, there is NO useful, *reliable* concept of "default" font for a page. |
// The fact that "default" (reuse font used before) font worked before in basic cases is an accident |
// - readers dealing smartly with brokenness of jsPDF's markup. |
|
var curY; |
|
if (todo){ |
//this.addPage(); |
//this._runningPageHeight += y - (activeFontSize * 1.7); |
//curY = f2(activeFontSize * 1.7); |
} else { |
curY = f2(y); |
} |
//curY = f2(((y - this._runningPageHeight)); |
|
// if (curY < 0){ |
// console.log('auto page break'); |
// this.addPage(); |
// this._runningPageHeight = y - (activeFontSize * 1.7); |
// curY = f2(activeFontSize * 1.7); |
// } |
|
var translate = new Matrix(1, 0, 0, -1, x, curY); |
transform = matrixMult(translate, transform); |
var position = transform.toString() + " Tm"; |
|
out( |
'BT\n' + |
(activeFontSize * lineHeightProportion) + ' TL\n' + // line spacing |
strokeOption +// stroke option |
position + '\n(' + |
text + |
') Tj\nET'); |
|
if (todo) { |
//this.text( todo, x, activeFontSize * 1.7); |
//this.text( todo, x, this._runningPageHeight + (activeFontSize * 1.7)); |
this.text( todo, x, y);// + (activeFontSize * 1.7)); |
} |
|
return this; |
}; |
|
|
API.lstext = function(text, x, y, spacing) { |
for (var i = 0, len = text.length ; i < len; i++, x += spacing) this.text(text[i], x, y); |
}; |
|
/** |
* Draw a line |
* @param {number} x1 |
* @param {number} y1 |
* @param {number} x2 |
* @param {number} y2 |
* @function |
* @returns {jsPDF} |
* @methodOf jsPDF# |
* @name line |
*/ |
API.line = function(x1, y1, x2, y2) { |
return this.lines([[x2 - x1, y2 - y1]], x1, y1, [1, 1], "D"); |
}; |
|
API.clip = function() { |
// By patrick-roberts, github.com/MrRio/jsPDF/issues/328 |
// Call .clip() after calling .rect() with a style argument of null |
out('W'); // clip |
out('S'); // stroke path; necessary for clip to work |
}; |
|
|
/** |
* @typedef {Object} PatternData |
* {Matrix|undefined} matrix |
* {Number|undefined} xStep |
* {Number|undefined} yStep |
* {Array.<Number>|undefined} boundingBox |
*/ |
|
/** |
* Adds series of curves (straight lines or cubic bezier curves) to canvas, starting at `x`, `y` coordinates. |
* All data points in `lines` are relative to last line origin. |
* `x`, `y` become x1,y1 for first line / curve in the set. |
* For lines you only need to specify [x2, y2] - (ending point) vector against x1, y1 starting point. |
* For bezier curves you need to specify [x2,y2,x3,y3,x4,y4] - vectors to control points 1, 2, ending point. All vectors are against the start of the curve - x1,y1. |
* |
* @example .lines([[2,2],[-2,2],[1,1,2,2,3,3],[2,1]], 212,110, 10) // line, line, bezier curve, line |
* @param {Array} lines Array of *vector* shifts as pairs (lines) or sextets (cubic bezier curves). |
* @param {Number} x Coordinate (in units declared at inception of PDF document) against left edge of the page |
* @param {Number} y Coordinate (in units declared at inception of PDF document) against upper edge of the page |
* @param {Number} scale (Defaults to [1.0,1.0]) x,y Scaling factor for all vectors. Elements can be any floating number Sub-one makes drawing smaller. Over-one grows the drawing. Negative flips the direction. |
* @param {String} style A string specifying the painting style or null. Valid styles include: 'S' [default] - stroke, 'F' - fill, and 'DF' (or 'FD') - fill then stroke. A null value postpones setting the style so that a shape may be composed using multiple method calls. The last drawing method call used to define the shape should not have a null style argument. |
* @param {Boolean} closed If true, the path is closed with a straight line from the end of the last curve to the starting point. |
* @param {String} patternKey The pattern key for the pattern that should be used to fill the path. |
* @param {Matrix|PatternData} patternData The matrix that transforms the pattern into user space, or an object that |
* will modify the pattern on use. |
* @function |
* @returns {jsPDF} |
* @methodOf jsPDF# |
* @name lines |
*/ |
API.lines = function(lines, x, y, scale, style, closed, patternKey, patternData) { |
var scalex,scaley,i,l,leg,x2,y2,x3,y3,x4,y4; |
|
// Pre-August-2012 the order of arguments was function(x, y, lines, scale, style) |
// in effort to make all calls have similar signature like |
// function(content, coordinateX, coordinateY , miscellaneous) |
// this method had its args flipped. |
// code below allows backward compatibility with old arg order. |
if (typeof lines === 'number') { |
var tmp = y; |
y = x; |
x = lines; |
lines = tmp; |
} |
|
scale = scale || [1, 1]; |
|
// starting point |
out(f3(x) + ' ' + f3(y) + ' m '); |
|
scalex = scale[0]; |
scaley = scale[1]; |
l = lines.length; |
//, x2, y2 // bezier only. In page default measurement "units", *after* scaling |
//, x3, y3 // bezier only. In page default measurement "units", *after* scaling |
// ending point for all, lines and bezier. . In page default measurement "units", *after* scaling |
x4 = x; // last / ending point = starting point for first item. |
y4 = y; // last / ending point = starting point for first item. |
|
for (i = 0; i < l; i++) { |
leg = lines[i]; |
if (leg.length === 2) { |
// simple line |
x4 = leg[0] * scalex + x4; // here last x4 was prior ending point |
y4 = leg[1] * scaley + y4; // here last y4 was prior ending point |
out(f3(x4) + ' ' + f3(y4) + ' l'); |
} else { |
// bezier curve |
x2 = leg[0] * scalex + x4; // here last x4 is prior ending point |
y2 = leg[1] * scaley + y4; // here last y4 is prior ending point |
x3 = leg[2] * scalex + x4; // here last x4 is prior ending point |
y3 = leg[3] * scaley + y4; // here last y4 is prior ending point |
x4 = leg[4] * scalex + x4; // here last x4 was prior ending point |
y4 = leg[5] * scaley + y4; // here last y4 was prior ending point |
out( |
f3(x2) + ' ' + |
f3(y2) + ' ' + |
f3(x3) + ' ' + |
f3(y3) + ' ' + |
f3(x4) + ' ' + |
f3(y4) + ' c'); |
} |
} |
|
if (closed) { |
out('h'); |
} |
|
putStyle(style, patternKey, patternData); |
|
return this; |
}; |
|
/** |
* Similar to {@link API.lines} but all coordinates are interpreted as absolute coordinates instead of relative. |
* @param {Array<Object>} lines An array of {op: operator, c: coordinates} object, where op is one of "m" (move to), "l" (line to) |
* "c" (cubic bezier curve) and "h" (close (sub)path)). c is an array of coordinates. "m" and "l" expect two, "c" |
* six and "h" an empty array (or undefined). |
* @param {String} style The style |
* @param {String} patternKey The pattern key for the pattern that should be used to fill the path. |
* @param {Matrix|PatternData} patternData The matrix that transforms the pattern into user space, or an object that |
* will modify the pattern on use. |
* @function |
* @returns {jsPDF} |
* @methodOf jsPDF# |
* @name path |
*/ |
API.path = function (lines, style, patternKey, patternData) { |
|
for (var i = 0; i < lines.length; i++) { |
var leg = lines[i]; |
var coords = leg.c; |
switch (leg.op) { |
case "m": |
// move |
out(f3(coords[0]) + ' ' + f3(coords[1]) + ' m'); |
break; |
case "l": |
// simple line |
out(f3(coords[0]) + ' ' + f3(coords[1]) + ' l'); |
break; |
case "c": |
// bezier curve |
out([ |
f3(coords[0]), |
f3(coords[1]), |
f3(coords[2]), |
f3(coords[3]), |
f3(coords[4]), |
f3(coords[5]), |
"c" |
].join(" ")); |
break; |
case "h": |
// close path |
out("h"); |
} |
|
|
} |
|
putStyle(style, patternKey, patternData); |
|
return this; |
}; |
|
/** |
* Adds a rectangle to PDF |
* |
* @param {Number} x Coordinate (in units declared at inception of PDF document) against left edge of the page |
* @param {Number} y Coordinate (in units declared at inception of PDF document) against upper edge of the page |
* @param {Number} w Width (in units declared at inception of PDF document) |
* @param {Number} h Height (in units declared at inception of PDF document) |
* @param {String} style A string specifying the painting style or null. Valid styles include: 'S' [default] - stroke, 'F' - fill, and 'DF' (or 'FD') - fill then stroke. A null value postpones setting the style so that a shape may be composed using multiple method calls. The last drawing method call used to define the shape should not have a null style argument. |
* @param {String} patternKey The pattern key for the pattern that should be used to fill the primitive. |
* @param {Matrix|PatternData} patternData The matrix that transforms the pattern into user space, or an object that |
* will modify the pattern on use. |
* @function |
* @returns {jsPDF} |
* @methodOf jsPDF# |
* @name rect |
*/ |
API.rect = function(x, y, w, h, style, patternKey, patternData) { |
out([ |
f2(x), |
f2(y), |
f2(w), |
f2(-h), |
're' |
].join(' ')); |
|
putStyle(style, patternKey, patternData); |
|
return this; |
}; |
|
/** |
* Adds a triangle to PDF |
* |
* @param {Number} x1 Coordinate (in units declared at inception of PDF document) against left edge of the page |
* @param {Number} y1 Coordinate (in units declared at inception of PDF document) against upper edge of the page |
* @param {Number} x2 Coordinate (in units declared at inception of PDF document) against left edge of the page |
* @param {Number} y2 Coordinate (in units declared at inception of PDF document) against upper edge of the page |
* @param {Number} x3 Coordinate (in units declared at inception of PDF document) against left edge of the page |
* @param {Number} y3 Coordinate (in units declared at inception of PDF document) against upper edge of the page |
* @param {String} style A string specifying the painting style or null. Valid styles include: 'S' [default] - stroke, 'F' - fill, and 'DF' (or 'FD') - fill then stroke. A null value postpones setting the style so that a shape may be composed using multiple method calls. The last drawing method call used to define the shape should not have a null style argument. |
* @param {String} patternKey The pattern key for the pattern that should be used to fill the primitive. |
* @param {Matrix|PatternData} patternData The matrix that transforms the pattern into user space, or an object that |
* will modify the pattern on use. |
* @function |
* @returns {jsPDF} |
* @methodOf jsPDF# |
* @name triangle |
*/ |
API.triangle = function(x1, y1, x2, y2, x3, y3, style, patternKey, patternData) { |
this.lines( |
[ |
[x2 - x1, y2 - y1], // vector to point 2 |
[x3 - x2, y3 - y2], // vector to point 3 |
[x1 - x3, y1 - y3]// closing vector back to point 1 |
], |
x1, |
y1, // start of path |
[1, 1], |
style, |
true, |
patternKey, |
patternData |
); |
return this; |
}; |
|
/** |
* Adds a rectangle with rounded corners to PDF |
* |
* @param {Number} x Coordinate (in units declared at inception of PDF document) against left edge of the page |
* @param {Number} y Coordinate (in units declared at inception of PDF document) against upper edge of the page |
* @param {Number} w Width (in units declared at inception of PDF document) |
* @param {Number} h Height (in units declared at inception of PDF document) |
* @param {Number} rx Radius along x axis (in units declared at inception of PDF document) |
* @param {Number} ry Radius along y axis (in units declared at inception of PDF document) |
* @param {String} style A string specifying the painting style or null. Valid styles include: 'S' [default] - stroke, 'F' - fill, and 'DF' (or 'FD') - fill then stroke. A null value postpones setting the style so that a shape may be composed using multiple method calls. The last drawing method call used to define the shape should not have a null style argument. |
* @param {String} patternKey The pattern key for the pattern that should be used to fill the primitive. |
* @param {Matrix|PatternData} patternData The matrix that transforms the pattern into user space, or an object that |
* will modify the pattern on use. |
* @function |
* @returns {jsPDF} |
* @methodOf jsPDF# |
* @name roundedRect |
*/ |
API.roundedRect = function(x, y, w, h, rx, ry, style, patternKey, patternData) { |
var MyArc = 4 / 3 * (Math.SQRT2 - 1); |
|
rx = Math.min(rx, w * 0.5); |
ry = Math.min(ry, h * 0.5); |
|
this.lines( |
[ |
[(w - 2 * rx), 0], |
[(rx * MyArc), 0, rx, ry - (ry * MyArc), rx, ry], |
[0, (h - 2 * ry)], |
[0, (ry * MyArc), - (rx * MyArc), ry, -rx, ry], |
[(-w + 2 * rx), 0], |
[ - (rx * MyArc), 0, -rx, - (ry * MyArc), -rx, -ry], |
[0, (-h + 2 * ry)], |
[0, - (ry * MyArc), (rx * MyArc), -ry, rx, -ry] |
], |
x + rx, |
y, // start of path |
[1, 1], |
style, |
true, |
patternKey, |
patternData |
); |
return this; |
}; |
|
/** |
* Adds an ellipse to PDF |
* |
* @param {Number} x Coordinate (in units declared at inception of PDF document) against left edge of the page |
* @param {Number} y Coordinate (in units declared at inception of PDF document) against upper edge of the page |
* @param {Number} rx Radius along x axis (in units declared at inception of PDF document) |
* @param {Number} ry Radius along y axis (in units declared at inception of PDF document) |
* @param {String} style A string specifying the painting style or null. Valid styles include: 'S' [default] - stroke, 'F' - fill, and 'DF' (or 'FD') - fill then stroke. A null value postpones setting the style so that a shape may be composed using multiple method calls. The last drawing method call used to define the shape should not have a null style argument. |
* @param {String} patternKey The pattern key for the pattern that should be used to fill the primitive. |
* @param {Matrix|PatternData} patternData The matrix that transforms the pattern into user space, or an object that |
* will modify the pattern on use. |
* @function |
* @returns {jsPDF} |
* @methodOf jsPDF# |
* @name ellipse |
*/ |
API.ellipse = function(x, y, rx, ry, style, patternKey, patternData) { |
var lx = 4 / 3 * (Math.SQRT2 - 1) * rx, |
ly = 4 / 3 * (Math.SQRT2 - 1) * ry; |
|
out([ |
f2(x + rx), |
f2(y), |
'm', |
f2(x + rx), |
f2(y - ly), |
f2(x + lx), |
f2(y - ry), |
f2(x), |
f2(y - ry), |
'c' |
].join(' ')); |
out([ |
f2(x - lx), |
f2(y - ry), |
f2(x - rx), |
f2(y - ly), |
f2(x - rx), |
f2(y), |
'c' |
].join(' ')); |
out([ |
f2(x - rx), |
f2(y + ly), |
f2(x - lx), |
f2(y + ry), |
f2(x), |
f2(y + ry), |
'c' |
].join(' ')); |
out([ |
f2(x + lx), |
f2(y + ry), |
f2(x + rx), |
f2(y + ly), |
f2(x + rx), |
f2(y), |
'c' |
].join(' ')); |
|
putStyle(style, patternKey, patternData); |
|
return this; |
}; |
|
/** |
* Adds an circle to PDF |
* |
* @param {Number} x Coordinate (in units declared at inception of PDF document) against left edge of the page |
* @param {Number} y Coordinate (in units declared at inception of PDF document) against upper edge of the page |
* @param {Number} r Radius (in units declared at inception of PDF document) |
* @param {String} style A string specifying the painting style or null. Valid styles include: 'S' [default] - stroke, 'F' - fill, and 'DF' (or 'FD') - fill then stroke. A null value postpones setting the style so that a shape may be composed using multiple method calls. The last drawing method call used to define the shape should not have a null style argument. |
* @param {String} patternKey The pattern key for the pattern that should be used to fill the primitive. |
* @param {Matrix|PatternData} patternData The matrix that transforms the pattern into user space, or an object that |
* will modify the pattern on use. |
* @function |
* @returns {jsPDF} |
* @methodOf jsPDF# |
* @name circle |
*/ |
API.circle = function(x, y, r, style, patternKey, patternData) { |
return this.ellipse(x, y, r, r, style, patternKey, patternData); |
}; |
|
/** |
* Adds a properties to the PDF document |
* |
* @param {Object} properties A property_name-to-property_value object structure. |
* @function |
* @returns {jsPDF} |
* @methodOf jsPDF# |
* @name setProperties |
*/ |
API.setProperties = function(properties) { |
// copying only those properties we can render. |
for (var property in documentProperties) { |
if (documentProperties.hasOwnProperty(property) && properties[property]) { |
documentProperties[property] = properties[property]; |
} |
} |
return this; |
}; |
|
/** |
* Sets font size for upcoming text elements. |
* |
* @param {Number} size Font size in points. |
* @function |
* @returns {jsPDF} |
* @methodOf jsPDF# |
* @name setFontSize |
*/ |
API.setFontSize = function(size) { |
activeFontSize = size; |
out("/" + activeFontKey + " " + activeFontSize + " Tf"); |
return this; |
}; |
|
API.getFontSize = function () { |
return activeFontSize; |
}; |
|
/** |
* Sets text font face, variant for upcoming text elements. |
* See output of jsPDF.getFontList() for possible font names, styles. |
* |
* @param {String} fontName Font name or family. Example: "times" |
* @param {String} fontStyle Font style or variant. Example: "italic" |
* @function |
* @returns {jsPDF} |
* @methodOf jsPDF# |
* @name setFont |
*/ |
API.setFont = function(fontName, fontStyle) { |
activeFontKey = getFont(fontName, fontStyle); |
// if font is not found, the above line blows up and we never go further |
out("/" + activeFontKey + " " + activeFontSize + " Tf"); |
return this; |
}; |
|
/** |
* Switches font style or variant for upcoming text elements, |
* while keeping the font face or family same. |
* See output of jsPDF.getFontList() for possible font names, styles. |
* |
* @param {String} style Font style or variant. Example: "italic" |
* @function |
* @returns {jsPDF} |
* @methodOf jsPDF# |
* @name setFontStyle |
*/ |
API.setFontStyle = API.setFontType = function(style) { |
activeFontKey = getFont(undefined, style); |
// if font is not found, the above line blows up and we never go further |
return this; |
}; |
|
/** |
* Returns an object - a tree of fontName to fontStyle relationships available to |
* active PDF document. |
* |
* @public |
* @function |
* @returns {Object} Like {'times':['normal', 'italic', ... ], 'arial':['normal', 'bold', ... ], ... } |
* @methodOf jsPDF# |
* @name getFontList |
*/ |
API.getFontList = function() { |
// TODO: iterate over fonts array or return copy of fontmap instead in case more are ever added. |
var list = {},fontName,fontStyle,tmp; |
|
for (fontName in fontmap) { |
if (fontmap.hasOwnProperty(fontName)) { |
list[fontName] = tmp = []; |
for (fontStyle in fontmap[fontName]) { |
if (fontmap[fontName].hasOwnProperty(fontStyle)) { |
tmp.push(fontStyle); |
} |
} |
} |
} |
|
return list; |
}; |
|
/** |
* Add a custom font. |
* |
* @param {String} postScriptName name of the Font. Example: "Menlo-Regular" |
* @param {String} fontName of font-family from @font-face definition. Example: "Menlo Regular" |
* @param {String} fontStyle style. Example: "normal" |
* @function |
* @returns the {fontKey} (same as the internal method) |
* @methodOf jsPDF# |
* @name addFont |
*/ |
API.addFont = function(postScriptName, fontName, fontStyle) { |
addFont(postScriptName, fontName, fontStyle, 'StandardEncoding'); |
}; |
|
/** |
* Sets line width for upcoming lines. |
* |
* @param {Number} width Line width (in units declared at inception of PDF document) |
* @function |
* @returns {jsPDF} |
* @methodOf jsPDF# |
* @name setLineWidth |
*/ |
API.setLineWidth = function(width) { |
out(width.toFixed(2) + ' w'); |
return this; |
}; |
|
/** |
* Sets the stroke color for upcoming elements. |
* |
* Depending on the number of arguments given, Gray, RGB, or CMYK |
* color space is implied. |
* |
* When only ch1 is given, "Gray" color space is implied and it |
* must be a value in the range from 0.00 (solid black) to to 1.00 (white) |
* if values are communicated as String types, or in range from 0 (black) |
* to 255 (white) if communicated as Number type. |
* The RGB-like 0-255 range is provided for backward compatibility. |
* |
* When only ch1,ch2,ch3 are given, "RGB" color space is implied and each |
* value must be in the range from 0.00 (minimum intensity) to to 1.00 |
* (max intensity) if values are communicated as String types, or |
* from 0 (min intensity) to to 255 (max intensity) if values are communicated |
* as Number types. |
* The RGB-like 0-255 range is provided for backward compatibility. |
* |
* When ch1,ch2,ch3,ch4 are given, "CMYK" color space is implied and each |
* value must be a in the range from 0.00 (0% concentration) to to |
* 1.00 (100% concentration) |
* |
* Because JavaScript treats fixed point numbers badly (rounds to |
* floating point nearest to binary representation) it is highly advised to |
* communicate the fractional numbers as String types, not JavaScript Number type. |
* |
* @param {Number|String} ch1 Color channel value |
* @param {Number|String} ch2 Color channel value |
* @param {Number|String} ch3 Color channel value |
* @param {Number|String} ch4 Color channel value |
* |
* @function |
* @returns {jsPDF} |
* @methodOf jsPDF# |
* @name setDrawColor |
*/ |
API.setDrawColor = function(ch1, ch2, ch3, ch4) { |
var color; |
if (ch2 === undefined || (ch4 === undefined && ch1 === ch2 === ch3)) { |
// Gray color space. |
if (typeof ch1 === 'string') { |
color = ch1 + ' G'; |
} else { |
color = f2(ch1 / 255) + ' G'; |
} |
} else if (ch4 === undefined) { |
// RGB |
if (typeof ch1 === 'string') { |
color = [ch1, ch2, ch3, 'RG'].join(' '); |
} else { |
color = [f2(ch1 / 255), f2(ch2 / 255), f2(ch3 / 255), 'RG'].join(' '); |
} |
} else { |
// CMYK |
if (typeof ch1 === 'string') { |
color = [ch1, ch2, ch3, ch4, 'K'].join(' '); |
} else { |
color = [f2(ch1), f2(ch2), f2(ch3), f2(ch4), 'K'].join(' '); |
} |
} |
|
out(color); |
return this; |
}; |
|
/** |
* Sets the fill color for upcoming elements. |
* |
* Depending on the number of arguments given, Gray, RGB, or CMYK |
* color space is implied. |
* |
* When only ch1 is given, "Gray" color space is implied and it |
* must be a value in the range from 0.00 (solid black) to to 1.00 (white) |
* if values are communicated as String types, or in range from 0 (black) |
* to 255 (white) if communicated as Number type. |
* The RGB-like 0-255 range is provided for backward compatibility. |
* |
* When only ch1,ch2,ch3 are given, "RGB" color space is implied and each |
* value must be in the range from 0.00 (minimum intensity) to to 1.00 |
* (max intensity) if values are communicated as String types, or |
* from 0 (min intensity) to to 255 (max intensity) if values are communicated |
* as Number types. |
* The RGB-like 0-255 range is provided for backward compatibility. |
* |
* When ch1,ch2,ch3,ch4 are given, "CMYK" color space is implied and each |
* value must be a in the range from 0.00 (0% concentration) to to |
* 1.00 (100% concentration) |
* |
* Because JavaScript treats fixed point numbers badly (rounds to |
* floating point nearest to binary representation) it is highly advised to |
* communicate the fractional numbers as String types, not JavaScript Number type. |
* |
* @param {Number|String} ch1 Color channel value |
* @param {Number|String} ch2 Color channel value |
* @param {Number|String} ch3 Color channel value |
* @param {Number|String} ch4 Color channel value |
* |
* @function |
* @returns {jsPDF} |
* @methodOf jsPDF# |
* @name setFillColor |
*/ |
API.setFillColor = function(ch1, ch2, ch3, ch4) { |
var color; |
|
if (ch2 === undefined || (ch4 === undefined && ch1 === ch2 === ch3)) { |
// Gray color space. |
if (typeof ch1 === 'string') { |
color = ch1 + ' g'; |
} else { |
color = f2(ch1 / 255) + ' g'; |
} |
} else if (ch4 === undefined || typeof ch4 === 'object') { |
// RGB |
if (typeof ch1 === 'string') { |
color = [ch1, ch2, ch3, 'rg'].join(' '); |
} else { |
color = [f2(ch1 / 255), f2(ch2 / 255), f2(ch3 / 255), 'rg'].join(' '); |
} |
if (ch4 && ch4.a === 0){ |
//TODO Implement transparency. |
//WORKAROUND use white for now |
color = ['255', '255', '255', 'rg'].join(' '); |
} |
} else { |
// CMYK |
if (typeof ch1 === 'string') { |
color = [ch1, ch2, ch3, ch4, 'k'].join(' '); |
} else { |
color = [f2(ch1), f2(ch2), f2(ch3), f2(ch4), 'k'].join(' '); |
} |
} |
|
out(color); |
return this; |
}; |
|
/** |
* Sets the text color for upcoming elements. |
* If only one, first argument is given, |
* treats the value as gray-scale color value. |
* |
* @param {Number} r Red channel color value in range 0-255 or {String} r color value in hexadecimal, example: '#FFFFFF' |
* @param {Number} g Green channel color value in range 0-255 |
* @param {Number} b Blue channel color value in range 0-255 |
* @function |
* @returns {jsPDF} |
* @methodOf jsPDF# |
* @name setTextColor |
*/ |
API.setTextColor = function(r, g, b) { |
if ((typeof r === 'string') && /^#[0-9A-Fa-f]{6}$/.test(r)) { |
var hex = parseInt(r.substr(1), 16); |
r = (hex >> 16) & 255; |
g = (hex >> 8) & 255; |
b = (hex & 255); |
} |
|
if ((r === 0 && g === 0 && b === 0) || (typeof g === 'undefined')) { |
textColor = f3(r / 255) + ' g'; |
} else { |
textColor = [f3(r / 255), f3(g / 255), f3(b / 255), 'rg'].join(' '); |
} |
|
out(textColor); |
|
return this; |
}; |
|
/** |
* Sets a either previously added {@link GState} (via {@link addGState}) or a new {@link GState}. |
* @param {String|GState} gState If type is string, a previously added GState is used, if type is GState |
* it will be added before use. |
* @function |
* @returns {jsPDF} |
* @methodOf jsPDF# |
* @name setGState |
*/ |
API.setGState = function (gState) { |
if (typeof gState === "string") { |
gState = gStates[gStatesMap[gState]]; |
} else { |
gState = addGState(null, gState); |
} |
|
if (!gState.equals(activeGState)) { |
out("/" + gState.id + " gs"); |
activeGState = gState; |
} |
}; |
|
/** |
* Is an Object providing a mapping from human-readable to |
* integer flag values designating the varieties of line cap |
* and join styles. |
* |
* @returns {Object} |
* @fieldOf jsPDF# |
* @name CapJoinStyles |
*/ |
API.CapJoinStyles = { |
0 : 0, |
'butt' : 0, |
'but' : 0, |
'miter' : 0, |
1 : 1, |
'round' : 1, |
'rounded' : 1, |
'circle' : 1, |
2 : 2, |
'projecting' : 2, |
'project' : 2, |
'square' : 2, |
'bevel' : 2 |
}; |
|
/** |
* Sets the line cap styles |
* See {jsPDF.CapJoinStyles} for variants |
* |
* @param {String|Number} style A string or number identifying the type of line cap |
* @function |
* @returns {jsPDF} |
* @methodOf jsPDF# |
* @name setLineCap |
*/ |
API.setLineCap = function(style) { |
var id = this.CapJoinStyles[style]; |
if (id === undefined) { |
throw new Error("Line cap style of '" + style + "' is not recognized. See or extend .CapJoinStyles property for valid styles"); |
} |
lineCapID = id; |
out(id + ' J'); |
|
return this; |
}; |
|
/** |
* Sets the line join styles |
* See {jsPDF.CapJoinStyles} for variants |
* |
* @param {String|Number} style A string or number identifying the type of line join |
* @function |
* @returns {jsPDF} |
* @methodOf jsPDF# |
* @name setLineJoin |
*/ |
API.setLineJoin = function(style) { |
var id = this.CapJoinStyles[style]; |
if (id === undefined) { |
throw new Error("Line join style of '" + style + "' is not recognized. See or extend .CapJoinStyles property for valid styles"); |
} |
lineJoinID = id; |
out(id + ' j'); |
|
return this; |
}; |
|
/** |
* Sets the miter limit. |
* @param {number} miterLimit |
* @function |
* @returns {jsPDF} |
* @methodOf jsPDF# |
* @name setMiterLimit |
*/ |
API.setLineMiterLimit = function (miterLimit) { |
out(f2(miterLimit) + " M"); |
|
return this; |
}; |
|
/** |
* Sets the line dash pattern. |
* @param {Array<number>} array An array containing 0-2 numbers. The first number sets the length of the |
* dashes, the second number the length of the gaps. If the second number is missing, the gaps are considered |
* to be as long as the dashes. An empty array means solid, unbroken lines. |
* @param phase The phase lines start with. |
* @function |
* @returns {jsPDF} |
* @methodOf jsPDF# |
* @name setLineDashPattern |
*/ |
API.setLineDashPattern = function (array, phase) { |
out([ |
"[" + (array[0] !== undefined ? array[0] : ""), |
(array[1] !== undefined ? array[1] : "" ) + "]", |
phase, |
"d" |
].join(" ")); |
|
return this; |
}; |
|
// Output is both an internal (for plugins) and external function |
API.output = output; |
|
/** |
* Saves as PDF document. An alias of jsPDF.output('save', 'filename.pdf') |
* @param {String} filename The filename including extension. |
* |
* @function |
* @returns {jsPDF} |
* @methodOf jsPDF# |
* @name save |
*/ |
API.save = function(filename) { |
API.output('save', filename); |
}; |
|
// applying plugins (more methods) ON TOP of built-in API. |
// this is intentional as we allow plugins to override |
// built-ins |
for (var plugin in jsPDF.API) { |
if (jsPDF.API.hasOwnProperty(plugin)) { |
if (plugin === 'events' && jsPDF.API.events.length) { |
(function(events, newEvents) { |
|
// jsPDF.API.events is a JS Array of Arrays |
// where each Array is a pair of event name, handler |
// Events were added by plugins to the jsPDF instantiator. |
// These are always added to the new instance and some ran |
// during instantiation. |
var eventname,handler_and_args,i; |
|
for (i = newEvents.length - 1; i !== -1; i--) { |
// subscribe takes 3 args: 'topic', function, runonce_flag |
// if undefined, runonce is false. |
// users can attach callback directly, |
// or they can attach an array with [callback, runonce_flag] |
// that's what the "apply" magic is for below. |
eventname = newEvents[i][0]; |
handler_and_args = newEvents[i][1]; |
events.subscribe.apply( |
events, |
[eventname].concat( |
typeof handler_and_args === 'function' ? |
[handler_and_args] : handler_and_args)); |
} |
}(events, jsPDF.API.events)); |
} else { |
API[plugin] = jsPDF.API[plugin]; |
} |
} |
} |
|
////////////////////////////////////////////////////// |
// continuing initialization of jsPDF Document object |
////////////////////////////////////////////////////// |
// Add the first page automatically |
addFonts(); |
activeFontKey = 'F1'; |
_addPage(format, orientation); |
|
events.publish('initialized'); |
return API; |
} |
|
/** |
* jsPDF.API is a STATIC property of jsPDF class. |
* jsPDF.API is an object you can add methods and properties to. |
* The methods / properties you add will show up in new jsPDF objects. |
* |
* One property is prepopulated. It is the 'events' Object. Plugin authors can add topics, |
* callbacks to this object. These will be reassigned to all new instances of jsPDF. |
* Examples: |
* jsPDF.API.events['initialized'] = function(){ 'this' is API object } |
* jsPDF.API.events['addFont'] = function(added_font_object){ 'this' is API object } |
* |
* @static |
* @public |
* @memberOf jsPDF |
* @name API |
* |
* @example |
* jsPDF.API.mymethod = function(){ |
* // 'this' will be ref to internal API object. see jsPDF source |
* // , so you can refer to built-in methods like so: |
* // this.line(....) |
* // this.text(....) |
* } |
* var pdfdoc = new jsPDF() |
* pdfdoc.mymethod() // <- !!!!!! |
*/ |
jsPDF.API = {events:[]}; |
jsPDF.version = "1.0.0-trunk"; |
|
if (typeof define === 'function' && define.amd) { |
define('jsPDF', function() { |
return jsPDF; |
}); |
} else if (typeof module !== 'undefined' && module.exports) { |
module.exports = jsPDF; |
} else { |
global.jsPDF = jsPDF; |
} |
return jsPDF; |
}(typeof self !== "undefined" && self || typeof window !== "undefined" && window || this)); |
/base/000_base/node_modules/highcharts/lib/svg2pdf.js |
@@ -0,0 +1,26 @@ |
/** |
* Modules in this bundle |
* @license |
* |
* svg2pdf.js: |
* license: MIT (http://opensource.org/licenses/MIT) |
* author: yFiles for HTML Support Team <yfileshtml@yworks.com> |
* homepage: https://github.com/yWorks/svg2pdf.js#readme |
* version: 1.0.5 |
* |
* svgpath: |
* license: MIT (http://opensource.org/licenses/MIT) |
* maintainers: vitaly <vitaly@rcdesign.ru> |
* homepage: https://github.com/fontello/svgpath#readme |
* version: 2.2.1 |
* |
* This header is generated by licensify (https://github.com/twada/licensify) |
*/ |
!function(t){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=t();else if("function"==typeof define&&define.amd)define([],t);else{var e;e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,e.svg2pdf=t()}}(function(){var t;return function t(e,r,a){function i(s,o){if(!r[s]){if(!e[s]){var u="function"==typeof require&&require;if(!o&&u)return u(s,!0);if(n)return n(s,!0);var c=new Error("Cannot find module '"+s+"'");throw c.code="MODULE_NOT_FOUND",c}var h=r[s]={exports:{}};e[s][0].call(h.exports,function(t){var r=e[s][1][t];return i(r||t)},h,h.exports,t,e,r,a)}return r[s].exports}for(var n="function"==typeof require&&require,s=0;s<a.length;s++)i(a[s]);return i}({1:[function(t,e,r){"use strict";e.exports=t("./lib/svgpath")},{"./lib/svgpath":6}],2:[function(t,e,r){"use strict";function a(t,e,r,a){var i=t*a-e*r<0?-1:1,n=Math.sqrt(t*t+e*e),s=Math.sqrt(t*t+e*e),o=t*r+e*a,u=o/(n*s);return u>1&&(u=1),u<-1&&(u=-1),i*Math.acos(u)}function i(t,e,r,i,n,o,u,c,h,f){var l=f*(t-r)/2+h*(e-i)/2,d=-h*(t-r)/2+f*(e-i)/2,g=u*u,p=c*c,b=l*l,x=d*d,m=g*p-g*x-p*b;m<0&&(m=0),m/=g*x+p*b,m=Math.sqrt(m)*(n===o?-1:1);var v=m*u/c*d,y=m*-c/u*l,A=f*v-h*y+(t+r)/2,w=h*v+f*y+(e+i)/2,k=(l-v)/u,M=(d-y)/c,F=(-l-v)/u,C=(-d-y)/c,S=a(1,0,k,M),I=a(k,M,F,C);return 0===o&&I>0&&(I-=s),1===o&&I<0&&(I+=s),[A,w,S,I]}function n(t,e){var r=4/3*Math.tan(e/4),a=Math.cos(t),i=Math.sin(t),n=Math.cos(t+e),s=Math.sin(t+e);return[a,i,a-i*r,i+a*r,n+s*r,s-n*r,n,s]}var s=2*Math.PI;e.exports=function(t,e,r,a,o,u,c,h,f){var l=Math.sin(f*s/360),d=Math.cos(f*s/360),g=d*(t-r)/2+l*(e-a)/2,p=-l*(t-r)/2+d*(e-a)/2;if(0===g&&0===p)return[];if(0===c||0===h)return[];c=Math.abs(c),h=Math.abs(h);var b=g*g/(c*c)+p*p/(h*h);b>1&&(c*=Math.sqrt(b),h*=Math.sqrt(b));var x=i(t,e,r,a,o,u,c,h,l,d),m=[],v=x[2],y=x[3],A=Math.max(Math.ceil(Math.abs(y)/(s/4)),1);y/=A;for(var w=0;w<A;w++)m.push(n(v,y)),v+=y;return m.map(function(t){for(var e=0;e<t.length;e+=2){var r=t[e+0],a=t[e+1];r*=c,a*=h;var i=d*r-l*a,n=l*r+d*a;t[e+0]=i+x[0],t[e+1]=n+x[1]}return t})}},{}],3:[function(t,e,r){"use strict";function a(t,e,r){if(!(this instanceof a))return new a(t,e,r);this.rx=t,this.ry=e,this.ax=r}var i=Math.PI/180;a.prototype.transform=function(t){var e=Math.cos(this.ax*i),r=Math.sin(this.ax*i),a=[this.rx*(t[0]*e+t[2]*r),this.rx*(t[1]*e+t[3]*r),this.ry*(-t[0]*r+t[2]*e),this.ry*(-t[1]*r+t[3]*e)],n=a[0]*a[0]+a[2]*a[2],s=a[1]*a[1]+a[3]*a[3],o=((a[0]-a[3])*(a[0]-a[3])+(a[2]+a[1])*(a[2]+a[1]))*((a[0]+a[3])*(a[0]+a[3])+(a[2]-a[1])*(a[2]-a[1])),u=(n+s)/2;if(o<1e-10*u)return this.rx=this.ry=Math.sqrt(u),this.ax=0,this;var c=a[0]*a[1]+a[2]*a[3];o=Math.sqrt(o);var h=u+o/2,f=u-o/2;return this.ax=Math.abs(c)<1e-10&&Math.abs(h-s)<1e-10?90:180*Math.atan(Math.abs(c)>Math.abs(h-s)?(h-n)/c:c/(h-s))/Math.PI,this.ax>=0?(this.rx=Math.sqrt(h),this.ry=Math.sqrt(f)):(this.ax+=90,this.rx=Math.sqrt(f),this.ry=Math.sqrt(h)),this},a.prototype.isDegenerate=function(){return this.rx<1e-10*this.ry||this.ry<1e-10*this.rx},e.exports=a},{}],4:[function(t,e,r){"use strict";function a(t,e){return[t[0]*e[0]+t[2]*e[1],t[1]*e[0]+t[3]*e[1],t[0]*e[2]+t[2]*e[3],t[1]*e[2]+t[3]*e[3],t[0]*e[4]+t[2]*e[5]+t[4],t[1]*e[4]+t[3]*e[5]+t[5]]}function i(){if(!(this instanceof i))return new i;this.queue=[],this.cache=null}i.prototype.matrix=function(t){return 1===t[0]&&0===t[1]&&0===t[2]&&1===t[3]&&0===t[4]&&0===t[5]?this:(this.cache=null,this.queue.push(t),this)},i.prototype.translate=function(t,e){return 0===t&&0===e||(this.cache=null,this.queue.push([1,0,0,1,t,e])),this},i.prototype.scale=function(t,e){return 1===t&&1===e||(this.cache=null,this.queue.push([t,0,0,e,0,0])),this},i.prototype.rotate=function(t,e,r){var a,i,n;return 0!==t&&(this.translate(e,r),a=t*Math.PI/180,i=Math.cos(a),n=Math.sin(a),this.queue.push([i,n,-n,i,0,0]),this.cache=null,this.translate(-e,-r)),this},i.prototype.skewX=function(t){return 0!==t&&(this.cache=null,this.queue.push([1,0,Math.tan(t*Math.PI/180),1,0,0])),this},i.prototype.skewY=function(t){return 0!==t&&(this.cache=null,this.queue.push([1,Math.tan(t*Math.PI/180),0,1,0,0])),this},i.prototype.toArray=function(){if(this.cache)return this.cache;if(!this.queue.length)return this.cache=[1,0,0,1,0,0],this.cache;if(this.cache=this.queue[0],1===this.queue.length)return this.cache;for(var t=1;t<this.queue.length;t++)this.cache=a(this.cache,this.queue[t]);return this.cache},i.prototype.calc=function(t,e,r){var a;return this.queue.length?(this.cache||(this.cache=this.toArray()),a=this.cache,[t*a[0]+e*a[2]+(r?0:a[4]),t*a[1]+e*a[3]+(r?0:a[5])]):[t,e]},e.exports=i},{}],5:[function(t,e,r){"use strict";function a(t){return 10===t||13===t||8232===t||8233===t||32===t||9===t||11===t||12===t||160===t||t>=5760&&d.indexOf(t)>=0}function i(t){switch(32|t){case 109:case 122:case 108:case 104:case 118:case 99:case 115:case 113:case 116:case 97:case 114:return!0}return!1}function n(t){return t>=48&&t<=57}function s(t){return t>=48&&t<=57||43===t||45===t||46===t}function o(t){this.index=0,this.path=t,this.max=t.length,this.result=[],this.param=0,this.err="",this.segmentStart=0,this.data=[]}function u(t){for(;t.index<t.max&&a(t.path.charCodeAt(t.index));)t.index++}function c(t){var e,r=t.index,a=r,i=t.max,s=!1,o=!1,u=!1,c=!1;if(a>=i)return void(t.err="SvgPath: missed param (at pos "+a+")");if(e=t.path.charCodeAt(a),43!==e&&45!==e||(a++,e=a<i?t.path.charCodeAt(a):0),!n(e)&&46!==e)return void(t.err="SvgPath: param should start with 0..9 or `.` (at pos "+a+")");if(46!==e){if(s=48===e,a++,e=a<i?t.path.charCodeAt(a):0,s&&a<i&&e&&n(e))return void(t.err="SvgPath: numbers started with `0` such as `09` are ilegal (at pos "+r+")");for(;a<i&&n(t.path.charCodeAt(a));)a++,o=!0;e=a<i?t.path.charCodeAt(a):0}if(46===e){for(c=!0,a++;n(t.path.charCodeAt(a));)a++,u=!0;e=a<i?t.path.charCodeAt(a):0}if(101===e||69===e){if(c&&!o&&!u)return void(t.err="SvgPath: invalid float exponent (at pos "+a+")");if(a++,e=a<i?t.path.charCodeAt(a):0,43!==e&&45!==e||a++,!(a<i&&n(t.path.charCodeAt(a))))return void(t.err="SvgPath: invalid float exponent (at pos "+a+")");for(;a<i&&n(t.path.charCodeAt(a));)a++}t.index=a,t.param=parseFloat(t.path.slice(r,a))+0}function h(t){var e,r;e=t.path[t.segmentStart],r=e.toLowerCase();var a=t.data;if("m"===r&&a.length>2&&(t.result.push([e,a[0],a[1]]),a=a.slice(2),r="l",e="m"===e?"l":"L"),"r"===r)t.result.push([e].concat(a));else for(;a.length>=l[r]&&(t.result.push([e].concat(a.splice(0,l[r]))),l[r]););}function f(t){var e,r,a,n,o=t.max;if(t.segmentStart=t.index,e=t.path.charCodeAt(t.index),!i(e))return void(t.err="SvgPath: bad command "+t.path[t.index]+" (at pos "+t.index+")");if(a=l[t.path[t.index].toLowerCase()],t.index++,u(t),t.data=[],!a)return void h(t);for(r=!1;;){for(n=a;n>0;n--){if(c(t),t.err.length)return;t.data.push(t.param),u(t),r=!1,t.index<o&&44===t.path.charCodeAt(t.index)&&(t.index++,u(t),r=!0)}if(!r){if(t.index>=t.max)break;if(!s(t.path.charCodeAt(t.index)))break}}h(t)}var l={a:7,c:6,h:1,l:2,m:2,r:4,q:4,s:4,t:2,v:1,z:0},d=[5760,6158,8192,8193,8194,8195,8196,8197,8198,8199,8200,8201,8202,8239,8287,12288,65279];e.exports=function(t){var e=new o(t),r=e.max;for(u(e);e.index<r&&!e.err.length;)f(e);return e.err.length?e.result=[]:e.result.length&&("mM".indexOf(e.result[0][0])<0?(e.err="SvgPath: string should start with `M` or `m`",e.result=[]):e.result[0][0]="M"),{err:e.err,segments:e.result}}},{}],6:[function(t,e,r){"use strict";function a(t){if(!(this instanceof a))return new a(t);var e=i(t);this.segments=e.segments,this.err=e.err,this.__stack=[]}var i=t("./path_parse"),n=t("./transform_parse"),s=t("./matrix"),o=t("./a2c"),u=t("./ellipse");a.prototype.__matrix=function(t){var e,r=this;t.queue.length&&this.iterate(function(a,i,n,s){var o,c,h,f;switch(a[0]){case"v":o=t.calc(0,a[1],!0),c=0===o[0]?["v",o[1]]:["l",o[0],o[1]];break;case"V":o=t.calc(n,a[1],!1),c=o[0]===t.calc(n,s,!1)[0]?["V",o[1]]:["L",o[0],o[1]];break;case"h":o=t.calc(a[1],0,!0),c=0===o[1]?["h",o[0]]:["l",o[0],o[1]];break;case"H":o=t.calc(a[1],s,!1),c=o[1]===t.calc(n,s,!1)[1]?["H",o[0]]:["L",o[0],o[1]];break;case"a":case"A":var l=t.toArray(),d=u(a[1],a[2],a[3]).transform(l);if(l[0]*l[3]-l[1]*l[2]<0&&(a[5]=a[5]?"0":"1"),o=t.calc(a[6],a[7],"a"===a[0]),"A"===a[0]&&a[6]===n&&a[7]===s||"a"===a[0]&&0===a[6]&&0===a[7]){c=["a"===a[0]?"l":"L",o[0],o[1]];break}c=d.isDegenerate()?["a"===a[0]?"l":"L",o[0],o[1]]:[a[0],d.rx,d.ry,d.ax,a[4],a[5],o[0],o[1]];break;case"m":f=i>0,o=t.calc(a[1],a[2],f),c=["m",o[0],o[1]];break;default:for(h=a[0],c=[h],f=h.toLowerCase()===h,e=1;e<a.length;e+=2)o=t.calc(a[e],a[e+1],f),c.push(o[0],o[1])}r.segments[i]=c},!0)},a.prototype.__evaluateStack=function(){var t,e;if(this.__stack.length){if(1===this.__stack.length)return this.__matrix(this.__stack[0]),void(this.__stack=[]);for(t=s(),e=this.__stack.length;--e>=0;)t.matrix(this.__stack[e].toArray());this.__matrix(t),this.__stack=[]}},a.prototype.toString=function(){var t,e,r=[];this.__evaluateStack();for(var a=0;a<this.segments.length;a++)e=this.segments[a][0],t=a>0&&"m"!==e&&"M"!==e&&e===this.segments[a-1][0],r=r.concat(t?this.segments[a].slice(1):this.segments[a]);return r.join(" ").replace(/ ?([achlmqrstvz]) ?/gi,"$1").replace(/ \-/g,"-").replace(/zm/g,"z m")},a.prototype.translate=function(t,e){return this.__stack.push(s().translate(t,e||0)),this},a.prototype.scale=function(t,e){return this.__stack.push(s().scale(t,e||0===e?e:t)),this},a.prototype.rotate=function(t,e,r){return this.__stack.push(s().rotate(t,e||0,r||0)),this},a.prototype.skewX=function(t){return this.__stack.push(s().skewX(t)),this},a.prototype.skewY=function(t){return this.__stack.push(s().skewY(t)),this},a.prototype.matrix=function(t){return this.__stack.push(s().matrix(t)),this},a.prototype.transform=function(t){return t.trim()?(this.__stack.push(n(t)),this):this},a.prototype.round=function(t){var e,r=0,a=0,i=0,n=0;return t=t||0,this.__evaluateStack(),this.segments.forEach(function(s){var o=s[0].toLowerCase()===s[0];switch(s[0]){case"H":case"h":return o&&(s[1]+=i),i=s[1]-s[1].toFixed(t),void(s[1]=+s[1].toFixed(t));case"V":case"v":return o&&(s[1]+=n),n=s[1]-s[1].toFixed(t),void(s[1]=+s[1].toFixed(t));case"Z":case"z":return i=r,void(n=a);case"M":case"m":return o&&(s[1]+=i,s[2]+=n),i=s[1]-s[1].toFixed(t),n=s[2]-s[2].toFixed(t),r=i,a=n,s[1]=+s[1].toFixed(t),void(s[2]=+s[2].toFixed(t));case"A":case"a":return o&&(s[6]+=i,s[7]+=n),i=s[6]-s[6].toFixed(t),n=s[7]-s[7].toFixed(t),s[1]=+s[1].toFixed(t),s[2]=+s[2].toFixed(t),s[3]=+s[3].toFixed(t+2),s[6]=+s[6].toFixed(t),void(s[7]=+s[7].toFixed(t));default:return e=s.length,o&&(s[e-2]+=i,s[e-1]+=n),i=s[e-2]-s[e-2].toFixed(t),n=s[e-1]-s[e-1].toFixed(t),void s.forEach(function(e,r){r&&(s[r]=+s[r].toFixed(t))})}}),this},a.prototype.iterate=function(t,e){var r,a,i,n=this.segments,s={},o=!1,u=0,c=0,h=0,f=0;if(e||this.__evaluateStack(),n.forEach(function(e,r){var a=t(e,r,u,c);Array.isArray(a)&&(s[r]=a,o=!0);var i=e[0]===e[0].toLowerCase();switch(e[0]){case"m":case"M":return u=e[1]+(i?u:0),c=e[2]+(i?c:0),h=u,void(f=c);case"h":case"H":return void(u=e[1]+(i?u:0));case"v":case"V":return void(c=e[1]+(i?c:0));case"z":case"Z":return u=h,void(c=f);default:u=e[e.length-2]+(i?u:0),c=e[e.length-1]+(i?c:0)}}),!o)return this;for(i=[],r=0;r<n.length;r++)if(void 0!==s[r])for(a=0;a<s[r].length;a++)i.push(s[r][a]);else i.push(n[r]);return this.segments=i,this},a.prototype.abs=function(){return this.iterate(function(t,e,r,a){var i,n=t[0],s=n.toUpperCase();if(n!==s)switch(t[0]=s,n){case"v":return void(t[1]+=a);case"a":return t[6]+=r,void(t[7]+=a);default:for(i=1;i<t.length;i++)t[i]+=i%2?r:a}},!0),this},a.prototype.rel=function(){return this.iterate(function(t,e,r,a){var i,n=t[0],s=n.toLowerCase();if(n!==s&&(0!==e||"M"!==n))switch(t[0]=s,n){case"V":return void(t[1]-=a);case"A":return t[6]-=r,void(t[7]-=a);default:for(i=1;i<t.length;i++)t[i]-=i%2?r:a}},!0),this},a.prototype.unarc=function(){return this.iterate(function(t,e,r,a){var i,n,s,u=[],c=t[0];return"A"!==c&&"a"!==c?null:("a"===c?(n=r+t[6],s=a+t[7]):(n=t[6],s=t[7]),i=o(r,a,n,s,t[4],t[5],t[1],t[2],t[3]),0===i.length?[["a"===t[0]?"l":"L",t[6],t[7]]]:(i.forEach(function(t){u.push(["C",t[2],t[3],t[4],t[5],t[6],t[7]])}),u))}),this},a.prototype.unshort=function(){var t,e,r,a,i,n=this.segments;return this.iterate(function(s,o,u,c){var h,f=s[0],l=f.toUpperCase();o&&("T"===l?(h="t"===f,r=n[o-1],"Q"===r[0]?(t=r[1]-u,e=r[2]-c):"q"===r[0]?(t=r[1]-r[3],e=r[2]-r[4]):(t=0,e=0),a=-t,i=-e,h||(a+=u,i+=c),n[o]=[h?"q":"Q",a,i,s[1],s[2]]):"S"===l&&(h="s"===f,r=n[o-1],"C"===r[0]?(t=r[3]-u,e=r[4]-c):"c"===r[0]?(t=r[3]-r[5],e=r[4]-r[6]):(t=0,e=0),a=-t,i=-e,h||(a+=u,i+=c),n[o]=[h?"c":"C",a,i,s[1],s[2],s[3],s[4]]))}),this},e.exports=a},{"./a2c":2,"./ellipse":3,"./matrix":4,"./path_parse":5,"./transform_parse":7}],7:[function(t,e,r){"use strict";var a=t("./matrix"),i={matrix:!0,scale:!0,rotate:!0,translate:!0,skewX:!0,skewY:!0};e.exports=function(t){var e,r,n=new a;return t.split(/\s*(matrix|translate|scale|rotate|skewX|skewY)\s*\(\s*(.+?)\s*\)[\s,]*/).forEach(function(t){if(t.length){if(void 0!==i[t])return void(e=t);switch(r=t.split(/[\s,]+/).map(function(t){return+t||0}),e){case"matrix":return void(6===r.length&&n.matrix(r));case"scale":return void(1===r.length?n.scale(r[0],r[0]):2===r.length&&n.scale(r[0],r[1]));case"rotate":return void(1===r.length?n.rotate(r[0],0,0):3===r.length&&n.rotate(r[0],r[1],r[2]));case"translate":return void(1===r.length?n.translate(r[0],0):2===r.length&&n.translate(r[0],r[1]));case"skewX":return void(1===r.length&&n.skewX(r[0]));case"skewY":return void(1===r.length&&n.skewY(r[0]))}}}),n}},{"./matrix":4}],8:[function(e,r,a){/** |
* A class to parse color values |
* @author Stoyan Stefanov <sstoo@gmail.com> |
* @link http://www.phpied.com/rgb-color-parser-in-javascript/ |
* @license Use it if you like it |
*/ |
!function(e){function a(t){this.ok=!1,"#"==t.charAt(0)&&(t=t.substr(1,6)),t=t.replace(/ /g,""),t=t.toLowerCase();var e={aliceblue:"f0f8ff",antiquewhite:"faebd7",aqua:"00ffff",aquamarine:"7fffd4",azure:"f0ffff",beige:"f5f5dc",bisque:"ffe4c4",black:"000000",blanchedalmond:"ffebcd",blue:"0000ff",blueviolet:"8a2be2",brown:"a52a2a",burlywood:"deb887",cadetblue:"5f9ea0",chartreuse:"7fff00",chocolate:"d2691e",coral:"ff7f50",cornflowerblue:"6495ed",cornsilk:"fff8dc",crimson:"dc143c",cyan:"00ffff",darkblue:"00008b",darkcyan:"008b8b",darkgoldenrod:"b8860b",darkgray:"a9a9a9",darkgreen:"006400",darkkhaki:"bdb76b",darkmagenta:"8b008b",darkolivegreen:"556b2f",darkorange:"ff8c00",darkorchid:"9932cc",darkred:"8b0000",darksalmon:"e9967a",darkseagreen:"8fbc8f",darkslateblue:"483d8b",darkslategray:"2f4f4f",darkturquoise:"00ced1",darkviolet:"9400d3",deeppink:"ff1493",deepskyblue:"00bfff",dimgray:"696969",dodgerblue:"1e90ff",feldspar:"d19275",firebrick:"b22222",floralwhite:"fffaf0",forestgreen:"228b22",fuchsia:"ff00ff",gainsboro:"dcdcdc",ghostwhite:"f8f8ff",gold:"ffd700",goldenrod:"daa520",gray:"808080",green:"008000",greenyellow:"adff2f",honeydew:"f0fff0",hotpink:"ff69b4",indianred:"cd5c5c",indigo:"4b0082",ivory:"fffff0",khaki:"f0e68c",lavender:"e6e6fa",lavenderblush:"fff0f5",lawngreen:"7cfc00",lemonchiffon:"fffacd",lightblue:"add8e6",lightcoral:"f08080",lightcyan:"e0ffff",lightgoldenrodyellow:"fafad2",lightgrey:"d3d3d3",lightgreen:"90ee90",lightpink:"ffb6c1",lightsalmon:"ffa07a",lightseagreen:"20b2aa",lightskyblue:"87cefa",lightslateblue:"8470ff",lightslategray:"778899",lightsteelblue:"b0c4de",lightyellow:"ffffe0",lime:"00ff00",limegreen:"32cd32",linen:"faf0e6",magenta:"ff00ff",maroon:"800000",mediumaquamarine:"66cdaa",mediumblue:"0000cd",mediumorchid:"ba55d3",mediumpurple:"9370d8",mediumseagreen:"3cb371",mediumslateblue:"7b68ee",mediumspringgreen:"00fa9a",mediumturquoise:"48d1cc",mediumvioletred:"c71585",midnightblue:"191970",mintcream:"f5fffa",mistyrose:"ffe4e1",moccasin:"ffe4b5",navajowhite:"ffdead",navy:"000080",oldlace:"fdf5e6",olive:"808000",olivedrab:"6b8e23",orange:"ffa500",orangered:"ff4500",orchid:"da70d6",palegoldenrod:"eee8aa",palegreen:"98fb98",paleturquoise:"afeeee",palevioletred:"d87093",papayawhip:"ffefd5",peachpuff:"ffdab9",peru:"cd853f",pink:"ffc0cb",plum:"dda0dd",powderblue:"b0e0e6",purple:"800080",red:"ff0000",rosybrown:"bc8f8f",royalblue:"4169e1",saddlebrown:"8b4513",salmon:"fa8072",sandybrown:"f4a460",seagreen:"2e8b57",seashell:"fff5ee",sienna:"a0522d",silver:"c0c0c0",skyblue:"87ceeb",slateblue:"6a5acd",slategray:"708090",snow:"fffafa",springgreen:"00ff7f",steelblue:"4682b4",tan:"d2b48c",teal:"008080",thistle:"d8bfd8",tomato:"ff6347",turquoise:"40e0d0",violet:"ee82ee",violetred:"d02090",wheat:"f5deb3",white:"ffffff",whitesmoke:"f5f5f5",yellow:"ffff00",yellowgreen:"9acd32"};for(var r in e)t==r&&(t=e[r]);for(var i=[{re:/^rgb\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})\)$/,example:["rgb(123, 234, 45)","rgb(255,234,245)"],process:function(t){return[parseInt(t[1]),parseInt(t[2]),parseInt(t[3])]}},{re:/^(\w{2})(\w{2})(\w{2})$/,example:["#00ff00","336699"],process:function(t){return[parseInt(t[1],16),parseInt(t[2],16),parseInt(t[3],16)]}},{re:/^(\w{1})(\w{1})(\w{1})$/,example:["#fb0","f0f"],process:function(t){return[parseInt(t[1]+t[1],16),parseInt(t[2]+t[2],16),parseInt(t[3]+t[3],16)]}}],n=0;n<i.length;n++){var s=i[n].re,o=i[n].process,u=s.exec(t);if(u){var c=o(u);this.r=c[0],this.g=c[1],this.b=c[2],this.ok=!0}}this.r=this.r<0||isNaN(this.r)?0:this.r>255?255:this.r,this.g=this.g<0||isNaN(this.g)?0:this.g>255?255:this.g,this.b=this.b<0||isNaN(this.b)?0:this.b>255?255:this.b,this.toRGB=function(){return"rgb("+this.r+", "+this.g+", "+this.b+")"},this.toHex=function(){var t=this.r.toString(16),e=this.g.toString(16),r=this.b.toString(16);return 1==t.length&&(t="0"+t),1==e.length&&(e="0"+e),1==r.length&&(r="0"+r),"#"+t+e+r},this.getHelpXML=function(){for(var t=new Array,r=0;r<i.length;r++)for(var n=i[r].example,s=0;s<n.length;s++)t[t.length]=n[s];for(var o in e)t[t.length]=o;var u=document.createElement("ul");u.setAttribute("id","rgbcolor-examples");for(var r=0;r<t.length;r++)try{var c=document.createElement("li"),h=new a(t[r]),f=document.createElement("div");f.style.cssText="margin: 3px; border: 1px solid black; background:"+h.toHex()+"; color:"+h.toHex(),f.appendChild(document.createTextNode("test"));var l=document.createTextNode(" "+t[r]+" -> "+h.toRGB()+" -> "+h.toHex());c.appendChild(f),c.appendChild(l),u.appendChild(c)}catch(t){}return u}}"function"==typeof t&&t.amd?t(function(){return a}):void 0!==r&&r.exports?r.exports=a:e.RGBColor=a,a}("undefined"!=typeof self&&self||"undefined"!=typeof window&&window||this)},{}],9:[function(e,r,a){!function(a){function i(t,e){var r=h(t,"font-family");r&&o.setFont(r),e&&e.ok&&o.setTextColor(e.r,e.g,e.b);var a,i=h(t,"font-weight");i&&"bold"===i&&(a="bold");var n=h(t,"font-style");n&&"italic"===n&&(a+="italic"),o.setFontType(a);var s=16,u=h(t,"font-size");u&&(s=parseFloat(u),o.setFontSize(s))}var n,s,o,u=/url\(#([^)]+)\)/,c=function(t){var e=t.getAttribute("d");s&&(e=s(e).unshort().unarc().abs().toString(),t.setAttribute("d",e));var r=t.pathSegList;if(r)return r;r=[];for(var a,i=/([a-df-zA-DF-Z])([^a-df-zA-DF-Z]*)/g;a=i.exec(e);){var n=M(a[2]),o=a[1],u="zZ".indexOf(o)>=0?0:"hHvV".indexOf(o)>=0?1:"mMlLtT".indexOf(o)>=0?2:"sSqQ".indexOf(o)>=0?4:"aA".indexOf(o)>=0?7:"cC".indexOf(o)>=0?6:-1,c=0;do{var h={pathSegTypeAsLetter:o};switch(o){case"h":case"H":h.x=n[c];break;case"v":case"V":h.y=n[c];break;case"c":case"C":h.x1=n[c+u-6],h.y1=n[c+u-5];case"s":case"S":h.x2=n[c+u-4],h.y2=n[c+u-3];case"t":case"T":case"l":case"L":case"m":case"M":h.x=n[c+u-2],h.y=n[c+u-1];break;case"q":case"Q":h.x1=n[c],h.y1=n[c+1],h.x=n[c+2],h.y=n[c+3];break;case"a":case"A":throw new Error("Cannot convert Arcs without SvgPath package")}r.push(h),c+=u}while(c<n.length)}return r.getItem=function(t){return this[t]},r.numberOfItems=r.length,r},h=function(t,e,r){return r=r||e,t.getAttribute(e)||t.style[r]},f=function(t,e){return e.split(",").indexOf(t.tagName.toLowerCase())>=0},l=function(t,e){for(var r=[],a=0;a<t.childNodes.length;a++){var i=t.childNodes[a];"#"!==i.nodeName.charAt(0)&&r.push(i)}for(a=0;a<r.length;a++)e(a,r[a])},d=function(t,e){return Math.atan2(e[1]-t[1],e[0]-t[0])},g=function(t,e){var r=e[0]-t[0],a=e[1]-t[1];return[t[0]+2*r,t[1]+2*a]},p=function(t,e){return[2/3*(e[0]-t[0])+t[0],2/3*(e[1]-t[1])+t[1]]},b=function(t,e,r,a,i){var n=r.getItem(t-1);return t>0&&("C"===n.pathSegTypeAsLetter||"S"===n.pathSegTypeAsLetter)?g([n.x2,n.y2],e):t>0&&("c"===n.pathSegTypeAsLetter||"s"===n.pathSegTypeAsLetter)?g([n.x2+a,n.y2+i],e):[e[0],e[1]]},x=function(t){this.prefix=t,this.id=0,this.nextChild=function(){return new x("_"+this.id+++"_"+this.get())},this.get=function(){return this.prefix}},m=function(t,e){for(var r=/_\d+_/;!e[t]&&r.exec(t);)t=t.replace(r,"");return e[t]},v=function(t){return t.replace(/[\n\s\r]+/," ").trim()},y=function(t){var e={};for(var r in t)t.hasOwnProperty(r)&&(e[r]=t[r]);return e},A=function(t){var e,r,a,i,n,s,u,c,h=o.unitMatrix;if(f(t,"svg,g"))c=parseFloat(t.getAttribute("x"))||0,u=parseFloat(t.getAttribute("y"))||0,s=t.getAttribute("viewBox"),s?(n=M(s),i=n[2]-n[0],a=n[3]-n[1],r=parseFloat(t.getAttribute("width"))||i,e=parseFloat(t.getAttribute("height"))||a,h=new o.Matrix(r/i,0,0,e/a,c-n[0],u-n[1])):h=new o.Matrix(1,0,0,1,c,u);else if(f(t,"marker"))if(c=-parseFloat(t.getAttribute("refX"))||0,u=-parseFloat(t.getAttribute("refY"))||0,s=t.getAttribute("viewBox")){n=M(s),i=n[2]-n[0],a=n[3]-n[1],r=parseFloat(t.getAttribute("markerWidth"))||i,e=parseFloat(t.getAttribute("markerHeight"))||a;var l=new o.Matrix(r/i,0,0,e/a,0,0),d=new o.Matrix(1,0,0,1,c,u);h=o.matrixMult(d,l)}else h=new o.Matrix(1,0,0,1,c,u);var g=t.getAttribute("transform");return g?o.matrixMult(h,k(g)):h},w=function(t){for(var e=M(t),r=[],a=0;a<e.length-1;a+=2){var i=e[a],n=e[a+1];r.push([i,n])}return r},k=function(t){if(!t)return o.unitMatrix;for(var e,r=/^\s*matrix\(([^\)]+)\)\s*/,a=/^\s*translate\(([^\)]+)\)\s*/,i=/^\s*rotate\(([^\)]+)\)\s*/,n=/^\s*scale\(([^\)]+)\)\s*/,s=/^\s*skewX\(([^\)]+)\)\s*/,u=/^\s*skewY\(([^\)]+)\)\s*/,c=o.unitMatrix;t.length>0;){var h=r.exec(t);if(h&&(e=M(h[1]),c=o.matrixMult(new o.Matrix(e[0],e[1],e[2],e[3],e[4],e[5]),c),t=t.substr(h[0].length)),h=i.exec(t)){e=M(h[1]);var f=Math.PI*e[0]/180;if(c=o.matrixMult(new o.Matrix(Math.cos(f),Math.sin(f),-Math.sin(f),Math.cos(f),0,0),c),e[1]&&e[2]){var l=new o.Matrix(1,0,0,1,e[1],e[2]),d=new o.Matrix(1,0,0,1,-e[1],-e[2]);c=o.matrixMult(d,o.matrixMult(c,l))}t=t.substr(h[0].length)}h=a.exec(t),h&&(e=M(h[1]),c=o.matrixMult(new o.Matrix(1,0,0,1,e[0],e[1]||0),c),t=t.substr(h[0].length)),h=n.exec(t),h&&(e=M(h[1]),e[1]||(e[1]=e[0]),c=o.matrixMult(new o.Matrix(e[0],0,0,e[1],0,0),c),t=t.substr(h[0].length)),h=s.exec(t),h&&(e=parseFloat(h[1]),c=o.matrixMult(new o.Matrix(1,0,Math.tan(e),1,0,0),c),t=t.substr(h[0].length)),h=u.exec(t),h&&(e=parseFloat(h[1]),c=o.matrixMult(new o.Matrix(1,Math.tan(e),0,1,0,0),c),t=t.substr(h[0].length))}return c},M=function(t){for(var e,r=[],a=/[+-]?(?:(?:\d+\.?\d*)|(?:\d*\.?\d+))(?:[eE][+-]?\d+)?/g;e=a.exec(t);)r.push(parseFloat(e[0]));return r},F=function(t){var e=/\s*rgba\(((?:[^,\)]*,){3}[^,\)]*)\)\s*/.exec(t);if(e){var r=M(e[1]),a=new n("rgb("+r.slice(0,3).join(",")+")");return a.a=r[3],a}return new n(t)},C=function(t,e){var r=t[0],a=t[1];return[e.a*r+e.c*a+e.e,e.b*r+e.d*a+e.f]},S=function(t){var e,r,a,i,n,s,o,u,d=parseFloat;if(f(t,"polygon")){var g=w(t.getAttribute("points"));for(r=Number.POSITIVE_INFINITY,a=Number.POSITIVE_INFINITY,i=Number.NEGATIVE_INFINITY,n=Number.NEGATIVE_INFINITY,e=0;e<g.length;e++){var x=g[e];r=Math.min(r,x[0]),i=Math.max(i,x[0]),a=Math.min(a,x[1]),n=Math.max(n,x[1])}u=[r,a,i-r,n-a]}else if(f(t,"path")){var m=c(t);r=Number.POSITIVE_INFINITY,a=Number.POSITIVE_INFINITY,i=Number.NEGATIVE_INFINITY,n=Number.NEGATIVE_INFINITY;var v,y,A,k,F,C,I,_=0,T=0;for(e=0;e<m.numberOfItems;e++){var q=m.getItem(e),L=q.pathSegTypeAsLetter;switch(L){case"H":A=q.x,k=T;break;case"h":A=q.x+_,k=T;break;case"V":A=_,k=q.y;break;case"v":A=_,k=q.y+T;break;case"C":F=[q.x1,q.y1],C=[q.x2,q.y2],I=[q.x,q.y];break;case"c":F=[q.x1+_,q.y1+T],C=[q.x2+_,q.y2+T],I=[q.x+_,q.y+T];break;case"S":F=b(e,[_,T],m,v,y),C=[q.x2,q.y2],I=[q.x,q.y];break;case"s":F=b(e,[_,T],m,v,y),C=[q.x2+_,q.y2+T],I=[q.x+_,q.y+T];break;case"Q":d=[q.x1,q.y1],F=p([_,T],d),C=p([q.x,q.y],d),I=[q.x,q.y];break;case"q":d=[q.x1+_,q.y1+T],F=p([_,T],d),C=p([_+q.x,T+q.y],d),I=[q.x+_,q.y+T];break;case"T":F=b(e,[_,T],m,v,y),F=p([_,T],d),C=p([q.x,q.y],d),I=[q.x,q.y];break;case"t":d=b(e,[_,T],m,v,y),F=p([_,T],d),C=p([_+q.x,T+q.y],d),I=[q.x+_,q.y+T]}"sScCqQtT".indexOf(L)>=0&&(v=_,y=T),"MLCSQT".indexOf(L)>=0?(_=q.x,T=q.y):"mlcsqt".indexOf(L)>=0?(_=q.x+_,T=q.y+T):"zZ".indexOf(L)<0&&(_=A,T=k),"CSQTcsqt".indexOf(L)>=0?(r=Math.min(r,_,F[0],C[0],I[0]),i=Math.max(i,_,F[0],C[0],I[0]),a=Math.min(a,T,F[1],C[1],I[1]),n=Math.max(n,T,F[1],C[1],I[1])):(r=Math.min(r,_),i=Math.max(i,_),a=Math.min(a,T),n=Math.max(n,T))}u=[r,a,i-r,n-a]}else{if(f(t,"svg"))return s=t.getAttribute("viewBox"),s&&(o=M(s)),[d(t.getAttribute("x"))||o&&o[0]||0,d(t.getAttribute("y"))||o&&o[1]||0,d(t.getAttribute("width"))||o&&o[2]||0,d(t.getAttribute("height"))||o&&o[3]||0];if(f(t,"g"))u=[0,0,0,0],l(t,function(t,e){var r=S(e);u=[Math.min(u[0],r[0]),Math.min(u[1],r[1]),Math.max(u[0]+u[2],r[0]+r[2])-Math.min(u[0],r[0]),Math.max(u[1]+u[3],r[1]+r[3])-Math.min(u[1],r[1])]});else{if(f(t,"marker"))return s=t.getAttribute("viewBox"),s&&(o=M(s)),[o&&o[0]||0,o&&o[1]||0,o&&o[2]||d(t.getAttribute("marker-width"))||0,o&&o[3]||d(t.getAttribute("marker-height"))||0];if(f(t,"pattern"))return[d(t.getAttribute("x"))||0,d(t.getAttribute("y"))||0,d(t.getAttribute("width"))||0,d(t.getAttribute("height"))||0];var N=d(t.getAttribute("x1"))||d(t.getAttribute("x"))||d(t.getAttribute("cx")-d(t.getAttribute("r")))||0,O=d(t.getAttribute("x2"))||N+d(t.getAttribute("width"))||d(t.getAttribute("cx"))+d(t.getAttribute("r"))||0,P=d(t.getAttribute("y1"))||d(t.getAttribute("y"))||d(t.getAttribute("cy"))-d(t.getAttribute("r"))||0,E=d(t.getAttribute("y2"))||P+d(t.getAttribute("height"))||d(t.getAttribute("cy"))+d(t.getAttribute("r"))||0;u=[Math.min(N,O),Math.min(P,E),Math.max(N,O)-Math.min(N,O),Math.max(P,E)-Math.min(P,E)]}}if(!f(t,"marker,svg,g")){var G=h(t,"stroke-width")||1;return h(t,"stroke-miterlimit")&&(G*=.5/Math.sin(Math.PI/12)),[u[0]-G,u[1]-G,u[2]+2*G,u[3]+2*G]}return u},I=function(t,e,r,a,i){for(var n=w(t.getAttribute("points")),s=[{op:"m",c:C(n[0],e)}],u=1;u<n.length;u++){var c=n[u],h=C(c,e);s.push({op:"l",c:h})}s.push({op:"h"}),o.path(s,r,a,i)},_=function(t){var e=t.getAttribute("xlink:href")||t.getAttribute("href"),r=new Image;r.src=e;var a=document.createElement("canvas"),i=parseFloat(t.getAttribute("width")),n=parseFloat(t.getAttribute("height")),s=parseFloat(t.getAttribute("x")||0),u=parseFloat(t.getAttribute("y")||0);a.width=i,a.height=n;var c=a.getContext("2d");c.fillStyle="#fff",c.fillRect(0,0,i,n),c.drawImage(r,0,0,i,n);var h=a.toDataURL("image/jpeg");o.addImage(h,"jpeg",s,u,i,n)},T=function(t,e,r,a,i,n){var s=c(t),h=t.getAttribute("marker-end"),f=t.getAttribute("marker-start"),l=t.getAttribute("marker-mid"),g=function(t,e){for(var r,a,i,n,u,c,g,x,m,v,y=0,A=0,w=y,k=A,M=[],F=[],S=0,I=function(t,r,a){var i,n=Math.cos(t),s=Math.sin(t);i=new o.Matrix(n,s,-s,n,r[0],r[1]),F.push({type:a,tf:o.matrixMult(i,e)})},_=0;_<s.numberOfItems;_++){var T=s.getItem(_),q=T.pathSegTypeAsLetter;switch(q){case"M":w=y,k=A,u=[T.x,T.y],m="m";break;case"m":w=y,k=A,u=[T.x+y,T.y+A],m="m";break;case"L":u=[T.x,T.y],m="l";break;case"l":u=[T.x+y,T.y+A],m="l";break;case"H":u=[T.x,A],m="l",i=T.x,n=A;break;case"h":u=[T.x+y,A],m="l",i=T.x+y,n=A;break;case"V":u=[y,T.y],m="l",i=y,n=T.y;break;case"v":u=[y,T.y+A],m="l",i=y,n=T.y+A;break;case"C":g=[T.x1,T.y1],x=[T.x2,T.y2],u=[T.x,T.y];break;case"c":g=[T.x1+y,T.y1+A],x=[T.x2+y,T.y2+A],u=[T.x+y,T.y+A];break;case"S":g=b(_,[y,A],s,r,a),x=[T.x2,T.y2],u=[T.x,T.y];break;case"s":g=b(_,[y,A],s,r,a),x=[T.x2+y,T.y2+A],u=[T.x+y,T.y+A];break;case"Q":c=[T.x1,T.y1],g=p([y,A],c),x=p([T.x,T.y],c),u=[T.x,T.y];break;case"q":c=[T.x1+y,T.y1+A],g=p([y,A],c),x=p([y+T.x,A+T.y],c),u=[T.x+y,T.y+A];break;case"T":g=b(_,[y,A],s,r,a),g=p([y,A],c),x=p([T.x,T.y],c),u=[T.x,T.y];break;case"t":c=b(_,[y,A],s,r,a),g=p([y,A],c),x=p([y+T.x,A+T.y],c),u=[T.x+y,T.y+A];break;case"Z":case"z":y=w,A=k,M.push({op:"h"})}var L=f&&(1===_||"mM".indexOf(q)<0&&"mM".indexOf(s.getItem(_-1).pathSegTypeAsLetter)>=0),N=h&&(_===s.numberOfItems-1||"mM".indexOf(q)<0&&"mM".indexOf(s.getItem(_+1).pathSegTypeAsLetter)>=0),O=l&&_>0&&!(1===_&&"mM".indexOf(s.getItem(_-1).pathSegTypeAsLetter)>=0);if("sScCqQtT".indexOf(q)>=0)L&&I(d([y,A],g),[y,A],"start"),N&&I(d(x,u),u,"end"),O&&(v=d([y,A],g),v="mM".indexOf(s.getItem(_-1).pathSegTypeAsLetter)>=0?v:.5*(S+v),I(v,[y,A],"mid")),S=d(x,u),r=y,a=A,g=C(g,e),x=C(x,e),c=C(u,e),M.push({op:"c",c:[g[0],g[1],x[0],x[1],c[0],c[1]]});else if("lLhHvVmM".indexOf(q)>=0){if(v=d([y,A],u),L&&I(v,[y,A],"start"),N&&I(v,u,"end"),O){var P="mM".indexOf(q)>=0?S:"mM".indexOf(s.getItem(_-1).pathSegTypeAsLetter)>=0?v:.5*(S+v);I(P,[y,A],"mid")}S=v,c=C(u,e),M.push({op:m,c:c})}"MLCSQT".indexOf(q)>=0?(y=T.x,A=T.y):"mlcsqt".indexOf(q)>=0?(y=T.x+y,A=T.y+A):"zZ".indexOf(q)<0&&(y=i,A=n)}return{lines:M,markers:F}}(0,e);if(h||f||l)for(var x=0;x<g.markers.length;x++){var m,v=g.markers[x];switch(v.type){case"start":m=r.get()+u.exec(f)[1];break;case"end":m=r.get()+u.exec(h)[1];break;case"mid":m=r.get()+u.exec(l)[1]}o.doFormObject(m,v.tf)}g.lines.length>0&&o.path(g.lines,a,i,n)},q=function(t,e,r){var a=t.getAttribute("href")||t.getAttribute("xlink:href");if(a){var i=o.getFormObject(r.get()+a.substring(1)),n=t.getAttribute("x")||0,s=t.getAttribute("y")||0,u=t.getAttribute("width")||i.width,c=t.getAttribute("height")||i.height,h=new o.Matrix(u/i.width||0,0,0,c/i.height||0,n,s);h=o.matrixMult(h,e),o.doFormObject(r.get()+a.substring(1),h)}},L=function(t,e){var r=C([parseFloat(t.getAttribute("x1")),parseFloat(t.getAttribute("y1"))],e),a=C([parseFloat(t.getAttribute("x2")),parseFloat(t.getAttribute("y2"))],e);o.line(r[0],r[1],a[0],a[1])},N=function(t,e,r,a){o.roundedRect(parseFloat(t.getAttribute("x"))||0,parseFloat(t.getAttribute("y"))||0,parseFloat(t.getAttribute("width")),parseFloat(t.getAttribute("height")),parseFloat(t.getAttribute("rx"))||0,parseFloat(t.getAttribute("ry"))||0,e,r,a)},O=function(t,e,r,a){o.ellipse(parseFloat(t.getAttribute("cx"))||0,parseFloat(t.getAttribute("cy"))||0,parseFloat(t.getAttribute("rx")),parseFloat(t.getAttribute("ry")),e,r,a)},P=function(t,e,r,a){var i=parseFloat(t.getAttribute("r"))||0;o.ellipse(parseFloat(t.getAttribute("cx"))||0,parseFloat(t.getAttribute("cy"))||0,i,i,e,r,a)},E=function(t,e){switch(h(t,"text-transform")){case"uppercase":return e.toUpperCase();case"lowercase":return e.toLowerCase();default:return e}},G=function(t,e,r,a){o.saveGraphicsState(),i(t,a);var s=function(t,e){var r;return(r=t&&t.toString().match(/^([\-0-9.]+)em$/))?parseFloat(r[1])*e:(r=t&&t.toString().match(/^([\-0-9.]+)(px|)$/),r?parseFloat(r[1]):0)},u=document.createElementNS("http://www.w3.org/2000/svg","svg");u.appendChild(t),u.setAttribute("visibility","hidden"),document.body.appendChild(u);var c,d,g=t.getBBox(),p=0,b=h(t,"text-anchor");b&&(p=function(t,e){var r=0;switch(t){case"end":r=e;break;case"middle":r=e/2}return r}(b,g.width));var x=o.getFontSize(),m=s(t.getAttribute("x"),x),y=s(t.getAttribute("y"),x),A=o.matrixMult(new o.Matrix(1,0,0,1,m,y),e);c=s(t.getAttribute("dx"),x),d=s(t.getAttribute("dy"),x),0===t.childElementCount?o.text(c-p,d,E(t,v(t.textContent)),void 0,A):l(t,function(e,r){if(r.textContent&&!f(r,"title,desc,metadata")){o.saveGraphicsState();var a=h(r,"fill");i(r,a&&new n(a));var s=r.getExtentOfChar(0);o.text(s.x-m,s.y+.7*s.height-y,E(t,v(r.textContent)),void 0,A),o.restoreGraphicsState()}}),document.body.removeChild(u),o.restoreGraphicsState()},j=function(t,e,r,a,i){l(t,function(t,n){"defs"===n.tagName.toLowerCase()&&(B(n,e,r,a,i),n.parentNode.removeChild(n))})},V=function(t,e,r,a,i){var n=a.nextChild(),s=y(r);j(t,e,s,n,i),Y(t,e,s,n,i)},Y=function(t,e,r,a,i){l(t,function(t,n){B(n,e,r,a,i)})},z=function(t,e,r,a,i){var s,u=[],c=0,f=!1;l(t,function(t,e){if("stop"===e.tagName.toLowerCase()){var r=new n(h(e,"stop-color"));u.push({offset:parseFloat(e.getAttribute("offset")),color:[r.r,r.g,r.b]});var a=h(e,"stop-opacity");a&&1!=a&&(c+=parseFloat(a),f=!0)}}),f&&(s=new o.GState({opacity:c/r.length}));var d=new o.ShadingPattern(e,r,u,s),g=i.get()+t.getAttribute("id");o.addShadingPattern(g,d),a[g]=t},H=function(t,e,r){var a=r.get()+t.getAttribute("id");e[a]=t;var i=S(t),n=new o.TilingPattern([i[0],i[1],i[0]+i[2],i[1]+i[3]],i[2],i[3],null,A(t));o.beginTilingPattern(n),Y(t,o.unitMatrix,e,r,!1),o.endTilingPattern(a,n)},B=function(t,e,r,a,s){function c(){p=new n("rgb(0, 0, 0)"),g=!0,b="F"}var l,d,g=!1,p=null,b=null,x=null,v=null,y=s&&!f(t,"lineargradient,radialgradient,pattern");if(y?(l=A(t),d=S(t),o.beginFormObject(d[0],d[1],d[2],d[3],l),l=o.unitMatrix,s=!1):(l=o.matrixMult(A(t),e),o.saveGraphicsState()),f(t,"g,path,rect,text,ellipse,line,circle,polygon")){var w=h(t,"fill");if(w){var C=u.exec(w);if(C){x=a.get()+C[1];var E=m(x,r);if(E&&f(E,"lineargradient,radialgradient")){var B=l;if(!E.hasAttribute("gradientUnits")||"objectboundingbox"===E.getAttribute("gradientUnits").toLowerCase()){d||(d=S(t)),B=new o.Matrix(d[2],0,0,d[3],d[0],d[1]);var U=A(t);B=o.matrixMult(B,U)}var Q=k(E.getAttribute("gradientTransform"));v=o.matrixMult(Q,B)}else if(E&&f(E,"pattern")){var D,X,Z,R,$;v={};var W=o.unitMatrix;E.hasAttribute("patternUnits")&&"objectboundingbox"!==E.getAttribute("patternUnits").toLowerCase()||(d||(d=S(t)),W=new o.Matrix(1,0,0,1,d[0],d[1]),D=S(E),$=D[0]*d[0],X=D[1]*d[1],Z=D[2]*d[2],R=D[3]*d[3],v.boundingBox=[$,X,$+Z,X+R],v.xStep=Z,v.yStep=R);var J=o.unitMatrix;E.hasAttribute("patternContentUnits")&&"objectboundingbox"===E.getAttribute("patternContentUnits").toLowerCase()&&(d||(d=S(t)),J=new o.Matrix(d[2],0,0,d[3],0,0),D=v.boundingBox||S(E),$=D[0]/d[0],X=D[1]/d[1],Z=D[2]/d[2],R=D[3]/d[3],v.boundingBox=[$,X,$+Z,X+R],v.xStep=Z,v.yStep=R),v.matrix=o.matrixMult(o.matrixMult(J,W),l),b="F"}else x=E=null,c()}else p=F(w),p.ok?(g=!0,b="F"):b=null}else c();var K=1,tt=t.getAttribute("opacity")||t.getAttribute("fill-opacity");tt&&(K*=parseFloat(tt)),p&&"number"==typeof p.a&&(K*=p.a),o.setGState(new o.GState({opacity:K}))}if(f(t,"g,path,rect,ellipse,line,circle,polygon")){g&&o.setFillColor(p.r,p.g,p.b);var et=t.getAttribute("stroke");if(et){var rt;t.hasAttribute("stroke-width")&&(rt=Math.abs(parseFloat(t.getAttribute("stroke-width"))),o.setLineWidth(rt));var at=new n(et);at.ok&&(o.setDrawColor(at.r,at.g,at.b),0!==rt&&(b=(b||"")+"D")),t.hasAttribute("stroke-linecap")&&o.setLineCap(t.getAttribute("stroke-linecap")),t.hasAttribute("stroke-linejoin")&&o.setLineJoin(t.getAttribute("stroke-linejoin")),t.hasAttribute("stroke-dasharray")&&o.setLineDashPattern(M(t.getAttribute("stroke-dasharray")),parseInt(t.getAttribute("stroke-dashoffset"))||0),t.hasAttribute("stroke-miterlimit")&&o.setLineMiterLimit(parseFloat(t.getAttribute("stroke-miterlimit")))}}switch(i(t,p),t.tagName.toLowerCase()){case"svg":V(t,l,r,a,s);break;case"g":j(t,l,r,a,s);case"a":case"marker":Y(t,l,r,a,s);break;case"defs":Y(t,l,r,a,!0);break;case"use":q(t,l,a);break;case"line":L(t,l);break;case"rect":o.setCurrentTransformationMatrix(l),N(t,b,x,v);break;case"ellipse":o.setCurrentTransformationMatrix(l),O(t,b,x,v);break;case"circle":o.setCurrentTransformationMatrix(l),P(t,b,x,v);break;case"text":G(t,l,0,p);break;case"path":T(t,l,a,b,x,v);break;case"polygon":I(t,l,b,x,v);break;case"image":o.setCurrentTransformationMatrix(l),_(t);break;case"lineargradient":z(t,"axial",[t.getAttribute("x1"),t.getAttribute("y1"),t.getAttribute("x2"),t.getAttribute("y2")],r,a);break;case"radialgradient":z(t,"radial",[t.getAttribute("fx")||t.getAttribute("cx"),t.getAttribute("fy")||t.getAttribute("cy"),0,t.getAttribute("cx")||0,t.getAttribute("cy")||0,t.getAttribute("r")||0],r,a);break;case"pattern":H(t,r,a)}y?o.endFormObject(a.get()+t.getAttribute("id")):o.restoreGraphicsState()},U=function(t,e,r){o=e;var a=r.scale||1,i=r.xOffset||0,n=r.yOffset||0;return o.saveGraphicsState(),o.setCurrentTransformationMatrix(new o.Matrix(a,0,0,a,i,n)),B(t.cloneNode(!0),o.unitMatrix,{},new x(""),!1),o.restoreGraphicsState(),o};"function"==typeof t&&t.amd?t(["./rgbcolor","SvgPath"],function(t,e){return n=t,s=e,U}):void 0!==r&&r.exports?(n=e("./rgbcolor.js"),s=e("SvgPath"),r.exports=U):(s=a.SvgPath,n=a.RGBColor,a.svg2pdf=U,a.svgElementToPdf=U),U}("undefined"!=typeof self&&self||"undefined"!=typeof window&&window||this)},{"./rgbcolor.js":8,SvgPath:1}]},{},[9])(9)}); |
//# sourceMappingURL=svg2pdf.min.js.map |
/base/000_base/node_modules/highcharts/lib/svg2pdf.src.js |
@@ -0,0 +1,3244 @@ |
/** |
* Modules in this bundle |
* @license |
* |
* svg2pdf.js: |
* license: MIT (http://opensource.org/licenses/MIT) |
* author: yFiles for HTML Support Team <yfileshtml@yworks.com> |
* homepage: https://github.com/yWorks/svg2pdf.js#readme |
* version: 1.0.5 |
* |
* svgpath: |
* license: MIT (http://opensource.org/licenses/MIT) |
* maintainers: vitaly <vitaly@rcdesign.ru> |
* homepage: https://github.com/fontello/svgpath#readme |
* version: 2.2.1 |
* |
* This header is generated by licensify (https://github.com/twada/licensify) |
*/ |
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.svg2pdf = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){ |
'use strict'; |
|
module.exports = require('./lib/svgpath'); |
|
},{"./lib/svgpath":6}],2:[function(require,module,exports){ |
// Convert an arc to a sequence of cubic bézier curves |
// |
'use strict'; |
|
|
var TAU = Math.PI * 2; |
|
|
/* eslint-disable space-infix-ops */ |
|
// Calculate an angle between two vectors |
// |
function vector_angle(ux, uy, vx, vy) { |
var sign = (ux * vy - uy * vx < 0) ? -1 : 1; |
var umag = Math.sqrt(ux * ux + uy * uy); |
var vmag = Math.sqrt(ux * ux + uy * uy); |
var dot = ux * vx + uy * vy; |
var div = dot / (umag * vmag); |
|
// rounding errors, e.g. -1.0000000000000002 can screw up this |
if (div > 1.0) { div = 1.0; } |
if (div < -1.0) { div = -1.0; } |
|
return sign * Math.acos(div); |
} |
|
|
// Convert from endpoint to center parameterization, |
// see http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes |
// |
// Return [cx, cy, theta1, delta_theta] |
// |
function get_arc_center(x1, y1, x2, y2, fa, fs, rx, ry, sin_phi, cos_phi) { |
// Step 1. |
// |
// Moving an ellipse so origin will be the middlepoint between our two |
// points. After that, rotate it to line up ellipse axes with coordinate |
// axes. |
// |
var x1p = cos_phi*(x1-x2)/2 + sin_phi*(y1-y2)/2; |
var y1p = -sin_phi*(x1-x2)/2 + cos_phi*(y1-y2)/2; |
|
var rx_sq = rx * rx; |
var ry_sq = ry * ry; |
var x1p_sq = x1p * x1p; |
var y1p_sq = y1p * y1p; |
|
// Step 2. |
// |
// Compute coordinates of the centre of this ellipse (cx', cy') |
// in the new coordinate system. |
// |
var radicant = (rx_sq * ry_sq) - (rx_sq * y1p_sq) - (ry_sq * x1p_sq); |
|
if (radicant < 0) { |
// due to rounding errors it might be e.g. -1.3877787807814457e-17 |
radicant = 0; |
} |
|
radicant /= (rx_sq * y1p_sq) + (ry_sq * x1p_sq); |
radicant = Math.sqrt(radicant) * (fa === fs ? -1 : 1); |
|
var cxp = radicant * rx/ry * y1p; |
var cyp = radicant * -ry/rx * x1p; |
|
// Step 3. |
// |
// Transform back to get centre coordinates (cx, cy) in the original |
// coordinate system. |
// |
var cx = cos_phi*cxp - sin_phi*cyp + (x1+x2)/2; |
var cy = sin_phi*cxp + cos_phi*cyp + (y1+y2)/2; |
|
// Step 4. |
// |
// Compute angles (theta1, delta_theta). |
// |
var v1x = (x1p - cxp) / rx; |
var v1y = (y1p - cyp) / ry; |
var v2x = (-x1p - cxp) / rx; |
var v2y = (-y1p - cyp) / ry; |
|
var theta1 = vector_angle(1, 0, v1x, v1y); |
var delta_theta = vector_angle(v1x, v1y, v2x, v2y); |
|
if (fs === 0 && delta_theta > 0) { |
delta_theta -= TAU; |
} |
if (fs === 1 && delta_theta < 0) { |
delta_theta += TAU; |
} |
|
return [ cx, cy, theta1, delta_theta ]; |
} |
|
// |
// Approximate one unit arc segment with bézier curves, |
// see http://math.stackexchange.com/questions/873224 |
// |
function approximate_unit_arc(theta1, delta_theta) { |
var alpha = 4/3 * Math.tan(delta_theta/4); |
|
var x1 = Math.cos(theta1); |
var y1 = Math.sin(theta1); |
var x2 = Math.cos(theta1 + delta_theta); |
var y2 = Math.sin(theta1 + delta_theta); |
|
return [ x1, y1, x1 - y1*alpha, y1 + x1*alpha, x2 + y2*alpha, y2 - x2*alpha, x2, y2 ]; |
} |
|
module.exports = function a2c(x1, y1, x2, y2, fa, fs, rx, ry, phi) { |
var sin_phi = Math.sin(phi * TAU / 360); |
var cos_phi = Math.cos(phi * TAU / 360); |
|
// Make sure radii are valid |
// |
var x1p = cos_phi*(x1-x2)/2 + sin_phi*(y1-y2)/2; |
var y1p = -sin_phi*(x1-x2)/2 + cos_phi*(y1-y2)/2; |
|
if (x1p === 0 && y1p === 0) { |
// we're asked to draw line to itself |
return []; |
} |
|
if (rx === 0 || ry === 0) { |
// one of the radii is zero |
return []; |
} |
|
|
// Compensate out-of-range radii |
// |
rx = Math.abs(rx); |
ry = Math.abs(ry); |
|
var lambda = (x1p * x1p) / (rx * rx) + (y1p * y1p) / (ry * ry); |
if (lambda > 1) { |
rx *= Math.sqrt(lambda); |
ry *= Math.sqrt(lambda); |
} |
|
|
// Get center parameters (cx, cy, theta1, delta_theta) |
// |
var cc = get_arc_center(x1, y1, x2, y2, fa, fs, rx, ry, sin_phi, cos_phi); |
|
var result = []; |
var theta1 = cc[2]; |
var delta_theta = cc[3]; |
|
// Split an arc to multiple segments, so each segment |
// will be less than τ/4 (= 90°) |
// |
var segments = Math.max(Math.ceil(Math.abs(delta_theta) / (TAU / 4)), 1); |
delta_theta /= segments; |
|
for (var i = 0; i < segments; i++) { |
result.push(approximate_unit_arc(theta1, delta_theta)); |
theta1 += delta_theta; |
} |
|
// We have a bezier approximation of a unit circle, |
// now need to transform back to the original ellipse |
// |
return result.map(function (curve) { |
for (var i = 0; i < curve.length; i += 2) { |
var x = curve[i + 0]; |
var y = curve[i + 1]; |
|
// scale |
x *= rx; |
y *= ry; |
|
// rotate |
var xp = cos_phi*x - sin_phi*y; |
var yp = sin_phi*x + cos_phi*y; |
|
// translate |
curve[i + 0] = xp + cc[0]; |
curve[i + 1] = yp + cc[1]; |
} |
|
return curve; |
}); |
}; |
|
},{}],3:[function(require,module,exports){ |
'use strict'; |
|
/* eslint-disable space-infix-ops */ |
|
// The precision used to consider an ellipse as a circle |
// |
var epsilon = 0.0000000001; |
|
// To convert degree in radians |
// |
var torad = Math.PI / 180; |
|
// Class constructor : |
// an ellipse centred at 0 with radii rx,ry and x - axis - angle ax. |
// |
function Ellipse(rx, ry, ax) { |
if (!(this instanceof Ellipse)) { return new Ellipse(rx, ry, ax); } |
this.rx = rx; |
this.ry = ry; |
this.ax = ax; |
} |
|
// Apply a linear transform m to the ellipse |
// m is an array representing a matrix : |
// - - |
// | m[0] m[2] | |
// | m[1] m[3] | |
// - - |
// |
Ellipse.prototype.transform = function (m) { |
// We consider the current ellipse as image of the unit circle |
// by first scale(rx,ry) and then rotate(ax) ... |
// So we apply ma = m x rotate(ax) x scale(rx,ry) to the unit circle. |
var c = Math.cos(this.ax * torad), s = Math.sin(this.ax * torad); |
var ma = [ |
this.rx * (m[0]*c + m[2]*s), |
this.rx * (m[1]*c + m[3]*s), |
this.ry * (-m[0]*s + m[2]*c), |
this.ry * (-m[1]*s + m[3]*c) |
]; |
|
// ma * transpose(ma) = [ J L ] |
// [ L K ] |
// L is calculated later (if the image is not a circle) |
var J = ma[0]*ma[0] + ma[2]*ma[2], |
K = ma[1]*ma[1] + ma[3]*ma[3]; |
|
// the discriminant of the characteristic polynomial of ma * transpose(ma) |
var D = ((ma[0]-ma[3])*(ma[0]-ma[3]) + (ma[2]+ma[1])*(ma[2]+ma[1])) * |
((ma[0]+ma[3])*(ma[0]+ma[3]) + (ma[2]-ma[1])*(ma[2]-ma[1])); |
|
// the "mean eigenvalue" |
var JK = (J + K) / 2; |
|
// check if the image is (almost) a circle |
if (D < epsilon * JK) { |
// if it is |
this.rx = this.ry = Math.sqrt(JK); |
this.ax = 0; |
return this; |
} |
|
// if it is not a circle |
var L = ma[0]*ma[1] + ma[2]*ma[3]; |
|
D = Math.sqrt(D); |
|
// {l1,l2} = the two eigen values of ma * transpose(ma) |
var l1 = JK + D/2, |
l2 = JK - D/2; |
// the x - axis - rotation angle is the argument of the l1 - eigenvector |
this.ax = (Math.abs(L) < epsilon && Math.abs(l1 - K) < epsilon) ? |
90 |
: |
Math.atan(Math.abs(L) > Math.abs(l1 - K) ? |
(l1 - J) / L |
: |
L / (l1 - K) |
) * 180 / Math.PI; |
|
// if ax > 0 => rx = sqrt(l1), ry = sqrt(l2), else exchange axes and ax += 90 |
if (this.ax >= 0) { |
// if ax in [0,90] |
this.rx = Math.sqrt(l1); |
this.ry = Math.sqrt(l2); |
} else { |
// if ax in ]-90,0[ => exchange axes |
this.ax += 90; |
this.rx = Math.sqrt(l2); |
this.ry = Math.sqrt(l1); |
} |
|
return this; |
}; |
|
// Check if the ellipse is (almost) degenerate, i.e. rx = 0 or ry = 0 |
// |
Ellipse.prototype.isDegenerate = function () { |
return (this.rx < epsilon * this.ry || this.ry < epsilon * this.rx); |
}; |
|
module.exports = Ellipse; |
|
},{}],4:[function(require,module,exports){ |
'use strict'; |
|
// combine 2 matrixes |
// m1, m2 - [a, b, c, d, e, g] |
// |
function combine(m1, m2) { |
return [ |
m1[0] * m2[0] + m1[2] * m2[1], |
m1[1] * m2[0] + m1[3] * m2[1], |
m1[0] * m2[2] + m1[2] * m2[3], |
m1[1] * m2[2] + m1[3] * m2[3], |
m1[0] * m2[4] + m1[2] * m2[5] + m1[4], |
m1[1] * m2[4] + m1[3] * m2[5] + m1[5] |
]; |
} |
|
|
function Matrix() { |
if (!(this instanceof Matrix)) { return new Matrix(); } |
this.queue = []; // list of matrixes to apply |
this.cache = null; // combined matrix cache |
} |
|
|
Matrix.prototype.matrix = function (m) { |
if (m[0] === 1 && m[1] === 0 && m[2] === 0 && m[3] === 1 && m[4] === 0 && m[5] === 0) { |
return this; |
} |
this.cache = null; |
this.queue.push(m); |
return this; |
}; |
|
|
Matrix.prototype.translate = function (tx, ty) { |
if (tx !== 0 || ty !== 0) { |
this.cache = null; |
this.queue.push([ 1, 0, 0, 1, tx, ty ]); |
} |
return this; |
}; |
|
|
Matrix.prototype.scale = function (sx, sy) { |
if (sx !== 1 || sy !== 1) { |
this.cache = null; |
this.queue.push([ sx, 0, 0, sy, 0, 0 ]); |
} |
return this; |
}; |
|
|
Matrix.prototype.rotate = function (angle, rx, ry) { |
var rad, cos, sin; |
|
if (angle !== 0) { |
this.translate(rx, ry); |
|
rad = angle * Math.PI / 180; |
cos = Math.cos(rad); |
sin = Math.sin(rad); |
|
this.queue.push([ cos, sin, -sin, cos, 0, 0 ]); |
this.cache = null; |
|
this.translate(-rx, -ry); |
} |
return this; |
}; |
|
|
Matrix.prototype.skewX = function (angle) { |
if (angle !== 0) { |
this.cache = null; |
this.queue.push([ 1, 0, Math.tan(angle * Math.PI / 180), 1, 0, 0 ]); |
} |
return this; |
}; |
|
|
Matrix.prototype.skewY = function (angle) { |
if (angle !== 0) { |
this.cache = null; |
this.queue.push([ 1, Math.tan(angle * Math.PI / 180), 0, 1, 0, 0 ]); |
} |
return this; |
}; |
|
|
// Flatten queue |
// |
Matrix.prototype.toArray = function () { |
if (this.cache) { |
return this.cache; |
} |
|
if (!this.queue.length) { |
this.cache = [ 1, 0, 0, 1, 0, 0 ]; |
return this.cache; |
} |
|
this.cache = this.queue[0]; |
|
if (this.queue.length === 1) { |
return this.cache; |
} |
|
for (var i = 1; i < this.queue.length; i++) { |
this.cache = combine(this.cache, this.queue[i]); |
} |
|
return this.cache; |
}; |
|
|
// Apply list of matrixes to (x,y) point. |
// If `isRelative` set, `translate` component of matrix will be skipped |
// |
Matrix.prototype.calc = function (x, y, isRelative) { |
var m; |
|
// Don't change point on empty transforms queue |
if (!this.queue.length) { return [ x, y ]; } |
|
// Calculate final matrix, if not exists |
// |
// NB. if you deside to apply transforms to point one-by-one, |
// they should be taken in reverse order |
|
if (!this.cache) { |
this.cache = this.toArray(); |
} |
|
m = this.cache; |
|
// Apply matrix to point |
return [ |
x * m[0] + y * m[2] + (isRelative ? 0 : m[4]), |
x * m[1] + y * m[3] + (isRelative ? 0 : m[5]) |
]; |
}; |
|
|
module.exports = Matrix; |
|
},{}],5:[function(require,module,exports){ |
'use strict'; |
|
|
var paramCounts = { a: 7, c: 6, h: 1, l: 2, m: 2, r: 4, q: 4, s: 4, t: 2, v: 1, z: 0 }; |
|
var SPECIAL_SPACES = [ |
0x1680, 0x180E, 0x2000, 0x2001, 0x2002, 0x2003, 0x2004, 0x2005, 0x2006, |
0x2007, 0x2008, 0x2009, 0x200A, 0x202F, 0x205F, 0x3000, 0xFEFF |
]; |
|
function isSpace(ch) { |
return (ch === 0x0A) || (ch === 0x0D) || (ch === 0x2028) || (ch === 0x2029) || // Line terminators |
// White spaces |
(ch === 0x20) || (ch === 0x09) || (ch === 0x0B) || (ch === 0x0C) || (ch === 0xA0) || |
(ch >= 0x1680 && SPECIAL_SPACES.indexOf(ch) >= 0); |
} |
|
function isCommand(code) { |
/*eslint-disable no-bitwise*/ |
switch (code | 0x20) { |
case 0x6D/* m */: |
case 0x7A/* z */: |
case 0x6C/* l */: |
case 0x68/* h */: |
case 0x76/* v */: |
case 0x63/* c */: |
case 0x73/* s */: |
case 0x71/* q */: |
case 0x74/* t */: |
case 0x61/* a */: |
case 0x72/* r */: |
return true; |
} |
return false; |
} |
|
function isDigit(code) { |
return (code >= 48 && code <= 57); // 0..9 |
} |
|
function isDigitStart(code) { |
return (code >= 48 && code <= 57) || /* 0..9 */ |
code === 0x2B || /* + */ |
code === 0x2D || /* - */ |
code === 0x2E; /* . */ |
} |
|
|
function State(path) { |
this.index = 0; |
this.path = path; |
this.max = path.length; |
this.result = []; |
this.param = 0.0; |
this.err = ''; |
this.segmentStart = 0; |
this.data = []; |
} |
|
function skipSpaces(state) { |
while (state.index < state.max && isSpace(state.path.charCodeAt(state.index))) { |
state.index++; |
} |
} |
|
|
function scanParam(state) { |
var start = state.index, |
index = start, |
max = state.max, |
zeroFirst = false, |
hasCeiling = false, |
hasDecimal = false, |
hasDot = false, |
ch; |
|
if (index >= max) { |
state.err = 'SvgPath: missed param (at pos ' + index + ')'; |
return; |
} |
ch = state.path.charCodeAt(index); |
|
if (ch === 0x2B/* + */ || ch === 0x2D/* - */) { |
index++; |
ch = (index < max) ? state.path.charCodeAt(index) : 0; |
} |
|
// This logic is shamelessly borrowed from Esprima |
// https://github.com/ariya/esprimas |
// |
if (!isDigit(ch) && ch !== 0x2E/* . */) { |
state.err = 'SvgPath: param should start with 0..9 or `.` (at pos ' + index + ')'; |
return; |
} |
|
if (ch !== 0x2E/* . */) { |
zeroFirst = (ch === 0x30/* 0 */); |
index++; |
|
ch = (index < max) ? state.path.charCodeAt(index) : 0; |
|
if (zeroFirst && index < max) { |
// decimal number starts with '0' such as '09' is illegal. |
if (ch && isDigit(ch)) { |
state.err = 'SvgPath: numbers started with `0` such as `09` are ilegal (at pos ' + start + ')'; |
return; |
} |
} |
|
while (index < max && isDigit(state.path.charCodeAt(index))) { |
index++; |
hasCeiling = true; |
} |
ch = (index < max) ? state.path.charCodeAt(index) : 0; |
} |
|
if (ch === 0x2E/* . */) { |
hasDot = true; |
index++; |
while (isDigit(state.path.charCodeAt(index))) { |
index++; |
hasDecimal = true; |
} |
ch = (index < max) ? state.path.charCodeAt(index) : 0; |
} |
|
if (ch === 0x65/* e */ || ch === 0x45/* E */) { |
if (hasDot && !hasCeiling && !hasDecimal) { |
state.err = 'SvgPath: invalid float exponent (at pos ' + index + ')'; |
return; |
} |
|
index++; |
|
ch = (index < max) ? state.path.charCodeAt(index) : 0; |
if (ch === 0x2B/* + */ || ch === 0x2D/* - */) { |
index++; |
} |
if (index < max && isDigit(state.path.charCodeAt(index))) { |
while (index < max && isDigit(state.path.charCodeAt(index))) { |
index++; |
} |
} else { |
state.err = 'SvgPath: invalid float exponent (at pos ' + index + ')'; |
return; |
} |
} |
|
state.index = index; |
state.param = parseFloat(state.path.slice(start, index)) + 0.0; |
} |
|
|
function finalizeSegment(state) { |
var cmd, cmdLC; |
|
// Process duplicated commands (without comand name) |
|
// This logic is shamelessly borrowed from Raphael |
// https://github.com/DmitryBaranovskiy/raphael/ |
// |
cmd = state.path[state.segmentStart]; |
cmdLC = cmd.toLowerCase(); |
|
var params = state.data; |
|
if (cmdLC === 'm' && params.length > 2) { |
state.result.push([ cmd, params[0], params[1] ]); |
params = params.slice(2); |
cmdLC = 'l'; |
cmd = (cmd === 'm') ? 'l' : 'L'; |
} |
|
if (cmdLC === 'r') { |
state.result.push([ cmd ].concat(params)); |
} else { |
|
while (params.length >= paramCounts[cmdLC]) { |
state.result.push([ cmd ].concat(params.splice(0, paramCounts[cmdLC]))); |
if (!paramCounts[cmdLC]) { |
break; |
} |
} |
} |
} |
|
|
function scanSegment(state) { |
var max = state.max, |
cmdCode, comma_found, need_params, i; |
|
state.segmentStart = state.index; |
cmdCode = state.path.charCodeAt(state.index); |
|
if (!isCommand(cmdCode)) { |
state.err = 'SvgPath: bad command ' + state.path[state.index] + ' (at pos ' + state.index + ')'; |
return; |
} |
|
need_params = paramCounts[state.path[state.index].toLowerCase()]; |
|
state.index++; |
skipSpaces(state); |
|
state.data = []; |
|
if (!need_params) { |
// Z |
finalizeSegment(state); |
return; |
} |
|
comma_found = false; |
|
for (;;) { |
for (i = need_params; i > 0; i--) { |
scanParam(state); |
if (state.err.length) { |
return; |
} |
state.data.push(state.param); |
|
skipSpaces(state); |
comma_found = false; |
|
if (state.index < max && state.path.charCodeAt(state.index) === 0x2C/* , */) { |
state.index++; |
skipSpaces(state); |
comma_found = true; |
} |
} |
|
// after ',' param is mandatory |
if (comma_found) { |
continue; |
} |
|
if (state.index >= state.max) { |
break; |
} |
|
// Stop on next segment |
if (!isDigitStart(state.path.charCodeAt(state.index))) { |
break; |
} |
} |
|
finalizeSegment(state); |
} |
|
|
/* Returns array of segments: |
* |
* [ |
* [ command, coord1, coord2, ... ] |
* ] |
*/ |
module.exports = function pathParse(svgPath) { |
var state = new State(svgPath); |
var max = state.max; |
|
skipSpaces(state); |
|
while (state.index < max && !state.err.length) { |
scanSegment(state); |
} |
|
if (state.err.length) { |
state.result = []; |
|
} else if (state.result.length) { |
|
if ('mM'.indexOf(state.result[0][0]) < 0) { |
state.err = 'SvgPath: string should start with `M` or `m`'; |
state.result = []; |
} else { |
state.result[0][0] = 'M'; |
} |
} |
|
return { |
err: state.err, |
segments: state.result |
}; |
}; |
|
},{}],6:[function(require,module,exports){ |
// SVG Path transformations library |
// |
// Usage: |
// |
// SvgPath('...') |
// .translate(-150, -100) |
// .scale(0.5) |
// .translate(-150, -100) |
// .toFixed(1) |
// .toString() |
// |
|
'use strict'; |
|
|
var pathParse = require('./path_parse'); |
var transformParse = require('./transform_parse'); |
var matrix = require('./matrix'); |
var a2c = require('./a2c'); |
var ellipse = require('./ellipse'); |
|
|
// Class constructor |
// |
function SvgPath(path) { |
if (!(this instanceof SvgPath)) { return new SvgPath(path); } |
|
var pstate = pathParse(path); |
|
// Array of path segments. |
// Each segment is array [command, param1, param2, ...] |
this.segments = pstate.segments; |
|
// Error message on parse error. |
this.err = pstate.err; |
|
// Transforms stack for lazy evaluation |
this.__stack = []; |
} |
|
|
SvgPath.prototype.__matrix = function (m) { |
var self = this, i; |
|
// Quick leave for empty matrix |
if (!m.queue.length) { return; } |
|
this.iterate(function (s, index, x, y) { |
var p, result, name, isRelative; |
|
switch (s[0]) { |
|
// Process 'assymetric' commands separately |
case 'v': |
p = m.calc(0, s[1], true); |
result = (p[0] === 0) ? [ 'v', p[1] ] : [ 'l', p[0], p[1] ]; |
break; |
|
case 'V': |
p = m.calc(x, s[1], false); |
result = (p[0] === m.calc(x, y, false)[0]) ? [ 'V', p[1] ] : [ 'L', p[0], p[1] ]; |
break; |
|
case 'h': |
p = m.calc(s[1], 0, true); |
result = (p[1] === 0) ? [ 'h', p[0] ] : [ 'l', p[0], p[1] ]; |
break; |
|
case 'H': |
p = m.calc(s[1], y, false); |
result = (p[1] === m.calc(x, y, false)[1]) ? [ 'H', p[0] ] : [ 'L', p[0], p[1] ]; |
break; |
|
case 'a': |
case 'A': |
// ARC is: ['A', rx, ry, x-axis-rotation, large-arc-flag, sweep-flag, x, y] |
|
// Drop segment if arc is empty (end point === start point) |
/*if ((s[0] === 'A' && s[6] === x && s[7] === y) || |
(s[0] === 'a' && s[6] === 0 && s[7] === 0)) { |
return []; |
}*/ |
|
// Transform rx, ry and the x-axis-rotation |
var ma = m.toArray(); |
var e = ellipse(s[1], s[2], s[3]).transform(ma); |
|
// flip sweep-flag if matrix is not orientation-preserving |
if (ma[0] * ma[3] - ma[1] * ma[2] < 0) { |
s[5] = s[5] ? '0' : '1'; |
} |
|
// Transform end point as usual (without translation for relative notation) |
p = m.calc(s[6], s[7], s[0] === 'a'); |
|
// Empty arcs can be ignored by renderer, but should not be dropped |
// to avoid collisions with `S A S` and so on. Replace with empty line. |
if ((s[0] === 'A' && s[6] === x && s[7] === y) || |
(s[0] === 'a' && s[6] === 0 && s[7] === 0)) { |
result = [ s[0] === 'a' ? 'l' : 'L', p[0], p[1] ]; |
break; |
} |
|
// if the resulting ellipse is (almost) a segment ... |
if (e.isDegenerate()) { |
// replace the arc by a line |
result = [ s[0] === 'a' ? 'l' : 'L', p[0], p[1] ]; |
} else { |
// if it is a real ellipse |
// s[0], s[4] and s[5] are not modified |
result = [ s[0], e.rx, e.ry, e.ax, s[4], s[5], p[0], p[1] ]; |
} |
|
break; |
|
case 'm': |
// Edge case. The very first `m` should be processed as absolute, if happens. |
// Make sense for coord shift transforms. |
isRelative = index > 0; |
|
p = m.calc(s[1], s[2], isRelative); |
result = [ 'm', p[0], p[1] ]; |
break; |
|
default: |
name = s[0]; |
result = [ name ]; |
isRelative = (name.toLowerCase() === name); |
|
// Apply transformations to the segment |
for (i = 1; i < s.length; i += 2) { |
p = m.calc(s[i], s[i + 1], isRelative); |
result.push(p[0], p[1]); |
} |
} |
|
self.segments[index] = result; |
}, true); |
}; |
|
|
// Apply stacked commands |
// |
SvgPath.prototype.__evaluateStack = function () { |
var m, i; |
|
if (!this.__stack.length) { return; } |
|
if (this.__stack.length === 1) { |
this.__matrix(this.__stack[0]); |
this.__stack = []; |
return; |
} |
|
m = matrix(); |
i = this.__stack.length; |
|
while (--i >= 0) { |
m.matrix(this.__stack[i].toArray()); |
} |
|
this.__matrix(m); |
this.__stack = []; |
}; |
|
|
// Convert processed SVG Path back to string |
// |
SvgPath.prototype.toString = function () { |
var elements = [], skipCmd, cmd; |
|
this.__evaluateStack(); |
|
for (var i = 0; i < this.segments.length; i++) { |
// remove repeating commands names |
cmd = this.segments[i][0]; |
skipCmd = i > 0 && cmd !== 'm' && cmd !== 'M' && cmd === this.segments[i - 1][0]; |
elements = elements.concat(skipCmd ? this.segments[i].slice(1) : this.segments[i]); |
} |
|
return elements.join(' ') |
// Optimizations: remove spaces around commands & before `-` |
// |
// We could also remove leading zeros for `0.5`-like values, |
// but their count is too small to spend time for. |
.replace(/ ?([achlmqrstvz]) ?/gi, '$1') |
.replace(/ \-/g, '-') |
// workaround for FontForge SVG importing bug |
.replace(/zm/g, 'z m'); |
}; |
|
|
// Translate path to (x [, y]) |
// |
SvgPath.prototype.translate = function (x, y) { |
this.__stack.push(matrix().translate(x, y || 0)); |
return this; |
}; |
|
|
// Scale path to (sx [, sy]) |
// sy = sx if not defined |
// |
SvgPath.prototype.scale = function (sx, sy) { |
this.__stack.push(matrix().scale(sx, (!sy && (sy !== 0)) ? sx : sy)); |
return this; |
}; |
|
|
// Rotate path around point (sx [, sy]) |
// sy = sx if not defined |
// |
SvgPath.prototype.rotate = function (angle, rx, ry) { |
this.__stack.push(matrix().rotate(angle, rx || 0, ry || 0)); |
return this; |
}; |
|
|
// Skew path along the X axis by `degrees` angle |
// |
SvgPath.prototype.skewX = function (degrees) { |
this.__stack.push(matrix().skewX(degrees)); |
return this; |
}; |
|
|
// Skew path along the Y axis by `degrees` angle |
// |
SvgPath.prototype.skewY = function (degrees) { |
this.__stack.push(matrix().skewY(degrees)); |
return this; |
}; |
|
|
// Apply matrix transform (array of 6 elements) |
// |
SvgPath.prototype.matrix = function (m) { |
this.__stack.push(matrix().matrix(m)); |
return this; |
}; |
|
|
// Transform path according to "transform" attr of SVG spec |
// |
SvgPath.prototype.transform = function (transformString) { |
if (!transformString.trim()) { |
return this; |
} |
this.__stack.push(transformParse(transformString)); |
return this; |
}; |
|
|
// Round coords with given decimal precition. |
// 0 by default (to integers) |
// |
SvgPath.prototype.round = function (d) { |
var contourStartDeltaX = 0, contourStartDeltaY = 0, deltaX = 0, deltaY = 0, l; |
|
d = d || 0; |
|
this.__evaluateStack(); |
|
this.segments.forEach(function (s) { |
var isRelative = (s[0].toLowerCase() === s[0]); |
|
switch (s[0]) { |
case 'H': |
case 'h': |
if (isRelative) { s[1] += deltaX; } |
deltaX = s[1] - s[1].toFixed(d); |
s[1] = +s[1].toFixed(d); |
return; |
|
case 'V': |
case 'v': |
if (isRelative) { s[1] += deltaY; } |
deltaY = s[1] - s[1].toFixed(d); |
s[1] = +s[1].toFixed(d); |
return; |
|
case 'Z': |
case 'z': |
deltaX = contourStartDeltaX; |
deltaY = contourStartDeltaY; |
return; |
|
case 'M': |
case 'm': |
if (isRelative) { |
s[1] += deltaX; |
s[2] += deltaY; |
} |
|
deltaX = s[1] - s[1].toFixed(d); |
deltaY = s[2] - s[2].toFixed(d); |
|
contourStartDeltaX = deltaX; |
contourStartDeltaY = deltaY; |
|
s[1] = +s[1].toFixed(d); |
s[2] = +s[2].toFixed(d); |
return; |
|
case 'A': |
case 'a': |
// [cmd, rx, ry, x-axis-rotation, large-arc-flag, sweep-flag, x, y] |
if (isRelative) { |
s[6] += deltaX; |
s[7] += deltaY; |
} |
|
deltaX = s[6] - s[6].toFixed(d); |
deltaY = s[7] - s[7].toFixed(d); |
|
s[1] = +s[1].toFixed(d); |
s[2] = +s[2].toFixed(d); |
s[3] = +s[3].toFixed(d + 2); // better precision for rotation |
s[6] = +s[6].toFixed(d); |
s[7] = +s[7].toFixed(d); |
return; |
|
default: |
// a c l q s t |
l = s.length; |
|
if (isRelative) { |
s[l - 2] += deltaX; |
s[l - 1] += deltaY; |
} |
|
deltaX = s[l - 2] - s[l - 2].toFixed(d); |
deltaY = s[l - 1] - s[l - 1].toFixed(d); |
|
s.forEach(function (val, i) { |
if (!i) { return; } |
s[i] = +s[i].toFixed(d); |
}); |
return; |
} |
}); |
|
return this; |
}; |
|
|
// Apply iterator function to all segments. If function returns result, |
// current segment will be replaced to array of returned segments. |
// If empty array is returned, current regment will be deleted. |
// |
SvgPath.prototype.iterate = function (iterator, keepLazyStack) { |
var segments = this.segments, |
replacements = {}, |
needReplace = false, |
lastX = 0, |
lastY = 0, |
countourStartX = 0, |
countourStartY = 0; |
var i, j, newSegments; |
|
if (!keepLazyStack) { |
this.__evaluateStack(); |
} |
|
segments.forEach(function (s, index) { |
|
var res = iterator(s, index, lastX, lastY); |
|
if (Array.isArray(res)) { |
replacements[index] = res; |
needReplace = true; |
} |
|
var isRelative = (s[0] === s[0].toLowerCase()); |
|
// calculate absolute X and Y |
switch (s[0]) { |
case 'm': |
case 'M': |
lastX = s[1] + (isRelative ? lastX : 0); |
lastY = s[2] + (isRelative ? lastY : 0); |
countourStartX = lastX; |
countourStartY = lastY; |
return; |
|
case 'h': |
case 'H': |
lastX = s[1] + (isRelative ? lastX : 0); |
return; |
|
case 'v': |
case 'V': |
lastY = s[1] + (isRelative ? lastY : 0); |
return; |
|
case 'z': |
case 'Z': |
// That make sence for multiple contours |
lastX = countourStartX; |
lastY = countourStartY; |
return; |
|
default: |
lastX = s[s.length - 2] + (isRelative ? lastX : 0); |
lastY = s[s.length - 1] + (isRelative ? lastY : 0); |
} |
}); |
|
// Replace segments if iterator return results |
|
if (!needReplace) { return this; } |
|
newSegments = []; |
|
for (i = 0; i < segments.length; i++) { |
if (typeof replacements[i] !== 'undefined') { |
for (j = 0; j < replacements[i].length; j++) { |
newSegments.push(replacements[i][j]); |
} |
} else { |
newSegments.push(segments[i]); |
} |
} |
|
this.segments = newSegments; |
|
return this; |
}; |
|
|
// Converts segments from relative to absolute |
// |
SvgPath.prototype.abs = function () { |
|
this.iterate(function (s, index, x, y) { |
var name = s[0], |
nameUC = name.toUpperCase(), |
i; |
|
// Skip absolute commands |
if (name === nameUC) { return; } |
|
s[0] = nameUC; |
|
switch (name) { |
case 'v': |
// v has shifted coords parity |
s[1] += y; |
return; |
|
case 'a': |
// ARC is: ['A', rx, ry, x-axis-rotation, large-arc-flag, sweep-flag, x, y] |
// touch x, y only |
s[6] += x; |
s[7] += y; |
return; |
|
default: |
for (i = 1; i < s.length; i++) { |
s[i] += i % 2 ? x : y; // odd values are X, even - Y |
} |
} |
}, true); |
|
return this; |
}; |
|
|
// Converts segments from absolute to relative |
// |
SvgPath.prototype.rel = function () { |
|
this.iterate(function (s, index, x, y) { |
var name = s[0], |
nameLC = name.toLowerCase(), |
i; |
|
// Skip relative commands |
if (name === nameLC) { return; } |
|
// Don't touch the first M to avoid potential confusions. |
if (index === 0 && name === 'M') { return; } |
|
s[0] = nameLC; |
|
switch (name) { |
case 'V': |
// V has shifted coords parity |
s[1] -= y; |
return; |
|
case 'A': |
// ARC is: ['A', rx, ry, x-axis-rotation, large-arc-flag, sweep-flag, x, y] |
// touch x, y only |
s[6] -= x; |
s[7] -= y; |
return; |
|
default: |
for (i = 1; i < s.length; i++) { |
s[i] -= i % 2 ? x : y; // odd values are X, even - Y |
} |
} |
}, true); |
|
return this; |
}; |
|
|
// Converts arcs to cubic bézier curves |
// |
SvgPath.prototype.unarc = function () { |
this.iterate(function (s, index, x, y) { |
var new_segments, nextX, nextY, result = [], name = s[0]; |
|
// Skip anything except arcs |
if (name !== 'A' && name !== 'a') { return null; } |
|
if (name === 'a') { |
// convert relative arc coordinates to absolute |
nextX = x + s[6]; |
nextY = y + s[7]; |
} else { |
nextX = s[6]; |
nextY = s[7]; |
} |
|
new_segments = a2c(x, y, nextX, nextY, s[4], s[5], s[1], s[2], s[3]); |
|
// Degenerated arcs can be ignored by renderer, but should not be dropped |
// to avoid collisions with `S A S` and so on. Replace with empty line. |
if (new_segments.length === 0) { |
return [ [ s[0] === 'a' ? 'l' : 'L', s[6], s[7] ] ]; |
} |
|
new_segments.forEach(function (s) { |
result.push([ 'C', s[2], s[3], s[4], s[5], s[6], s[7] ]); |
}); |
|
return result; |
}); |
|
return this; |
}; |
|
|
// Converts smooth curves (with missed control point) to generic curves |
// |
SvgPath.prototype.unshort = function () { |
var segments = this.segments; |
var prevControlX, prevControlY, prevSegment; |
var curControlX, curControlY; |
|
// TODO: add lazy evaluation flag when relative commands supported |
|
this.iterate(function (s, idx, x, y) { |
var name = s[0], nameUC = name.toUpperCase(), isRelative; |
|
// First command MUST be M|m, it's safe to skip. |
// Protect from access to [-1] for sure. |
if (!idx) { return; } |
|
if (nameUC === 'T') { // quadratic curve |
isRelative = (name === 't'); |
|
prevSegment = segments[idx - 1]; |
|
if (prevSegment[0] === 'Q') { |
prevControlX = prevSegment[1] - x; |
prevControlY = prevSegment[2] - y; |
} else if (prevSegment[0] === 'q') { |
prevControlX = prevSegment[1] - prevSegment[3]; |
prevControlY = prevSegment[2] - prevSegment[4]; |
} else { |
prevControlX = 0; |
prevControlY = 0; |
} |
|
curControlX = -prevControlX; |
curControlY = -prevControlY; |
|
if (!isRelative) { |
curControlX += x; |
curControlY += y; |
} |
|
segments[idx] = [ |
isRelative ? 'q' : 'Q', |
curControlX, curControlY, |
s[1], s[2] |
]; |
|
} else if (nameUC === 'S') { // cubic curve |
isRelative = (name === 's'); |
|
prevSegment = segments[idx - 1]; |
|
if (prevSegment[0] === 'C') { |
prevControlX = prevSegment[3] - x; |
prevControlY = prevSegment[4] - y; |
} else if (prevSegment[0] === 'c') { |
prevControlX = prevSegment[3] - prevSegment[5]; |
prevControlY = prevSegment[4] - prevSegment[6]; |
} else { |
prevControlX = 0; |
prevControlY = 0; |
} |
|
curControlX = -prevControlX; |
curControlY = -prevControlY; |
|
if (!isRelative) { |
curControlX += x; |
curControlY += y; |
} |
|
segments[idx] = [ |
isRelative ? 'c' : 'C', |
curControlX, curControlY, |
s[1], s[2], s[3], s[4] |
]; |
} |
}); |
|
return this; |
}; |
|
|
module.exports = SvgPath; |
|
},{"./a2c":2,"./ellipse":3,"./matrix":4,"./path_parse":5,"./transform_parse":7}],7:[function(require,module,exports){ |
'use strict'; |
|
|
var Matrix = require('./matrix'); |
|
var operations = { |
matrix: true, |
scale: true, |
rotate: true, |
translate: true, |
skewX: true, |
skewY: true |
}; |
|
var CMD_SPLIT_RE = /\s*(matrix|translate|scale|rotate|skewX|skewY)\s*\(\s*(.+?)\s*\)[\s,]*/; |
var PARAMS_SPLIT_RE = /[\s,]+/; |
|
|
module.exports = function transformParse(transformString) { |
var matrix = new Matrix(); |
var cmd, params; |
|
// Split value into ['', 'translate', '10 50', '', 'scale', '2', '', 'rotate', '-45', ''] |
transformString.split(CMD_SPLIT_RE).forEach(function (item) { |
|
// Skip empty elements |
if (!item.length) { return; } |
|
// remember operation |
if (typeof operations[item] !== 'undefined') { |
cmd = item; |
return; |
} |
|
// extract params & att operation to matrix |
params = item.split(PARAMS_SPLIT_RE).map(function (i) { |
return +i || 0; |
}); |
|
// If params count is not correct - ignore command |
switch (cmd) { |
case 'matrix': |
if (params.length === 6) { |
matrix.matrix(params); |
} |
return; |
|
case 'scale': |
if (params.length === 1) { |
matrix.scale(params[0], params[0]); |
} else if (params.length === 2) { |
matrix.scale(params[0], params[1]); |
} |
return; |
|
case 'rotate': |
if (params.length === 1) { |
matrix.rotate(params[0], 0, 0); |
} else if (params.length === 3) { |
matrix.rotate(params[0], params[1], params[2]); |
} |
return; |
|
case 'translate': |
if (params.length === 1) { |
matrix.translate(params[0], 0); |
} else if (params.length === 2) { |
matrix.translate(params[0], params[1]); |
} |
return; |
|
case 'skewX': |
if (params.length === 1) { |
matrix.skewX(params[0]); |
} |
return; |
|
case 'skewY': |
if (params.length === 1) { |
matrix.skewY(params[0]); |
} |
return; |
} |
}); |
|
return matrix; |
}; |
|
},{"./matrix":4}],8:[function(require,module,exports){ |
/** |
* A class to parse color values |
* @author Stoyan Stefanov <sstoo@gmail.com> |
* @link http://www.phpied.com/rgb-color-parser-in-javascript/ |
* @license Use it if you like it |
*/ |
(function (global) { |
function RGBColor(color_string) |
{ |
this.ok = false; |
|
// strip any leading # |
if (color_string.charAt(0) == '#') { // remove # if any |
color_string = color_string.substr(1,6); |
} |
|
color_string = color_string.replace(/ /g,''); |
color_string = color_string.toLowerCase(); |
|
// before getting into regexps, try simple matches |
// and overwrite the input |
var simple_colors = { |
aliceblue: 'f0f8ff', |
antiquewhite: 'faebd7', |
aqua: '00ffff', |
aquamarine: '7fffd4', |
azure: 'f0ffff', |
beige: 'f5f5dc', |
bisque: 'ffe4c4', |
black: '000000', |
blanchedalmond: 'ffebcd', |
blue: '0000ff', |
blueviolet: '8a2be2', |
brown: 'a52a2a', |
burlywood: 'deb887', |
cadetblue: '5f9ea0', |
chartreuse: '7fff00', |
chocolate: 'd2691e', |
coral: 'ff7f50', |
cornflowerblue: '6495ed', |
cornsilk: 'fff8dc', |
crimson: 'dc143c', |
cyan: '00ffff', |
darkblue: '00008b', |
darkcyan: '008b8b', |
darkgoldenrod: 'b8860b', |
darkgray: 'a9a9a9', |
darkgreen: '006400', |
darkkhaki: 'bdb76b', |
darkmagenta: '8b008b', |
darkolivegreen: '556b2f', |
darkorange: 'ff8c00', |
darkorchid: '9932cc', |
darkred: '8b0000', |
darksalmon: 'e9967a', |
darkseagreen: '8fbc8f', |
darkslateblue: '483d8b', |
darkslategray: '2f4f4f', |
darkturquoise: '00ced1', |
darkviolet: '9400d3', |
deeppink: 'ff1493', |
deepskyblue: '00bfff', |
dimgray: '696969', |
dodgerblue: '1e90ff', |
feldspar: 'd19275', |
firebrick: 'b22222', |
floralwhite: 'fffaf0', |
forestgreen: '228b22', |
fuchsia: 'ff00ff', |
gainsboro: 'dcdcdc', |
ghostwhite: 'f8f8ff', |
gold: 'ffd700', |
goldenrod: 'daa520', |
gray: '808080', |
green: '008000', |
greenyellow: 'adff2f', |
honeydew: 'f0fff0', |
hotpink: 'ff69b4', |
indianred : 'cd5c5c', |
indigo : '4b0082', |
ivory: 'fffff0', |
khaki: 'f0e68c', |
lavender: 'e6e6fa', |
lavenderblush: 'fff0f5', |
lawngreen: '7cfc00', |
lemonchiffon: 'fffacd', |
lightblue: 'add8e6', |
lightcoral: 'f08080', |
lightcyan: 'e0ffff', |
lightgoldenrodyellow: 'fafad2', |
lightgrey: 'd3d3d3', |
lightgreen: '90ee90', |
lightpink: 'ffb6c1', |
lightsalmon: 'ffa07a', |
lightseagreen: '20b2aa', |
lightskyblue: '87cefa', |
lightslateblue: '8470ff', |
lightslategray: '778899', |
lightsteelblue: 'b0c4de', |
lightyellow: 'ffffe0', |
lime: '00ff00', |
limegreen: '32cd32', |
linen: 'faf0e6', |
magenta: 'ff00ff', |
maroon: '800000', |
mediumaquamarine: '66cdaa', |
mediumblue: '0000cd', |
mediumorchid: 'ba55d3', |
mediumpurple: '9370d8', |
mediumseagreen: '3cb371', |
mediumslateblue: '7b68ee', |
mediumspringgreen: '00fa9a', |
mediumturquoise: '48d1cc', |
mediumvioletred: 'c71585', |
midnightblue: '191970', |
mintcream: 'f5fffa', |
mistyrose: 'ffe4e1', |
moccasin: 'ffe4b5', |
navajowhite: 'ffdead', |
navy: '000080', |
oldlace: 'fdf5e6', |
olive: '808000', |
olivedrab: '6b8e23', |
orange: 'ffa500', |
orangered: 'ff4500', |
orchid: 'da70d6', |
palegoldenrod: 'eee8aa', |
palegreen: '98fb98', |
paleturquoise: 'afeeee', |
palevioletred: 'd87093', |
papayawhip: 'ffefd5', |
peachpuff: 'ffdab9', |
peru: 'cd853f', |
pink: 'ffc0cb', |
plum: 'dda0dd', |
powderblue: 'b0e0e6', |
purple: '800080', |
red: 'ff0000', |
rosybrown: 'bc8f8f', |
royalblue: '4169e1', |
saddlebrown: '8b4513', |
salmon: 'fa8072', |
sandybrown: 'f4a460', |
seagreen: '2e8b57', |
seashell: 'fff5ee', |
sienna: 'a0522d', |
silver: 'c0c0c0', |
skyblue: '87ceeb', |
slateblue: '6a5acd', |
slategray: '708090', |
snow: 'fffafa', |
springgreen: '00ff7f', |
steelblue: '4682b4', |
tan: 'd2b48c', |
teal: '008080', |
thistle: 'd8bfd8', |
tomato: 'ff6347', |
turquoise: '40e0d0', |
violet: 'ee82ee', |
violetred: 'd02090', |
wheat: 'f5deb3', |
white: 'ffffff', |
whitesmoke: 'f5f5f5', |
yellow: 'ffff00', |
yellowgreen: '9acd32' |
}; |
for (var key in simple_colors) { |
if (color_string == key) { |
color_string = simple_colors[key]; |
} |
} |
// emd of simple type-in colors |
|
// array of color definition objects |
var color_defs = [ |
{ |
re: /^rgb\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})\)$/, |
example: ['rgb(123, 234, 45)', 'rgb(255,234,245)'], |
process: function (bits){ |
return [ |
parseInt(bits[1]), |
parseInt(bits[2]), |
parseInt(bits[3]) |
]; |
} |
}, |
{ |
re: /^(\w{2})(\w{2})(\w{2})$/, |
example: ['#00ff00', '336699'], |
process: function (bits){ |
return [ |
parseInt(bits[1], 16), |
parseInt(bits[2], 16), |
parseInt(bits[3], 16) |
]; |
} |
}, |
{ |
re: /^(\w{1})(\w{1})(\w{1})$/, |
example: ['#fb0', 'f0f'], |
process: function (bits){ |
return [ |
parseInt(bits[1] + bits[1], 16), |
parseInt(bits[2] + bits[2], 16), |
parseInt(bits[3] + bits[3], 16) |
]; |
} |
} |
]; |
|
// search through the definitions to find a match |
for (var i = 0; i < color_defs.length; i++) { |
var re = color_defs[i].re; |
var processor = color_defs[i].process; |
var bits = re.exec(color_string); |
if (bits) { |
var channels = processor(bits); |
this.r = channels[0]; |
this.g = channels[1]; |
this.b = channels[2]; |
this.ok = true; |
} |
|
} |
|
// validate/cleanup values |
this.r = (this.r < 0 || isNaN(this.r)) ? 0 : ((this.r > 255) ? 255 : this.r); |
this.g = (this.g < 0 || isNaN(this.g)) ? 0 : ((this.g > 255) ? 255 : this.g); |
this.b = (this.b < 0 || isNaN(this.b)) ? 0 : ((this.b > 255) ? 255 : this.b); |
|
// some getters |
this.toRGB = function () { |
return 'rgb(' + this.r + ', ' + this.g + ', ' + this.b + ')'; |
} |
this.toHex = function () { |
var r = this.r.toString(16); |
var g = this.g.toString(16); |
var b = this.b.toString(16); |
if (r.length == 1) r = '0' + r; |
if (g.length == 1) g = '0' + g; |
if (b.length == 1) b = '0' + b; |
return '#' + r + g + b; |
} |
|
// help |
this.getHelpXML = function () { |
|
var examples = new Array(); |
// add regexps |
for (var i = 0; i < color_defs.length; i++) { |
var example = color_defs[i].example; |
for (var j = 0; j < example.length; j++) { |
examples[examples.length] = example[j]; |
} |
} |
// add type-in colors |
for (var sc in simple_colors) { |
examples[examples.length] = sc; |
} |
|
var xml = document.createElement('ul'); |
xml.setAttribute('id', 'rgbcolor-examples'); |
for (var i = 0; i < examples.length; i++) { |
try { |
var list_item = document.createElement('li'); |
var list_color = new RGBColor(examples[i]); |
var example_div = document.createElement('div'); |
example_div.style.cssText = |
'margin: 3px; ' |
+ 'border: 1px solid black; ' |
+ 'background:' + list_color.toHex() + '; ' |
+ 'color:' + list_color.toHex() |
; |
example_div.appendChild(document.createTextNode('test')); |
var list_item_value = document.createTextNode( |
' ' + examples[i] + ' -> ' + list_color.toRGB() + ' -> ' + list_color.toHex() |
); |
list_item.appendChild(example_div); |
list_item.appendChild(list_item_value); |
xml.appendChild(list_item); |
|
} catch(e){} |
} |
return xml; |
|
} |
|
} |
if (typeof define === "function" && define.amd) { |
define(function () { |
return RGBColor; |
}); |
} else if (typeof module !== "undefined" && module.exports) { |
module.exports = RGBColor; |
} else { |
global.RGBColor = RGBColor; |
} |
return RGBColor; |
})(typeof self !== "undefined" && self || typeof window !== "undefined" && window || this); |
|
},{}],9:[function(require,module,exports){ |
/* |
The MIT License (MIT) |
|
Copyright (c) 2015-2016 yWorks GmbH |
|
Permission is hereby granted, free of charge, to any person obtaining a copy |
of this software and associated documentation files (the "Software"), to deal |
in the Software without restriction, including without limitation the rights |
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
copies of the Software, and to permit persons to whom the Software is |
furnished to do so, subject to the following conditions: |
|
The above copyright notice and this permission notice shall be included in all |
copies or substantial portions of the Software. |
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
SOFTWARE. |
*/ |
|
/** |
* Renders an svg element to a jsPDF document. |
* For accurate results a DOM document is required (mainly used for text size measurement and image format conversion) |
* @param element {HTMLElement} The svg element, which will be cloned, so the original stays unchanged. |
* @param pdf {jsPDF} The jsPDF object. |
* @param options {object} An object that may contain render options. Currently supported are: |
* scale: The global factor by which everything is scaled. |
* xOffset, yOffset: Offsets that are added to every coordinate AFTER scaling (They are not |
* influenced by the scale attribute). |
*/ |
(function (global) { |
var RGBColor; |
var SvgPath; |
|
var _pdf; // jsPDF pdf-document |
|
var cToQ = 2 / 3; // ratio to convert quadratic bezier curves to cubic ones |
|
var iriReference = /url\(#([^)]+)\)/; |
|
|
// pathSegList is marked deprecated in chrome, so parse the d attribute manually if necessary |
var getPathSegList = function (node) { |
var d = node.getAttribute("d"); |
|
// Replace arcs before path segment list is handled |
if (SvgPath) { |
d = SvgPath(d).unshort().unarc().abs().toString(); |
node.setAttribute('d', d); |
} |
|
var pathSegList = node.pathSegList; |
|
if (pathSegList) { |
return pathSegList; |
} |
|
pathSegList = []; |
|
var regex = /([a-df-zA-DF-Z])([^a-df-zA-DF-Z]*)/g, |
match; |
while (match = regex.exec(d)) { |
var coords = parseFloats(match[2]); |
|
var type = match[1]; |
var length = "zZ".indexOf(type) >= 0 ? 0 : |
"hHvV".indexOf(type) >= 0 ? 1 : |
"mMlLtT".indexOf(type) >= 0 ? 2 : |
"sSqQ".indexOf(type) >= 0 ? 4 : |
"aA".indexOf(type) >= 0 ? 7 : |
"cC".indexOf(type) >= 0 ? 6 : -1; |
|
var i = 0; |
do { |
var pathSeg = {pathSegTypeAsLetter: type}; |
switch (type) { |
case "h": |
case "H": |
pathSeg.x = coords[i]; |
break; |
|
case "v": |
case "V": |
pathSeg.y = coords[i]; |
break; |
|
case "c": |
case "C": |
pathSeg.x1 = coords[i + length - 6]; |
pathSeg.y1 = coords[i + length - 5]; |
case "s": |
case "S": |
pathSeg.x2 = coords[i + length - 4]; |
pathSeg.y2 = coords[i + length - 3]; |
case "t": |
case "T": |
case "l": |
case "L": |
case "m": |
case "M": |
pathSeg.x = coords[i + length - 2]; |
pathSeg.y = coords[i + length - 1]; |
break; |
|
case "q": |
case "Q": |
pathSeg.x1 = coords[i]; |
pathSeg.y1 = coords[i + 1]; |
pathSeg.x = coords[i + 2]; |
pathSeg.y = coords[i + 3]; |
break; |
case "a": |
case "A": |
throw new Error("Cannot convert Arcs without SvgPath package"); |
} |
|
pathSegList.push(pathSeg); |
i += length; |
} while(i < coords.length); |
} |
|
pathSegList.getItem = function (i) { |
return this[i] |
}; |
pathSegList.numberOfItems = pathSegList.length; |
|
return pathSegList; |
}; |
|
// returns an attribute of a node, either from the node directly or from css |
var getAttribute = function (node, propertyNode, propertyCss) { |
propertyCss = propertyCss || propertyNode; |
return node.getAttribute(propertyNode) || node.style[propertyCss]; |
}; |
|
var nodeIs = function (node, tagsString) { |
return tagsString.split(",").indexOf(node.tagName.toLowerCase()) >= 0; |
}; |
|
var forEachChild = function (node, fn) { |
// copy list of children, as the original might be modified |
var children = []; |
for (var i = 0; i < node.childNodes.length; i++) { |
var childNode = node.childNodes[i]; |
if (childNode.nodeName.charAt(0) !== "#") |
children.push(childNode); |
} |
for (i = 0; i < children.length; i++) { |
fn(i, children[i]); |
} |
}; |
|
var getAngle = function (from, to) { |
return Math.atan2(to[1] - from[1], to[0] - from[0]); |
}; |
|
// mirrors p1 at p2 |
var mirrorPoint = function (p1, p2) { |
var dx = p2[0] - p1[0]; |
var dy = p2[1] - p1[1]; |
|
return [p1[0] + 2 * dx, p1[1] + 2 * dy]; |
}; |
|
// transforms a cubic bezier control point to a quadratic one: returns from + (2/3) * (to - from) |
var toCubic = function (from, to) { |
return [cToQ * (to[0] - from[0]) + from[0], cToQ * (to[1] - from[1]) + from[1]]; |
}; |
|
// extracts a control point from a previous path segment (for t,T,s,S segments) |
var getControlPointFromPrevious = function (i, from, list, prevX, prevY) { |
var prev = list.getItem(i - 1); |
var p2; |
if (i > 0 && (prev.pathSegTypeAsLetter === "C" || prev.pathSegTypeAsLetter === "S")) { |
p2 = mirrorPoint([prev.x2, prev.y2], from); |
} else if (i > 0 && (prev.pathSegTypeAsLetter === "c" || prev.pathSegTypeAsLetter === "s")) { |
p2 = mirrorPoint([prev.x2 + prevX, prev.y2 + prevY], from); |
} else { |
p2 = [from[0], from[1]]; |
} |
return p2; |
}; |
|
// an id prefix to handle duplicate ids |
var SvgPrefix = function (prefix) { |
this.prefix = prefix; |
this.id = 0; |
this.nextChild = function () { |
return new SvgPrefix("_" + this.id++ + "_" + this.get()); |
}; |
this.get = function () { |
return this.prefix; |
} |
}; |
|
// returns the node for the specified id or incrementally removes prefixes to search "higher" levels |
var getFromDefs = function (id, defs) { |
var regExp = /_\d+_/; |
while (!defs[id] && regExp.exec(id)) { |
id = id.replace(regExp, ""); |
} |
return defs[id]; |
}; |
|
// replace any newline characters by space and trim |
var removeNewlinesAndTrim = function (str) { |
return str.replace(/[\n\s\r]+/, " ").trim(); |
}; |
|
// clones the defs object (or basically any object) |
var cloneDefs = function (defs) { |
var clone = {}; |
for (var key in defs) { |
if (defs.hasOwnProperty(key)) { |
clone[key] = defs[key]; |
} |
} |
return clone; |
}; |
|
// computes the transform directly applied at the node (such as viewbox scaling and the "transform" atrribute) |
// x,y,cx,cy,r,... are omitted |
var computeNodeTransform = function (node) { |
var height, width, viewBoxHeight, viewBoxWidth, bounds, viewBox, y, x; |
var nodeTransform = _pdf.unitMatrix; |
if (nodeIs(node, "svg,g")) { |
x = parseFloat(node.getAttribute("x")) || 0; |
y = parseFloat(node.getAttribute("y")) || 0; |
|
// jquery doesn't like camelCase notation... |
viewBox = node.getAttribute("viewBox"); |
if (viewBox) { |
bounds = parseFloats(viewBox); |
viewBoxWidth = bounds[2] - bounds[0]; |
viewBoxHeight = bounds[3] - bounds[1]; |
width = parseFloat(node.getAttribute("width")) || viewBoxWidth; |
height = parseFloat(node.getAttribute("height")) || viewBoxHeight; |
nodeTransform = new _pdf.Matrix(width / viewBoxWidth, 0, 0, height / viewBoxHeight, x - bounds[0], y - bounds[1]); |
} else { |
nodeTransform = new _pdf.Matrix(1, 0, 0, 1, x, y); |
} |
} else if (nodeIs(node, "marker")) { |
x = -parseFloat(node.getAttribute("refX")) || 0; |
y = -parseFloat(node.getAttribute("refY")) || 0; |
|
viewBox = node.getAttribute("viewBox"); |
if (viewBox) { |
bounds = parseFloats(viewBox); |
viewBoxWidth = bounds[2] - bounds[0]; |
viewBoxHeight = bounds[3] - bounds[1]; |
width = parseFloat(node.getAttribute("markerWidth")) || viewBoxWidth; |
height = parseFloat(node.getAttribute("markerHeight")) || viewBoxHeight; |
|
var s = new _pdf.Matrix(width / viewBoxWidth, 0, 0, height / viewBoxHeight, 0, 0); |
var t = new _pdf.Matrix(1, 0, 0, 1, x, y); |
nodeTransform = _pdf.matrixMult(t, s); |
} else { |
nodeTransform = new _pdf.Matrix(1, 0, 0, 1, x, y); |
} |
} |
|
var transformString = node.getAttribute("transform"); |
if (!transformString) |
return nodeTransform; |
else |
return _pdf.matrixMult(nodeTransform, parseTransform(transformString)); |
}; |
|
// parses the "points" string used by polygons and returns an array of points |
var parsePointsString = function (string) { |
var floats = parseFloats(string); |
var result = []; |
for (var i = 0; i < floats.length - 1; i += 2) { |
var x = floats[i]; |
var y = floats[i + 1]; |
result.push([x, y]); |
} |
return result; |
}; |
|
// parses the "transform" string |
var parseTransform = function (transformString) { |
if (!transformString) |
return _pdf.unitMatrix; |
|
var mRegex = /^\s*matrix\(([^\)]+)\)\s*/, |
tRegex = /^\s*translate\(([^\)]+)\)\s*/, |
rRegex = /^\s*rotate\(([^\)]+)\)\s*/, |
sRegex = /^\s*scale\(([^\)]+)\)\s*/, |
sXRegex = /^\s*skewX\(([^\)]+)\)\s*/, |
sYRegex = /^\s*skewY\(([^\)]+)\)\s*/; |
|
var resultMatrix = _pdf.unitMatrix, m; |
|
while (transformString.length > 0) { |
var match = mRegex.exec(transformString); |
if (match) { |
m = parseFloats(match[1]); |
resultMatrix = _pdf.matrixMult(new _pdf.Matrix(m[0], m[1], m[2], m[3], m[4], m[5]), resultMatrix); |
transformString = transformString.substr(match[0].length); |
} |
match = rRegex.exec(transformString); |
if (match) { |
m = parseFloats(match[1]); |
var a = Math.PI * m[0] / 180; |
resultMatrix = _pdf.matrixMult(new _pdf.Matrix(Math.cos(a), Math.sin(a), -Math.sin(a), Math.cos(a), 0, 0), resultMatrix); |
if (m[1] && m[2]) { |
var t1 = new _pdf.Matrix(1, 0, 0, 1, m[1], m[2]); |
var t2 = new _pdf.Matrix(1, 0, 0, 1, -m[1], -m[2]); |
resultMatrix = _pdf.matrixMult(t2, _pdf.matrixMult(resultMatrix, t1)); |
} |
transformString = transformString.substr(match[0].length); |
} |
match = tRegex.exec(transformString); |
if (match) { |
m = parseFloats(match[1]); |
resultMatrix = _pdf.matrixMult(new _pdf.Matrix(1, 0, 0, 1, m[0], m[1] || 0), resultMatrix); |
transformString = transformString.substr(match[0].length); |
} |
match = sRegex.exec(transformString); |
if (match) { |
m = parseFloats(match[1]); |
if (!m[1]) |
m[1] = m[0]; |
resultMatrix = _pdf.matrixMult(new _pdf.Matrix(m[0], 0, 0, m[1], 0, 0), resultMatrix); |
transformString = transformString.substr(match[0].length); |
} |
match = sXRegex.exec(transformString); |
if (match) { |
m = parseFloat(match[1]); |
resultMatrix = _pdf.matrixMult(new _pdf.Matrix(1, 0, Math.tan(m), 1, 0, 0), resultMatrix); |
transformString = transformString.substr(match[0].length); |
} |
match = sYRegex.exec(transformString); |
if (match) { |
m = parseFloat(match[1]); |
resultMatrix = _pdf.matrixMult(new _pdf.Matrix(1, Math.tan(m), 0, 1, 0, 0), resultMatrix); |
transformString = transformString.substr(match[0].length); |
} |
} |
return resultMatrix; |
}; |
|
// parses a comma, sign and/or whitespace separated string of floats and returns the single floats in an array |
var parseFloats = function (str) { |
var floats = [], match, |
regex = /[+-]?(?:(?:\d+\.?\d*)|(?:\d*\.?\d+))(?:[eE][+-]?\d+)?/g; |
while(match = regex.exec(str)) { |
floats.push(parseFloat(match[0])); |
} |
return floats; |
}; |
|
// extends RGBColor by rgba colors as RGBColor is not capable of it |
var parseColor = function (colorString) { |
var match = /\s*rgba\(((?:[^,\)]*,){3}[^,\)]*)\)\s*/.exec(colorString); |
if (match) { |
var floats = parseFloats(match[1]); |
var color = new RGBColor("rgb(" + floats.slice(0,3).join(",") + ")"); |
color.a = floats[3]; |
return color; |
} else { |
return new RGBColor(colorString); |
} |
}; |
|
// multiplies a vector with a matrix: vec' = vec * matrix |
var multVecMatrix = function (vec, matrix) { |
var x = vec[0]; |
var y = vec[1]; |
return [ |
matrix.a * x + matrix.c * y + matrix.e, |
matrix.b * x + matrix.d * y + matrix.f |
]; |
}; |
|
// returns the untransformed bounding box [x, y, width, height] of an svg element (quite expensive for path and polygon objects, as |
// the whole points/d-string has to be processed) |
var getUntransformedBBox = function (node) { |
var i, minX, minY, maxX, maxY, viewBox, vb, boundingBox; |
var pf = parseFloat; |
|
if (nodeIs(node, "polygon")) { |
var points = parsePointsString(node.getAttribute("points")); |
minX = Number.POSITIVE_INFINITY; |
minY = Number.POSITIVE_INFINITY; |
maxX = Number.NEGATIVE_INFINITY; |
maxY = Number.NEGATIVE_INFINITY; |
for (i = 0; i < points.length; i++) { |
var point = points[i]; |
minX = Math.min(minX, point[0]); |
maxX = Math.max(maxX, point[0]); |
minY = Math.min(minY, point[1]); |
maxY = Math.max(maxY, point[1]); |
} |
boundingBox = [ |
minX, |
minY, |
maxX - minX, |
maxY - minY |
]; |
} else if (nodeIs(node, "path")) { |
var list = getPathSegList(node); |
minX = Number.POSITIVE_INFINITY; |
minY = Number.POSITIVE_INFINITY; |
maxX = Number.NEGATIVE_INFINITY; |
maxY = Number.NEGATIVE_INFINITY; |
var x = 0, y = 0; |
var prevX, prevY, newX, newY; |
var p2, p3, to; |
for (i = 0; i < list.numberOfItems; i++) { |
var seg = list.getItem(i); |
var cmd = seg.pathSegTypeAsLetter; |
switch (cmd) { |
case "H": |
newX = seg.x; |
newY = y; |
break; |
case "h": |
newX = seg.x + x; |
newY = y; |
break; |
case "V": |
newX = x; |
newY = seg.y; |
break; |
case "v": |
newX = x; |
newY = seg.y + y; |
break; |
case "C": |
p2 = [seg.x1, seg.y1]; |
p3 = [seg.x2, seg.y2]; |
to = [seg.x, seg.y]; |
break; |
case "c": |
p2 = [seg.x1 + x, seg.y1 + y]; |
p3 = [seg.x2 + x, seg.y2 + y]; |
to = [seg.x + x, seg.y + y]; |
break; |
case "S": |
p2 = getControlPointFromPrevious(i, [x, y], list, prevX, prevY); |
p3 = [seg.x2, seg.y2]; |
to = [seg.x, seg.y]; |
break; |
case "s": |
p2 = getControlPointFromPrevious(i, [x, y], list, prevX, prevY); |
p3 = [seg.x2 + x, seg.y2 + y]; |
to = [seg.x + x, seg.y + y]; |
break; |
case "Q": |
pf = [seg.x1, seg.y1]; |
p2 = toCubic([x, y], pf); |
p3 = toCubic([seg.x, seg.y], pf); |
to = [seg.x, seg.y]; |
break; |
case "q": |
pf = [seg.x1 + x, seg.y1 + y]; |
p2 = toCubic([x, y], pf); |
p3 = toCubic([x + seg.x, y + seg.y], pf); |
to = [seg.x + x, seg.y + y]; |
break; |
case "T": |
p2 = getControlPointFromPrevious(i, [x, y], list, prevX, prevY); |
p2 = toCubic([x, y], pf); |
p3 = toCubic([seg.x, seg.y], pf); |
to = [seg.x, seg.y]; |
break; |
case "t": |
pf = getControlPointFromPrevious(i, [x, y], list, prevX, prevY); |
p2 = toCubic([x, y], pf); |
p3 = toCubic([x + seg.x, y + seg.y], pf); |
to = [seg.x + x, seg.y + y]; |
break; |
// TODO: A,a |
} |
if ("sScCqQtT".indexOf(cmd) >= 0) { |
prevX = x; |
prevY = y; |
} |
if ("MLCSQT".indexOf(cmd) >= 0) { |
x = seg.x; |
y = seg.y; |
} else if ("mlcsqt".indexOf(cmd) >= 0) { |
x = seg.x + x; |
y = seg.y + y; |
} else if ("zZ".indexOf(cmd) < 0) { |
x = newX; |
y = newY; |
} |
if ("CSQTcsqt".indexOf(cmd) >= 0) { |
minX = Math.min(minX, x, p2[0], p3[0], to[0]); |
maxX = Math.max(maxX, x, p2[0], p3[0], to[0]); |
minY = Math.min(minY, y, p2[1], p3[1], to[1]); |
maxY = Math.max(maxY, y, p2[1], p3[1], to[1]); |
} else { |
minX = Math.min(minX, x); |
maxX = Math.max(maxX, x); |
minY = Math.min(minY, y); |
maxY = Math.max(maxY, y); |
} |
} |
boundingBox = [ |
minX, |
minY, |
maxX - minX, |
maxY - minY |
]; |
} else if (nodeIs(node, "svg")) { |
viewBox = node.getAttribute("viewBox"); |
if (viewBox) { |
vb = parseFloats(viewBox); |
} |
return [ |
pf(node.getAttribute("x")) || (vb && vb[0]) || 0, |
pf(node.getAttribute("y")) || (vb && vb[1]) || 0, |
pf(node.getAttribute("width")) || (vb && vb[2]) || 0, |
pf(node.getAttribute("height")) || (vb && vb[3]) || 0 |
]; |
} else if (nodeIs(node, "g")) { |
boundingBox = [0, 0, 0, 0]; |
forEachChild(node, function (i, node) { |
var nodeBox = getUntransformedBBox(node); |
boundingBox = [ |
Math.min(boundingBox[0], nodeBox[0]), |
Math.min(boundingBox[1], nodeBox[1]), |
Math.max(boundingBox[0] + boundingBox[2], nodeBox[0] + nodeBox[2]) - Math.min(boundingBox[0], nodeBox[0]), |
Math.max(boundingBox[1] + boundingBox[3], nodeBox[1] + nodeBox[3]) - Math.min(boundingBox[1], nodeBox[1]) |
]; |
}); |
} else if (nodeIs(node, "marker")) { |
viewBox = node.getAttribute("viewBox"); |
if (viewBox) { |
vb = parseFloats(viewBox); |
} |
return [ |
(vb && vb[0]) || 0, |
(vb && vb[1]) || 0, |
(vb && vb[2]) || pf(node.getAttribute("marker-width")) || 0, |
(vb && vb[3]) || pf(node.getAttribute("marker-height")) || 0 |
]; |
} else if (nodeIs(node, "pattern")) { |
return [ |
pf(node.getAttribute("x")) || 0, |
pf(node.getAttribute("y")) || 0, |
pf(node.getAttribute("width")) || 0, |
pf(node.getAttribute("height")) || 0 |
] |
} else { |
// TODO: check if there are other possible coordinate attributes |
var x1 = pf(node.getAttribute("x1")) || pf(node.getAttribute("x")) || pf((node.getAttribute("cx")) - pf(node.getAttribute("r"))) || 0; |
var x2 = pf(node.getAttribute("x2")) || (x1 + pf(node.getAttribute("width"))) || (pf(node.getAttribute("cx")) + pf(node.getAttribute("r"))) || 0; |
var y1 = pf(node.getAttribute("y1")) || pf(node.getAttribute("y")) || (pf(node.getAttribute("cy")) - pf(node.getAttribute("r"))) || 0; |
var y2 = pf(node.getAttribute("y2")) || (y1 + pf(node.getAttribute("height"))) || (pf(node.getAttribute("cy")) + pf(node.getAttribute("r"))) || 0; |
boundingBox = [ |
Math.min(x1, x2), |
Math.min(y1, y2), |
Math.max(x1, x2) - Math.min(x1, x2), |
Math.max(y1, y2) - Math.min(y1, y2) |
]; |
} |
|
if (!nodeIs(node, "marker,svg,g")) { |
// add line-width |
var lineWidth = getAttribute(node, "stroke-width") || 1; |
var miterLimit = getAttribute(node, "stroke-miterlimit"); |
// miterLength / lineWidth = 1 / sin(phi / 2) |
miterLimit && (lineWidth *= 0.5 / (Math.sin(Math.PI / 12))); |
return [ |
boundingBox[0] - lineWidth, |
boundingBox[1] - lineWidth, |
boundingBox[2] + 2 * lineWidth, |
boundingBox[3] + 2 * lineWidth |
]; |
} |
|
return boundingBox; |
}; |
|
// transforms a bounding box and returns a new rect that contains it |
var transformBBox = function (box, matrix) { |
var bl = multVecMatrix([box[0], box[1]], matrix); |
var br = multVecMatrix([box[0] + box[2], box[1]], matrix); |
var tl = multVecMatrix([box[0], box[1] + box[3]], matrix); |
var tr = multVecMatrix([box[0] + box[2], box[1] + box[3]], matrix); |
|
var bottom = Math.min(bl[1], br[1], tl[1], tr[1]); |
var left = Math.min(bl[0], br[0], tl[0], tr[0]); |
var top = Math.max(bl[1], br[1], tl[1], tr[1]); |
var right = Math.max(bl[0], br[0], tl[0], tr[0]); |
|
return [ |
left, |
bottom, |
right - left, |
top - bottom |
] |
}; |
|
// draws a polygon |
var polygon = function (node, tfMatrix, colorMode, gradient, gradientMatrix) { |
var points = parsePointsString(node.getAttribute("points")); |
var lines = [{op: "m", c: multVecMatrix(points[0], tfMatrix)}]; |
for (var i = 1; i < points.length; i++) { |
var p = points[i]; |
var to = multVecMatrix(p, tfMatrix); |
lines.push({op: "l", c: to}); |
} |
lines.push({op: "h"}); |
_pdf.path(lines, colorMode, gradient, gradientMatrix); |
}; |
|
// draws an image (converts it to jpeg first, as jsPDF doesn't support png or other formats) |
var image = function (node) { |
// convert image to jpeg |
var imageUrl = node.getAttribute("xlink:href") || node.getAttribute("href"); |
var image = new Image(); |
image.src = imageUrl; |
|
var canvas = document.createElement("canvas"); |
var width = parseFloat(node.getAttribute("width")), |
height = parseFloat(node.getAttribute("height")), |
x = parseFloat(node.getAttribute("x") || 0), |
y = parseFloat(node.getAttribute("y") || 0); |
canvas.width = width; |
canvas.height = height; |
var context = canvas.getContext("2d"); |
context.fillStyle = "#fff"; |
context.fillRect(0, 0, width, height); |
context.drawImage(image, 0, 0, width, height); |
var jpegUrl = canvas.toDataURL("image/jpeg"); |
|
_pdf.addImage(jpegUrl, |
"jpeg", |
x, |
y, |
width, |
height |
); |
}; |
|
// draws a path |
var path = function (node, tfMatrix, svgIdPrefix, colorMode, gradient, gradientMatrix) { |
var list = getPathSegList(node); |
var markerEnd = node.getAttribute("marker-end"), |
markerStart = node.getAttribute("marker-start"), |
markerMid = node.getAttribute("marker-mid"); |
|
var getLinesFromPath = function (pathSegList, tfMatrix) { |
var x = 0, y = 0; |
var x0 = x, y0 = y; |
var prevX, prevY, newX, newY; |
var to, p, p2, p3; |
var lines = []; |
var markers = []; |
var op; |
var prevAngle = 0, curAngle; |
|
var addMarker = function (angle, anchor, type) { |
var cos = Math.cos(angle); |
var sin = Math.sin(angle); |
var tf; |
tf = new _pdf.Matrix(cos, sin, -sin, cos, anchor[0], anchor[1]); |
markers.push({type: type, tf: _pdf.matrixMult(tf, tfMatrix)}); |
}; |
|
for (var i = 0; i < list.numberOfItems; i++) { |
var seg = list.getItem(i); |
var cmd = seg.pathSegTypeAsLetter; |
switch (cmd) { |
case "M": |
x0 = x; |
y0 = y; |
to = [seg.x, seg.y]; |
op = "m"; |
break; |
case "m": |
x0 = x; |
y0 = y; |
to = [seg.x + x, seg.y + y]; |
op = "m"; |
break; |
case "L": |
to = [seg.x, seg.y]; |
op = "l"; |
break; |
case "l": |
to = [seg.x + x, seg.y + y]; |
op = "l"; |
break; |
case "H": |
to = [seg.x, y]; |
op = "l"; |
newX = seg.x; |
newY = y; |
break; |
case "h": |
to = [seg.x + x, y]; |
op = "l"; |
newX = seg.x + x; |
newY = y; |
break; |
case "V": |
to = [x, seg.y]; |
op = "l"; |
newX = x; |
newY = seg.y; |
break; |
case "v": |
to = [x, seg.y + y]; |
op = "l"; |
newX = x; |
newY = seg.y + y; |
break; |
case "C": |
p2 = [seg.x1, seg.y1]; |
p3 = [seg.x2, seg.y2]; |
to = [seg.x, seg.y]; |
break; |
case "c": |
p2 = [seg.x1 + x, seg.y1 + y]; |
p3 = [seg.x2 + x, seg.y2 + y]; |
to = [seg.x + x, seg.y + y]; |
break; |
case "S": |
p2 = getControlPointFromPrevious(i, [x, y], list, prevX, prevY); |
p3 = [seg.x2, seg.y2]; |
to = [seg.x, seg.y]; |
break; |
case "s": |
p2 = getControlPointFromPrevious(i, [x, y], list, prevX, prevY); |
p3 = [seg.x2 + x, seg.y2 + y]; |
to = [seg.x + x, seg.y + y]; |
break; |
case "Q": |
p = [seg.x1, seg.y1]; |
p2 = toCubic([x, y], p); |
p3 = toCubic([seg.x, seg.y], p); |
to = [seg.x, seg.y]; |
break; |
case "q": |
p = [seg.x1 + x, seg.y1 + y]; |
p2 = toCubic([x, y], p); |
p3 = toCubic([x + seg.x, y + seg.y], p); |
to = [seg.x + x, seg.y + y]; |
break; |
case "T": |
p2 = getControlPointFromPrevious(i, [x, y], list, prevX, prevY); |
p2 = toCubic([x, y], p); |
p3 = toCubic([seg.x, seg.y], p); |
to = [seg.x, seg.y]; |
break; |
case "t": |
p = getControlPointFromPrevious(i, [x, y], list, prevX, prevY); |
p2 = toCubic([x, y], p); |
p3 = toCubic([x + seg.x, y + seg.y], p); |
to = [seg.x + x, seg.y + y]; |
break; |
// TODO: A,a |
case "Z": |
case "z": |
x = x0; |
y = y0; |
lines.push({op: "h"}); |
break; |
} |
|
var hasStartMarker = markerStart |
&& (i === 1 |
|| ("mM".indexOf(cmd) < 0 && "mM".indexOf(list.getItem(i - 1).pathSegTypeAsLetter) >= 0)); |
var hasEndMarker = markerEnd |
&& (i === list.numberOfItems - 1 |
|| ("mM".indexOf(cmd) < 0 && "mM".indexOf(list.getItem(i + 1).pathSegTypeAsLetter) >= 0)); |
var hasMidMarker = markerMid |
&& i > 0 |
&& !(i === 1 && "mM".indexOf(list.getItem(i - 1).pathSegTypeAsLetter) >= 0); |
|
if ("sScCqQtT".indexOf(cmd) >= 0) { |
hasStartMarker && addMarker(getAngle([x, y], p2), [x, y], "start"); |
hasEndMarker && addMarker(getAngle(p3, to), to, "end"); |
if (hasMidMarker) { |
curAngle = getAngle([x, y], p2); |
curAngle = "mM".indexOf(list.getItem(i - 1).pathSegTypeAsLetter) >= 0 ? |
curAngle : .5 * (prevAngle + curAngle); |
addMarker(curAngle, [x, y], "mid"); |
} |
|
prevAngle = getAngle(p3, to); |
|
prevX = x; |
prevY = y; |
p2 = multVecMatrix(p2, tfMatrix); |
p3 = multVecMatrix(p3, tfMatrix); |
p = multVecMatrix(to, tfMatrix); |
lines.push({ |
op: "c", c: [ |
p2[0], p2[1], |
p3[0], p3[1], |
p[0], p[1] |
] |
}); |
} else if ("lLhHvVmM".indexOf(cmd) >= 0) { |
curAngle = getAngle([x, y], to); |
hasStartMarker && addMarker(curAngle, [x, y], "start"); |
hasEndMarker && addMarker(curAngle, to, "end"); |
if (hasMidMarker) { |
var angle = "mM".indexOf(cmd) >= 0 ? |
prevAngle : "mM".indexOf(list.getItem(i - 1).pathSegTypeAsLetter) >= 0 ? |
curAngle : .5 * (prevAngle + curAngle); |
addMarker(angle, [x, y], "mid"); |
} |
prevAngle = curAngle; |
|
p = multVecMatrix(to, tfMatrix); |
lines.push({op: op, c: p}); |
} |
|
if ("MLCSQT".indexOf(cmd) >= 0) { |
x = seg.x; |
y = seg.y; |
} else if ("mlcsqt".indexOf(cmd) >= 0) { |
x = seg.x + x; |
y = seg.y + y; |
} else if ("zZ".indexOf(cmd) < 0) { |
x = newX; |
y = newY; |
} |
} |
|
return {lines: lines, markers: markers}; |
}; |
var lines = getLinesFromPath(list, tfMatrix); |
|
if (markerEnd || markerStart || markerMid) { |
for (var i = 0; i < lines.markers.length; i++) { |
var marker = lines.markers[i]; |
var markerElement; |
switch (marker.type) { |
case "start": |
markerElement = svgIdPrefix.get() + iriReference.exec(markerStart)[1]; |
break; |
case "end": |
markerElement = svgIdPrefix.get() + iriReference.exec(markerEnd)[1]; |
break; |
case "mid": |
markerElement = svgIdPrefix.get() + iriReference.exec(markerMid)[1]; |
break; |
} |
_pdf.doFormObject(markerElement, marker.tf); |
} |
} |
|
if (lines.lines.length > 0) { |
_pdf.path(lines.lines, colorMode, gradient, gradientMatrix); |
} |
}; |
|
// draws the element referenced by a use node, makes use of pdf's XObjects/FormObjects so nodes are only written once |
// to the pdf document. This highly reduces the file size and computation time. |
var use = function (node, tfMatrix, svgIdPrefix) { |
var url = (node.getAttribute("href") || node.getAttribute("xlink:href")); |
// just in case someone has the idea to use empty use-tags, wtf??? |
if (!url) |
return; |
|
// get the size of the referenced form object (to apply the correct scaling) |
var formObject = _pdf.getFormObject(svgIdPrefix.get() + url.substring(1)); |
|
// scale and position it right |
var x = node.getAttribute("x") || 0; |
var y = node.getAttribute("y") || 0; |
var width = node.getAttribute("width") || formObject.width; |
var height = node.getAttribute("height") || formObject.height; |
var t = new _pdf.Matrix(width / formObject.width || 0, 0, 0, height / formObject.height || 0, x, y); |
t = _pdf.matrixMult(t, tfMatrix); |
_pdf.doFormObject(svgIdPrefix.get() + url.substring(1), t); |
}; |
|
// draws a line |
var line = function (node, tfMatrix) { |
var p1 = multVecMatrix([parseFloat(node.getAttribute('x1')), parseFloat(node.getAttribute('y1'))], tfMatrix); |
var p2 = multVecMatrix([parseFloat(node.getAttribute('x2')), parseFloat(node.getAttribute('y2'))], tfMatrix); |
_pdf.line(p1[0], p1[1], p2[0], p2[1]); |
}; |
|
// draws a rect |
var rect = function (node, colorMode, gradient, gradientMatrix) { |
_pdf.roundedRect( |
parseFloat(node.getAttribute('x')) || 0, |
parseFloat(node.getAttribute('y')) || 0, |
parseFloat(node.getAttribute('width')), |
parseFloat(node.getAttribute('height')), |
parseFloat(node.getAttribute('rx')) || 0, |
parseFloat(node.getAttribute('ry')) || 0, |
colorMode, |
gradient, |
gradientMatrix |
); |
}; |
|
// draws an ellipse |
var ellipse = function (node, colorMode, gradient, gradientMatrix) { |
_pdf.ellipse( |
parseFloat(node.getAttribute('cx')) || 0, |
parseFloat(node.getAttribute('cy')) || 0, |
parseFloat(node.getAttribute('rx')), |
parseFloat(node.getAttribute('ry')), |
colorMode, |
gradient, |
gradientMatrix |
); |
}; |
|
// draws a circle |
var circle = function (node, colorMode, gradient, gradientMatrix) { |
var radius = parseFloat(node.getAttribute('r')) || 0; |
_pdf.ellipse( |
parseFloat(node.getAttribute('cx')) || 0, |
parseFloat(node.getAttribute('cy')) || 0, |
radius, |
radius, |
colorMode, |
gradient, |
gradientMatrix |
); |
}; |
|
// applies text transformations to a text node |
var transformText = function (node, text) { |
var textTransform = getAttribute(node, "text-transform"); |
switch (textTransform) { |
case "uppercase": return text.toUpperCase(); |
case "lowercase": return text.toLowerCase(); |
default: return text; |
// TODO: capitalize, full-width |
} |
}; |
|
// draws a text element and its tspan children |
var text = function (node, tfMatrix, hasFillColor, fillRGB) { |
_pdf.saveGraphicsState(); |
setTextProperties(node, fillRGB); |
|
var getTextOffset = function (textAnchor, width) { |
var xOffset = 0; |
switch (textAnchor) { |
case 'end': |
xOffset = width; |
break; |
case 'middle': |
xOffset = width / 2; |
break; |
case 'start': |
break; |
} |
return xOffset; |
}; |
|
/** |
* Convert em, px and bare number attributes to pixel values |
*/ |
var toPixels = function (value, pdfFontSize) { |
var match; |
|
// em |
match = value && value.toString().match(/^([\-0-9.]+)em$/); |
if (match) { |
return parseFloat(match[1]) * pdfFontSize; |
} |
|
// pixels |
match = value && value.toString().match(/^([\-0-9.]+)(px|)$/); |
if (match) { |
return parseFloat(match[1]); |
} |
return 0; |
}; |
|
// creates an svg element and append the text node to properly measure the text size |
var svg = document.createElementNS("http://www.w3.org/2000/svg", "svg"); |
svg.appendChild(node); |
svg.setAttribute("visibility", "hidden"); |
document.body.appendChild(svg); |
|
var box = node.getBBox(); |
var x, y, xOffset = 0; |
var textAnchor = getAttribute(node, "text-anchor"); |
if (textAnchor) { |
xOffset = getTextOffset(textAnchor, box.width); |
} |
|
var pdfFontSize = _pdf.getFontSize(); |
var textX = toPixels(node.getAttribute('x'), pdfFontSize); |
var textY = toPixels(node.getAttribute('y'), pdfFontSize); |
var m = _pdf.matrixMult(new _pdf.Matrix(1, 0, 0, 1, textX, textY), tfMatrix); |
|
x = toPixels(node.getAttribute("dx"), pdfFontSize); |
y = toPixels(node.getAttribute("dy"), pdfFontSize); |
|
// when there are no tspans draw the text directly |
if (node.childElementCount === 0) { |
_pdf.text( |
(x - xOffset), |
y, |
transformText(node, removeNewlinesAndTrim(node.textContent)), |
void 0, |
m |
); |
} else { |
// otherwise loop over tspans and position each relative to the previous one |
forEachChild(node, function (i, tSpan) { |
if (!tSpan.textContent || nodeIs(tSpan, 'title,desc,metadata')) { |
return; |
} |
_pdf.saveGraphicsState(); |
var tSpanColor = getAttribute(tSpan, "fill"); |
setTextProperties(tSpan, tSpanColor && new RGBColor(tSpanColor)); |
var extent = tSpan.getExtentOfChar(0); |
_pdf.text( |
extent.x - textX,//x - xOffset, |
extent.y + extent.height * 0.7 - textY, // 0.7 roughly mimicks the text baseline |
transformText(node, removeNewlinesAndTrim(tSpan.textContent)), |
void 0, |
m |
); |
|
_pdf.restoreGraphicsState(); |
}); |
|
} |
|
document.body.removeChild(svg); |
_pdf.restoreGraphicsState(); |
}; |
|
// As defs elements are allowed to appear after they are referenced, we search for them first |
var findAndRenderDefs = function (node, tfMatrix, defs, svgIdPrefix, withinDefs) { |
forEachChild(node, function (i, child) { |
if (child.tagName.toLowerCase() === "defs") { |
renderNode(child, tfMatrix, defs, svgIdPrefix, withinDefs); |
// prevent defs from being evaluated twice // TODO: make this better |
child.parentNode.removeChild(child); |
} |
}); |
}; |
|
// processes a svg node |
var svg = function (node, tfMatrix, defs, svgIdPrefix, withinDefs) { |
// create a new prefix and clone the defs, as defs within the svg should not be visible outside |
var newSvgIdPrefix = svgIdPrefix.nextChild(); |
var newDefs = cloneDefs(defs); |
findAndRenderDefs(node, tfMatrix, newDefs, newSvgIdPrefix, withinDefs); |
renderChildren(node, tfMatrix, newDefs, newSvgIdPrefix, withinDefs); |
}; |
|
// renders all children of a node |
var renderChildren = function (node, tfMatrix, defs, svgIdPrefix, withinDefs) { |
forEachChild(node, function (i, node) { |
renderNode(node, tfMatrix, defs, svgIdPrefix, withinDefs); |
}); |
}; |
|
// adds a gradient to defs and the pdf document for later use, type is either "axial" or "radial" |
// opacity is only supported rudimentary by averaging over all stops |
// transforms are applied on use |
var putGradient = function (node, type, coords, defs, svgIdPrefix) { |
var colors = []; |
var opacitySum = 0; |
var hasOpacity = false; |
var gState; |
forEachChild(node, function (i, element) { |
// since opacity gradients are hard to realize, average the opacity over the control points |
if (element.tagName.toLowerCase() === "stop") { |
var color = new RGBColor(getAttribute(element, "stop-color")); |
colors.push({ |
offset: parseFloat(element.getAttribute("offset")), |
color: [color.r, color.g, color.b] |
}); |
var opacity = getAttribute(element, "stop-opacity"); |
if (opacity && opacity != 1) { |
opacitySum += parseFloat(opacity); |
hasOpacity = true; |
} |
} |
}); |
|
if (hasOpacity) { |
gState = new _pdf.GState({opacity: opacitySum / coords.length}); |
} |
|
var pattern = new _pdf.ShadingPattern(type, coords, colors, gState); |
var id = svgIdPrefix.get() + node.getAttribute("id"); |
_pdf.addShadingPattern(id, pattern); |
defs[id] = node; |
}; |
|
var pattern = function (node, defs, svgIdPrefix) { |
var id = svgIdPrefix.get() + node.getAttribute("id"); |
defs[id] = node; |
|
// the transformations directly at the node are written to the pattern transformation matrix |
var bBox = getUntransformedBBox(node); |
var pattern = new _pdf.TilingPattern([bBox[0], bBox[1], bBox[0] + bBox[2], bBox[1] + bBox[3]], bBox[2], bBox[3], |
null, computeNodeTransform(node)); |
|
_pdf.beginTilingPattern(pattern); |
// continue without transformation |
renderChildren(node, _pdf.unitMatrix, defs, svgIdPrefix, false); |
_pdf.endTilingPattern(id, pattern); |
}; |
|
function setTextProperties(node, fillRGB) { |
var fontFamily = getAttribute(node, "font-family"); |
if (fontFamily) { |
_pdf.setFont(fontFamily); |
} |
|
if (fillRGB && fillRGB.ok) { |
_pdf.setTextColor(fillRGB.r, fillRGB.g, fillRGB.b); |
} |
|
var fontType; |
var fontWeight = getAttribute(node, "font-weight"); |
if (fontWeight) { |
if (fontWeight === "bold") { |
fontType = "bold"; |
} |
} |
|
var fontStyle = getAttribute(node, "font-style"); |
if (fontStyle) { |
if (fontStyle === "italic") { |
fontType += "italic"; |
} |
} |
_pdf.setFontType(fontType); |
|
var pdfFontSize = 16; |
var fontSize = getAttribute(node, "font-size"); |
if (fontSize) { |
pdfFontSize = parseFloat(fontSize); |
_pdf.setFontSize(pdfFontSize); |
} |
} |
|
|
/** |
* Renders a svg node. |
* @param node The svg element |
* @param contextTransform The current transformation matrix |
* @param defs The defs map holding all svg nodes that can be referenced |
* @param svgIdPrefix The current id prefix |
* @param withinDefs True iff we are top-level within a defs node, so the target can be switched to an pdf form object |
*/ |
var renderNode = function (node, contextTransform, defs, svgIdPrefix, withinDefs) { |
var tfMatrix, |
hasFillColor = false, |
fillRGB = null, |
colorMode = null, |
fillUrl = null, |
fillData = null, |
bBox; |
|
// |
// Decide about the render target and set the correct transformation |
// |
|
// if we are within a defs node, start a new pdf form object and draw this node and all children on that instead |
// of the top-level page |
var targetIsFormObject = withinDefs && !nodeIs(node, "lineargradient,radialgradient,pattern"); |
if (targetIsFormObject) { |
|
// the transformations directly at the node are written to the pdf form object transformation matrix |
tfMatrix = computeNodeTransform(node); |
bBox = getUntransformedBBox(node); |
|
_pdf.beginFormObject(bBox[0], bBox[1], bBox[2], bBox[3], tfMatrix); |
|
// continue without transformation and set withinDefs to false to prevent child nodes from starting new form objects |
tfMatrix = _pdf.unitMatrix; |
withinDefs = false; |
|
} else { |
tfMatrix = _pdf.matrixMult(computeNodeTransform(node), contextTransform); |
_pdf.saveGraphicsState(); |
} |
|
// |
// extract fill and stroke mode |
// |
|
// fill mode |
if (nodeIs(node, "g,path,rect,text,ellipse,line,circle,polygon")) { |
function setDefaultColor() { |
fillRGB = new RGBColor("rgb(0, 0, 0)"); |
hasFillColor = true; |
colorMode = "F"; |
} |
|
var fillColor = getAttribute(node, "fill"); |
if (fillColor) { |
var url = iriReference.exec(fillColor); |
if (url) { |
// probably a gradient (or something unsupported) |
fillUrl = svgIdPrefix.get() + url[1]; |
var fill = getFromDefs(fillUrl, defs); |
if (fill && nodeIs(fill, "lineargradient,radialgradient")) { |
|
// matrix to convert between gradient space and user space |
// for "userSpaceOnUse" this is the current transformation: tfMatrix |
// for "objectBoundingBox" or default, the gradient gets scaled and transformed to the bounding box |
var gradientUnitsMatrix = tfMatrix; |
if (!fill.hasAttribute("gradientUnits") |
|| fill.getAttribute("gradientUnits").toLowerCase() === "objectboundingbox") { |
bBox || (bBox = getUntransformedBBox(node)); |
gradientUnitsMatrix = new _pdf.Matrix(bBox[2], 0, 0, bBox[3], bBox[0], bBox[1]); |
|
var nodeTransform = computeNodeTransform(node); |
gradientUnitsMatrix = _pdf.matrixMult(gradientUnitsMatrix, nodeTransform); |
} |
|
// matrix that is applied to the gradient before any other transformations |
var gradientTransform = parseTransform(fill.getAttribute("gradientTransform")); |
|
fillData = _pdf.matrixMult(gradientTransform, gradientUnitsMatrix); |
} else if (fill && nodeIs(fill, "pattern")) { |
var fillBBox, y, width, height, x; |
fillData = {}; |
|
var patternUnitsMatrix = _pdf.unitMatrix; |
if (!fill.hasAttribute("patternUnits") |
|| fill.getAttribute("patternUnits").toLowerCase() === "objectboundingbox") { |
bBox || (bBox = getUntransformedBBox(node)); |
patternUnitsMatrix = new _pdf.Matrix(1, 0, 0, 1, bBox[0], bBox[1]); |
|
// TODO: slightly inaccurate (rounding errors? line width bBoxes?) |
fillBBox = getUntransformedBBox(fill); |
x = fillBBox[0] * bBox[0]; |
y = fillBBox[1] * bBox[1]; |
width = fillBBox[2] * bBox[2]; |
height = fillBBox[3] * bBox[3]; |
fillData.boundingBox = [x, y, x + width, y + height]; |
fillData.xStep = width; |
fillData.yStep = height; |
} |
|
var patternContentUnitsMatrix = _pdf.unitMatrix; |
if (fill.hasAttribute("patternContentUnits") |
&& fill.getAttribute("patternContentUnits").toLowerCase() === "objectboundingbox") { |
bBox || (bBox = getUntransformedBBox(node)); |
patternContentUnitsMatrix = new _pdf.Matrix(bBox[2], 0, 0, bBox[3], 0, 0); |
|
fillBBox = fillData.boundingBox || getUntransformedBBox(fill); |
x = fillBBox[0] / bBox[0]; |
y = fillBBox[1] / bBox[1]; |
width = fillBBox[2] / bBox[2]; |
height = fillBBox[3] / bBox[3]; |
fillData.boundingBox = [x, y, x + width, y + height]; |
fillData.xStep = width; |
fillData.yStep = height; |
} |
|
fillData.matrix = _pdf.matrixMult( |
_pdf.matrixMult(patternContentUnitsMatrix, patternUnitsMatrix), tfMatrix); |
|
colorMode = "F"; |
} else { |
// unsupported fill argument (e.g. patterns) -> fill black |
fillUrl = fill = null; |
setDefaultColor(); |
} |
} else { |
// plain color |
fillRGB = parseColor(fillColor); |
if (fillRGB.ok) { |
hasFillColor = true; |
colorMode = 'F'; |
} else { |
colorMode = null; |
} |
} |
} else { |
// if no fill attribute is provided the default fill color is black |
setDefaultColor(); |
} |
|
// opacity is realized via a pdf graphics state |
var opacity = 1.0; |
var nodeOpacity = node.getAttribute("opacity") || node.getAttribute("fill-opacity"); |
if (nodeOpacity) { |
opacity *= parseFloat(nodeOpacity); |
} |
if (fillRGB && typeof fillRGB.a === "number") { |
opacity *= fillRGB.a; |
} |
_pdf.setGState(new _pdf.GState({opacity: opacity})); |
} |
|
if (nodeIs(node, "g,path,rect,ellipse,line,circle,polygon")) { |
// text has no fill color, so don't apply it until here |
if (hasFillColor) { |
_pdf.setFillColor(fillRGB.r, fillRGB.g, fillRGB.b); |
} |
|
// stroke mode |
var strokeColor = node.getAttribute('stroke'); |
if (strokeColor) { |
var strokeWidth; |
if (node.hasAttribute("stroke-width")) { |
strokeWidth = Math.abs(parseFloat(node.getAttribute('stroke-width'))); |
_pdf.setLineWidth(strokeWidth); |
} |
var strokeRGB = new RGBColor(strokeColor); |
if (strokeRGB.ok) { |
_pdf.setDrawColor(strokeRGB.r, strokeRGB.g, strokeRGB.b); |
if (strokeWidth !== 0) { |
// pdf spec states: "A line width of 0 denotes the thinnest line that can be rendered at device resolution: |
// 1 device pixel wide". SVG, however, does not draw zero width lines. |
colorMode = (colorMode || "") + "D"; |
} |
} |
if (node.hasAttribute("stroke-linecap")) { |
_pdf.setLineCap(node.getAttribute("stroke-linecap")); |
} |
if (node.hasAttribute("stroke-linejoin")) { |
_pdf.setLineJoin(node.getAttribute("stroke-linejoin")); |
} |
if (node.hasAttribute("stroke-dasharray")) { |
_pdf.setLineDashPattern( |
parseFloats(node.getAttribute("stroke-dasharray")), |
parseInt(node.getAttribute("stroke-dashoffset")) || 0 |
); |
} |
if (node.hasAttribute("stroke-miterlimit")) { |
_pdf.setLineMiterLimit(parseFloat(node.getAttribute("stroke-miterlimit"))); |
} |
} |
} |
|
setTextProperties(node, fillRGB); |
|
// do the actual drawing |
switch (node.tagName.toLowerCase()) { |
case 'svg': |
svg(node, tfMatrix, defs, svgIdPrefix, withinDefs); |
break; |
case 'g': |
findAndRenderDefs(node, tfMatrix, defs, svgIdPrefix, withinDefs); |
case 'a': |
case "marker": |
renderChildren(node, tfMatrix, defs, svgIdPrefix, withinDefs); |
break; |
|
case 'defs': |
renderChildren(node, tfMatrix, defs, svgIdPrefix, true); |
break; |
|
case 'use': |
use(node, tfMatrix, svgIdPrefix); |
break; |
|
case 'line': |
line(node, tfMatrix); |
break; |
|
case 'rect': |
_pdf.setCurrentTransformationMatrix(tfMatrix); |
rect(node, colorMode, fillUrl, fillData); |
break; |
|
case 'ellipse': |
_pdf.setCurrentTransformationMatrix(tfMatrix); |
ellipse(node, colorMode, fillUrl, fillData); |
break; |
|
case 'circle': |
_pdf.setCurrentTransformationMatrix(tfMatrix); |
circle(node, colorMode, fillUrl, fillData); |
break; |
case 'text': |
text(node, tfMatrix, hasFillColor, fillRGB); |
break; |
|
case 'path': |
path(node, tfMatrix, svgIdPrefix, colorMode, fillUrl, fillData); |
break; |
|
case 'polygon': |
polygon(node, tfMatrix, colorMode, fillUrl, fillData); |
break; |
|
case 'image': |
_pdf.setCurrentTransformationMatrix(tfMatrix); |
image(node); |
break; |
|
case "lineargradient": |
putGradient(node, "axial", [ |
node.getAttribute("x1"), |
node.getAttribute("y1"), |
node.getAttribute("x2"), |
node.getAttribute("y2") |
], defs, svgIdPrefix); |
break; |
|
case "radialgradient": |
putGradient(node, "radial", [ |
node.getAttribute("fx") || node.getAttribute("cx"), |
node.getAttribute("fy") || node.getAttribute("cy"), |
0, |
node.getAttribute("cx") || 0, |
node.getAttribute("cy") || 0, |
node.getAttribute("r") || 0 |
], defs, svgIdPrefix); |
break; |
|
case "pattern": |
pattern(node, defs, svgIdPrefix); |
break; |
} |
|
// close either the formObject or the graphics context |
if (targetIsFormObject) { |
_pdf.endFormObject(svgIdPrefix.get() + node.getAttribute("id")); |
} else { |
_pdf.restoreGraphicsState(); |
} |
}; |
|
// the actual svgToPdf function (see above) |
var svg2pdf = function (element, pdf, options) { |
_pdf = pdf; |
|
var k = options.scale || 1.0, |
xOffset = options.xOffset || 0.0, |
yOffset = options.yOffset || 0.0; |
|
// set offsets and scale everything by k |
_pdf.saveGraphicsState(); |
_pdf.setCurrentTransformationMatrix(new _pdf.Matrix(k, 0, 0, k, xOffset, yOffset)); |
|
renderNode(element.cloneNode(true), _pdf.unitMatrix, {}, new SvgPrefix(""), false); |
|
_pdf.restoreGraphicsState(); |
|
return _pdf; |
}; |
|
if (typeof define === "function" && define.amd) { |
define(["./rgbcolor", "SvgPath"], function (rgbcolor, svgpath) { |
RGBColor = rgbcolor; |
SvgPath = svgpath; |
return svg2pdf; |
}); |
} else if (typeof module !== "undefined" && module.exports) { |
RGBColor = require("./rgbcolor.js"); |
SvgPath = require("SvgPath"); |
module.exports = svg2pdf; |
} else { |
SvgPath = global.SvgPath; |
RGBColor = global.RGBColor; |
global.svg2pdf = svg2pdf; |
// for compatibility reasons |
global.svgElementToPdf = svg2pdf; |
} |
return svg2pdf; |
}(typeof self !== "undefined" && self || typeof window !== "undefined" && window || this)); |
|
},{"./rgbcolor.js":8,"SvgPath":1}]},{},[9])(9) |
}); |
//# sourceMappingURL=svg2pdf.js.map |