1
if(!window.console){window.console={};window.console.log=function(a){};window.console.dir=function(a){}}if(!Array.indexOf){Array.prototype.indexOf=function(b){for(var a=0;a<this.length;a++){if(this[a]==b){return a}}return -1}}(function(){this.canvg=function(j,m,b){if(j==null&&m==null&&b==null){var e=document.getElementsByTagName("svg");for(var g=0;g<e.length;g++){var f=e[g];var k=document.createElement("canvas");k.width=f.clientWidth;k.height=f.clientHeight;f.parentNode.insertBefore(k,f);f.parentNode.removeChild(f);var d=document.createElement("div");d.appendChild(f);canvg(k,d.innerHTML)}return}if(typeof j=="string"){j=document.getElementById(j)}var h;if(j.svg==null){h=a();j.svg=h}else{h=j.svg;h.stop()}h.opts=b;var l=j.getContext("2d");if(m.substr(0,1)=="<"){h.loadXml(l,m)}else{h.load(l,m)}};function a(){var b={};b.FRAMERATE=30;b.init=function(c){b.Definitions={};b.Styles={};b.Animations=[];b.Images=[];b.ctx=c;b.ViewPort=new (function(){this.viewPorts=[];this.SetCurrent=function(e,d){this.viewPorts.push({width:e,height:d})};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(e){if(e!=null&&typeof(e)=="number"){return e}if(e=="x"){return this.width()}if(e=="y"){return this.height()}return Math.sqrt(Math.pow(this.width(),2)+Math.pow(this.height(),2))/Math.sqrt(2)}})};b.init();b.ImagesLoaded=function(){for(var c=0;c<b.Images.length;c++){if(!b.Images[c].loaded){return false}}return true};b.trim=function(c){return c.replace(/^\s+|\s+$/g,"")};b.compressSpaces=function(c){return c.replace(/[\s\r\t\n]+/gm," ")};b.ajax=function(d){var c;if(window.XMLHttpRequest){c=new XMLHttpRequest()}else{c=new ActiveXObject("Microsoft.XMLHTTP")}if(c){c.open("GET",d,false);c.send(null);return c.responseText}return null};b.parseXml=function(c){if(window.DOMParser){var e=new DOMParser();return e.parseFromString(c,"text/xml")}else{c=c.replace(/<!DOCTYPE svg[^>]*>/,"");var d=new ActiveXObject("Microsoft.XMLDOM");d.async="false";d.loadXML(c);return d}};b.Property=function(c,e){this.name=c;this.value=e;this.hasValue=function(){return(this.value!=null&&this.value!="")};this.numValue=function(){if(!this.hasValue()){return 0}var f=parseFloat(this.value);if((this.value+"").match(/%$/)){f=f/100}return f};this.valueOrDefault=function(f){if(this.hasValue()){return this.value}return f};this.numValueOrDefault=function(f){if(this.hasValue()){return this.numValue()}return f};var d=this;this.Color={addOpacity:function(g){var h=d.value;if(g!=null&&g!=""){var f=new RGBColor(d.value);if(f.ok){h="rgba("+f.r+", "+f.g+", "+f.b+", "+g+")"}}return new b.Property(d.name,h)}};this.Definition={getDefinition:function(){var f=d.value.replace(/^(url\()?#([^\)]+)\)?$/,"$2");return b.Definitions[f]},isUrl:function(){return d.value.indexOf("url(")==0},getFillStyle:function(g){var f=this.getDefinition();if(f!=null&&f.createGradient){return f.createGradient(b.ctx,g)}if(f!=null&&f.createPattern){return f.createPattern(b.ctx,g)}return null}};this.Length={DPI:function(f){return 96},EM:function(h){var f=12;var g=new b.Property("fontSize",b.Font.Parse(b.ctx.font).fontSize);if(g.hasValue()){f=g.Length.toPixels(h)}return f},toPixels:function(g){if(!d.hasValue()){return 0}var f=d.value+"";if(f.match(/em$/)){return d.numValue()*this.EM(g)}if(f.match(/ex$/)){return d.numValue()*this.EM(g)/2}if(f.match(/px$/)){return d.numValue()}if(f.match(/pt$/)){return d.numValue()*1.25}if(f.match(/pc$/)){return d.numValue()*15}if(f.match(/cm$/)){return d.numValue()*this.DPI(g)/2.54}if(f.match(/mm$/)){return d.numValue()*this.DPI(g)/25.4}if(f.match(/in$/)){return d.numValue()*this.DPI(g)}if(f.match(/%$/)){return d.numValue()*b.ViewPort.ComputeSize(g)}return d.numValue()}};this.Time={toMilliseconds:function(){if(!d.hasValue()){return 0}var f=d.value+"";if(f.match(/s$/)){return d.numValue()*1000}if(f.match(/ms$/)){return d.numValue()}return d.numValue()}};this.Angle={toRadians:function(){if(!d.hasValue()){return 0}var f=d.value+"";if(f.match(/deg$/)){return d.numValue()*(Math.PI/180)}if(f.match(/grad$/)){return d.numValue()*(Math.PI/200)}if(f.match(/rad$/)){return d.numValue()}return d.numValue()*(Math.PI/180)}}};b.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(l,h,e,k,d,g){var j=g!=null?this.Parse(g):this.CreateFont("","","","","",b.ctx.font);return{fontFamily:d||j.fontFamily,fontSize:k||j.fontSize,fontStyle:l||j.fontStyle,fontWeight:e||j.fontWeight,fontVariant:h||j.fontVariant,toString:function(){return[this.fontStyle,this.fontVariant,this.fontWeight,this.fontSize,this.fontFamily].join(" ")}}};var c=this;this.Parse=function(h){var j={};var k=b.trim(b.compressSpaces(h||"")).split(" ");var l={fontSize:false,fontStyle:false,fontWeight:false,fontVariant:false};var e="";for(var g=0;g<k.length;g++){if(!l.fontStyle&&c.Styles.indexOf(k[g])!=-1){if(k[g]!="inherit"){j.fontStyle=k[g]}l.fontStyle=true}else{if(!l.fontVariant&&c.Variants.indexOf(k[g])!=-1){if(k[g]!="inherit"){j.fontVariant=k[g]}l.fontStyle=l.fontVariant=true}else{if(!l.fontWeight&&c.Weights.indexOf(k[g])!=-1){if(k[g]!="inherit"){j.fontWeight=k[g]}l.fontStyle=l.fontVariant=l.fontWeight=true}else{if(!l.fontSize){if(k[g]!="inherit"){j.fontSize=k[g].split("/")[0]}l.fontStyle=l.fontVariant=l.fontWeight=l.fontSize=true}else{if(k[g]!="inherit"){e+=k[g]}}}}}}if(e!=""){j.fontFamily=e}return j}});b.ToNumberArray=function(e){var c=b.trim(b.compressSpaces((e||"").replace(/,/g," "))).split(" ");for(var d=0;d<c.length;d++){c[d]=parseFloat(c[d])}return c};b.Point=function(c,d){this.x=c;this.y=d;this.angleTo=function(e){return Math.atan2(e.y-this.y,e.x-this.x)};this.applyTransform=function(e){var f=this.x*e[0]+this.y*e[2]+e[4];var g=this.x*e[1]+this.y*e[3]+e[5];this.x=f;this.y=g}};b.CreatePoint=function(d){var c=b.ToNumberArray(d);return new b.Point(c[0],c[1])};b.CreatePath=function(e){var c=b.ToNumberArray(e);var f=[];for(var d=0;d<c.length;d+=2){f.push(new b.Point(c[d],c[d+1]))}return f};b.BoundingBox=function(d,f,c,e){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(g,h){if(g!=null){if(isNaN(this.x1)||isNaN(this.x2)){this.x1=g;this.x2=g}if(g<this.x1){this.x1=g}if(g>this.x2){this.x2=g}}if(h!=null){if(isNaN(this.y1)||isNaN(this.y2)){this.y1=h;this.y2=h}if(h<this.y1){this.y1=h}if(h>this.y2){this.y2=h}}};this.addX=function(g){this.addPoint(g,null)};this.addY=function(g){this.addPoint(null,g)};this.addBoundingBox=function(g){this.addPoint(g.x1,g.y1);this.addPoint(g.x2,g.y2)};this.addQuadraticCurve=function(m,l,h,g,o,n){var k=m+2/3*(h-m);var j=l+2/3*(g-l);var q=k+1/3*(o-m);var p=j+1/3*(n-l);this.addBezierCurve(m,l,k,q,j,p,o,n)};this.addBezierCurve=function(v,u,l,j,q,o,x,w){var m=[v,u],k=[l,j],h=[q,o],g=[x,w];this.addPoint(m[0],m[1]);this.addPoint(g[0],g[1]);for(i=0;i<=1;i++){var y=function(C){return Math.pow(1-C,3)*m[i]+3*Math.pow(1-C,2)*C*k[i]+3*(1-C)*Math.pow(C,2)*h[i]+Math.pow(C,3)*g[i]};var A=6*m[i]-12*k[i]+6*h[i];var B=-3*m[i]+9*k[i]-9*h[i]+3*g[i];var z=3*k[i]-3*m[i];if(B==0){if(A==0){continue}var s=-z/A;if(0<s&&s<1){if(i==0){this.addX(y(s))}if(i==1){this.addY(y(s))}}continue}var n=Math.pow(A,2)-4*z*B;if(n<0){continue}var r=(-A+Math.sqrt(n))/(2*B);if(0<r&&r<1){if(i==0){this.addX(y(r))}if(i==1){this.addY(y(r))}}var p=(-A-Math.sqrt(n))/(2*B);if(0<p&&p<1){if(i==0){this.addX(y(p))}if(i==1){this.addY(y(p))}}}};this.isPointInBox=function(g,h){return(this.x1<=g&&g<=this.x2&&this.y1<=h&&h<=this.y2)};this.addPoint(d,f);this.addPoint(c,e)};b.Transform=function(c){var h=this;this.Type={};this.Type.translate=function(k){this.p=b.CreatePoint(k);this.apply=function(l){l.translate(this.p.x||0,this.p.y||0)};this.applyToPoint=function(l){l.applyTransform([1,0,0,1,this.p.x||0,this.p.y||0])}};this.Type.rotate=function(l){var k=b.ToNumberArray(l);this.angle=new b.Property("angle",k[0]);this.cx=k[1]||0;this.cy=k[2]||0;this.apply=function(m){m.translate(this.cx,this.cy);m.rotate(this.angle.Angle.toRadians());m.translate(-this.cx,-this.cy)};this.applyToPoint=function(n){var m=this.angle.Angle.toRadians();n.applyTransform([1,0,0,1,this.p.x||0,this.p.y||0]);n.applyTransform([Math.cos(m),Math.sin(m),-Math.sin(m),Math.cos(m),0,0]);n.applyTransform([1,0,0,1,-this.p.x||0,-this.p.y||0])}};this.Type.scale=function(k){this.p=b.CreatePoint(k);this.apply=function(l){l.scale(this.p.x||1,this.p.y||this.p.x||1)};this.applyToPoint=function(l){l.applyTransform([this.p.x||0,0,0,this.p.y||0,0,0])}};this.Type.matrix=function(k){this.m=b.ToNumberArray(k);this.apply=function(l){l.transform(this.m[0],this.m[1],this.m[2],this.m[3],this.m[4],this.m[5])};this.applyToPoint=function(l){l.applyTransform(this.m)}};this.Type.SkewBase=function(k){this.base=h.Type.matrix;this.base(k);this.angle=new b.Property("angle",k)};this.Type.SkewBase.prototype=new this.Type.matrix;this.Type.skewX=function(k){this.base=h.Type.SkewBase;this.base(k);this.m=[1,0,Math.tan(this.angle.Angle.toRadians()),1,0,0]};this.Type.skewX.prototype=new this.Type.SkewBase;this.Type.skewY=function(k){this.base=h.Type.SkewBase;this.base(k);this.m=[1,Math.tan(this.angle.Angle.toRadians()),0,1,0,0]};this.Type.skewY.prototype=new this.Type.SkewBase;this.transforms=[];this.apply=function(k){for(var l=0;l<this.transforms.length;l++){this.transforms[l].apply(k)}};this.applyToPoint=function(l){for(var k=0;k<this.transforms.length;k++){this.transforms[k].applyToPoint(l)}};var j=c.split(/\s(?=[a-z])/);for(var e=0;e<j.length;e++){var g=j[e].split("(")[0];var f=j[e].split("(")[1].replace(")","");var d=new this.Type[g](f);this.transforms.push(d)}};b.AspectRatio=function(s,q,d,k,r,c,g,f,p,o){q=b.compressSpaces(q);q=q.replace(/^defer\s/,"");var j=q.split(" ")[0]||"xMidYMid";var e=q.split(" ")[1]||"meet";var n=d/k;var m=r/c;var h=Math.min(n,m);var l=Math.max(n,m);if(e=="meet"){k*=h;c*=h}if(e=="slice"){k*=l;c*=l}p=new b.Property("refX",p);o=new b.Property("refY",o);if(p.hasValue()&&o.hasValue()){s.translate(-h*p.Length.toPixels("x"),-h*o.Length.toPixels("y"))}else{if(j.match(/^xMid/)&&((e=="meet"&&h==m)||(e=="slice"&&l==m))){s.translate(d/2-k/2,0)}if(j.match(/YMid$/)&&((e=="meet"&&h==n)||(e=="slice"&&l==n))){s.translate(0,r/2-c/2)}if(j.match(/^xMax/)&&((e=="meet"&&h==m)||(e=="slice"&&l==m))){s.translate(d-k,0)}if(j.match(/YMax$/)&&((e=="meet"&&h==n)||(e=="slice"&&l==n))){s.translate(0,r-c)}}if(j=="none"){s.scale(n,m)}else{if(e=="meet"){s.scale(h,h)}else{if(e=="slice"){s.scale(l,l)}}}s.translate(g==null?0:-g,f==null?0:-f)};b.Element={};b.Element.ElementBase=function(g){this.attributes={};this.styles={};this.children=[];this.attribute=function(o,p){var j=this.attributes[o];if(j!=null){return j}j=new b.Property(o,"");if(p==true){this.attributes[o]=j}return j};this.style=function(o,q){var p=this.styles[o];if(p!=null){return p}var j=this.attribute(o);if(j!=null&&j.hasValue()){return j}p=new b.Property(o,"");if(q==true){this.styles[o]=p}return p};this.render=function(j){if(this.attribute("display").value=="none"){return}j.save();this.setContext(j);this.renderChildren(j);this.clearContext(j);j.restore()};this.setContext=function(j){};this.clearContext=function(j){};this.renderChildren=function(j){for(var o=0;o<this.children.length;o++){this.children[o].render(j)}};this.addChild=function(o,j){var p=o;if(j){p=b.CreateElement(o)}p.parent=this;this.children.push(p)};if(g!=null&&g.nodeType==1){for(var l=0;l<g.childNodes.length;l++){var c=g.childNodes[l];if(c.nodeType==1){this.addChild(c,true)}}for(var l=0;l<g.attributes.length;l++){var f=g.attributes[l];this.attributes[f.nodeName]=new b.Property(f.nodeName,f.nodeValue)}var n=b.Styles[this.type];if(n!=null){for(var e in n){this.styles[e]=n[e]}}if(this.attribute("class").hasValue()){var h=b.compressSpaces(this.attribute("class").value).split(" ");for(var k=0;k<h.length;k++){n=b.Styles["."+h[k]];if(n!=null){for(var e in n){this.styles[e]=n[e]}}}}if(this.attribute("style").hasValue()){var n=this.attribute("style").value.split(";");for(var l=0;l<n.length;l++){if(b.trim(n[l])!=""){var d=n[l].split(":");var e=b.trim(d[0]);var m=b.trim(d[1]);this.styles[e]=new b.Property(e,m)}}}if(this.attribute("id").hasValue()){if(b.Definitions[this.attribute("id").value]==null){b.Definitions[this.attribute("id").value]=this}}}};b.Element.RenderedElementBase=function(c){this.base=b.Element.ElementBase;this.base(c);this.setContext=function(e){if(this.style("fill").Definition.isUrl()){var d=this.style("fill").Definition.getFillStyle(this);if(d!=null){e.fillStyle=d}}else{if(this.style("fill").hasValue()){var f=this.style("fill");if(this.style("fill-opacity").hasValue()){f=f.Color.addOpacity(this.style("fill-opacity").value)}e.fillStyle=(f.value=="none"?"rgba(0,0,0,0)":f.value)}}if(this.style("stroke").Definition.isUrl()){var d=this.style("stroke").Definition.getFillStyle(this);if(d!=null){e.strokeStyle=d}}else{if(this.style("stroke").hasValue()){var j=this.style("stroke");if(this.style("stroke-opacity").hasValue()){j=j.Color.addOpacity(this.style("stroke-opacity").value)}e.strokeStyle=(j.value=="none"?"rgba(0,0,0,0)":j.value)}}if(this.style("stroke-width").hasValue()){e.lineWidth=this.style("stroke-width").Length.toPixels()}if(this.style("stroke-linecap").hasValue()){e.lineCap=this.style("stroke-linecap").value}if(this.style("stroke-linejoin").hasValue()){e.lineJoin=this.style("stroke-linejoin").value}if(this.style("stroke-miterlimit").hasValue()){e.miterLimit=this.style("stroke-miterlimit").value}if(typeof(e.font)!="undefined"){e.font=b.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").Length.toPixels()+"px":"",this.style("font-family").value).toString()}if(this.attribute("transform").hasValue()){var g=new b.Transform(this.attribute("transform").value);g.apply(e)}if(this.attribute("clip-path").hasValue()){var h=this.attribute("clip-path").Definition.getDefinition();if(h!=null){h.apply(e)}}if(this.style("opacity").hasValue()){e.globalAlpha=this.style("opacity").numValue()}}};b.Element.RenderedElementBase.prototype=new b.Element.ElementBase;b.Element.PathElementBase=function(c){this.base=b.Element.RenderedElementBase;this.base(c);this.path=function(d){if(d!=null){d.beginPath()}return new b.BoundingBox()};this.renderChildren=function(e){this.path(e);b.Mouse.checkPath(this,e);if(e.fillStyle!=""){e.fill()}if(e.strokeStyle!=""){e.stroke()}var g=this.getMarkers();if(g!=null){if(this.attribute("marker-start").Definition.isUrl()){var d=this.attribute("marker-start").Definition.getDefinition();d.render(e,g[0][0],g[0][1])}if(this.attribute("marker-mid").Definition.isUrl()){var d=this.attribute("marker-mid").Definition.getDefinition();for(var f=1;f<g.length-1;f++){d.render(e,g[f][0],g[f][1])}}if(this.attribute("marker-end").Definition.isUrl()){var d=this.attribute("marker-end").Definition.getDefinition();d.render(e,g[g.length-1][0],g[g.length-1][1])}}};this.getBoundingBox=function(){return this.path()};this.getMarkers=function(){return null}};b.Element.PathElementBase.prototype=new b.Element.RenderedElementBase;b.Element.svg=function(c){this.base=b.Element.RenderedElementBase;this.base(c);this.baseClearContext=this.clearContext;this.clearContext=function(d){this.baseClearContext(d);b.ViewPort.RemoveCurrent()};this.baseSetContext=this.setContext;this.setContext=function(g){g.strokeStyle="rgba(0,0,0,0)";g.lineCap="butt";g.lineJoin="miter";g.miterLimit=4;this.baseSetContext(g);if(this.attribute("x").hasValue()&&this.attribute("y").hasValue()){g.translate(this.attribute("x").Length.toPixels("x"),this.attribute("y").Length.toPixels("y"))}var h=b.ViewPort.width();var f=b.ViewPort.height();if(this.attribute("width").hasValue()&&this.attribute("height").hasValue()){h=this.attribute("width").Length.toPixels("x");f=this.attribute("height").Length.toPixels("y");var e=0;var l=0;if(this.attribute("refX").hasValue()&&this.attribute("refY").hasValue()){e=-this.attribute("refX").Length.toPixels("x");l=-this.attribute("refY").Length.toPixels("y")}g.beginPath();g.moveTo(e,l);g.lineTo(h,l);g.lineTo(h,f);g.lineTo(e,f);g.closePath();g.clip()}b.ViewPort.SetCurrent(h,f);if(this.attribute("viewBox").hasValue()){var j=b.ToNumberArray(this.attribute("viewBox").value);var d=j[0];var k=j[1];h=j[2];f=j[3];b.AspectRatio(g,this.attribute("preserveAspectRatio").value,b.ViewPort.width(),h,b.ViewPort.height(),f,d,k,this.attribute("refX").value,this.attribute("refY").value);b.ViewPort.RemoveCurrent();b.ViewPort.SetCurrent(j[2],j[3])}}};b.Element.svg.prototype=new b.Element.RenderedElementBase;b.Element.rect=function(c){this.base=b.Element.PathElementBase;this.base(c);this.path=function(f){var e=this.attribute("x").Length.toPixels("x");var k=this.attribute("y").Length.toPixels("y");var g=this.attribute("width").Length.toPixels("x");var d=this.attribute("height").Length.toPixels("y");var j=this.attribute("rx").Length.toPixels("x");var h=this.attribute("ry").Length.toPixels("y");if(this.attribute("rx").hasValue()&&!this.attribute("ry").hasValue()){h=j}if(this.attribute("ry").hasValue()&&!this.attribute("rx").hasValue()){j=h}if(f!=null){f.beginPath();f.moveTo(e+j,k);f.lineTo(e+g-j,k);f.quadraticCurveTo(e+g,k,e+g,k+h);f.lineTo(e+g,k+d-h);f.quadraticCurveTo(e+g,k+d,e+g-j,k+d);f.lineTo(e+j,k+d);f.quadraticCurveTo(e,k+d,e,k+d-h);f.lineTo(e,k+h);f.quadraticCurveTo(e,k,e+j,k);f.closePath()}return new b.BoundingBox(e,k,e+g,k+d)}};b.Element.rect.prototype=new b.Element.PathElementBase;b.Element.circle=function(c){this.base=b.Element.PathElementBase;this.base(c);this.path=function(e){var d=this.attribute("cx").Length.toPixels("x");var g=this.attribute("cy").Length.toPixels("y");var f=this.attribute("r").Length.toPixels();if(e!=null){e.beginPath();e.arc(d,g,f,0,Math.PI*2,true);e.closePath()}return new b.BoundingBox(d-f,g-f,d+f,g+f)}};b.Element.circle.prototype=new b.Element.PathElementBase;b.Element.ellipse=function(c){this.base=b.Element.PathElementBase;this.base(c);this.path=function(e){var g=4*((Math.sqrt(2)-1)/3);var h=this.attribute("rx").Length.toPixels("x");var f=this.attribute("ry").Length.toPixels("y");var d=this.attribute("cx").Length.toPixels("x");var j=this.attribute("cy").Length.toPixels("y");if(e!=null){e.beginPath();e.moveTo(d,j-f);e.bezierCurveTo(d+(g*h),j-f,d+h,j-(g*f),d+h,j);e.bezierCurveTo(d+h,j+(g*f),d+(g*h),j+f,d,j+f);e.bezierCurveTo(d-(g*h),j+f,d-h,j+(g*f),d-h,j);e.bezierCurveTo(d-h,j-(g*f),d-(g*h),j-f,d,j-f);e.closePath()}return new b.BoundingBox(d-h,j-f,d+h,j+f)}};b.Element.ellipse.prototype=new b.Element.PathElementBase;b.Element.line=function(c){this.base=b.Element.PathElementBase;this.base(c);this.getPoints=function(){return[new b.Point(this.attribute("x1").Length.toPixels("x"),this.attribute("y1").Length.toPixels("y")),new b.Point(this.attribute("x2").Length.toPixels("x"),this.attribute("y2").Length.toPixels("y"))]};this.path=function(d){var e=this.getPoints();if(d!=null){d.beginPath();d.moveTo(e[0].x,e[0].y);d.lineTo(e[1].x,e[1].y)}return new b.BoundingBox(e[0].x,e[0].y,e[1].x,e[1].y)};this.getMarkers=function(){var e=this.getPoints();var d=e[0].angleTo(e[1]);return[[e[0],d],[e[1],d]]}};b.Element.line.prototype=new b.Element.PathElementBase;b.Element.polyline=function(c){this.base=b.Element.PathElementBase;this.base(c);this.points=b.CreatePath(this.attribute("points").value);this.path=function(d){var f=new b.BoundingBox(this.points[0].x,this.points[0].y);if(d!=null){d.beginPath();d.moveTo(this.points[0].x,this.points[0].y)}for(var e=1;e<this.points.length;e++){f.addPoint(this.points[e].x,this.points[e].y);if(d!=null){d.lineTo(this.points[e].x,this.points[e].y)}}return f};this.getMarkers=function(){var e=[];for(var d=0;d<this.points.length-1;d++){e.push([this.points[d],this.points[d].angleTo(this.points[d+1])])}e.push([this.points[this.points.length-1],e[e.length-1][1]]);return e}};b.Element.polyline.prototype=new b.Element.PathElementBase;b.Element.polygon=function(c){this.base=b.Element.polyline;this.base(c);this.basePath=this.path;this.path=function(d){var e=this.basePath(d);if(d!=null){d.lineTo(this.points[0].x,this.points[0].y);d.closePath()}return e}};b.Element.polygon.prototype=new b.Element.polyline;b.Element.path=function(c){this.base=b.Element.PathElementBase;this.base(c);var e=this.attribute("d").value;e=e.replace(/,/gm," ");e=e.replace(/([MmZzLlHhVvCcSsQqTtAa])([MmZzLlHhVvCcSsQqTtAa])/gm,"$1 $2");e=e.replace(/([MmZzLlHhVvCcSsQqTtAa])([MmZzLlHhVvCcSsQqTtAa])/gm,"$1 $2");e=e.replace(/([MmZzLlHhVvCcSsQqTtAa])([^\s])/gm,"$1 $2");e=e.replace(/([^\s])([MmZzLlHhVvCcSsQqTtAa])/gm,"$1 $2");e=e.replace(/([0-9])([+\-])/gm,"$1 $2");e=e.replace(/(\.[0-9]*)(\.)/gm,"$1 $2");e=e.replace(/([Aa](\s+[0-9]+){3})\s+([01])\s*([01])/gm,"$1 $3 $4 ");e=b.compressSpaces(e);e=b.trim(e);this.PathParser=new (function(f){this.tokens=f.split(" ");this.reset=function(){this.i=-1;this.command="";this.previousCommand="";this.start=new b.Point(0,0);this.control=new b.Point(0,0);this.current=new b.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(){return this.command==this.command.toLowerCase()};this.getToken=function(){this.i=this.i+1;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 d=new b.Point(this.getScalar(),this.getScalar());return this.makeAbsolute(d)};this.getAsControlPoint=function(){var d=this.getPoint();this.control=d;return d};this.getAsCurrentPoint=function(){var d=this.getPoint();this.current=d;return d};this.getReflectedControlPoint=function(){if(this.previousCommand.toLowerCase()!="c"&&this.previousCommand.toLowerCase()!="s"){return this.current}var d=new b.Point(2*this.current.x-this.control.x,2*this.current.y-this.control.y);return d};this.makeAbsolute=function(d){if(this.isRelativeCommand()){d.x=this.current.x+d.x;d.y=this.current.y+d.y}return d};this.addMarker=function(d,g){this.addMarkerAngle(d,g==null?null:g.angleTo(d))};this.addMarkerAngle=function(g,d){this.points.push(g);this.angles.push(d)};this.getMarkerPoints=function(){return this.points};this.getMarkerAngles=function(){for(var g=0;g<this.angles.length;g++){if(this.angles[g]==null){for(var d=g+1;d<this.angles.length;d++){if(this.angles[d]!=null){this.angles[g]=this.angles[d];break}}}}return this.angles}})(e);this.path=function(H){var J=this.PathParser;J.reset();var t=new b.BoundingBox();if(this.attribute("visibility").value=="hidden"){return}if(H!=null){H.beginPath()}while(!J.isEnd()){J.nextCommand();switch(J.command.toUpperCase()){case"M":var F=J.getAsCurrentPoint();J.addMarker(F);t.addPoint(F.x,F.y);if(H!=null){H.moveTo(F.x,F.y)}J.start=J.current;while(!J.isCommandOrEnd()){var F=J.getAsCurrentPoint();J.addMarker(F);t.addPoint(F.x,F.y);if(H!=null){H.lineTo(F.x,F.y)}}break;case"L":while(!J.isCommandOrEnd()){var M=J.current;var F=J.getAsCurrentPoint();J.addMarker(F,M);t.addPoint(F.x,F.y);if(H!=null){H.lineTo(F.x,F.y)}}break;case"H":while(!J.isCommandOrEnd()){var g=new b.Point((J.isRelativeCommand()?J.current.x:0)+J.getScalar(),J.current.y);J.addMarker(g,J.current);J.current=g;t.addPoint(J.current.x,J.current.y);if(H!=null){H.lineTo(J.current.x,J.current.y)}}break;case"V":while(!J.isCommandOrEnd()){var g=new b.Point(J.current.x,(J.isRelativeCommand()?J.current.y:0)+J.getScalar());J.addMarker(g,J.current);J.current=g;t.addPoint(J.current.x,J.current.y);if(H!=null){H.lineTo(J.current.x,J.current.y)}}break;case"C":while(!J.isCommandOrEnd()){var K=J.current;var j=J.getPoint();var k=J.getAsControlPoint();var x=J.getAsCurrentPoint();J.addMarker(x,k);t.addBezierCurve(K.x,K.y,j.x,j.y,k.x,k.y,x.x,x.y);if(H!=null){H.bezierCurveTo(j.x,j.y,k.x,k.y,x.x,x.y)}}break;case"S":while(!J.isCommandOrEnd()){var K=J.current;var j=J.getReflectedControlPoint();var k=J.getAsControlPoint();var x=J.getAsCurrentPoint();J.addMarker(x,k);t.addBezierCurve(K.x,K.y,j.x,j.y,k.x,k.y,x.x,x.y);if(H!=null){H.bezierCurveTo(j.x,j.y,k.x,k.y,x.x,x.y)}}break;case"Q":while(!J.isCommandOrEnd()){var K=J.current;var k=J.getAsControlPoint();var x=J.getAsCurrentPoint();J.addMarker(x,k);t.addQuadraticCurve(K.x,K.y,k.x,k.y,x.x,x.y);if(H!=null){H.quadraticCurveTo(k.x,k.y,x.x,x.y)}}break;case"T":while(!J.isCommandOrEnd()){var K=J.current;var k=J.getReflectedControlPoint();J.control=k;var x=J.getAsCurrentPoint();J.addMarker(x,k);t.addQuadraticCurve(K.x,K.y,k.x,k.y,x.x,x.y);if(H!=null){H.quadraticCurveTo(k.x,k.y,x.x,x.y)}}break;case"A":while(!J.isCommandOrEnd()){var K=J.current;var q=J.getScalar();var o=J.getScalar();var f=J.getScalar()*(Math.PI/180);var w=J.getScalar();var n=J.getScalar();var x=J.getAsCurrentPoint();var P=new b.Point(Math.cos(f)*(K.x-x.x)/2+Math.sin(f)*(K.y-x.y)/2,-Math.sin(f)*(K.x-x.x)/2+Math.cos(f)*(K.y-x.y)/2);var I=Math.pow(P.x,2)/Math.pow(q,2)+Math.pow(P.y,2)/Math.pow(o,2);if(I>1){q*=Math.sqrt(I);o*=Math.sqrt(I)}var B=(w==n?-1:1)*Math.sqrt(((Math.pow(q,2)*Math.pow(o,2))-(Math.pow(q,2)*Math.pow(P.y,2))-(Math.pow(o,2)*Math.pow(P.x,2)))/(Math.pow(q,2)*Math.pow(P.y,2)+Math.pow(o,2)*Math.pow(P.x,2)));if(isNaN(B)){B=0}var A=new b.Point(B*q*P.y/o,B*-o*P.x/q);var h=new b.Point((K.x+x.x)/2+Math.cos(f)*A.x-Math.sin(f)*A.y,(K.y+x.y)/2+Math.sin(f)*A.x+Math.cos(f)*A.y);var G=function(l){return Math.sqrt(Math.pow(l[0],2)+Math.pow(l[1],2))};var D=function(m,l){return(m[0]*l[0]+m[1]*l[1])/(G(m)*G(l))};var N=function(m,l){return(m[0]*l[1]<m[1]*l[0]?-1:1)*Math.acos(D(m,l))};var O=N([1,0],[(P.x-A.x)/q,(P.y-A.y)/o]);var z=[(P.x-A.x)/q,(P.y-A.y)/o];var y=[(-P.x-A.x)/q,(-P.y-A.y)/o];var L=N(z,y);if(D(z,y)<=-1){L=Math.PI}if(D(z,y)>=1){L=0}if(n==0&&L>0){L=L-2*Math.PI}if(n==1&&L<0){L=L+2*Math.PI}var d=new b.Point(h.x-q*Math.cos((O+L)/2),h.y-o*Math.sin((O+L)/2));J.addMarkerAngle(d,(O+L)/2+(n==0?1:-1)*Math.PI/2);J.addMarkerAngle(x,L+(n==0?1:-1)*Math.PI/2);t.addPoint(x.x,x.y);if(H!=null){var D=q>o?q:o;var E=q>o?1:q/o;var C=q>o?o/q:1;H.translate(h.x,h.y);H.rotate(f);H.scale(E,C);H.arc(0,0,D,O,O+L,1-n);H.scale(1/E,1/C);H.rotate(-f);H.translate(-h.x,-h.y)}}break;case"Z":if(H!=null){H.closePath()}J.current=J.start}}return t};this.getMarkers=function(){var f=this.PathParser.getMarkerPoints();var h=this.PathParser.getMarkerAngles();var g=[];for(var d=0;d<f.length;d++){g.push([f[d],h[d]])}return g}};b.Element.path.prototype=new b.Element.PathElementBase;b.Element.pattern=function(c){this.base=b.Element.ElementBase;this.base(c);this.createPattern=function(d,e){var f=new b.Element.svg();f.attributes.viewBox=new b.Property("viewBox",this.attribute("viewBox").value);f.attributes.x=new b.Property("x",this.attribute("x").value);f.attributes.y=new b.Property("y",this.attribute("y").value);f.attributes.width=new b.Property("width",this.attribute("width").value);f.attributes.height=new b.Property("height",this.attribute("height").value);f.children=this.children;var g=document.createElement("canvas");g.width=this.attribute("width").Length.toPixels();g.height=this.attribute("height").Length.toPixels();f.render(g.getContext("2d"));return d.createPattern(g,"repeat")}};b.Element.pattern.prototype=new b.Element.ElementBase;b.Element.marker=function(c){this.base=b.Element.ElementBase;this.base(c);this.baseRender=this.render;this.render=function(e,d,g){e.translate(d.x,d.y);if(this.attribute("orient").valueOrDefault("auto")=="auto"){e.rotate(g)}if(this.attribute("markerUnits").valueOrDefault("strokeWidth")=="strokeWidth"){e.scale(e.lineWidth,e.lineWidth)}e.save();var f=new b.Element.svg();f.attributes.viewBox=new b.Property("viewBox",this.attribute("viewBox").value);f.attributes.refX=new b.Property("refX",this.attribute("refX").value);f.attributes.refY=new b.Property("refY",this.attribute("refY").value);f.attributes.width=new b.Property("width",this.attribute("markerWidth").value);f.attributes.height=new b.Property("height",this.attribute("markerHeight").value);f.attributes.fill=new b.Property("fill",this.attribute("fill").valueOrDefault("black"));f.attributes.stroke=new b.Property("stroke",this.attribute("stroke").valueOrDefault("none"));f.children=this.children;f.render(e);e.restore();if(this.attribute("markerUnits").valueOrDefault("strokeWidth")=="strokeWidth"){e.scale(1/e.lineWidth,1/e.lineWidth)}if(this.attribute("orient").valueOrDefault("auto")=="auto"){e.rotate(-g)}e.translate(-d.x,-d.y)}};b.Element.marker.prototype=new b.Element.ElementBase;b.Element.defs=function(c){this.base=b.Element.ElementBase;this.base(c);this.render=function(d){}};b.Element.defs.prototype=new b.Element.ElementBase;b.Element.GradientBase=function(d){this.base=b.Element.ElementBase;this.base(d);this.gradientUnits=this.attribute("gradientUnits").valueOrDefault("objectBoundingBox");this.stops=[];for(var c=0;c<this.children.length;c++){var e=this.children[c];this.stops.push(e)}this.getGradient=function(){};this.createGradient=function(f,k){var h=this;if(this.attribute("xlink:href").hasValue()){h=this.attribute("xlink:href").Definition.getDefinition()}var l=this.getGradient(f,k);for(var j=0;j<h.stops.length;j++){l.addColorStop(h.stops[j].offset,h.stops[j].color)}return l}};b.Element.GradientBase.prototype=new b.Element.ElementBase;b.Element.linearGradient=function(c){this.base=b.Element.GradientBase;this.base(c);this.getGradient=function(n,g){var h=g.getBoundingBox();var e=(this.gradientUnits=="objectBoundingBox"?h.x()+h.width()*this.attribute("x1").numValue():this.attribute("x1").Length.toPixels("x"));var k=(this.gradientUnits=="objectBoundingBox"?h.y()+h.height()*this.attribute("y1").numValue():this.attribute("y1").Length.toPixels("y"));var d=(this.gradientUnits=="objectBoundingBox"?h.x()+h.width()*this.attribute("x2").numValue():this.attribute("x2").Length.toPixels("x"));var j=(this.gradientUnits=="objectBoundingBox"?h.y()+h.height()*this.attribute("y2").numValue():this.attribute("y2").Length.toPixels("y"));var m=new b.Point(e,k);var l=new b.Point(d,j);if(this.attribute("gradientTransform").hasValue()){var f=new b.Transform(this.attribute("gradientTransform").value);f.applyToPoint(m);f.applyToPoint(l)}return n.createLinearGradient(m.x,m.y,l.x,l.y)}};b.Element.linearGradient.prototype=new b.Element.GradientBase;b.Element.radialGradient=function(c){this.base=b.Element.GradientBase;this.base(c);this.getGradient=function(t,m){var q=m.getBoundingBox();var k=(this.gradientUnits=="objectBoundingBox"?q.x()+q.width()*this.attribute("cx").numValue():this.attribute("cx").Length.toPixels("x"));var h=(this.gradientUnits=="objectBoundingBox"?q.y()+q.height()*this.attribute("cy").numValue():this.attribute("cy").Length.toPixels("y"));var j=k;var g=h;if(this.attribute("fx").hasValue()){j=(this.gradientUnits=="objectBoundingBox"?q.x()+q.width()*this.attribute("fx").numValue():this.attribute("fx").Length.toPixels("x"))}if(this.attribute("fy").hasValue()){g=(this.gradientUnits=="objectBoundingBox"?q.y()+q.height()*this.attribute("fy").numValue():this.attribute("fy").Length.toPixels("y"))}var d=(this.gradientUnits=="objectBoundingBox"?(q.width()+q.height())/2*this.attribute("r").numValue():this.attribute("r").Length.toPixels());var s=new b.Point(k,h);var p=new b.Point(j,g);if(this.attribute("gradientTransform").hasValue()){var e=new b.Transform(this.attribute("gradientTransform").value);e.applyToPoint(s);e.applyToPoint(p);for(var l=0;l<e.transforms.length;l++){var o=e.transforms[l].m[0];var n=e.transforms[l].m[3];d=d*((o+n)/2)}}return t.createRadialGradient(p.x,p.y,0,s.x,s.y,d)}};b.Element.radialGradient.prototype=new b.Element.GradientBase;b.Element.stop=function(d){this.base=b.Element.ElementBase;this.base(d);this.offset=this.attribute("offset").numValue();var c=this.style("stop-color");if(this.style("stop-opacity").hasValue()){c=c.Color.addOpacity(this.style("stop-opacity").value)}this.color=c.value};b.Element.stop.prototype=new b.Element.ElementBase;b.Element.AnimateBase=function(c){this.base=b.Element.ElementBase;this.base(c);b.Animations.push(this);this.duration=0;this.begin=this.attribute("begin").Time.toMilliseconds();this.maxDuration=this.begin+this.attribute("dur").Time.toMilliseconds();this.getProperty=function(){var e=this.attribute("attributeType").value;var d=this.attribute("attributeName").value;if(e=="CSS"){return this.parent.style(d,true)}return this.parent.attribute(d,true)};this.initialValue=null;this.removed=false;this.calcValue=function(){return""};this.update=function(g){if(this.initialValue==null){this.initialValue=this.getProperty().value}if(this.duration>this.maxDuration){if(this.attribute("repeatCount").value=="indefinite"){this.duration=0}else{if(this.attribute("fill").valueOrDefault("remove")=="remove"&&!this.removed){this.removed=true;this.getProperty().value=this.initialValue;return true}else{return false}}}this.duration=this.duration+g;var d=false;if(this.begin<this.duration){var f=this.calcValue();if(this.attribute("type").hasValue()){var e=this.attribute("type").value;f=e+"("+f+")"}this.getProperty().value=f;d=true}return d};this.progress=function(){return((this.duration-this.begin)/(this.maxDuration-this.begin))}};b.Element.AnimateBase.prototype=new b.Element.ElementBase;b.Element.animate=function(c){this.base=b.Element.AnimateBase;this.base(c);this.calcValue=function(){var e=this.attribute("from").numValue();var d=this.attribute("to").numValue();return e+(d-e)*this.progress()}};b.Element.animate.prototype=new b.Element.AnimateBase;b.Element.animateColor=function(c){this.base=b.Element.AnimateBase;this.base(c);this.calcValue=function(){var j=new RGBColor(this.attribute("from").value);var h=new RGBColor(this.attribute("to").value);if(j.ok&&h.ok){var f=j.r+(h.r-j.r)*this.progress();var e=j.g+(h.g-j.g)*this.progress();var d=j.b+(h.b-j.b)*this.progress();return"rgb("+parseInt(f,10)+","+parseInt(e,10)+","+parseInt(d,10)+")"}return this.attribute("from").value}};b.Element.animateColor.prototype=new b.Element.AnimateBase;b.Element.animateTransform=function(c){this.base=b.Element.animate;this.base(c)};b.Element.animateTransform.prototype=new b.Element.animate;b.Element.text=function(e){this.base=b.Element.RenderedElementBase;this.base(e);if(e!=null){this.children=[];for(var d=0;d<e.childNodes.length;d++){var c=e.childNodes[d];if(c.nodeType==1){this.addChild(c,true)}else{if(c.nodeType==3){this.addChild(new b.Element.tspan(c),false)}}}}this.baseSetContext=this.setContext;this.setContext=function(g){this.baseSetContext(g);if(this.attribute("text-anchor").hasValue()){var f=this.attribute("text-anchor").value;g.textAlign=f=="middle"?"center":f}if(this.attribute("alignment-baseline").hasValue()){g.textBaseline=this.attribute("alignment-baseline").value}};this.renderChildren=function(g){if(this.attribute("visibility").value=="hidden"){return}var f=this.attribute("x").Length.toPixels("x");var k=this.attribute("y").Length.toPixels("y");for(var h=0;h<this.children.length;h++){var j=this.children[h];if(j.attribute("x").hasValue()){j.x=j.attribute("x").Length.toPixels("x")}else{if(j.attribute("dx").hasValue()){f+=j.attribute("dx").Length.toPixels("x")}j.x=f;f+=j.measureText(g)}if(j.attribute("y").hasValue()){j.y=j.attribute("y").Length.toPixels("y")}else{if(j.attribute("dy").hasValue()){k+=j.attribute("dy").Length.toPixels("y")}j.y=k}j.render(g)}}};b.Element.text.prototype=new b.Element.RenderedElementBase;b.Element.TextElementBase=function(c){this.base=b.Element.RenderedElementBase;this.base(c);this.renderChildren=function(d){d.fillText(b.compressSpaces(this.getText()),this.x,this.y)};this.getText=function(){};this.measureText=function(d){var e=b.compressSpaces(this.getText());if(!d.measureText){return e.length*10}return d.measureText(e).width}};b.Element.TextElementBase.prototype=new b.Element.RenderedElementBase;b.Element.tspan=function(c){this.base=b.Element.TextElementBase;this.base(c);this.text=c.nodeType==3?c.nodeValue:c.childNodes[0].nodeValue;this.getText=function(){return this.text}};b.Element.tspan.prototype=new b.Element.TextElementBase;b.Element.tref=function(c){this.base=b.Element.TextElementBase;this.base(c);this.getText=function(){var d=this.attribute("xlink:href").Definition.getDefinition();if(d!=null){return d.children[0].getText()}}};b.Element.tref.prototype=new b.Element.TextElementBase;b.Element.a=function(d){this.base=b.Element.TextElementBase;this.base(d);this.hasText=true;for(var c=0;c<d.childNodes.length;c++){if(d.childNodes[c].nodeType!=3){this.hasText=false}}this.text=this.hasText?d.childNodes[0].nodeValue:"";this.getText=function(){return this.text};this.baseRenderChildren=this.renderChildren;this.renderChildren=function(e){if(this.hasText){this.baseRenderChildren(e);var h=new b.Property("fontSize",b.Font.Parse(b.ctx.font).fontSize);b.Mouse.checkBoundingBox(this,new b.BoundingBox(this.x,this.y-h.Length.toPixels("y"),this.x+this.measureText(e),this.y))}else{var f=new b.Element.g();f.children=this.children;f.parent=this;f.render(e)}};this.onclick=function(){window.open(this.attribute("xlink:href").value)};this.onmousemove=function(){b.ctx.canvas.style.cursor="pointer"}};b.Element.a.prototype=new b.Element.TextElementBase;b.Element.image=function(d){this.base=b.Element.RenderedElementBase;this.base(d);b.Images.push(this);this.img=document.createElement("img");this.loaded=false;var c=this;this.img.onload=function(){c.loaded=true};this.img.src=this.attribute("xlink:href").value;this.renderChildren=function(g){var f=this.attribute("x").Length.toPixels("x");var j=this.attribute("y").Length.toPixels("y");var h=this.attribute("width").Length.toPixels("x");var e=this.attribute("height").Length.toPixels("y");if(h==0||e==0){return}g.save();g.translate(f,j);b.AspectRatio(g,this.attribute("preserveAspectRatio").value,h,this.img.width,e,this.img.height,0,0);g.drawImage(this.img,0,0);g.restore()}};b.Element.image.prototype=new b.Element.RenderedElementBase;b.Element.g=function(c){this.base=b.Element.RenderedElementBase;this.base(c);this.getBoundingBox=function(){var e=new b.BoundingBox();for(var d=0;d<this.children.length;d++){e.addBoundingBox(this.children[d].getBoundingBox())}return e}};b.Element.g.prototype=new b.Element.RenderedElementBase;b.Element.symbol=function(c){this.base=b.Element.RenderedElementBase;this.base(c);this.baseSetContext=this.setContext;this.setContext=function(e){this.baseSetContext(e);if(this.attribute("viewBox").hasValue()){var f=b.ToNumberArray(this.attribute("viewBox").value);var d=f[0];var g=f[1];width=f[2];height=f[3];b.AspectRatio(e,this.attribute("preserveAspectRatio").value,this.attribute("width").Length.toPixels("x"),width,this.attribute("height").Length.toPixels("y"),height,d,g);b.ViewPort.SetCurrent(f[2],f[3])}}};b.Element.symbol.prototype=new b.Element.RenderedElementBase;b.Element.style=function(e){this.base=b.Element.ElementBase;this.base(e);var m=e.childNodes[0].nodeValue;m=m.replace(/(\/\*([^*]|[\r\n]|(\*+([^*\/]|[\r\n])))*\*+\/)|(\/\/.*)/gm,"");m=b.compressSpaces(m);var q=m.split("}");for(var l=0;l<q.length;l++){if(b.trim(q[l])!=""){var n=q[l].split("{");var o=n[0].split(",");var g=n[1].split(";");for(var h=0;h<o.length;h++){var s=b.trim(o[h]);if(s!=""){var p={};for(var f=0;f<g.length;f++){var d=g[f].split(":");var c=d[0];var r=d[1];if(c!=null&&r!=null){p[b.trim(d[0])]=new b.Property(b.trim(d[0]),b.trim(d[1]))}}b.Styles[s]=p}}}}};b.Element.style.prototype=new b.Element.ElementBase;b.Element.use=function(c){this.base=b.Element.RenderedElementBase;this.base(c);this.baseSetContext=this.setContext;this.setContext=function(d){this.baseSetContext(d);if(this.attribute("x").hasValue()){d.translate(this.attribute("x").Length.toPixels("x"),0)}if(this.attribute("y").hasValue()){d.translate(0,this.attribute("y").Length.toPixels("y"))}};this.getDefinition=function(){var d=this.attribute("xlink:href").Definition.getDefinition();if(this.attribute("width").hasValue()){d.attribute("width",true).value=this.attribute("width").value}if(this.attribute("height").hasValue()){d.attribute("height",true).value=this.attribute("height").value}return d};this.path=function(d){var e=this.getDefinition();if(e!=null){e.path(d)}};this.renderChildren=function(d){var e=this.getDefinition();if(e!=null){e.render(d)}}};b.Element.use.prototype=new b.Element.RenderedElementBase;b.Element.clipPath=function(c){this.base=b.Element.ElementBase;this.base(c);this.apply=function(d){for(var e=0;e<this.children.length;e++){if(this.children[e].path){this.children[e].path(d);d.clip()}}}};b.Element.clipPath.prototype=new b.Element.ElementBase;b.Element.title=function(c){};b.Element.title.prototype=new b.Element.ElementBase;b.Element.desc=function(c){};b.Element.desc.prototype=new b.Element.ElementBase;b.Element.MISSING=function(c){console.log("ERROR: Element '"+c.nodeName+"' not yet implemented.")};b.Element.MISSING.prototype=new b.Element.ElementBase;b.CreateElement=function(d){var c=d.nodeName.replace(/^[^:]+:/,"");var f=null;if(typeof(b.Element[c])!="undefined"){f=new b.Element[c](d)}else{f=new b.Element.MISSING(d)}f.type=d.nodeName;return f};b.load=function(c,d){b.loadXml(c,b.ajax(d))};b.loadXml=function(g,j){b.init(g);var f=function(n){var m=g.canvas;while(m){n.x-=m.offsetLeft;n.y-=m.offsetTop;m=m.offsetParent}if(window.scrollX){n.x+=window.scrollX}if(window.scrollY){n.y+=window.scrollY}return n};if(b.opts==null||b.opts.ignoreMouse!=true){g.canvas.onclick=function(n){var m=f(new b.Point(n!=null?n.clientX:event.clientX,n!=null?n.clientY:event.clientY));b.Mouse.onclick(m.x,m.y)};g.canvas.onmousemove=function(n){var m=f(new b.Point(n!=null?n.clientX:event.clientX,n!=null?n.clientY:event.clientY));b.Mouse.onmousemove(m.x,m.y)}}var l=b.parseXml(j);var k=b.CreateElement(l.documentElement);var h=true;var d=function(){if(b.opts==null||b.opts.ignoreDimensions!=true){if(k.style("width").hasValue()){g.canvas.width=k.style("width").Length.toPixels(g.canvas.parentNode.clientWidth)}if(k.style("height").hasValue()){g.canvas.height=k.style("height").Length.toPixels(g.canvas.parentNode.clientHeight)}}b.ViewPort.SetCurrent(g.canvas.clientWidth,g.canvas.clientHeight);if(b.opts!=null&&b.opts.offsetX!=null){k.attribute("x",true).value=b.opts.offsetX}if(b.opts!=null&&b.opts.offsetY!=null){k.attribute("y",true).value=b.opts.offsetY}if(b.opts!=null&&b.opts.scaleWidth!=null&&b.opts.scaleHeight!=null){k.attribute("width",true).value=b.opts.scaleWidth;k.attribute("height",true).value=b.opts.scaleHeight;k.attribute("viewBox",true).value="0 0 "+g.canvas.clientWidth+" "+g.canvas.clientHeight;k.attribute("preserveAspectRatio",true).value="none"}if(b.opts==null||b.opts.ignoreClear!=true){g.clearRect(0,0,g.canvas.clientWidth,g.canvas.clientHeight)}k.render(g);if(h){h=false;if(b.opts!=null&&typeof(b.opts.renderCallback)=="function"){b.opts.renderCallback()}}};var c=true;if(b.ImagesLoaded()){c=false;d()}b.intervalID=setInterval(function(){var m=false;if(c&&b.ImagesLoaded()){c=false;m=true}if(b.opts==null||b.opts.ignoreMouse!=true){m=m|b.Mouse.hasEvents()}if(b.opts==null||b.opts.ignoreAnimation!=true){for(var e=0;e<b.Animations.length;e++){m=m|b.Animations[e].update(1000/b.FRAMERATE)}}if(b.opts!=null&&typeof(b.opts.forceRedraw)=="function"){if(b.opts.forceRedraw()==true){m=true}}if(m){d();b.Mouse.runEvents()}},1000/b.FRAMERATE)};b.stop=function(){if(b.intervalID){clearInterval(b.intervalID)}};b.Mouse=new (function(){this.events=[];this.hasEvents=function(){return this.events.length!=0};this.onclick=function(c,d){this.events.push({type:"onclick",x:c,y:d,run:function(f){if(f.onclick){f.onclick()}}})};this.onmousemove=function(c,d){this.events.push({type:"onmousemove",x:c,y:d,run:function(f){if(f.onmousemove){f.onmousemove()}}})};this.eventElements=[];this.checkPath=function(f,c){for(var d=0;d<this.events.length;d++){var g=this.events[d];if(c.isPointInPath&&c.isPointInPath(g.x,g.y)){this.eventElements[d]=f}}};this.checkBoundingBox=function(d,g){for(var c=0;c<this.events.length;c++){var f=this.events[c];if(g.isPointInBox(f.x,f.y)){this.eventElements[c]=d}}};this.runEvents=function(){b.ctx.canvas.style.cursor="";for(var d=0;d<this.events.length;d++){var f=this.events[d];var c=this.eventElements[d];while(c){f.run(c);c=c.parent}}this.events=[];this.eventElements=[]}});return b}})();if(CanvasRenderingContext2D){CanvasRenderingContext2D.prototype.drawSvg=function(d,b,a,c,e){canvg(this.canvas,d,{ignoreMouse:true,ignoreAnimation:true,ignoreDimensions:true,ignoreClear:true,offsetX:b,offsetY:a,scaleWidth:c,scaleHeight:e})}}function RGBColor(g){this.ok=false;if(g.charAt(0)=="#"){g=g.substr(1,6)}g=g.replace(/ /g,"");g=g.toLowerCase();var a={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 c in a){if(g==c){g=a[c]}}var h=[{re:/^rgb\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})\)$/,example:["rgb(123, 234, 45)","rgb(255,234,245)"],process:function(j){return[parseInt(j[1]),parseInt(j[2]),parseInt(j[3])]}},{re:/^(\w{2})(\w{2})(\w{2})$/,example:["#00ff00","336699"],process:function(j){return[parseInt(j[1],16),parseInt(j[2],16),parseInt(j[3],16)]}},{re:/^(\w{1})(\w{1})(\w{1})$/,example:["#fb0","f0f"],process:function(j){return[parseInt(j[1]+j[1],16),parseInt(j[2]+j[2],16),parseInt(j[3]+j[3],16)]}}];for(var b=0;b<h.length;b++){var e=h[b].re;var d=h[b].process;var f=e.exec(g);if(f){channels=d(f);this.r=channels[0];this.g=channels[1];this.b=channels[2];this.ok=true}}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 l=this.r.toString(16);var k=this.g.toString(16);var j=this.b.toString(16);if(l.length==1){l="0"+l}if(k.length==1){k="0"+k}if(j.length==1){j="0"+j}return"#"+l+k+j};this.getHelpXML=function(){var m=new Array();for(var o=0;o<h.length;o++){var l=h[o].example;for(var n=0;n<l.length;n++){m[m.length]=l[n]}}for(var t in a){m[m.length]=t}var p=document.createElement("ul");p.setAttribute("id","rgbcolor-examples");for(var o=0;o<m.length;o++){try{var q=document.createElement("li");var s=new RGBColor(m[o]);var u=document.createElement("div");u.style.cssText="margin: 3px; border: 1px solid black; background:"+s.toHex()+"; color:"+s.toHex();u.appendChild(document.createTextNode("test"));var k=document.createTextNode(" "+m[o]+" -> "+s.toRGB()+" -> "+s.toHex());q.appendChild(u);q.appendChild(k);p.appendChild(q)}catch(r){}}return p}};
b'\\ No newline at end of file'
2
* canvg.js - Javascript SVG parser and renderer on Canvas
4
* Gabe Lerner (gabelerner@gmail.com)
5
* http://code.google.com/p/canvg/
7
* Requires: rgbcolor.js - http://www.phpied.com/rgb-color-parser-in-javascript/
11
window.console.log = function(str) {};
12
window.console.dir = function(str) {};
17
Array.prototype.indexOf = function(obj){
18
for(var i=0; i<this.length; i++){
29
// empty parameters: replace all 'svg' elements on page with 'canvas' elements
30
// target: canvas element or the id of a canvas element
31
// s: svg string or url to svg file
32
// opts: optional hash of options
33
// ignoreMouse: true => ignore mouse events
34
// ignoreAnimation: true => ignore animations
35
// ignoreDimensions: true => does not try to resize canvas
36
// ignoreClear: true => does not clear canvas
37
// offsetX: int => draws at a x offset
38
// offsetY: int => draws at a y offset
39
// scaleWidth: int => scales horizontally to width
40
// scaleHeight: int => scales vertically to height
41
// renderCallback: function => will call the function after the first render is completed
42
// forceRedraw: function => will call the function on every frame, if it returns true, will redraw
43
this.canvg = function (target, s, opts) {
45
if (target == null && s == null && opts == null) {
46
var svgTags = document.getElementsByTagName('svg');
47
for (var i=0; i<svgTags.length; i++) {
48
var svgTag = svgTags[i];
49
var c = document.createElement('canvas');
50
c.width = svgTag.clientWidth;
51
c.height = svgTag.clientHeight;
52
svgTag.parentNode.insertBefore(c, svgTag);
53
svgTag.parentNode.removeChild(svgTag);
54
var div = document.createElement('div');
55
div.appendChild(svgTag);
56
canvg(c, div.innerHTML);
61
if (typeof target == 'string') {
62
target = document.getElementById(target);
65
// reuse class per canvas
67
if (target.svg == null) {
77
var ctx = target.getContext('2d');
78
if (s.substr(0,1) == '<') {
79
// load from xml string
94
svg.init = function(ctx) {
100
svg.ViewPort = new (function () {
102
this.SetCurrent = function(width, height) { this.viewPorts.push({ width: width, height: height }); }
103
this.RemoveCurrent = function() { this.viewPorts.pop(); }
104
this.Current = function() { return this.viewPorts[this.viewPorts.length - 1]; }
105
this.width = function() { return this.Current().width; }
106
this.height = function() { return this.Current().height; }
107
this.ComputeSize = function(d) {
108
if (d != null && typeof(d) == 'number') return d;
109
if (d == 'x') return this.width();
110
if (d == 'y') return this.height();
111
return Math.sqrt(Math.pow(this.width(), 2) + Math.pow(this.height(), 2)) / Math.sqrt(2);
118
svg.ImagesLoaded = function() {
119
for (var i=0; i<svg.Images.length; i++) {
120
if (!svg.Images[i].loaded) return false;
126
svg.trim = function(s) { return s.replace(/^\s+|\s+$/g, ''); }
129
svg.compressSpaces = function(s) { return s.replace(/[\s\r\t\n]+/gm,' '); }
132
svg.ajax = function(url) {
134
if(window.XMLHttpRequest){AJAX=new XMLHttpRequest();}
135
else{AJAX=new ActiveXObject('Microsoft.XMLHTTP');}
137
AJAX.open('GET',url,false);
139
return AJAX.responseText;
145
svg.parseXml = function(xml) {
146
if (window.DOMParser)
148
var parser = new DOMParser();
149
return parser.parseFromString(xml, 'text/xml');
153
xml = xml.replace(/<!DOCTYPE svg[^>]*>/, '');
154
var xmlDoc = new ActiveXObject('Microsoft.XMLDOM');
155
xmlDoc.async = 'false';
161
svg.Property = function(name, value) {
165
this.hasValue = function() {
166
return (this.value != null && this.value != '');
169
// return the numerical value of the property
170
this.numValue = function() {
171
if (!this.hasValue()) return 0;
173
var n = parseFloat(this.value);
174
if ((this.value + '').match(/%$/)) {
180
this.valueOrDefault = function(def) {
181
if (this.hasValue()) return this.value;
185
this.numValueOrDefault = function(def) {
186
if (this.hasValue()) return this.numValue();
195
// augment the current color value with the opacity
196
addOpacity: function(opacity) {
197
var newValue = that.value;
198
if (opacity != null && opacity != '') {
199
var color = new RGBColor(that.value);
201
newValue = 'rgba(' + color.r + ', ' + color.g + ', ' + color.b + ', ' + opacity + ')';
204
return new svg.Property(that.name, newValue);
208
// definition extensions
210
// get the definition from the definitions table
211
getDefinition: function() {
212
var name = that.value.replace(/^(url\()?#([^\)]+)\)?$/, '$2');
213
return svg.Definitions[name];
217
return that.value.indexOf('url(') == 0
220
getFillStyle: function(e) {
221
var def = this.getDefinition();
224
if (def != null && def.createGradient) {
225
return def.createGradient(svg.ctx, e);
229
if (def != null && def.createPattern) {
230
return def.createPattern(svg.ctx, e);
239
DPI: function(viewPort) {
240
return 96.0; // TODO: compute?
243
EM: function(viewPort) {
246
var fontSize = new svg.Property('fontSize', svg.Font.Parse(svg.ctx.font).fontSize);
247
if (fontSize.hasValue()) em = fontSize.Length.toPixels(viewPort);
252
// get the length as pixels
253
toPixels: function(viewPort) {
254
if (!that.hasValue()) return 0;
255
var s = that.value+'';
256
if (s.match(/em$/)) return that.numValue() * this.EM(viewPort);
257
if (s.match(/ex$/)) return that.numValue() * this.EM(viewPort) / 2.0;
258
if (s.match(/px$/)) return that.numValue();
259
if (s.match(/pt$/)) return that.numValue() * 1.25;
260
if (s.match(/pc$/)) return that.numValue() * 15;
261
if (s.match(/cm$/)) return that.numValue() * this.DPI(viewPort) / 2.54;
262
if (s.match(/mm$/)) return that.numValue() * this.DPI(viewPort) / 25.4;
263
if (s.match(/in$/)) return that.numValue() * this.DPI(viewPort);
264
if (s.match(/%$/)) return that.numValue() * svg.ViewPort.ComputeSize(viewPort);
265
return that.numValue();
271
// get the time as milliseconds
272
toMilliseconds: function() {
273
if (!that.hasValue()) return 0;
274
var s = that.value+'';
275
if (s.match(/s$/)) return that.numValue() * 1000;
276
if (s.match(/ms$/)) return that.numValue();
277
return that.numValue();
283
// get the angle as radians
284
toRadians: function() {
285
if (!that.hasValue()) return 0;
286
var s = that.value+'';
287
if (s.match(/deg$/)) return that.numValue() * (Math.PI / 180.0);
288
if (s.match(/grad$/)) return that.numValue() * (Math.PI / 200.0);
289
if (s.match(/rad$/)) return that.numValue();
290
return that.numValue() * (Math.PI / 180.0);
296
svg.Font = new (function() {
297
this.Styles = ['normal','italic','oblique','inherit'];
298
this.Variants = ['normal','small-caps','inherit'];
299
this.Weights = ['normal','bold','bolder','lighter','100','200','300','400','500','600','700','800','900','inherit'];
301
this.CreateFont = function(fontStyle, fontVariant, fontWeight, fontSize, fontFamily, inherit) {
302
var f = inherit != null ? this.Parse(inherit) : this.CreateFont('', '', '', '', '', svg.ctx.font);
304
fontFamily: fontFamily || f.fontFamily,
305
fontSize: fontSize || f.fontSize,
306
fontStyle: fontStyle || f.fontStyle,
307
fontWeight: fontWeight || f.fontWeight,
308
fontVariant: fontVariant || f.fontVariant,
309
toString: function () { return [this.fontStyle, this.fontVariant, this.fontWeight, this.fontSize, this.fontFamily].join(' ') }
314
this.Parse = function(s) {
316
var d = svg.trim(svg.compressSpaces(s || '')).split(' ');
317
var set = { fontSize: false, fontStyle: false, fontWeight: false, fontVariant: false }
319
for (var i=0; i<d.length; i++) {
320
if (!set.fontStyle && that.Styles.indexOf(d[i]) != -1) { if (d[i] != 'inherit') f.fontStyle = d[i]; set.fontStyle = true; }
321
else if (!set.fontVariant && that.Variants.indexOf(d[i]) != -1) { if (d[i] != 'inherit') f.fontVariant = d[i]; set.fontStyle = set.fontVariant = true; }
322
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; }
323
else if (!set.fontSize) { if (d[i] != 'inherit') f.fontSize = d[i].split('/')[0]; set.fontStyle = set.fontVariant = set.fontWeight = set.fontSize = true; }
324
else { if (d[i] != 'inherit') ff += d[i]; }
325
} if (ff != '') f.fontFamily = ff;
331
svg.ToNumberArray = function(s) {
332
var a = svg.trim(svg.compressSpaces((s || '').replace(/,/g, ' '))).split(' ');
333
for (var i=0; i<a.length; i++) {
334
a[i] = parseFloat(a[i]);
338
svg.Point = function(x, y) {
342
this.angleTo = function(p) {
343
return Math.atan2(p.y - this.y, p.x - this.x);
346
this.applyTransform = function(v) {
347
var xp = this.x * v[0] + this.y * v[2] + v[4];
348
var yp = this.x * v[1] + this.y * v[3] + v[5];
353
svg.CreatePoint = function(s) {
354
var a = svg.ToNumberArray(s);
355
return new svg.Point(a[0], a[1]);
357
svg.CreatePath = function(s) {
358
var a = svg.ToNumberArray(s);
360
for (var i=0; i<a.length; i+=2) {
361
path.push(new svg.Point(a[i], a[i+1]));
367
svg.BoundingBox = function(x1, y1, x2, y2) { // pass in initial points if you want
368
this.x1 = Number.NaN;
369
this.y1 = Number.NaN;
370
this.x2 = Number.NaN;
371
this.y2 = Number.NaN;
373
this.x = function() { return this.x1; }
374
this.y = function() { return this.y1; }
375
this.width = function() { return this.x2 - this.x1; }
376
this.height = function() { return this.y2 - this.y1; }
378
this.addPoint = function(x, y) {
380
if (isNaN(this.x1) || isNaN(this.x2)) {
384
if (x < this.x1) this.x1 = x;
385
if (x > this.x2) this.x2 = x;
389
if (isNaN(this.y1) || isNaN(this.y2)) {
393
if (y < this.y1) this.y1 = y;
394
if (y > this.y2) this.y2 = y;
397
this.addX = function(x) { this.addPoint(x, null); }
398
this.addY = function(y) { this.addPoint(null, y); }
400
this.addBoundingBox = function(bb) {
401
this.addPoint(bb.x1, bb.y1);
402
this.addPoint(bb.x2, bb.y2);
405
this.addQuadraticCurve = function(p0x, p0y, p1x, p1y, p2x, p2y) {
406
var cp1x = p0x + 2/3 * (p1x - p0x); // CP1 = QP0 + 2/3 *(QP1-QP0)
407
var cp1y = p0y + 2/3 * (p1y - p0y); // CP1 = QP0 + 2/3 *(QP1-QP0)
408
var cp2x = cp1x + 1/3 * (p2x - p0x); // CP2 = CP1 + 1/3 *(QP2-QP0)
409
var cp2y = cp1y + 1/3 * (p2y - p0y); // CP2 = CP1 + 1/3 *(QP2-QP0)
410
this.addBezierCurve(p0x, p0y, cp1x, cp2x, cp1y, cp2y, p2x, p2y);
413
this.addBezierCurve = function(p0x, p0y, p1x, p1y, p2x, p2y, p3x, p3y) {
414
// from http://blog.hackers-cafe.net/2009/06/how-to-calculate-bezier-curves-bounding.html
415
var p0 = [p0x, p0y], p1 = [p1x, p1y], p2 = [p2x, p2y], p3 = [p3x, p3y];
416
this.addPoint(p0[0], p0[1]);
417
this.addPoint(p3[0], p3[1]);
419
for (i=0; i<=1; i++) {
420
var f = function(t) {
421
return Math.pow(1-t, 3) * p0[i]
422
+ 3 * Math.pow(1-t, 2) * t * p1[i]
423
+ 3 * (1-t) * Math.pow(t, 2) * p2[i]
424
+ Math.pow(t, 3) * p3[i];
427
var b = 6 * p0[i] - 12 * p1[i] + 6 * p2[i];
428
var a = -3 * p0[i] + 9 * p1[i] - 9 * p2[i] + 3 * p3[i];
429
var c = 3 * p1[i] - 3 * p0[i];
432
if (b == 0) continue;
434
if (0 < t && t < 1) {
435
if (i == 0) this.addX(f(t));
436
if (i == 1) this.addY(f(t));
441
var b2ac = Math.pow(b, 2) - 4 * c * a;
442
if (b2ac < 0) continue;
443
var t1 = (-b + Math.sqrt(b2ac)) / (2 * a);
444
if (0 < t1 && t1 < 1) {
445
if (i == 0) this.addX(f(t1));
446
if (i == 1) this.addY(f(t1));
448
var t2 = (-b - Math.sqrt(b2ac)) / (2 * a);
449
if (0 < t2 && t2 < 1) {
450
if (i == 0) this.addX(f(t2));
451
if (i == 1) this.addY(f(t2));
456
this.isPointInBox = function(x, y) {
457
return (this.x1 <= x && x <= this.x2 && this.y1 <= y && y <= this.y2);
460
this.addPoint(x1, y1);
461
this.addPoint(x2, y2);
465
svg.Transform = function(v) {
470
this.Type.translate = function(s) {
471
this.p = svg.CreatePoint(s);
472
this.apply = function(ctx) {
473
ctx.translate(this.p.x || 0.0, this.p.y || 0.0);
475
this.applyToPoint = function(p) {
476
p.applyTransform([1, 0, 0, 1, this.p.x || 0.0, this.p.y || 0.0]);
481
this.Type.rotate = function(s) {
482
var a = svg.ToNumberArray(s);
483
this.angle = new svg.Property('angle', a[0]);
486
this.apply = function(ctx) {
487
ctx.translate(this.cx, this.cy);
488
ctx.rotate(this.angle.Angle.toRadians());
489
ctx.translate(-this.cx, -this.cy);
491
this.applyToPoint = function(p) {
492
var a = this.angle.Angle.toRadians();
493
p.applyTransform([1, 0, 0, 1, this.p.x || 0.0, this.p.y || 0.0]);
494
p.applyTransform([Math.cos(a), Math.sin(a), -Math.sin(a), Math.cos(a), 0, 0]);
495
p.applyTransform([1, 0, 0, 1, -this.p.x || 0.0, -this.p.y || 0.0]);
499
this.Type.scale = function(s) {
500
this.p = svg.CreatePoint(s);
501
this.apply = function(ctx) {
502
ctx.scale(this.p.x || 1.0, this.p.y || this.p.x || 1.0);
504
this.applyToPoint = function(p) {
505
p.applyTransform([this.p.x || 0.0, 0, 0, this.p.y || 0.0, 0, 0]);
509
this.Type.matrix = function(s) {
510
this.m = svg.ToNumberArray(s);
511
this.apply = function(ctx) {
512
ctx.transform(this.m[0], this.m[1], this.m[2], this.m[3], this.m[4], this.m[5]);
514
this.applyToPoint = function(p) {
515
p.applyTransform(this.m);
519
this.Type.SkewBase = function(s) {
520
this.base = that.Type.matrix;
522
this.angle = new svg.Property('angle', s);
524
this.Type.SkewBase.prototype = new this.Type.matrix;
526
this.Type.skewX = function(s) {
527
this.base = that.Type.SkewBase;
529
this.m = [1, 0, Math.tan(this.angle.Angle.toRadians()), 1, 0, 0];
531
this.Type.skewX.prototype = new this.Type.SkewBase;
533
this.Type.skewY = function(s) {
534
this.base = that.Type.SkewBase;
536
this.m = [1, Math.tan(this.angle.Angle.toRadians()), 0, 1, 0, 0];
538
this.Type.skewY.prototype = new this.Type.SkewBase;
540
this.transforms = [];
542
this.apply = function(ctx) {
543
for (var i=0; i<this.transforms.length; i++) {
544
this.transforms[i].apply(ctx);
548
this.applyToPoint = function(p) {
549
for (var i=0; i<this.transforms.length; i++) {
550
this.transforms[i].applyToPoint(p);
554
var data = v.split(/\s(?=[a-z])/);
555
for (var i=0; i<data.length; i++) {
556
var type = data[i].split('(')[0];
557
var s = data[i].split('(')[1].replace(')','');
558
var transform = new this.Type[type](s);
559
this.transforms.push(transform);
564
svg.AspectRatio = function(ctx, aspectRatio, width, desiredWidth, height, desiredHeight, minX, minY, refX, refY) {
565
// aspect ratio - http://www.w3.org/TR/SVG/coords.html#PreserveAspectRatioAttribute
566
aspectRatio = svg.compressSpaces(aspectRatio);
567
aspectRatio = aspectRatio.replace(/^defer\s/,''); // ignore defer
568
var align = aspectRatio.split(' ')[0] || 'xMidYMid';
569
var meetOrSlice = aspectRatio.split(' ')[1] || 'meet';
572
var scaleX = width / desiredWidth;
573
var scaleY = height / desiredHeight;
574
var scaleMin = Math.min(scaleX, scaleY);
575
var scaleMax = Math.max(scaleX, scaleY);
576
if (meetOrSlice == 'meet') { desiredWidth *= scaleMin; desiredHeight *= scaleMin; }
577
if (meetOrSlice == 'slice') { desiredWidth *= scaleMax; desiredHeight *= scaleMax; }
579
refX = new svg.Property('refX', refX);
580
refY = new svg.Property('refY', refY);
581
if (refX.hasValue() && refY.hasValue()) {
582
ctx.translate(-scaleMin * refX.Length.toPixels('x'), -scaleMin * refY.Length.toPixels('y'));
586
if (align.match(/^xMid/) && ((meetOrSlice == 'meet' && scaleMin == scaleY) || (meetOrSlice == 'slice' && scaleMax == scaleY))) ctx.translate(width / 2.0 - desiredWidth / 2.0, 0);
587
if (align.match(/YMid$/) && ((meetOrSlice == 'meet' && scaleMin == scaleX) || (meetOrSlice == 'slice' && scaleMax == scaleX))) ctx.translate(0, height / 2.0 - desiredHeight / 2.0);
588
if (align.match(/^xMax/) && ((meetOrSlice == 'meet' && scaleMin == scaleY) || (meetOrSlice == 'slice' && scaleMax == scaleY))) ctx.translate(width - desiredWidth, 0);
589
if (align.match(/YMax$/) && ((meetOrSlice == 'meet' && scaleMin == scaleX) || (meetOrSlice == 'slice' && scaleMax == scaleX))) ctx.translate(0, height - desiredHeight);
593
if (align == 'none') ctx.scale(scaleX, scaleY);
594
else if (meetOrSlice == 'meet') ctx.scale(scaleMin, scaleMin);
595
else if (meetOrSlice == 'slice') ctx.scale(scaleMax, scaleMax);
598
ctx.translate(minX == null ? 0 : -minX, minY == null ? 0 : -minY);
604
svg.Element.ElementBase = function(node) {
605
this.attributes = {};
609
// get or create attribute
610
this.attribute = function(name, createIfNotExists) {
611
var a = this.attributes[name];
612
if (a != null) return a;
614
a = new svg.Property(name, '');
615
if (createIfNotExists == true) this.attributes[name] = a;
619
// get or create style
620
this.style = function(name, createIfNotExists) {
621
var s = this.styles[name];
622
if (s != null) return s;
624
var a = this.attribute(name);
625
if (a != null && a.hasValue()) {
629
s = new svg.Property(name, '');
630
if (createIfNotExists == true) this.styles[name] = s;
635
this.render = function(ctx) {
636
// don't render display=none
637
if (this.attribute('display').value == 'none') return;
640
this.setContext(ctx);
641
this.renderChildren(ctx);
642
this.clearContext(ctx);
647
this.setContext = function(ctx) {
651
// base clear context
652
this.clearContext = function(ctx) {
656
// base render children
657
this.renderChildren = function(ctx) {
658
for (var i=0; i<this.children.length; i++) {
659
this.children[i].render(ctx);
663
this.addChild = function(childNode, create) {
664
var child = childNode;
665
if (create) child = svg.CreateElement(childNode);
667
this.children.push(child);
670
if (node != null && node.nodeType == 1) { //ELEMENT_NODE
672
for (var i=0; i<node.childNodes.length; i++) {
673
var childNode = node.childNodes[i];
674
if (childNode.nodeType == 1) this.addChild(childNode, true); //ELEMENT_NODE
678
for (var i=0; i<node.attributes.length; i++) {
679
var attribute = node.attributes[i];
680
this.attributes[attribute.nodeName] = new svg.Property(attribute.nodeName, attribute.nodeValue);
684
var styles = svg.Styles[this.type];
685
if (styles != null) {
686
for (var name in styles) {
687
this.styles[name] = styles[name];
692
if (this.attribute('class').hasValue()) {
693
var classes = svg.compressSpaces(this.attribute('class').value).split(' ');
694
for (var j=0; j<classes.length; j++) {
695
styles = svg.Styles['.'+classes[j]];
696
if (styles != null) {
697
for (var name in styles) {
698
this.styles[name] = styles[name];
705
if (this.attribute('style').hasValue()) {
706
var styles = this.attribute('style').value.split(';');
707
for (var i=0; i<styles.length; i++) {
708
if (svg.trim(styles[i]) != '') {
709
var style = styles[i].split(':');
710
var name = svg.trim(style[0]);
711
var value = svg.trim(style[1]);
712
this.styles[name] = new svg.Property(name, value);
718
if (this.attribute('id').hasValue()) {
719
if (svg.Definitions[this.attribute('id').value] == null) {
720
svg.Definitions[this.attribute('id').value] = this;
726
svg.Element.RenderedElementBase = function(node) {
727
this.base = svg.Element.ElementBase;
730
this.setContext = function(ctx) {
732
if (this.style('fill').Definition.isUrl()) {
733
var fs = this.style('fill').Definition.getFillStyle(this);
734
if (fs != null) ctx.fillStyle = fs;
736
else if (this.style('fill').hasValue()) {
737
var fillStyle = this.style('fill');
738
if (this.style('fill-opacity').hasValue()) fillStyle = fillStyle.Color.addOpacity(this.style('fill-opacity').value);
739
ctx.fillStyle = (fillStyle.value == 'none' ? 'rgba(0,0,0,0)' : fillStyle.value);
743
if (this.style('stroke').Definition.isUrl()) {
744
var fs = this.style('stroke').Definition.getFillStyle(this);
745
if (fs != null) ctx.strokeStyle = fs;
747
else if (this.style('stroke').hasValue()) {
748
var strokeStyle = this.style('stroke');
749
if (this.style('stroke-opacity').hasValue()) strokeStyle = strokeStyle.Color.addOpacity(this.style('stroke-opacity').value);
750
ctx.strokeStyle = (strokeStyle.value == 'none' ? 'rgba(0,0,0,0)' : strokeStyle.value);
752
if (this.style('stroke-width').hasValue()) ctx.lineWidth = this.style('stroke-width').Length.toPixels();
753
if (this.style('stroke-linecap').hasValue()) ctx.lineCap = this.style('stroke-linecap').value;
754
if (this.style('stroke-linejoin').hasValue()) ctx.lineJoin = this.style('stroke-linejoin').value;
755
if (this.style('stroke-miterlimit').hasValue()) ctx.miterLimit = this.style('stroke-miterlimit').value;
758
if (typeof(ctx.font) != 'undefined') {
759
ctx.font = svg.Font.CreateFont(
760
this.style('font-style').value,
761
this.style('font-variant').value,
762
this.style('font-weight').value,
763
this.style('font-size').hasValue() ? this.style('font-size').Length.toPixels() + 'px' : '',
764
this.style('font-family').value).toString();
768
if (this.attribute('transform').hasValue()) {
769
var transform = new svg.Transform(this.attribute('transform').value);
770
transform.apply(ctx);
774
if (this.attribute('clip-path').hasValue()) {
775
var clip = this.attribute('clip-path').Definition.getDefinition();
776
if (clip != null) clip.apply(ctx);
780
if (this.style('opacity').hasValue()) {
781
ctx.globalAlpha = this.style('opacity').numValue();
785
svg.Element.RenderedElementBase.prototype = new svg.Element.ElementBase;
787
svg.Element.PathElementBase = function(node) {
788
this.base = svg.Element.RenderedElementBase;
791
this.path = function(ctx) {
792
if (ctx != null) ctx.beginPath();
793
return new svg.BoundingBox();
796
this.renderChildren = function(ctx) {
798
svg.Mouse.checkPath(this, ctx);
799
if (ctx.fillStyle != '') ctx.fill();
800
if (ctx.strokeStyle != '') ctx.stroke();
802
var markers = this.getMarkers();
803
if (markers != null) {
804
if (this.attribute('marker-start').Definition.isUrl()) {
805
var marker = this.attribute('marker-start').Definition.getDefinition();
806
marker.render(ctx, markers[0][0], markers[0][1]);
808
if (this.attribute('marker-mid').Definition.isUrl()) {
809
var marker = this.attribute('marker-mid').Definition.getDefinition();
810
for (var i=1;i<markers.length-1;i++) {
811
marker.render(ctx, markers[i][0], markers[i][1]);
814
if (this.attribute('marker-end').Definition.isUrl()) {
815
var marker = this.attribute('marker-end').Definition.getDefinition();
816
marker.render(ctx, markers[markers.length-1][0], markers[markers.length-1][1]);
821
this.getBoundingBox = function() {
825
this.getMarkers = function() {
829
svg.Element.PathElementBase.prototype = new svg.Element.RenderedElementBase;
832
svg.Element.svg = function(node) {
833
this.base = svg.Element.RenderedElementBase;
836
this.baseClearContext = this.clearContext;
837
this.clearContext = function(ctx) {
838
this.baseClearContext(ctx);
839
svg.ViewPort.RemoveCurrent();
842
this.baseSetContext = this.setContext;
843
this.setContext = function(ctx) {
845
ctx.strokeStyle = 'rgba(0,0,0,0)';
846
ctx.lineCap = 'butt';
847
ctx.lineJoin = 'miter';
850
this.baseSetContext(ctx);
852
// create new view port
853
if (this.attribute('x').hasValue() && this.attribute('y').hasValue()) {
854
ctx.translate(this.attribute('x').Length.toPixels('x'), this.attribute('y').Length.toPixels('y'));
857
var width = svg.ViewPort.width();
858
var height = svg.ViewPort.height();
859
if (this.attribute('width').hasValue() && this.attribute('height').hasValue()) {
860
width = this.attribute('width').Length.toPixels('x');
861
height = this.attribute('height').Length.toPixels('y');
865
if (this.attribute('refX').hasValue() && this.attribute('refY').hasValue()) {
866
x = -this.attribute('refX').Length.toPixels('x');
867
y = -this.attribute('refY').Length.toPixels('y');
872
ctx.lineTo(width, y);
873
ctx.lineTo(width, height);
874
ctx.lineTo(x, height);
878
svg.ViewPort.SetCurrent(width, height);
881
if (this.attribute('viewBox').hasValue()) {
882
var viewBox = svg.ToNumberArray(this.attribute('viewBox').value);
883
var minX = viewBox[0];
884
var minY = viewBox[1];
889
this.attribute('preserveAspectRatio').value,
890
svg.ViewPort.width(),
892
svg.ViewPort.height(),
896
this.attribute('refX').value,
897
this.attribute('refY').value);
899
svg.ViewPort.RemoveCurrent();
900
svg.ViewPort.SetCurrent(viewBox[2], viewBox[3]);
904
svg.Element.svg.prototype = new svg.Element.RenderedElementBase;
907
svg.Element.rect = function(node) {
908
this.base = svg.Element.PathElementBase;
911
this.path = function(ctx) {
912
var x = this.attribute('x').Length.toPixels('x');
913
var y = this.attribute('y').Length.toPixels('y');
914
var width = this.attribute('width').Length.toPixels('x');
915
var height = this.attribute('height').Length.toPixels('y');
916
var rx = this.attribute('rx').Length.toPixels('x');
917
var ry = this.attribute('ry').Length.toPixels('y');
918
if (this.attribute('rx').hasValue() && !this.attribute('ry').hasValue()) ry = rx;
919
if (this.attribute('ry').hasValue() && !this.attribute('rx').hasValue()) rx = ry;
923
ctx.moveTo(x + rx, y);
924
ctx.lineTo(x + width - rx, y);
925
ctx.quadraticCurveTo(x + width, y, x + width, y + ry)
926
ctx.lineTo(x + width, y + height - ry);
927
ctx.quadraticCurveTo(x + width, y + height, x + width - rx, y + height)
928
ctx.lineTo(x + rx, y + height);
929
ctx.quadraticCurveTo(x, y + height, x, y + height - ry)
930
ctx.lineTo(x, y + ry);
931
ctx.quadraticCurveTo(x, y, x + rx, y)
935
return new svg.BoundingBox(x, y, x + width, y + height);
938
svg.Element.rect.prototype = new svg.Element.PathElementBase;
941
svg.Element.circle = function(node) {
942
this.base = svg.Element.PathElementBase;
945
this.path = function(ctx) {
946
var cx = this.attribute('cx').Length.toPixels('x');
947
var cy = this.attribute('cy').Length.toPixels('y');
948
var r = this.attribute('r').Length.toPixels();
952
ctx.arc(cx, cy, r, 0, Math.PI * 2, true);
956
return new svg.BoundingBox(cx - r, cy - r, cx + r, cy + r);
959
svg.Element.circle.prototype = new svg.Element.PathElementBase;
962
svg.Element.ellipse = function(node) {
963
this.base = svg.Element.PathElementBase;
966
this.path = function(ctx) {
967
var KAPPA = 4 * ((Math.sqrt(2) - 1) / 3);
968
var rx = this.attribute('rx').Length.toPixels('x');
969
var ry = this.attribute('ry').Length.toPixels('y');
970
var cx = this.attribute('cx').Length.toPixels('x');
971
var cy = this.attribute('cy').Length.toPixels('y');
975
ctx.moveTo(cx, cy - ry);
976
ctx.bezierCurveTo(cx + (KAPPA * rx), cy - ry, cx + rx, cy - (KAPPA * ry), cx + rx, cy);
977
ctx.bezierCurveTo(cx + rx, cy + (KAPPA * ry), cx + (KAPPA * rx), cy + ry, cx, cy + ry);
978
ctx.bezierCurveTo(cx - (KAPPA * rx), cy + ry, cx - rx, cy + (KAPPA * ry), cx - rx, cy);
979
ctx.bezierCurveTo(cx - rx, cy - (KAPPA * ry), cx - (KAPPA * rx), cy - ry, cx, cy - ry);
983
return new svg.BoundingBox(cx - rx, cy - ry, cx + rx, cy + ry);
986
svg.Element.ellipse.prototype = new svg.Element.PathElementBase;
989
svg.Element.line = function(node) {
990
this.base = svg.Element.PathElementBase;
993
this.getPoints = function() {
995
new svg.Point(this.attribute('x1').Length.toPixels('x'), this.attribute('y1').Length.toPixels('y')),
996
new svg.Point(this.attribute('x2').Length.toPixels('x'), this.attribute('y2').Length.toPixels('y'))];
999
this.path = function(ctx) {
1000
var points = this.getPoints();
1004
ctx.moveTo(points[0].x, points[0].y);
1005
ctx.lineTo(points[1].x, points[1].y);
1008
return new svg.BoundingBox(points[0].x, points[0].y, points[1].x, points[1].y);
1011
this.getMarkers = function() {
1012
var points = this.getPoints();
1013
var a = points[0].angleTo(points[1]);
1014
return [[points[0], a], [points[1], a]];
1017
svg.Element.line.prototype = new svg.Element.PathElementBase;
1020
svg.Element.polyline = function(node) {
1021
this.base = svg.Element.PathElementBase;
1024
this.points = svg.CreatePath(this.attribute('points').value);
1025
this.path = function(ctx) {
1026
var bb = new svg.BoundingBox(this.points[0].x, this.points[0].y);
1029
ctx.moveTo(this.points[0].x, this.points[0].y);
1031
for (var i=1; i<this.points.length; i++) {
1032
bb.addPoint(this.points[i].x, this.points[i].y);
1033
if (ctx != null) ctx.lineTo(this.points[i].x, this.points[i].y);
1038
this.getMarkers = function() {
1040
for (var i=0; i<this.points.length - 1; i++) {
1041
markers.push([this.points[i], this.points[i].angleTo(this.points[i+1])]);
1043
markers.push([this.points[this.points.length-1], markers[markers.length-1][1]]);
1047
svg.Element.polyline.prototype = new svg.Element.PathElementBase;
1050
svg.Element.polygon = function(node) {
1051
this.base = svg.Element.polyline;
1054
this.basePath = this.path;
1055
this.path = function(ctx) {
1056
var bb = this.basePath(ctx);
1058
ctx.lineTo(this.points[0].x, this.points[0].y);
1064
svg.Element.polygon.prototype = new svg.Element.polyline;
1067
svg.Element.path = function(node) {
1068
this.base = svg.Element.PathElementBase;
1071
var d = this.attribute('d').value;
1072
// TODO: floating points, convert to real lexer based on http://www.w3.org/TR/SVG11/paths.html#PathDataBNF
1073
d = d.replace(/,/gm,' '); // get rid of all commas
1074
d = d.replace(/([MmZzLlHhVvCcSsQqTtAa])([MmZzLlHhVvCcSsQqTtAa])/gm,'$1 $2'); // separate commands from commands
1075
d = d.replace(/([MmZzLlHhVvCcSsQqTtAa])([MmZzLlHhVvCcSsQqTtAa])/gm,'$1 $2'); // separate commands from commands
1076
d = d.replace(/([MmZzLlHhVvCcSsQqTtAa])([^\s])/gm,'$1 $2'); // separate commands from points
1077
d = d.replace(/([^\s])([MmZzLlHhVvCcSsQqTtAa])/gm,'$1 $2'); // separate commands from points
1078
d = d.replace(/([0-9])([+\-])/gm,'$1 $2'); // separate digits when no comma
1079
d = d.replace(/(\.[0-9]*)(\.)/gm,'$1 $2'); // separate digits when no comma
1080
d = d.replace(/([Aa](\s+[0-9]+){3})\s+([01])\s*([01])/gm,'$1 $3 $4 '); // shorthand elliptical arc path syntax
1081
d = svg.compressSpaces(d); // compress multiple spaces
1083
this.PathParser = new (function(d) {
1084
this.tokens = d.split(' ');
1086
this.reset = function() {
1089
this.previousCommand = '';
1090
this.start = new svg.Point(0, 0);
1091
this.control = new svg.Point(0, 0);
1092
this.current = new svg.Point(0, 0);
1097
this.isEnd = function() {
1098
return this.i >= this.tokens.length - 1;
1101
this.isCommandOrEnd = function() {
1102
if (this.isEnd()) return true;
1103
return this.tokens[this.i + 1].match(/[A-Za-z]/) != null;
1106
this.isRelativeCommand = function() {
1107
return this.command == this.command.toLowerCase();
1110
this.getToken = function() {
1111
this.i = this.i + 1;
1112
return this.tokens[this.i];
1115
this.getScalar = function() {
1116
return parseFloat(this.getToken());
1119
this.nextCommand = function() {
1120
this.previousCommand = this.command;
1121
this.command = this.getToken();
1124
this.getPoint = function() {
1125
var p = new svg.Point(this.getScalar(), this.getScalar());
1126
return this.makeAbsolute(p);
1129
this.getAsControlPoint = function() {
1130
var p = this.getPoint();
1135
this.getAsCurrentPoint = function() {
1136
var p = this.getPoint();
1141
this.getReflectedControlPoint = function() {
1142
if (this.previousCommand.toLowerCase() != 'c' && this.previousCommand.toLowerCase() != 's') {
1143
return this.current;
1147
var p = new svg.Point(2 * this.current.x - this.control.x, 2 * this.current.y - this.control.y);
1151
this.makeAbsolute = function(p) {
1152
if (this.isRelativeCommand()) {
1153
p.x = this.current.x + p.x;
1154
p.y = this.current.y + p.y;
1159
this.addMarker = function(p, from) {
1160
this.addMarkerAngle(p, from == null ? null : from.angleTo(p));
1163
this.addMarkerAngle = function(p, a) {
1164
this.points.push(p);
1165
this.angles.push(a);
1168
this.getMarkerPoints = function() { return this.points; }
1169
this.getMarkerAngles = function() {
1170
for (var i=0; i<this.angles.length; i++) {
1171
if (this.angles[i] == null) {
1172
for (var j=i+1; j<this.angles.length; j++) {
1173
if (this.angles[j] != null) {
1174
this.angles[i] = this.angles[j];
1184
this.path = function(ctx) {
1185
var pp = this.PathParser;
1188
var bb = new svg.BoundingBox();
1190
if(this.attribute('visibility').value=='hidden') return;
1192
if (ctx != null) ctx.beginPath();
1193
while (!pp.isEnd()) {
1195
switch (pp.command.toUpperCase()) {
1197
var p = pp.getAsCurrentPoint();
1199
bb.addPoint(p.x, p.y);
1200
if (ctx != null) ctx.moveTo(p.x, p.y);
1201
pp.start = pp.current;
1202
while (!pp.isCommandOrEnd()) {
1203
var p = pp.getAsCurrentPoint();
1205
bb.addPoint(p.x, p.y);
1206
if (ctx != null) ctx.lineTo(p.x, p.y);
1210
while (!pp.isCommandOrEnd()) {
1212
var p = pp.getAsCurrentPoint();
1214
bb.addPoint(p.x, p.y);
1215
if (ctx != null) ctx.lineTo(p.x, p.y);
1219
while (!pp.isCommandOrEnd()) {
1220
var newP = new svg.Point((pp.isRelativeCommand() ? pp.current.x : 0) + pp.getScalar(), pp.current.y);
1221
pp.addMarker(newP, pp.current);
1223
bb.addPoint(pp.current.x, pp.current.y);
1224
if (ctx != null) ctx.lineTo(pp.current.x, pp.current.y);
1228
while (!pp.isCommandOrEnd()) {
1229
var newP = new svg.Point(pp.current.x, (pp.isRelativeCommand() ? pp.current.y : 0) + pp.getScalar());
1230
pp.addMarker(newP, pp.current);
1232
bb.addPoint(pp.current.x, pp.current.y);
1233
if (ctx != null) ctx.lineTo(pp.current.x, pp.current.y);
1237
while (!pp.isCommandOrEnd()) {
1238
var curr = pp.current;
1239
var p1 = pp.getPoint();
1240
var cntrl = pp.getAsControlPoint();
1241
var cp = pp.getAsCurrentPoint();
1242
pp.addMarker(cp, cntrl);
1243
bb.addBezierCurve(curr.x, curr.y, p1.x, p1.y, cntrl.x, cntrl.y, cp.x, cp.y);
1244
if (ctx != null) ctx.bezierCurveTo(p1.x, p1.y, cntrl.x, cntrl.y, cp.x, cp.y);
1248
while (!pp.isCommandOrEnd()) {
1249
var curr = pp.current;
1250
var p1 = pp.getReflectedControlPoint();
1251
var cntrl = pp.getAsControlPoint();
1252
var cp = pp.getAsCurrentPoint();
1253
pp.addMarker(cp, cntrl);
1254
bb.addBezierCurve(curr.x, curr.y, p1.x, p1.y, cntrl.x, cntrl.y, cp.x, cp.y);
1255
if (ctx != null) ctx.bezierCurveTo(p1.x, p1.y, cntrl.x, cntrl.y, cp.x, cp.y);
1259
while (!pp.isCommandOrEnd()) {
1260
var curr = pp.current;
1261
var cntrl = pp.getAsControlPoint();
1262
var cp = pp.getAsCurrentPoint();
1263
pp.addMarker(cp, cntrl);
1264
bb.addQuadraticCurve(curr.x, curr.y, cntrl.x, cntrl.y, cp.x, cp.y);
1265
if (ctx != null) ctx.quadraticCurveTo(cntrl.x, cntrl.y, cp.x, cp.y);
1269
while (!pp.isCommandOrEnd()) {
1270
var curr = pp.current;
1271
var cntrl = pp.getReflectedControlPoint();
1273
var cp = pp.getAsCurrentPoint();
1274
pp.addMarker(cp, cntrl);
1275
bb.addQuadraticCurve(curr.x, curr.y, cntrl.x, cntrl.y, cp.x, cp.y);
1276
if (ctx != null) ctx.quadraticCurveTo(cntrl.x, cntrl.y, cp.x, cp.y);
1280
while (!pp.isCommandOrEnd()) {
1281
var curr = pp.current;
1282
var rx = pp.getScalar();
1283
var ry = pp.getScalar();
1284
var xAxisRotation = pp.getScalar() * (Math.PI / 180.0);
1285
var largeArcFlag = pp.getScalar();
1286
var sweepFlag = pp.getScalar();
1287
var cp = pp.getAsCurrentPoint();
1289
// Conversion from endpoint to center parameterization
1290
// http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes
1292
var currp = new svg.Point(
1293
Math.cos(xAxisRotation) * (curr.x - cp.x) / 2.0 + Math.sin(xAxisRotation) * (curr.y - cp.y) / 2.0,
1294
-Math.sin(xAxisRotation) * (curr.x - cp.x) / 2.0 + Math.cos(xAxisRotation) * (curr.y - cp.y) / 2.0
1297
var l = Math.pow(currp.x,2)/Math.pow(rx,2)+Math.pow(currp.y,2)/Math.pow(ry,2);
1303
var s = (largeArcFlag == sweepFlag ? -1 : 1) * Math.sqrt(
1304
((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))) /
1305
(Math.pow(rx,2)*Math.pow(currp.y,2)+Math.pow(ry,2)*Math.pow(currp.x,2))
1307
if (isNaN(s)) s = 0;
1308
var cpp = new svg.Point(s * rx * currp.y / ry, s * -ry * currp.x / rx);
1310
var centp = new svg.Point(
1311
(curr.x + cp.x) / 2.0 + Math.cos(xAxisRotation) * cpp.x - Math.sin(xAxisRotation) * cpp.y,
1312
(curr.y + cp.y) / 2.0 + Math.sin(xAxisRotation) * cpp.x + Math.cos(xAxisRotation) * cpp.y
1315
var m = function(v) { return Math.sqrt(Math.pow(v[0],2) + Math.pow(v[1],2)); }
1316
// ratio between two vectors
1317
var r = function(u, v) { return (u[0]*v[0]+u[1]*v[1]) / (m(u)*m(v)) }
1318
// angle between two vectors
1319
var a = function(u, v) { return (u[0]*v[1] < u[1]*v[0] ? -1 : 1) * Math.acos(r(u,v)); }
1321
var a1 = a([1,0], [(currp.x-cpp.x)/rx,(currp.y-cpp.y)/ry]);
1323
var u = [(currp.x-cpp.x)/rx,(currp.y-cpp.y)/ry];
1324
var v = [(-currp.x-cpp.x)/rx,(-currp.y-cpp.y)/ry];
1326
if (r(u,v) <= -1) ad = Math.PI;
1327
if (r(u,v) >= 1) ad = 0;
1329
if (sweepFlag == 0 && ad > 0) ad = ad - 2 * Math.PI;
1330
if (sweepFlag == 1 && ad < 0) ad = ad + 2 * Math.PI;
1333
var halfWay = new svg.Point(
1334
centp.x - rx * Math.cos((a1 + ad) / 2),
1335
centp.y - ry * Math.sin((a1 + ad) / 2)
1337
pp.addMarkerAngle(halfWay, (a1 + ad) / 2 + (sweepFlag == 0 ? 1 : -1) * Math.PI / 2);
1338
pp.addMarkerAngle(cp, ad + (sweepFlag == 0 ? 1 : -1) * Math.PI / 2);
1340
bb.addPoint(cp.x, cp.y); // TODO: this is too naive, make it better
1342
var r = rx > ry ? rx : ry;
1343
var sx = rx > ry ? 1 : rx / ry;
1344
var sy = rx > ry ? ry / rx : 1;
1346
ctx.translate(centp.x, centp.y);
1347
ctx.rotate(xAxisRotation);
1349
ctx.arc(0, 0, r, a1, a1 + ad, 1 - sweepFlag);
1350
ctx.scale(1/sx, 1/sy);
1351
ctx.rotate(-xAxisRotation);
1352
ctx.translate(-centp.x, -centp.y);
1357
if (ctx != null) ctx.closePath();
1358
pp.current = pp.start;
1365
this.getMarkers = function() {
1366
var points = this.PathParser.getMarkerPoints();
1367
var angles = this.PathParser.getMarkerAngles();
1370
for (var i=0; i<points.length; i++) {
1371
markers.push([points[i], angles[i]]);
1376
svg.Element.path.prototype = new svg.Element.PathElementBase;
1379
svg.Element.pattern = function(node) {
1380
this.base = svg.Element.ElementBase;
1383
this.createPattern = function(ctx, element) {
1384
// render me using a temporary svg element
1385
var tempSvg = new svg.Element.svg();
1386
tempSvg.attributes['viewBox'] = new svg.Property('viewBox', this.attribute('viewBox').value);
1387
tempSvg.attributes['x'] = new svg.Property('x', this.attribute('x').value);
1388
tempSvg.attributes['y'] = new svg.Property('y', this.attribute('y').value);
1389
tempSvg.attributes['width'] = new svg.Property('width', this.attribute('width').value);
1390
tempSvg.attributes['height'] = new svg.Property('height', this.attribute('height').value);
1391
tempSvg.children = this.children;
1393
var c = document.createElement('canvas');
1394
c.width = this.attribute('width').Length.toPixels();
1395
c.height = this.attribute('height').Length.toPixels();
1396
tempSvg.render(c.getContext('2d'));
1397
return ctx.createPattern(c, 'repeat');
1400
svg.Element.pattern.prototype = new svg.Element.ElementBase;
1403
svg.Element.marker = function(node) {
1404
this.base = svg.Element.ElementBase;
1407
this.baseRender = this.render;
1408
this.render = function(ctx, point, angle) {
1409
ctx.translate(point.x, point.y);
1410
if (this.attribute('orient').valueOrDefault('auto') == 'auto') ctx.rotate(angle);
1411
if (this.attribute('markerUnits').valueOrDefault('strokeWidth') == 'strokeWidth') ctx.scale(ctx.lineWidth, ctx.lineWidth);
1414
// render me using a temporary svg element
1415
var tempSvg = new svg.Element.svg();
1416
tempSvg.attributes['viewBox'] = new svg.Property('viewBox', this.attribute('viewBox').value);
1417
tempSvg.attributes['refX'] = new svg.Property('refX', this.attribute('refX').value);
1418
tempSvg.attributes['refY'] = new svg.Property('refY', this.attribute('refY').value);
1419
tempSvg.attributes['width'] = new svg.Property('width', this.attribute('markerWidth').value);
1420
tempSvg.attributes['height'] = new svg.Property('height', this.attribute('markerHeight').value);
1421
tempSvg.attributes['fill'] = new svg.Property('fill', this.attribute('fill').valueOrDefault('black'));
1422
tempSvg.attributes['stroke'] = new svg.Property('stroke', this.attribute('stroke').valueOrDefault('none'));
1423
tempSvg.children = this.children;
1424
tempSvg.render(ctx);
1427
if (this.attribute('markerUnits').valueOrDefault('strokeWidth') == 'strokeWidth') ctx.scale(1/ctx.lineWidth, 1/ctx.lineWidth);
1428
if (this.attribute('orient').valueOrDefault('auto') == 'auto') ctx.rotate(-angle);
1429
ctx.translate(-point.x, -point.y);
1432
svg.Element.marker.prototype = new svg.Element.ElementBase;
1434
// definitions element
1435
svg.Element.defs = function(node) {
1436
this.base = svg.Element.ElementBase;
1439
this.render = function(ctx) {
1443
svg.Element.defs.prototype = new svg.Element.ElementBase;
1445
// base for gradients
1446
svg.Element.GradientBase = function(node) {
1447
this.base = svg.Element.ElementBase;
1450
this.gradientUnits = this.attribute('gradientUnits').valueOrDefault('objectBoundingBox');
1453
for (var i=0; i<this.children.length; i++) {
1454
var child = this.children[i];
1455
this.stops.push(child);
1458
this.getGradient = function() {
1462
this.createGradient = function(ctx, element) {
1463
var stopsContainer = this;
1464
if (this.attribute('xlink:href').hasValue()) {
1465
stopsContainer = this.attribute('xlink:href').Definition.getDefinition();
1468
var g = this.getGradient(ctx, element);
1469
for (var i=0; i<stopsContainer.stops.length; i++) {
1470
g.addColorStop(stopsContainer.stops[i].offset, stopsContainer.stops[i].color);
1475
svg.Element.GradientBase.prototype = new svg.Element.ElementBase;
1477
// linear gradient element
1478
svg.Element.linearGradient = function(node) {
1479
this.base = svg.Element.GradientBase;
1482
this.getGradient = function(ctx, element) {
1483
var bb = element.getBoundingBox();
1485
var x1 = (this.gradientUnits == 'objectBoundingBox'
1486
? bb.x() + bb.width() * this.attribute('x1').numValue()
1487
: this.attribute('x1').Length.toPixels('x'));
1488
var y1 = (this.gradientUnits == 'objectBoundingBox'
1489
? bb.y() + bb.height() * this.attribute('y1').numValue()
1490
: this.attribute('y1').Length.toPixels('y'));
1491
var x2 = (this.gradientUnits == 'objectBoundingBox'
1492
? bb.x() + bb.width() * this.attribute('x2').numValue()
1493
: this.attribute('x2').Length.toPixels('x'));
1494
var y2 = (this.gradientUnits == 'objectBoundingBox'
1495
? bb.y() + bb.height() * this.attribute('y2').numValue()
1496
: this.attribute('y2').Length.toPixels('y'));
1498
var p1 = new svg.Point(x1, y1);
1499
var p2 = new svg.Point(x2, y2);
1500
if (this.attribute('gradientTransform').hasValue()) {
1501
var transform = new svg.Transform(this.attribute('gradientTransform').value);
1502
transform.applyToPoint(p1);
1503
transform.applyToPoint(p2);
1506
return ctx.createLinearGradient(p1.x, p1.y, p2.x, p2.y);
1509
svg.Element.linearGradient.prototype = new svg.Element.GradientBase;
1511
// radial gradient element
1512
svg.Element.radialGradient = function(node) {
1513
this.base = svg.Element.GradientBase;
1516
this.getGradient = function(ctx, element) {
1517
var bb = element.getBoundingBox();
1519
var cx = (this.gradientUnits == 'objectBoundingBox'
1520
? bb.x() + bb.width() * this.attribute('cx').numValue()
1521
: this.attribute('cx').Length.toPixels('x'));
1522
var cy = (this.gradientUnits == 'objectBoundingBox'
1523
? bb.y() + bb.height() * this.attribute('cy').numValue()
1524
: this.attribute('cy').Length.toPixels('y'));
1528
if (this.attribute('fx').hasValue()) {
1529
fx = (this.gradientUnits == 'objectBoundingBox'
1530
? bb.x() + bb.width() * this.attribute('fx').numValue()
1531
: this.attribute('fx').Length.toPixels('x'));
1533
if (this.attribute('fy').hasValue()) {
1534
fy = (this.gradientUnits == 'objectBoundingBox'
1535
? bb.y() + bb.height() * this.attribute('fy').numValue()
1536
: this.attribute('fy').Length.toPixels('y'));
1539
var r = (this.gradientUnits == 'objectBoundingBox'
1540
? (bb.width() + bb.height()) / 2.0 * this.attribute('r').numValue()
1541
: this.attribute('r').Length.toPixels());
1543
var c = new svg.Point(cx, cy);
1544
var f = new svg.Point(fx, fy);
1545
if (this.attribute('gradientTransform').hasValue()) {
1546
var transform = new svg.Transform(this.attribute('gradientTransform').value);
1547
transform.applyToPoint(c);
1548
transform.applyToPoint(f);
1550
for (var i=0; i<transform.transforms.length; i++) {
1551
// average the scaling part of the transform, apply to radius
1552
var scale1 = transform.transforms[i].m[0];
1553
var scale2 = transform.transforms[i].m[3];
1554
r = r * ((scale1 + scale2) / 2.0);
1558
return ctx.createRadialGradient(f.x, f.y, 0, c.x, c.y, r);
1561
svg.Element.radialGradient.prototype = new svg.Element.GradientBase;
1563
// gradient stop element
1564
svg.Element.stop = function(node) {
1565
this.base = svg.Element.ElementBase;
1568
this.offset = this.attribute('offset').numValue();
1570
var stopColor = this.style('stop-color');
1571
if (this.style('stop-opacity').hasValue()) stopColor = stopColor.Color.addOpacity(this.style('stop-opacity').value);
1572
this.color = stopColor.value;
1574
svg.Element.stop.prototype = new svg.Element.ElementBase;
1576
// animation base element
1577
svg.Element.AnimateBase = function(node) {
1578
this.base = svg.Element.ElementBase;
1581
svg.Animations.push(this);
1583
this.duration = 0.0;
1584
this.begin = this.attribute('begin').Time.toMilliseconds();
1585
this.maxDuration = this.begin + this.attribute('dur').Time.toMilliseconds();
1587
this.getProperty = function() {
1588
var attributeType = this.attribute('attributeType').value;
1589
var attributeName = this.attribute('attributeName').value;
1591
if (attributeType == 'CSS') {
1592
return this.parent.style(attributeName, true);
1594
return this.parent.attribute(attributeName, true);
1597
this.initialValue = null;
1598
this.removed = false;
1600
this.calcValue = function() {
1605
this.update = function(delta) {
1606
// set initial value
1607
if (this.initialValue == null) {
1608
this.initialValue = this.getProperty().value;
1611
// if we're past the end time
1612
if (this.duration > this.maxDuration) {
1613
// loop for indefinitely repeating animations
1614
if (this.attribute('repeatCount').value == 'indefinite') {
1617
else if (this.attribute('fill').valueOrDefault('remove') == 'remove' && !this.removed) {
1618
this.removed = true;
1619
this.getProperty().value = this.initialValue;
1623
return false; // no updates made
1626
this.duration = this.duration + delta;
1628
// if we're past the begin time
1629
var updated = false;
1630
if (this.begin < this.duration) {
1631
var newValue = this.calcValue(); // tween
1633
if (this.attribute('type').hasValue()) {
1634
// for transform, etc.
1635
var type = this.attribute('type').value;
1636
newValue = type + '(' + newValue + ')';
1639
this.getProperty().value = newValue;
1646
// fraction of duration we've covered
1647
this.progress = function() {
1648
return ((this.duration - this.begin) / (this.maxDuration - this.begin));
1651
svg.Element.AnimateBase.prototype = new svg.Element.ElementBase;
1654
svg.Element.animate = function(node) {
1655
this.base = svg.Element.AnimateBase;
1658
this.calcValue = function() {
1659
var from = this.attribute('from').numValue();
1660
var to = this.attribute('to').numValue();
1662
// tween value linearly
1663
return from + (to - from) * this.progress();
1666
svg.Element.animate.prototype = new svg.Element.AnimateBase;
1668
// animate color element
1669
svg.Element.animateColor = function(node) {
1670
this.base = svg.Element.AnimateBase;
1673
this.calcValue = function() {
1674
var from = new RGBColor(this.attribute('from').value);
1675
var to = new RGBColor(this.attribute('to').value);
1677
if (from.ok && to.ok) {
1678
// tween color linearly
1679
var r = from.r + (to.r - from.r) * this.progress();
1680
var g = from.g + (to.g - from.g) * this.progress();
1681
var b = from.b + (to.b - from.b) * this.progress();
1682
return 'rgb('+parseInt(r,10)+','+parseInt(g,10)+','+parseInt(b,10)+')';
1684
return this.attribute('from').value;
1687
svg.Element.animateColor.prototype = new svg.Element.AnimateBase;
1689
// animate transform element
1690
svg.Element.animateTransform = function(node) {
1691
this.base = svg.Element.animate;
1694
svg.Element.animateTransform.prototype = new svg.Element.animate;
1697
svg.Element.text = function(node) {
1698
this.base = svg.Element.RenderedElementBase;
1704
for (var i=0; i<node.childNodes.length; i++) {
1705
var childNode = node.childNodes[i];
1706
if (childNode.nodeType == 1) { // capture tspan and tref nodes
1707
this.addChild(childNode, true);
1709
else if (childNode.nodeType == 3) { // capture text
1710
this.addChild(new svg.Element.tspan(childNode), false);
1715
this.baseSetContext = this.setContext;
1716
this.setContext = function(ctx) {
1717
this.baseSetContext(ctx);
1718
if (this.attribute('text-anchor').hasValue()) {
1719
var textAnchor = this.attribute('text-anchor').value;
1720
ctx.textAlign = textAnchor == 'middle' ? 'center' : textAnchor;
1722
if (this.attribute('alignment-baseline').hasValue()) ctx.textBaseline = this.attribute('alignment-baseline').value;
1725
this.renderChildren = function(ctx) {
1726
if(this.attribute('visibility').value=='hidden') return;
1728
var x = this.attribute('x').Length.toPixels('x');
1729
var y = this.attribute('y').Length.toPixels('y');
1731
for (var i=0; i<this.children.length; i++) {
1732
var child = this.children[i];
1734
if (child.attribute('x').hasValue()) {
1735
child.x = child.attribute('x').Length.toPixels('x');
1738
if (child.attribute('dx').hasValue()) x += child.attribute('dx').Length.toPixels('x');
1740
x += child.measureText(ctx);
1743
if (child.attribute('y').hasValue()) {
1744
child.y = child.attribute('y').Length.toPixels('y');
1747
if (child.attribute('dy').hasValue()) y += child.attribute('dy').Length.toPixels('y');
1755
svg.Element.text.prototype = new svg.Element.RenderedElementBase;
1758
svg.Element.TextElementBase = function(node) {
1759
this.base = svg.Element.RenderedElementBase;
1762
this.renderChildren = function(ctx) {
1763
ctx.fillText(svg.compressSpaces(this.getText()), this.x, this.y);
1766
this.getText = function() {
1770
this.measureText = function(ctx) {
1771
var textToMeasure = svg.compressSpaces(this.getText());
1772
if (!ctx.measureText) return textToMeasure.length * 10;
1773
return ctx.measureText(textToMeasure).width;
1776
svg.Element.TextElementBase.prototype = new svg.Element.RenderedElementBase;
1779
svg.Element.tspan = function(node) {
1780
this.base = svg.Element.TextElementBase;
1784
this.text = node.nodeType == 3 ? node.nodeValue : node.childNodes[0].nodeValue;
1785
this.getText = function() {
1789
svg.Element.tspan.prototype = new svg.Element.TextElementBase;
1792
svg.Element.tref = function(node) {
1793
this.base = svg.Element.TextElementBase;
1796
this.getText = function() {
1797
var element = this.attribute('xlink:href').Definition.getDefinition();
1798
if (element != null) return element.children[0].getText();
1801
svg.Element.tref.prototype = new svg.Element.TextElementBase;
1804
svg.Element.a = function(node) {
1805
this.base = svg.Element.TextElementBase;
1808
this.hasText = true;
1809
for (var i=0; i<node.childNodes.length; i++) {
1810
if (node.childNodes[i].nodeType != 3) this.hasText = false;
1813
// this might contain text
1814
this.text = this.hasText ? node.childNodes[0].nodeValue : '';
1815
this.getText = function() {
1819
this.baseRenderChildren = this.renderChildren;
1820
this.renderChildren = function(ctx) {
1822
// render as text element
1823
this.baseRenderChildren(ctx);
1824
var fontSize = new svg.Property('fontSize', svg.Font.Parse(svg.ctx.font).fontSize);
1825
svg.Mouse.checkBoundingBox(this, new svg.BoundingBox(this.x, this.y - fontSize.Length.toPixels('y'), this.x + this.measureText(ctx), this.y));
1828
// render as temporary group
1829
var g = new svg.Element.g();
1830
g.children = this.children;
1836
this.onclick = function() {
1837
window.open(this.attribute('xlink:href').value);
1840
this.onmousemove = function() {
1841
svg.ctx.canvas.style.cursor = 'pointer';
1844
svg.Element.a.prototype = new svg.Element.TextElementBase;
1847
svg.Element.image = function(node) {
1848
this.base = svg.Element.RenderedElementBase;
1851
svg.Images.push(this);
1852
this.img = document.createElement('img');
1853
this.loaded = false;
1855
this.img.onload = function() { that.loaded = true; }
1856
this.img.src = this.attribute('xlink:href').value;
1858
this.renderChildren = function(ctx) {
1859
var x = this.attribute('x').Length.toPixels('x');
1860
var y = this.attribute('y').Length.toPixels('y');
1862
var width = this.attribute('width').Length.toPixels('x');
1863
var height = this.attribute('height').Length.toPixels('y');
1864
if (width == 0 || height == 0) return;
1867
ctx.translate(x, y);
1868
svg.AspectRatio(ctx,
1869
this.attribute('preserveAspectRatio').value,
1876
ctx.drawImage(this.img, 0, 0);
1880
svg.Element.image.prototype = new svg.Element.RenderedElementBase;
1883
svg.Element.g = function(node) {
1884
this.base = svg.Element.RenderedElementBase;
1887
this.getBoundingBox = function() {
1888
var bb = new svg.BoundingBox();
1889
for (var i=0; i<this.children.length; i++) {
1890
bb.addBoundingBox(this.children[i].getBoundingBox());
1895
svg.Element.g.prototype = new svg.Element.RenderedElementBase;
1898
svg.Element.symbol = function(node) {
1899
this.base = svg.Element.RenderedElementBase;
1902
this.baseSetContext = this.setContext;
1903
this.setContext = function(ctx) {
1904
this.baseSetContext(ctx);
1907
if (this.attribute('viewBox').hasValue()) {
1908
var viewBox = svg.ToNumberArray(this.attribute('viewBox').value);
1909
var minX = viewBox[0];
1910
var minY = viewBox[1];
1912
height = viewBox[3];
1914
svg.AspectRatio(ctx,
1915
this.attribute('preserveAspectRatio').value,
1916
this.attribute('width').Length.toPixels('x'),
1918
this.attribute('height').Length.toPixels('y'),
1923
svg.ViewPort.SetCurrent(viewBox[2], viewBox[3]);
1927
svg.Element.symbol.prototype = new svg.Element.RenderedElementBase;
1930
svg.Element.style = function(node) {
1931
this.base = svg.Element.ElementBase;
1934
var css = node.childNodes[0].nodeValue;
1935
css = css.replace(/(\/\*([^*]|[\r\n]|(\*+([^*\/]|[\r\n])))*\*+\/)|(\/\/.*)/gm, ''); // remove comments
1936
css = svg.compressSpaces(css); // replace whitespace
1937
var cssDefs = css.split('}');
1938
for (var i=0; i<cssDefs.length; i++) {
1939
if (svg.trim(cssDefs[i]) != '') {
1940
var cssDef = cssDefs[i].split('{');
1941
var cssClasses = cssDef[0].split(',');
1942
var cssProps = cssDef[1].split(';');
1943
for (var j=0; j<cssClasses.length; j++) {
1944
var cssClass = svg.trim(cssClasses[j]);
1945
if (cssClass != '') {
1947
for (var k=0; k<cssProps.length; k++) {
1948
var prop = cssProps[k].split(':');
1950
var value = prop[1];
1951
if (name != null && value != null) {
1952
props[svg.trim(prop[0])] = new svg.Property(svg.trim(prop[0]), svg.trim(prop[1]));
1955
svg.Styles[cssClass] = props;
1961
svg.Element.style.prototype = new svg.Element.ElementBase;
1964
svg.Element.use = function(node) {
1965
this.base = svg.Element.RenderedElementBase;
1968
this.baseSetContext = this.setContext;
1969
this.setContext = function(ctx) {
1970
this.baseSetContext(ctx);
1971
if (this.attribute('x').hasValue()) ctx.translate(this.attribute('x').Length.toPixels('x'), 0);
1972
if (this.attribute('y').hasValue()) ctx.translate(0, this.attribute('y').Length.toPixels('y'));
1975
this.getDefinition = function() {
1976
var element = this.attribute('xlink:href').Definition.getDefinition();
1977
if (this.attribute('width').hasValue()) element.attribute('width', true).value = this.attribute('width').value;
1978
if (this.attribute('height').hasValue()) element.attribute('height', true).value = this.attribute('height').value;
1982
this.path = function(ctx) {
1983
var element = this.getDefinition();
1984
if (element != null) element.path(ctx);
1987
this.renderChildren = function(ctx) {
1988
var element = this.getDefinition();
1989
if (element != null) element.render(ctx);
1992
svg.Element.use.prototype = new svg.Element.RenderedElementBase;
1995
svg.Element.clipPath = function(node) {
1996
this.base = svg.Element.ElementBase;
1999
this.apply = function(ctx) {
2000
for (var i=0; i<this.children.length; i++) {
2001
if (this.children[i].path) {
2002
this.children[i].path(ctx);
2008
svg.Element.clipPath.prototype = new svg.Element.ElementBase;
2010
// title element, do nothing
2011
svg.Element.title = function(node) {
2013
svg.Element.title.prototype = new svg.Element.ElementBase;
2015
// desc element, do nothing
2016
svg.Element.desc = function(node) {
2018
svg.Element.desc.prototype = new svg.Element.ElementBase;
2020
svg.Element.MISSING = function(node) {
2021
console.log('ERROR: Element \'' + node.nodeName + '\' not yet implemented.');
2023
svg.Element.MISSING.prototype = new svg.Element.ElementBase;
2026
svg.CreateElement = function(node) {
2027
var className = node.nodeName.replace(/^[^:]+:/,'');
2029
if (typeof(svg.Element[className]) != 'undefined') {
2030
e = new svg.Element[className](node);
2033
e = new svg.Element.MISSING(node);
2036
e.type = node.nodeName;
2041
svg.load = function(ctx, url) {
2042
svg.loadXml(ctx, svg.ajax(url));
2046
svg.loadXml = function(ctx, xml) {
2049
var mapXY = function(p) {
2052
p.x -= e.offsetLeft;
2056
if (window.scrollX) p.x += window.scrollX;
2057
if (window.scrollY) p.y += window.scrollY;
2062
if (svg.opts == null || svg.opts['ignoreMouse'] != true) {
2063
ctx.canvas.onclick = function(e) {
2064
var p = mapXY(new svg.Point(e != null ? e.clientX : event.clientX, e != null ? e.clientY : event.clientY));
2065
svg.Mouse.onclick(p.x, p.y);
2067
ctx.canvas.onmousemove = function(e) {
2068
var p = mapXY(new svg.Point(e != null ? e.clientX : event.clientX, e != null ? e.clientY : event.clientY));
2069
svg.Mouse.onmousemove(p.x, p.y);
2073
var dom = svg.parseXml(xml);
2074
var e = svg.CreateElement(dom.documentElement);
2077
var isFirstRender = true;
2078
var draw = function() {
2079
if (svg.opts == null || svg.opts['ignoreDimensions'] != true) {
2081
if (e.style('width').hasValue()) {
2082
ctx.canvas.width = e.style('width').Length.toPixels(ctx.canvas.parentNode.clientWidth);
2084
if (e.style('height').hasValue()) {
2085
ctx.canvas.height = e.style('height').Length.toPixels(ctx.canvas.parentNode.clientHeight);
2088
svg.ViewPort.SetCurrent(ctx.canvas.clientWidth, ctx.canvas.clientHeight);
2090
if (svg.opts != null && svg.opts['offsetX'] != null) e.attribute('x', true).value = svg.opts['offsetX'];
2091
if (svg.opts != null && svg.opts['offsetY'] != null) e.attribute('y', true).value = svg.opts['offsetY'];
2092
if (svg.opts != null && svg.opts['scaleWidth'] != null && svg.opts['scaleHeight'] != null) {
2093
e.attribute('width', true).value = svg.opts['scaleWidth'];
2094
e.attribute('height', true).value = svg.opts['scaleHeight'];
2095
e.attribute('viewBox', true).value = '0 0 ' + ctx.canvas.clientWidth + ' ' + ctx.canvas.clientHeight;
2096
e.attribute('preserveAspectRatio', true).value = 'none';
2100
if (svg.opts == null || svg.opts['ignoreClear'] != true) {
2101
ctx.clearRect(0, 0, ctx.canvas.clientWidth, ctx.canvas.clientHeight);
2104
if (isFirstRender) {
2105
isFirstRender = false;
2106
if (svg.opts != null && typeof(svg.opts['renderCallback']) == 'function') svg.opts['renderCallback']();
2110
var waitingForImages = true;
2111
if (svg.ImagesLoaded()) {
2112
waitingForImages = false;
2115
svg.intervalID = setInterval(function() {
2116
var needUpdate = false;
2118
if (waitingForImages && svg.ImagesLoaded()) {
2119
waitingForImages = false;
2123
// need update from mouse events?
2124
if (svg.opts == null || svg.opts['ignoreMouse'] != true) {
2125
needUpdate = needUpdate | svg.Mouse.hasEvents();
2128
// need update from animations?
2129
if (svg.opts == null || svg.opts['ignoreAnimation'] != true) {
2130
for (var i=0; i<svg.Animations.length; i++) {
2131
needUpdate = needUpdate | svg.Animations[i].update(1000 / svg.FRAMERATE);
2135
// need update from redraw?
2136
if (svg.opts != null && typeof(svg.opts['forceRedraw']) == 'function') {
2137
if (svg.opts['forceRedraw']() == true) needUpdate = true;
2143
svg.Mouse.runEvents(); // run and clear our events
2145
}, 1000 / svg.FRAMERATE);
2148
svg.stop = function() {
2149
if (svg.intervalID) {
2150
clearInterval(svg.intervalID);
2154
svg.Mouse = new (function() {
2156
this.hasEvents = function() { return this.events.length != 0; }
2158
this.onclick = function(x, y) {
2159
this.events.push({ type: 'onclick', x: x, y: y,
2160
run: function(e) { if (e.onclick) e.onclick(); }
2164
this.onmousemove = function(x, y) {
2165
this.events.push({ type: 'onmousemove', x: x, y: y,
2166
run: function(e) { if (e.onmousemove) e.onmousemove(); }
2170
this.eventElements = [];
2172
this.checkPath = function(element, ctx) {
2173
for (var i=0; i<this.events.length; i++) {
2174
var e = this.events[i];
2175
if (ctx.isPointInPath && ctx.isPointInPath(e.x, e.y)) this.eventElements[i] = element;
2179
this.checkBoundingBox = function(element, bb) {
2180
for (var i=0; i<this.events.length; i++) {
2181
var e = this.events[i];
2182
if (bb.isPointInBox(e.x, e.y)) this.eventElements[i] = element;
2186
this.runEvents = function() {
2187
svg.ctx.canvas.style.cursor = '';
2189
for (var i=0; i<this.events.length; i++) {
2190
var e = this.events[i];
2191
var element = this.eventElements[i];
2194
element = element.parent;
2198
// done running, clear
2200
this.eventElements = [];
2208
if (CanvasRenderingContext2D) {
2209
CanvasRenderingContext2D.prototype.drawSvg = function(s, dx, dy, dw, dh) {
2210
canvg(this.canvas, s, {
2212
ignoreAnimation: true,
2213
ignoreDimensions: true,
2224
* A class to parse color values
2225
* @author Stoyan Stefanov <sstoo@gmail.com>
2226
* @link http://www.phpied.com/rgb-color-parser-in-javascript/
2227
* @license Use it if you like it
2229
function RGBColor(color_string)
2233
// strip any leading #
2234
if (color_string.charAt(0) == '#') { // remove # if any
2235
color_string = color_string.substr(1,6);
2238
color_string = color_string.replace(/ /g,'');
2239
color_string = color_string.toLowerCase();
2241
// before getting into regexps, try simple matches
2242
// and overwrite the input
2243
var simple_colors = {
2244
aliceblue: 'f0f8ff',
2245
antiquewhite: 'faebd7',
2247
aquamarine: '7fffd4',
2252
blanchedalmond: 'ffebcd',
2254
blueviolet: '8a2be2',
2256
burlywood: 'deb887',
2257
cadetblue: '5f9ea0',
2258
chartreuse: '7fff00',
2259
chocolate: 'd2691e',
2261
cornflowerblue: '6495ed',
2267
darkgoldenrod: 'b8860b',
2269
darkgreen: '006400',
2270
darkkhaki: 'bdb76b',
2271
darkmagenta: '8b008b',
2272
darkolivegreen: '556b2f',
2273
darkorange: 'ff8c00',
2274
darkorchid: '9932cc',
2276
darksalmon: 'e9967a',
2277
darkseagreen: '8fbc8f',
2278
darkslateblue: '483d8b',
2279
darkslategray: '2f4f4f',
2280
darkturquoise: '00ced1',
2281
darkviolet: '9400d3',
2283
deepskyblue: '00bfff',
2285
dodgerblue: '1e90ff',
2287
firebrick: 'b22222',
2288
floralwhite: 'fffaf0',
2289
forestgreen: '228b22',
2291
gainsboro: 'dcdcdc',
2292
ghostwhite: 'f8f8ff',
2294
goldenrod: 'daa520',
2297
greenyellow: 'adff2f',
2300
indianred : 'cd5c5c',
2305
lavenderblush: 'fff0f5',
2306
lawngreen: '7cfc00',
2307
lemonchiffon: 'fffacd',
2308
lightblue: 'add8e6',
2309
lightcoral: 'f08080',
2310
lightcyan: 'e0ffff',
2311
lightgoldenrodyellow: 'fafad2',
2312
lightgrey: 'd3d3d3',
2313
lightgreen: '90ee90',
2314
lightpink: 'ffb6c1',
2315
lightsalmon: 'ffa07a',
2316
lightseagreen: '20b2aa',
2317
lightskyblue: '87cefa',
2318
lightslateblue: '8470ff',
2319
lightslategray: '778899',
2320
lightsteelblue: 'b0c4de',
2321
lightyellow: 'ffffe0',
2323
limegreen: '32cd32',
2327
mediumaquamarine: '66cdaa',
2328
mediumblue: '0000cd',
2329
mediumorchid: 'ba55d3',
2330
mediumpurple: '9370d8',
2331
mediumseagreen: '3cb371',
2332
mediumslateblue: '7b68ee',
2333
mediumspringgreen: '00fa9a',
2334
mediumturquoise: '48d1cc',
2335
mediumvioletred: 'c71585',
2336
midnightblue: '191970',
2337
mintcream: 'f5fffa',
2338
mistyrose: 'ffe4e1',
2340
navajowhite: 'ffdead',
2344
olivedrab: '6b8e23',
2346
orangered: 'ff4500',
2348
palegoldenrod: 'eee8aa',
2349
palegreen: '98fb98',
2350
paleturquoise: 'afeeee',
2351
palevioletred: 'd87093',
2352
papayawhip: 'ffefd5',
2353
peachpuff: 'ffdab9',
2357
powderblue: 'b0e0e6',
2360
rosybrown: 'bc8f8f',
2361
royalblue: '4169e1',
2362
saddlebrown: '8b4513',
2364
sandybrown: 'f4a460',
2370
slateblue: '6a5acd',
2371
slategray: '708090',
2373
springgreen: '00ff7f',
2374
steelblue: '4682b4',
2379
turquoise: '40e0d0',
2381
violetred: 'd02090',
2384
whitesmoke: 'f5f5f5',
2386
yellowgreen: '9acd32'
2388
for (var key in simple_colors) {
2389
if (color_string == key) {
2390
color_string = simple_colors[key];
2393
// emd of simple type-in colors
2395
// array of color definition objects
2398
re: /^rgb\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})\)$/,
2399
example: ['rgb(123, 234, 45)', 'rgb(255,234,245)'],
2400
process: function (bits){
2409
re: /^(\w{2})(\w{2})(\w{2})$/,
2410
example: ['#00ff00', '336699'],
2411
process: function (bits){
2413
parseInt(bits[1], 16),
2414
parseInt(bits[2], 16),
2415
parseInt(bits[3], 16)
2420
re: /^(\w{1})(\w{1})(\w{1})$/,
2421
example: ['#fb0', 'f0f'],
2422
process: function (bits){
2424
parseInt(bits[1] + bits[1], 16),
2425
parseInt(bits[2] + bits[2], 16),
2426
parseInt(bits[3] + bits[3], 16)
2432
// search through the definitions to find a match
2433
for (var i = 0; i < color_defs.length; i++) {
2434
var re = color_defs[i].re;
2435
var processor = color_defs[i].process;
2436
var bits = re.exec(color_string);
2438
channels = processor(bits);
2439
this.r = channels[0];
2440
this.g = channels[1];
2441
this.b = channels[2];
2447
// validate/cleanup values
2448
this.r = (this.r < 0 || isNaN(this.r)) ? 0 : ((this.r > 255) ? 255 : this.r);
2449
this.g = (this.g < 0 || isNaN(this.g)) ? 0 : ((this.g > 255) ? 255 : this.g);
2450
this.b = (this.b < 0 || isNaN(this.b)) ? 0 : ((this.b > 255) ? 255 : this.b);
2453
this.toRGB = function () {
2454
return 'rgb(' + this.r + ', ' + this.g + ', ' + this.b + ')';
2456
this.toHex = function () {
2457
var r = this.r.toString(16);
2458
var g = this.g.toString(16);
2459
var b = this.b.toString(16);
2460
if (r.length == 1) r = '0' + r;
2461
if (g.length == 1) g = '0' + g;
2462
if (b.length == 1) b = '0' + b;
2463
return '#' + r + g + b;
2467
this.getHelpXML = function () {
2469
var examples = new Array();
2471
for (var i = 0; i < color_defs.length; i++) {
2472
var example = color_defs[i].example;
2473
for (var j = 0; j < example.length; j++) {
2474
examples[examples.length] = example[j];
2477
// add type-in colors
2478
for (var sc in simple_colors) {
2479
examples[examples.length] = sc;
2482
var xml = document.createElement('ul');
2483
xml.setAttribute('id', 'rgbcolor-examples');
2484
for (var i = 0; i < examples.length; i++) {
2486
var list_item = document.createElement('li');
2487
var list_color = new RGBColor(examples[i]);
2488
var example_div = document.createElement('div');
2489
example_div.style.cssText =
2491
+ 'border: 1px solid black; '
2492
+ 'background:' + list_color.toHex() + '; '
2493
+ 'color:' + list_color.toHex()
2495
example_div.appendChild(document.createTextNode('test'));
2496
var list_item_value = document.createTextNode(
2497
' ' + examples[i] + ' -> ' + list_color.toRGB() + ' -> ' + list_color.toHex()
2499
list_item.appendChild(example_div);
2500
list_item.appendChild(list_item_value);
2501
xml.appendChild(list_item);
b'\\ No newline at end of file'