~ubuntu-branches/ubuntu/saucy/phpmyadmin/saucy-proposed

« back to all changes in this revision

Viewing changes to js/canvg/canvg.js

  • Committer: Package Import Robot
  • Author(s): Thijs Kinkhorst
  • Date: 2013-08-04 13:24:37 UTC
  • mfrom: (1.2.44)
  • Revision ID: package-import@ubuntu.com-20130804132437-jznw8efwy4hr1nms
Tags: 4:4.0.5-1
* New upstream release.
  - Fixes security issue PMASA-2013-10.

Show diffs side-by-side

added added

removed removed

Lines of Context:
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'
 
1
/*
 
2
 * canvg.js - Javascript SVG parser and renderer on Canvas
 
3
 * MIT Licensed 
 
4
 * Gabe Lerner (gabelerner@gmail.com)
 
5
 * http://code.google.com/p/canvg/
 
6
 *
 
7
 * Requires: rgbcolor.js - http://www.phpied.com/rgb-color-parser-in-javascript/
 
8
 */
 
9
if(!window.console) {
 
10
        window.console = {};
 
11
        window.console.log = function(str) {};
 
12
        window.console.dir = function(str) {};
 
13
}
 
14
 
 
15
// <3 IE
 
16
if(!Array.indexOf){
 
17
        Array.prototype.indexOf = function(obj){
 
18
                for(var i=0; i<this.length; i++){
 
19
                        if(this[i]==obj){
 
20
                                return i;
 
21
                        }
 
22
                }
 
23
                return -1;
 
24
        }
 
25
}
 
26
 
 
27
(function(){
 
28
        // canvg(target, s)
 
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) {
 
44
                // no parameters
 
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);
 
57
                        }
 
58
                        return;
 
59
                }       
 
60
        
 
61
                if (typeof target == 'string') {
 
62
                        target = document.getElementById(target);
 
63
                }
 
64
                
 
65
                // reuse class per canvas
 
66
                var svg;
 
67
                if (target.svg == null) {
 
68
                        svg = build();
 
69
                        target.svg = svg;
 
70
                }
 
71
                else {
 
72
                        svg = target.svg;
 
73
                        svg.stop();
 
74
                }
 
75
                svg.opts = opts;
 
76
                
 
77
                var ctx = target.getContext('2d');
 
78
                if (s.substr(0,1) == '<') {
 
79
                        // load from xml string
 
80
                        svg.loadXml(ctx, s);
 
81
                }
 
82
                else {
 
83
                        // load from url
 
84
                        svg.load(ctx, s);
 
85
                }
 
86
        }
 
87
 
 
88
        function build() {
 
89
                var svg = { };
 
90
                
 
91
                svg.FRAMERATE = 30;
 
92
                
 
93
                // globals
 
94
                svg.init = function(ctx) {
 
95
                        svg.Definitions = {};
 
96
                        svg.Styles = {};
 
97
                        svg.Animations = [];
 
98
                        svg.Images = [];
 
99
                        svg.ctx = ctx;
 
100
                        svg.ViewPort = new (function () {
 
101
                                this.viewPorts = [];
 
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);                        
 
112
                                }
 
113
                        });
 
114
                }
 
115
                svg.init();
 
116
                
 
117
                // images loaded
 
118
                svg.ImagesLoaded = function() { 
 
119
                        for (var i=0; i<svg.Images.length; i++) {
 
120
                                if (!svg.Images[i].loaded) return false;
 
121
                        }
 
122
                        return true;
 
123
                }
 
124
 
 
125
                // trim
 
126
                svg.trim = function(s) { return s.replace(/^\s+|\s+$/g, ''); }
 
127
                
 
128
                // compress spaces
 
129
                svg.compressSpaces = function(s) { return s.replace(/[\s\r\t\n]+/gm,' '); }
 
130
                
 
131
                // ajax
 
132
                svg.ajax = function(url) {
 
133
                        var AJAX;
 
134
                        if(window.XMLHttpRequest){AJAX=new XMLHttpRequest();}
 
135
                        else{AJAX=new ActiveXObject('Microsoft.XMLHTTP');}
 
136
                        if(AJAX){
 
137
                           AJAX.open('GET',url,false);
 
138
                           AJAX.send(null);
 
139
                           return AJAX.responseText;
 
140
                        }
 
141
                        return null;
 
142
                } 
 
143
                
 
144
                // parse xml
 
145
                svg.parseXml = function(xml) {
 
146
                        if (window.DOMParser)
 
147
                        {
 
148
                                var parser = new DOMParser();
 
149
                                return parser.parseFromString(xml, 'text/xml');
 
150
                        }
 
151
                        else 
 
152
                        {
 
153
                                xml = xml.replace(/<!DOCTYPE svg[^>]*>/, '');
 
154
                                var xmlDoc = new ActiveXObject('Microsoft.XMLDOM');
 
155
                                xmlDoc.async = 'false';
 
156
                                xmlDoc.loadXML(xml); 
 
157
                                return xmlDoc;
 
158
                        }               
 
159
                }
 
160
                
 
161
                svg.Property = function(name, value) {
 
162
                        this.name = name;
 
163
                        this.value = value;
 
164
                        
 
165
                        this.hasValue = function() {
 
166
                                return (this.value != null && this.value != '');
 
167
                        }
 
168
                                                        
 
169
                        // return the numerical value of the property
 
170
                        this.numValue = function() {
 
171
                                if (!this.hasValue()) return 0;
 
172
                                
 
173
                                var n = parseFloat(this.value);
 
174
                                if ((this.value + '').match(/%$/)) {
 
175
                                        n = n / 100.0;
 
176
                                }
 
177
                                return n;
 
178
                        }
 
179
                        
 
180
                        this.valueOrDefault = function(def) {
 
181
                                if (this.hasValue()) return this.value;
 
182
                                return def;
 
183
                        }
 
184
                        
 
185
                        this.numValueOrDefault = function(def) {
 
186
                                if (this.hasValue()) return this.numValue();
 
187
                                return def;
 
188
                        }
 
189
                        
 
190
                        /* EXTENSIONS */
 
191
                        var that = this;
 
192
                        
 
193
                        // color extensions
 
194
                        this.Color = {
 
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);
 
200
                                                if (color.ok) {
 
201
                                                        newValue = 'rgba(' + color.r + ', ' + color.g + ', ' + color.b + ', ' + opacity + ')';
 
202
                                                }
 
203
                                        }
 
204
                                        return new svg.Property(that.name, newValue);
 
205
                                }
 
206
                        }
 
207
                        
 
208
                        // definition extensions
 
209
                        this.Definition = {
 
210
                                // get the definition from the definitions table
 
211
                                getDefinition: function() {
 
212
                                        var name = that.value.replace(/^(url\()?#([^\)]+)\)?$/, '$2');
 
213
                                        return svg.Definitions[name];
 
214
                                },
 
215
                                
 
216
                                isUrl: function() {
 
217
                                        return that.value.indexOf('url(') == 0
 
218
                                },
 
219
                                
 
220
                                getFillStyle: function(e) {
 
221
                                        var def = this.getDefinition();
 
222
                                        
 
223
                                        // gradient
 
224
                                        if (def != null && def.createGradient) {
 
225
                                                return def.createGradient(svg.ctx, e);
 
226
                                        }
 
227
                                        
 
228
                                        // pattern
 
229
                                        if (def != null && def.createPattern) {
 
230
                                                return def.createPattern(svg.ctx, e);
 
231
                                        }
 
232
                                        
 
233
                                        return null;
 
234
                                }
 
235
                        }
 
236
                        
 
237
                        // length extensions
 
238
                        this.Length = {
 
239
                                DPI: function(viewPort) {
 
240
                                        return 96.0; // TODO: compute?
 
241
                                },
 
242
                                
 
243
                                EM: function(viewPort) {
 
244
                                        var em = 12;
 
245
                                        
 
246
                                        var fontSize = new svg.Property('fontSize', svg.Font.Parse(svg.ctx.font).fontSize);
 
247
                                        if (fontSize.hasValue()) em = fontSize.Length.toPixels(viewPort);
 
248
                                        
 
249
                                        return em;
 
250
                                },
 
251
                        
 
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();
 
266
                                }
 
267
                        }
 
268
                        
 
269
                        // time extensions
 
270
                        this.Time = {
 
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();
 
278
                                }
 
279
                        }
 
280
                        
 
281
                        // angle extensions
 
282
                        this.Angle = {
 
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);
 
291
                                }
 
292
                        }
 
293
                }
 
294
                
 
295
                // fonts
 
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'];
 
300
                        
 
301
                        this.CreateFont = function(fontStyle, fontVariant, fontWeight, fontSize, fontFamily, inherit) { 
 
302
                                var f = inherit != null ? this.Parse(inherit) : this.CreateFont('', '', '', '', '', svg.ctx.font);
 
303
                                return { 
 
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(' ') } 
 
310
                                } 
 
311
                        }
 
312
                        
 
313
                        var that = this;
 
314
                        this.Parse = function(s) {
 
315
                                var f = {};
 
316
                                var d = svg.trim(svg.compressSpaces(s || '')).split(' ');
 
317
                                var set = { fontSize: false, fontStyle: false, fontWeight: false, fontVariant: false }
 
318
                                var ff = '';
 
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;
 
326
                                return f;
 
327
                        }
 
328
                });
 
329
                
 
330
                // points and paths
 
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]);
 
335
                        }
 
336
                        return a;
 
337
                }               
 
338
                svg.Point = function(x, y) {
 
339
                        this.x = x;
 
340
                        this.y = y;
 
341
                        
 
342
                        this.angleTo = function(p) {
 
343
                                return Math.atan2(p.y - this.y, p.x - this.x);
 
344
                        }
 
345
                        
 
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];
 
349
                                this.x = xp;
 
350
                                this.y = yp;
 
351
                        }
 
352
                }
 
353
                svg.CreatePoint = function(s) {
 
354
                        var a = svg.ToNumberArray(s);
 
355
                        return new svg.Point(a[0], a[1]);
 
356
                }
 
357
                svg.CreatePath = function(s) {
 
358
                        var a = svg.ToNumberArray(s);
 
359
                        var path = [];
 
360
                        for (var i=0; i<a.length; i+=2) {
 
361
                                path.push(new svg.Point(a[i], a[i+1]));
 
362
                        }
 
363
                        return path;
 
364
                }
 
365
                
 
366
                // bounding box
 
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;
 
372
                        
 
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; }
 
377
                        
 
378
                        this.addPoint = function(x, y) {        
 
379
                                if (x != null) {
 
380
                                        if (isNaN(this.x1) || isNaN(this.x2)) {
 
381
                                                this.x1 = x;
 
382
                                                this.x2 = x;
 
383
                                        }
 
384
                                        if (x < this.x1) this.x1 = x;
 
385
                                        if (x > this.x2) this.x2 = x;
 
386
                                }
 
387
                        
 
388
                                if (y != null) {
 
389
                                        if (isNaN(this.y1) || isNaN(this.y2)) {
 
390
                                                this.y1 = y;
 
391
                                                this.y2 = y;
 
392
                                        }
 
393
                                        if (y < this.y1) this.y1 = y;
 
394
                                        if (y > this.y2) this.y2 = y;
 
395
                                }
 
396
                        }                       
 
397
                        this.addX = function(x) { this.addPoint(x, null); }
 
398
                        this.addY = function(y) { this.addPoint(null, y); }
 
399
                        
 
400
                        this.addBoundingBox = function(bb) {
 
401
                                this.addPoint(bb.x1, bb.y1);
 
402
                                this.addPoint(bb.x2, bb.y2);
 
403
                        }
 
404
                        
 
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);
 
411
                        }
 
412
                        
 
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]);
 
418
                                
 
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];
 
425
                                        }
 
426
                                        
 
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];
 
430
                                        
 
431
                                        if (a == 0) {
 
432
                                                if (b == 0) continue;
 
433
                                                var t = -c / b;
 
434
                                                if (0 < t && t < 1) {
 
435
                                                        if (i == 0) this.addX(f(t));
 
436
                                                        if (i == 1) this.addY(f(t));
 
437
                                                }
 
438
                                                continue;
 
439
                                        }
 
440
                                        
 
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));
 
447
                                        }
 
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));
 
452
                                        }
 
453
                                }
 
454
                        }
 
455
                        
 
456
                        this.isPointInBox = function(x, y) {
 
457
                                return (this.x1 <= x && x <= this.x2 && this.y1 <= y && y <= this.y2);
 
458
                        }
 
459
                        
 
460
                        this.addPoint(x1, y1);
 
461
                        this.addPoint(x2, y2);
 
462
                }
 
463
                
 
464
                // transforms
 
465
                svg.Transform = function(v) {   
 
466
                        var that = this;
 
467
                        this.Type = {}
 
468
                
 
469
                        // translate
 
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);
 
474
                                }
 
475
                                this.applyToPoint = function(p) {
 
476
                                        p.applyTransform([1, 0, 0, 1, this.p.x || 0.0, this.p.y || 0.0]);
 
477
                                }
 
478
                        }
 
479
                        
 
480
                        // rotate
 
481
                        this.Type.rotate = function(s) {
 
482
                                var a = svg.ToNumberArray(s);
 
483
                                this.angle = new svg.Property('angle', a[0]);
 
484
                                this.cx = a[1] || 0;
 
485
                                this.cy = a[2] || 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);
 
490
                                }
 
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]);
 
496
                                }                       
 
497
                        }
 
498
                        
 
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);
 
503
                                }
 
504
                                this.applyToPoint = function(p) {
 
505
                                        p.applyTransform([this.p.x || 0.0, 0, 0, this.p.y || 0.0, 0, 0]);
 
506
                                }                               
 
507
                        }
 
508
                        
 
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]);
 
513
                                }
 
514
                                this.applyToPoint = function(p) {
 
515
                                        p.applyTransform(this.m);
 
516
                                }                                       
 
517
                        }
 
518
                        
 
519
                        this.Type.SkewBase = function(s) {
 
520
                                this.base = that.Type.matrix;
 
521
                                this.base(s);
 
522
                                this.angle = new svg.Property('angle', s);
 
523
                        }
 
524
                        this.Type.SkewBase.prototype = new this.Type.matrix;
 
525
                        
 
526
                        this.Type.skewX = function(s) {
 
527
                                this.base = that.Type.SkewBase;
 
528
                                this.base(s);
 
529
                                this.m = [1, 0, Math.tan(this.angle.Angle.toRadians()), 1, 0, 0];
 
530
                        }
 
531
                        this.Type.skewX.prototype = new this.Type.SkewBase;
 
532
                        
 
533
                        this.Type.skewY = function(s) {
 
534
                                this.base = that.Type.SkewBase;
 
535
                                this.base(s);
 
536
                                this.m = [1, Math.tan(this.angle.Angle.toRadians()), 0, 1, 0, 0];
 
537
                        }
 
538
                        this.Type.skewY.prototype = new this.Type.SkewBase;
 
539
                
 
540
                        this.transforms = [];
 
541
                        
 
542
                        this.apply = function(ctx) {
 
543
                                for (var i=0; i<this.transforms.length; i++) {
 
544
                                        this.transforms[i].apply(ctx);
 
545
                                }
 
546
                        }
 
547
                        
 
548
                        this.applyToPoint = function(p) {
 
549
                                for (var i=0; i<this.transforms.length; i++) {
 
550
                                        this.transforms[i].applyToPoint(p);
 
551
                                }
 
552
                        }
 
553
                        
 
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);
 
560
                        }
 
561
                }
 
562
                
 
563
                // aspect ratio
 
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';                                  
 
570
        
 
571
                        // calculate scale
 
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; }    
 
578
                        
 
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'));
 
583
                        } 
 
584
                        else {                                  
 
585
                                // align
 
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); 
 
590
                        }
 
591
                        
 
592
                        // scale
 
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);         
 
596
                        
 
597
                        // translate
 
598
                        ctx.translate(minX == null ? 0 : -minX, minY == null ? 0 : -minY);                      
 
599
                }
 
600
                
 
601
                // elements
 
602
                svg.Element = {}
 
603
                
 
604
                svg.Element.ElementBase = function(node) {      
 
605
                        this.attributes = {};
 
606
                        this.styles = {};
 
607
                        this.children = [];
 
608
                        
 
609
                        // get or create attribute
 
610
                        this.attribute = function(name, createIfNotExists) {
 
611
                                var a = this.attributes[name];
 
612
                                if (a != null) return a;
 
613
                                                        
 
614
                                a = new svg.Property(name, '');
 
615
                                if (createIfNotExists == true) this.attributes[name] = a;
 
616
                                return a;
 
617
                        }
 
618
                        
 
619
                        // get or create style
 
620
                        this.style = function(name, createIfNotExists) {
 
621
                                var s = this.styles[name];
 
622
                                if (s != null) return s;
 
623
                                
 
624
                                var a = this.attribute(name);
 
625
                                if (a != null && a.hasValue()) {
 
626
                                        return a;
 
627
                                }
 
628
                                        
 
629
                                s = new svg.Property(name, '');
 
630
                                if (createIfNotExists == true) this.styles[name] = s;
 
631
                                return s;
 
632
                        }
 
633
                        
 
634
                        // base render
 
635
                        this.render = function(ctx) {
 
636
                                // don't render display=none
 
637
                                if (this.attribute('display').value == 'none') return;
 
638
                        
 
639
                                ctx.save();
 
640
                                this.setContext(ctx);
 
641
                                this.renderChildren(ctx);
 
642
                                this.clearContext(ctx);
 
643
                                ctx.restore();
 
644
                        }
 
645
                        
 
646
                        // base set context
 
647
                        this.setContext = function(ctx) {
 
648
                                // OVERRIDE ME!
 
649
                        }
 
650
                        
 
651
                        // base clear context
 
652
                        this.clearContext = function(ctx) {
 
653
                                // OVERRIDE ME!
 
654
                        }                       
 
655
                        
 
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);
 
660
                                }
 
661
                        }
 
662
                        
 
663
                        this.addChild = function(childNode, create) {
 
664
                                var child = childNode;
 
665
                                if (create) child = svg.CreateElement(childNode);
 
666
                                child.parent = this;
 
667
                                this.children.push(child);                      
 
668
                        }
 
669
                                
 
670
                        if (node != null && node.nodeType == 1) { //ELEMENT_NODE
 
671
                                // add children
 
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
 
675
                                }
 
676
                                
 
677
                                // add attributes
 
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);
 
681
                                }
 
682
                                                                                
 
683
                                // add tag styles
 
684
                                var styles = svg.Styles[this.type];
 
685
                                if (styles != null) {
 
686
                                        for (var name in styles) {
 
687
                                                this.styles[name] = styles[name];
 
688
                                        }
 
689
                                }                                       
 
690
                                
 
691
                                // add class styles
 
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];
 
699
                                                        }
 
700
                                                }
 
701
                                        }
 
702
                                }
 
703
                                
 
704
                                // add inline styles
 
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);
 
713
                                                }
 
714
                                        }
 
715
                                }       
 
716
 
 
717
                                // add id
 
718
                                if (this.attribute('id').hasValue()) {
 
719
                                        if (svg.Definitions[this.attribute('id').value] == null) {
 
720
                                                svg.Definitions[this.attribute('id').value] = this;
 
721
                                        }
 
722
                                }
 
723
                        }
 
724
                }
 
725
                
 
726
                svg.Element.RenderedElementBase = function(node) {
 
727
                        this.base = svg.Element.ElementBase;
 
728
                        this.base(node);
 
729
                        
 
730
                        this.setContext = function(ctx) {
 
731
                                // fill
 
732
                                if (this.style('fill').Definition.isUrl()) {
 
733
                                        var fs = this.style('fill').Definition.getFillStyle(this);
 
734
                                        if (fs != null) ctx.fillStyle = fs;
 
735
                                }
 
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);
 
740
                                }
 
741
                                                                        
 
742
                                // stroke
 
743
                                if (this.style('stroke').Definition.isUrl()) {
 
744
                                        var fs = this.style('stroke').Definition.getFillStyle(this);
 
745
                                        if (fs != null) ctx.strokeStyle = fs;
 
746
                                }
 
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);
 
751
                                }
 
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;
 
756
 
 
757
                                // font
 
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();
 
765
                                }
 
766
                                
 
767
                                // transform
 
768
                                if (this.attribute('transform').hasValue()) { 
 
769
                                        var transform = new svg.Transform(this.attribute('transform').value);
 
770
                                        transform.apply(ctx);
 
771
                                }
 
772
                                
 
773
                                // clip
 
774
                                if (this.attribute('clip-path').hasValue()) {
 
775
                                        var clip = this.attribute('clip-path').Definition.getDefinition();
 
776
                                        if (clip != null) clip.apply(ctx);
 
777
                                }
 
778
                                
 
779
                                // opacity
 
780
                                if (this.style('opacity').hasValue()) {
 
781
                                        ctx.globalAlpha = this.style('opacity').numValue();
 
782
                                }
 
783
                        }               
 
784
                }
 
785
                svg.Element.RenderedElementBase.prototype = new svg.Element.ElementBase;
 
786
                
 
787
                svg.Element.PathElementBase = function(node) {
 
788
                        this.base = svg.Element.RenderedElementBase;
 
789
                        this.base(node);
 
790
                        
 
791
                        this.path = function(ctx) {
 
792
                                if (ctx != null) ctx.beginPath();
 
793
                                return new svg.BoundingBox();
 
794
                        }
 
795
                        
 
796
                        this.renderChildren = function(ctx) {
 
797
                                this.path(ctx);
 
798
                                svg.Mouse.checkPath(this, ctx);
 
799
                                if (ctx.fillStyle != '') ctx.fill();
 
800
                                if (ctx.strokeStyle != '') ctx.stroke();
 
801
                                
 
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]);
 
807
                                        }
 
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]);
 
812
                                                }
 
813
                                        }
 
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]);
 
817
                                        }
 
818
                                }                                       
 
819
                        }
 
820
                        
 
821
                        this.getBoundingBox = function() {
 
822
                                return this.path();
 
823
                        }
 
824
                        
 
825
                        this.getMarkers = function() {
 
826
                                return null;
 
827
                        }
 
828
                }
 
829
                svg.Element.PathElementBase.prototype = new svg.Element.RenderedElementBase;
 
830
                
 
831
                // svg element
 
832
                svg.Element.svg = function(node) {
 
833
                        this.base = svg.Element.RenderedElementBase;
 
834
                        this.base(node);
 
835
                        
 
836
                        this.baseClearContext = this.clearContext;
 
837
                        this.clearContext = function(ctx) {
 
838
                                this.baseClearContext(ctx);
 
839
                                svg.ViewPort.RemoveCurrent();
 
840
                        }
 
841
                        
 
842
                        this.baseSetContext = this.setContext;
 
843
                        this.setContext = function(ctx) {
 
844
                                // initial values
 
845
                                ctx.strokeStyle = 'rgba(0,0,0,0)';
 
846
                                ctx.lineCap = 'butt';
 
847
                                ctx.lineJoin = 'miter';
 
848
                                ctx.miterLimit = 4;                     
 
849
                        
 
850
                                this.baseSetContext(ctx);
 
851
                                
 
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'));
 
855
                                }
 
856
                                
 
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');
 
862
                                        
 
863
                                        var x = 0;
 
864
                                        var y = 0;
 
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');
 
868
                                        }
 
869
                                        
 
870
                                        ctx.beginPath();
 
871
                                        ctx.moveTo(x, y);
 
872
                                        ctx.lineTo(width, y);
 
873
                                        ctx.lineTo(width, height);
 
874
                                        ctx.lineTo(x, height);
 
875
                                        ctx.closePath();
 
876
                                        ctx.clip();
 
877
                                }
 
878
                                svg.ViewPort.SetCurrent(width, height); 
 
879
                                                
 
880
                                // viewbox
 
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];
 
885
                                        width = viewBox[2];
 
886
                                        height = viewBox[3];
 
887
                                        
 
888
                                        svg.AspectRatio(ctx,
 
889
                                                                        this.attribute('preserveAspectRatio').value, 
 
890
                                                                        svg.ViewPort.width(), 
 
891
                                                                        width,
 
892
                                                                        svg.ViewPort.height(),
 
893
                                                                        height,
 
894
                                                                        minX,
 
895
                                                                        minY,
 
896
                                                                        this.attribute('refX').value,
 
897
                                                                        this.attribute('refY').value);
 
898
                                                                                
 
899
                                        svg.ViewPort.RemoveCurrent();   
 
900
                                        svg.ViewPort.SetCurrent(viewBox[2], viewBox[3]);                                                
 
901
                                }                               
 
902
                        }
 
903
                }
 
904
                svg.Element.svg.prototype = new svg.Element.RenderedElementBase;
 
905
 
 
906
                // rect element
 
907
                svg.Element.rect = function(node) {
 
908
                        this.base = svg.Element.PathElementBase;
 
909
                        this.base(node);
 
910
                        
 
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;
 
920
                                
 
921
                                if (ctx != null) {
 
922
                                        ctx.beginPath();
 
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)
 
932
                                        ctx.closePath();
 
933
                                }
 
934
                                
 
935
                                return new svg.BoundingBox(x, y, x + width, y + height);
 
936
                        }
 
937
                }
 
938
                svg.Element.rect.prototype = new svg.Element.PathElementBase;
 
939
                
 
940
                // circle element
 
941
                svg.Element.circle = function(node) {
 
942
                        this.base = svg.Element.PathElementBase;
 
943
                        this.base(node);
 
944
                        
 
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();
 
949
                        
 
950
                                if (ctx != null) {
 
951
                                        ctx.beginPath();
 
952
                                        ctx.arc(cx, cy, r, 0, Math.PI * 2, true); 
 
953
                                        ctx.closePath();
 
954
                                }
 
955
                                
 
956
                                return new svg.BoundingBox(cx - r, cy - r, cx + r, cy + r);
 
957
                        }
 
958
                }
 
959
                svg.Element.circle.prototype = new svg.Element.PathElementBase; 
 
960
 
 
961
                // ellipse element
 
962
                svg.Element.ellipse = function(node) {
 
963
                        this.base = svg.Element.PathElementBase;
 
964
                        this.base(node);
 
965
                        
 
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');
 
972
                                
 
973
                                if (ctx != null) {
 
974
                                        ctx.beginPath();
 
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);
 
980
                                        ctx.closePath();
 
981
                                }
 
982
                                
 
983
                                return new svg.BoundingBox(cx - rx, cy - ry, cx + rx, cy + ry);
 
984
                        }
 
985
                }
 
986
                svg.Element.ellipse.prototype = new svg.Element.PathElementBase;                        
 
987
                
 
988
                // line element
 
989
                svg.Element.line = function(node) {
 
990
                        this.base = svg.Element.PathElementBase;
 
991
                        this.base(node);
 
992
                        
 
993
                        this.getPoints = function() {
 
994
                                return [
 
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'))];
 
997
                        }
 
998
                                                                
 
999
                        this.path = function(ctx) {
 
1000
                                var points = this.getPoints();
 
1001
                                
 
1002
                                if (ctx != null) {
 
1003
                                        ctx.beginPath();
 
1004
                                        ctx.moveTo(points[0].x, points[0].y);
 
1005
                                        ctx.lineTo(points[1].x, points[1].y);
 
1006
                                }
 
1007
                                
 
1008
                                return new svg.BoundingBox(points[0].x, points[0].y, points[1].x, points[1].y);
 
1009
                        }
 
1010
                        
 
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]];
 
1015
                        }
 
1016
                }
 
1017
                svg.Element.line.prototype = new svg.Element.PathElementBase;           
 
1018
                                
 
1019
                // polyline element
 
1020
                svg.Element.polyline = function(node) {
 
1021
                        this.base = svg.Element.PathElementBase;
 
1022
                        this.base(node);
 
1023
                        
 
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);
 
1027
                                if (ctx != null) {
 
1028
                                        ctx.beginPath();
 
1029
                                        ctx.moveTo(this.points[0].x, this.points[0].y);
 
1030
                                }
 
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);
 
1034
                                }
 
1035
                                return bb;
 
1036
                        }
 
1037
                        
 
1038
                        this.getMarkers = function() {
 
1039
                                var markers = [];
 
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])]);
 
1042
                                }
 
1043
                                markers.push([this.points[this.points.length-1], markers[markers.length-1][1]]);
 
1044
                                return markers;
 
1045
                        }                       
 
1046
                }
 
1047
                svg.Element.polyline.prototype = new svg.Element.PathElementBase;                               
 
1048
                                
 
1049
                // polygon element
 
1050
                svg.Element.polygon = function(node) {
 
1051
                        this.base = svg.Element.polyline;
 
1052
                        this.base(node);
 
1053
                        
 
1054
                        this.basePath = this.path;
 
1055
                        this.path = function(ctx) {
 
1056
                                var bb = this.basePath(ctx);
 
1057
                                if (ctx != null) {
 
1058
                                        ctx.lineTo(this.points[0].x, this.points[0].y);
 
1059
                                        ctx.closePath();
 
1060
                                }
 
1061
                                return bb;
 
1062
                        }
 
1063
                }
 
1064
                svg.Element.polygon.prototype = new svg.Element.polyline;
 
1065
 
 
1066
                // path element
 
1067
                svg.Element.path = function(node) {
 
1068
                        this.base = svg.Element.PathElementBase;
 
1069
                        this.base(node);
 
1070
                                        
 
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
 
1082
                        d = svg.trim(d);
 
1083
                        this.PathParser = new (function(d) {
 
1084
                                this.tokens = d.split(' ');
 
1085
                                
 
1086
                                this.reset = function() {
 
1087
                                        this.i = -1;
 
1088
                                        this.command = '';
 
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);
 
1093
                                        this.points = [];
 
1094
                                        this.angles = [];
 
1095
                                }
 
1096
                                                                
 
1097
                                this.isEnd = function() {
 
1098
                                        return this.i >= this.tokens.length - 1;
 
1099
                                }
 
1100
                                
 
1101
                                this.isCommandOrEnd = function() {
 
1102
                                        if (this.isEnd()) return true;
 
1103
                                        return this.tokens[this.i + 1].match(/[A-Za-z]/) != null;
 
1104
                                }
 
1105
                                
 
1106
                                this.isRelativeCommand = function() {
 
1107
                                        return this.command == this.command.toLowerCase();
 
1108
                                }
 
1109
                                                        
 
1110
                                this.getToken = function() {
 
1111
                                        this.i = this.i + 1;
 
1112
                                        return this.tokens[this.i];
 
1113
                                }
 
1114
                                
 
1115
                                this.getScalar = function() {
 
1116
                                        return parseFloat(this.getToken());
 
1117
                                }
 
1118
                                
 
1119
                                this.nextCommand = function() {
 
1120
                                        this.previousCommand = this.command;
 
1121
                                        this.command = this.getToken();
 
1122
                                }                               
 
1123
                                
 
1124
                                this.getPoint = function() {
 
1125
                                        var p = new svg.Point(this.getScalar(), this.getScalar());
 
1126
                                        return this.makeAbsolute(p);
 
1127
                                }
 
1128
                                
 
1129
                                this.getAsControlPoint = function() {
 
1130
                                        var p = this.getPoint();
 
1131
                                        this.control = p;
 
1132
                                        return p;
 
1133
                                }
 
1134
                                
 
1135
                                this.getAsCurrentPoint = function() {
 
1136
                                        var p = this.getPoint();
 
1137
                                        this.current = p;
 
1138
                                        return p;       
 
1139
                                }
 
1140
                                
 
1141
                                this.getReflectedControlPoint = function() {
 
1142
                                        if (this.previousCommand.toLowerCase() != 'c' && this.previousCommand.toLowerCase() != 's') {
 
1143
                                                return this.current;
 
1144
                                        }
 
1145
                                        
 
1146
                                        // reflect point
 
1147
                                        var p = new svg.Point(2 * this.current.x - this.control.x, 2 * this.current.y - this.control.y);                                        
 
1148
                                        return p;
 
1149
                                }
 
1150
                                
 
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;
 
1155
                                        }
 
1156
                                        return p;
 
1157
                                }
 
1158
                                
 
1159
                                this.addMarker = function(p, from) {
 
1160
                                        this.addMarkerAngle(p, from == null ? null : from.angleTo(p));
 
1161
                                }
 
1162
                                
 
1163
                                this.addMarkerAngle = function(p, a) {
 
1164
                                        this.points.push(p);
 
1165
                                        this.angles.push(a);
 
1166
                                }                               
 
1167
                                
 
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];
 
1175
                                                                        break;
 
1176
                                                                }
 
1177
                                                        }
 
1178
                                                }
 
1179
                                        }
 
1180
                                        return this.angles;
 
1181
                                }
 
1182
                        })(d);
 
1183
 
 
1184
                        this.path = function(ctx) {
 
1185
                                var pp = this.PathParser;
 
1186
                                pp.reset();
 
1187
 
 
1188
                                var bb = new svg.BoundingBox();
 
1189
                                
 
1190
                                if(this.attribute('visibility').value=='hidden') return;
 
1191
                                
 
1192
                                if (ctx != null) ctx.beginPath();
 
1193
                                while (!pp.isEnd()) {
 
1194
                                        pp.nextCommand();
 
1195
                                        switch (pp.command.toUpperCase()) {
 
1196
                                        case 'M':
 
1197
                                                var p = pp.getAsCurrentPoint();
 
1198
                                                pp.addMarker(p);
 
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();
 
1204
                                                        pp.addMarker(p);
 
1205
                                                        bb.addPoint(p.x, p.y);
 
1206
                                                        if (ctx != null) ctx.lineTo(p.x, p.y);
 
1207
                                                }
 
1208
                                                break;
 
1209
                                        case 'L':
 
1210
                                                while (!pp.isCommandOrEnd()) {
 
1211
                                                        var c = pp.current;
 
1212
                                                        var p = pp.getAsCurrentPoint();
 
1213
                                                        pp.addMarker(p, c);
 
1214
                                                        bb.addPoint(p.x, p.y);
 
1215
                                                        if (ctx != null) ctx.lineTo(p.x, p.y);
 
1216
                                                }
 
1217
                                                break;
 
1218
                                        case 'H':
 
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);
 
1222
                                                        pp.current = newP;
 
1223
                                                        bb.addPoint(pp.current.x, pp.current.y);
 
1224
                                                        if (ctx != null) ctx.lineTo(pp.current.x, pp.current.y);
 
1225
                                                }
 
1226
                                                break;
 
1227
                                        case 'V':
 
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);
 
1231
                                                        pp.current = newP;
 
1232
                                                        bb.addPoint(pp.current.x, pp.current.y);
 
1233
                                                        if (ctx != null) ctx.lineTo(pp.current.x, pp.current.y);
 
1234
                                                }
 
1235
                                                break;
 
1236
                                        case 'C':
 
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);
 
1245
                                                }
 
1246
                                                break;
 
1247
                                        case 'S':
 
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);
 
1256
                                                }
 
1257
                                                break;
 
1258
                                        case 'Q':
 
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);
 
1266
                                                }
 
1267
                                                break;
 
1268
                                        case 'T':
 
1269
                                                while (!pp.isCommandOrEnd()) {
 
1270
                                                        var curr = pp.current;
 
1271
                                                        var cntrl = pp.getReflectedControlPoint();
 
1272
                                                        pp.control = cntrl;
 
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);
 
1277
                                                }
 
1278
                                                break;
 
1279
                                        case 'A':
 
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();
 
1288
 
 
1289
                                                        // Conversion from endpoint to center parameterization
 
1290
                                                        // http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes
 
1291
                                                        // x1', y1'
 
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
 
1295
                                                        );
 
1296
                                                        // adjust radii
 
1297
                                                        var l = Math.pow(currp.x,2)/Math.pow(rx,2)+Math.pow(currp.y,2)/Math.pow(ry,2);
 
1298
                                                        if (l > 1) {
 
1299
                                                                rx *= Math.sqrt(l);
 
1300
                                                                ry *= Math.sqrt(l);
 
1301
                                                        }
 
1302
                                                        // cx', cy'
 
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))
 
1306
                                                        );
 
1307
                                                        if (isNaN(s)) s = 0;
 
1308
                                                        var cpp = new svg.Point(s * rx * currp.y / ry, s * -ry * currp.x / rx);
 
1309
                                                        // cx, cy
 
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
 
1313
                                                        );
 
1314
                                                        // vector magnitude
 
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)); }
 
1320
                                                        // initial angle
 
1321
                                                        var a1 = a([1,0], [(currp.x-cpp.x)/rx,(currp.y-cpp.y)/ry]);
 
1322
                                                        // angle delta
 
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];
 
1325
                                                        var ad = a(u, v);
 
1326
                                                        if (r(u,v) <= -1) ad = Math.PI;
 
1327
                                                        if (r(u,v) >= 1) ad = 0;
 
1328
 
 
1329
                                                        if (sweepFlag == 0 && ad > 0) ad = ad - 2 * Math.PI;
 
1330
                                                        if (sweepFlag == 1 && ad < 0) ad = ad + 2 * Math.PI;
 
1331
 
 
1332
                                                        // for markers
 
1333
                                                        var halfWay = new svg.Point(
 
1334
                                                                centp.x - rx * Math.cos((a1 + ad) / 2),
 
1335
                                                                centp.y - ry * Math.sin((a1 + ad) / 2)
 
1336
                                                        );
 
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);
 
1339
 
 
1340
                                                        bb.addPoint(cp.x, cp.y); // TODO: this is too naive, make it better
 
1341
                                                        if (ctx != null) {
 
1342
                                                                var r = rx > ry ? rx : ry;
 
1343
                                                                var sx = rx > ry ? 1 : rx / ry;
 
1344
                                                                var sy = rx > ry ? ry / rx : 1;
 
1345
 
 
1346
                                                                ctx.translate(centp.x, centp.y);
 
1347
                                                                ctx.rotate(xAxisRotation);
 
1348
                                                                ctx.scale(sx, sy);
 
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);
 
1353
                                                        }
 
1354
                                                }
 
1355
                                                break;
 
1356
                                        case 'Z':
 
1357
                                                if (ctx != null) ctx.closePath();
 
1358
                                                pp.current = pp.start;
 
1359
                                        }
 
1360
                                }
 
1361
 
 
1362
                                return bb;
 
1363
                        }
 
1364
 
 
1365
                        this.getMarkers = function() {
 
1366
                                var points = this.PathParser.getMarkerPoints();
 
1367
                                var angles = this.PathParser.getMarkerAngles();
 
1368
                                
 
1369
                                var markers = [];
 
1370
                                for (var i=0; i<points.length; i++) {
 
1371
                                        markers.push([points[i], angles[i]]);
 
1372
                                }
 
1373
                                return markers;
 
1374
                        }
 
1375
                }
 
1376
                svg.Element.path.prototype = new svg.Element.PathElementBase;
 
1377
                
 
1378
                // pattern element
 
1379
                svg.Element.pattern = function(node) {
 
1380
                        this.base = svg.Element.ElementBase;
 
1381
                        this.base(node);
 
1382
                        
 
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;
 
1392
                                
 
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');
 
1398
                        }
 
1399
                }
 
1400
                svg.Element.pattern.prototype = new svg.Element.ElementBase;
 
1401
                
 
1402
                // marker element
 
1403
                svg.Element.marker = function(node) {
 
1404
                        this.base = svg.Element.ElementBase;
 
1405
                        this.base(node);
 
1406
                        
 
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);
 
1412
                                ctx.save();
 
1413
                                                        
 
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);
 
1425
                                
 
1426
                                ctx.restore();
 
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);
 
1430
                        }
 
1431
                }
 
1432
                svg.Element.marker.prototype = new svg.Element.ElementBase;
 
1433
                
 
1434
                // definitions element
 
1435
                svg.Element.defs = function(node) {
 
1436
                        this.base = svg.Element.ElementBase;
 
1437
                        this.base(node);        
 
1438
                        
 
1439
                        this.render = function(ctx) {
 
1440
                                // NOOP
 
1441
                        }
 
1442
                }
 
1443
                svg.Element.defs.prototype = new svg.Element.ElementBase;
 
1444
                
 
1445
                // base for gradients
 
1446
                svg.Element.GradientBase = function(node) {
 
1447
                        this.base = svg.Element.ElementBase;
 
1448
                        this.base(node);
 
1449
                        
 
1450
                        this.gradientUnits = this.attribute('gradientUnits').valueOrDefault('objectBoundingBox');
 
1451
                        
 
1452
                        this.stops = [];                        
 
1453
                        for (var i=0; i<this.children.length; i++) {
 
1454
                                var child = this.children[i];
 
1455
                                this.stops.push(child);
 
1456
                        }       
 
1457
                        
 
1458
                        this.getGradient = function() {
 
1459
                                // OVERRIDE ME!
 
1460
                        }                       
 
1461
 
 
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();
 
1466
                                }
 
1467
                        
 
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);
 
1471
                                }
 
1472
                                return g;                               
 
1473
                        }
 
1474
                }
 
1475
                svg.Element.GradientBase.prototype = new svg.Element.ElementBase;
 
1476
                
 
1477
                // linear gradient element
 
1478
                svg.Element.linearGradient = function(node) {
 
1479
                        this.base = svg.Element.GradientBase;
 
1480
                        this.base(node);
 
1481
                        
 
1482
                        this.getGradient = function(ctx, element) {
 
1483
                                var bb = element.getBoundingBox();
 
1484
                                
 
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'));
 
1497
                                
 
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);
 
1504
                                }
 
1505
                                
 
1506
                                return ctx.createLinearGradient(p1.x, p1.y, p2.x, p2.y);
 
1507
                        }
 
1508
                }
 
1509
                svg.Element.linearGradient.prototype = new svg.Element.GradientBase;
 
1510
                
 
1511
                // radial gradient element
 
1512
                svg.Element.radialGradient = function(node) {
 
1513
                        this.base = svg.Element.GradientBase;
 
1514
                        this.base(node);
 
1515
                        
 
1516
                        this.getGradient = function(ctx, element) {
 
1517
                                var bb = element.getBoundingBox();
 
1518
                                
 
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'));
 
1525
                                
 
1526
                                var fx = cx;
 
1527
                                var fy = cy;
 
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'));
 
1532
                                }
 
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'));
 
1537
                                }
 
1538
                                
 
1539
                                var r = (this.gradientUnits == 'objectBoundingBox' 
 
1540
                                        ? (bb.width() + bb.height()) / 2.0 * this.attribute('r').numValue()
 
1541
                                        : this.attribute('r').Length.toPixels());
 
1542
                                
 
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);
 
1549
                                        
 
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);
 
1555
                                        }
 
1556
                                }                               
 
1557
                                
 
1558
                                return ctx.createRadialGradient(f.x, f.y, 0, c.x, c.y, r);
 
1559
                        }
 
1560
                }
 
1561
                svg.Element.radialGradient.prototype = new svg.Element.GradientBase;
 
1562
                
 
1563
                // gradient stop element
 
1564
                svg.Element.stop = function(node) {
 
1565
                        this.base = svg.Element.ElementBase;
 
1566
                        this.base(node);
 
1567
                        
 
1568
                        this.offset = this.attribute('offset').numValue();
 
1569
                        
 
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;
 
1573
                }
 
1574
                svg.Element.stop.prototype = new svg.Element.ElementBase;
 
1575
                
 
1576
                // animation base element
 
1577
                svg.Element.AnimateBase = function(node) {
 
1578
                        this.base = svg.Element.ElementBase;
 
1579
                        this.base(node);
 
1580
                        
 
1581
                        svg.Animations.push(this);
 
1582
                        
 
1583
                        this.duration = 0.0;
 
1584
                        this.begin = this.attribute('begin').Time.toMilliseconds();
 
1585
                        this.maxDuration = this.begin + this.attribute('dur').Time.toMilliseconds();
 
1586
                        
 
1587
                        this.getProperty = function() {
 
1588
                                var attributeType = this.attribute('attributeType').value;
 
1589
                                var attributeName = this.attribute('attributeName').value;
 
1590
                                
 
1591
                                if (attributeType == 'CSS') {
 
1592
                                        return this.parent.style(attributeName, true);
 
1593
                                }
 
1594
                                return this.parent.attribute(attributeName, true);                      
 
1595
                        };
 
1596
                        
 
1597
                        this.initialValue = null;
 
1598
                        this.removed = false;                   
 
1599
 
 
1600
                        this.calcValue = function() {
 
1601
                                // OVERRIDE ME!
 
1602
                                return '';
 
1603
                        }
 
1604
                        
 
1605
                        this.update = function(delta) { 
 
1606
                                // set initial value
 
1607
                                if (this.initialValue == null) {
 
1608
                                        this.initialValue = this.getProperty().value;
 
1609
                                }
 
1610
                        
 
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') {
 
1615
                                                this.duration = 0.0
 
1616
                                        }
 
1617
                                        else if (this.attribute('fill').valueOrDefault('remove') == 'remove' && !this.removed) {
 
1618
                                                this.removed = true;
 
1619
                                                this.getProperty().value = this.initialValue;
 
1620
                                                return true;
 
1621
                                        }
 
1622
                                        else {
 
1623
                                                return false; // no updates made
 
1624
                                        }
 
1625
                                }                       
 
1626
                                this.duration = this.duration + delta;
 
1627
                        
 
1628
                                // if we're past the begin time
 
1629
                                var updated = false;
 
1630
                                if (this.begin < this.duration) {
 
1631
                                        var newValue = this.calcValue(); // tween
 
1632
                                        
 
1633
                                        if (this.attribute('type').hasValue()) {
 
1634
                                                // for transform, etc.
 
1635
                                                var type = this.attribute('type').value;
 
1636
                                                newValue = type + '(' + newValue + ')';
 
1637
                                        }
 
1638
                                        
 
1639
                                        this.getProperty().value = newValue;
 
1640
                                        updated = true;
 
1641
                                }
 
1642
                                
 
1643
                                return updated;
 
1644
                        }
 
1645
                        
 
1646
                        // fraction of duration we've covered
 
1647
                        this.progress = function() {
 
1648
                                return ((this.duration - this.begin) / (this.maxDuration - this.begin));
 
1649
                        }                       
 
1650
                }
 
1651
                svg.Element.AnimateBase.prototype = new svg.Element.ElementBase;
 
1652
                
 
1653
                // animate element
 
1654
                svg.Element.animate = function(node) {
 
1655
                        this.base = svg.Element.AnimateBase;
 
1656
                        this.base(node);
 
1657
                        
 
1658
                        this.calcValue = function() {
 
1659
                                var from = this.attribute('from').numValue();
 
1660
                                var to = this.attribute('to').numValue();
 
1661
                                
 
1662
                                // tween value linearly
 
1663
                                return from + (to - from) * this.progress(); 
 
1664
                        };
 
1665
                }
 
1666
                svg.Element.animate.prototype = new svg.Element.AnimateBase;
 
1667
                        
 
1668
                // animate color element
 
1669
                svg.Element.animateColor = function(node) {
 
1670
                        this.base = svg.Element.AnimateBase;
 
1671
                        this.base(node);
 
1672
 
 
1673
                        this.calcValue = function() {
 
1674
                                var from = new RGBColor(this.attribute('from').value);
 
1675
                                var to = new RGBColor(this.attribute('to').value);
 
1676
                                
 
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)+')';
 
1683
                                }
 
1684
                                return this.attribute('from').value;
 
1685
                        };
 
1686
                }
 
1687
                svg.Element.animateColor.prototype = new svg.Element.AnimateBase;
 
1688
                
 
1689
                // animate transform element
 
1690
                svg.Element.animateTransform = function(node) {
 
1691
                        this.base = svg.Element.animate;
 
1692
                        this.base(node);
 
1693
                }
 
1694
                svg.Element.animateTransform.prototype = new svg.Element.animate;
 
1695
                
 
1696
                // text element
 
1697
                svg.Element.text = function(node) {
 
1698
                        this.base = svg.Element.RenderedElementBase;
 
1699
                        this.base(node);
 
1700
                        
 
1701
                        if (node != null) {
 
1702
                                // add children
 
1703
                                this.children = [];
 
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);
 
1708
                                        }
 
1709
                                        else if (childNode.nodeType == 3) { // capture text
 
1710
                                                this.addChild(new svg.Element.tspan(childNode), false);
 
1711
                                        }
 
1712
                                }
 
1713
                        }
 
1714
                        
 
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;
 
1721
                                }
 
1722
                                if (this.attribute('alignment-baseline').hasValue()) ctx.textBaseline = this.attribute('alignment-baseline').value;
 
1723
                        }
 
1724
                        
 
1725
                        this.renderChildren = function(ctx) {
 
1726
                                if(this.attribute('visibility').value=='hidden') return;
 
1727
                                
 
1728
                                var x = this.attribute('x').Length.toPixels('x');
 
1729
                                var y = this.attribute('y').Length.toPixels('y');
 
1730
                                
 
1731
                                for (var i=0; i<this.children.length; i++) {
 
1732
                                        var child = this.children[i];
 
1733
                                
 
1734
                                        if (child.attribute('x').hasValue()) {
 
1735
                                                child.x = child.attribute('x').Length.toPixels('x');
 
1736
                                        }
 
1737
                                        else {
 
1738
                                                if (child.attribute('dx').hasValue()) x += child.attribute('dx').Length.toPixels('x');
 
1739
                                                child.x = x;
 
1740
                                                x += child.measureText(ctx);
 
1741
                                        }
 
1742
                                        
 
1743
                                        if (child.attribute('y').hasValue()) {
 
1744
                                                child.y = child.attribute('y').Length.toPixels('y');
 
1745
                                        }
 
1746
                                        else {
 
1747
                                                if (child.attribute('dy').hasValue()) y += child.attribute('dy').Length.toPixels('y');
 
1748
                                                child.y = y;
 
1749
                                        }       
 
1750
                                        
 
1751
                                        child.render(ctx);
 
1752
                                }
 
1753
                        }
 
1754
                }
 
1755
                svg.Element.text.prototype = new svg.Element.RenderedElementBase;
 
1756
                
 
1757
                // text base
 
1758
                svg.Element.TextElementBase = function(node) {
 
1759
                        this.base = svg.Element.RenderedElementBase;
 
1760
                        this.base(node);
 
1761
                        
 
1762
                        this.renderChildren = function(ctx) {
 
1763
                                ctx.fillText(svg.compressSpaces(this.getText()), this.x, this.y);
 
1764
                        }
 
1765
                        
 
1766
                        this.getText = function() {
 
1767
                                // OVERRIDE ME
 
1768
                        }
 
1769
                        
 
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;
 
1774
                        }
 
1775
                }
 
1776
                svg.Element.TextElementBase.prototype = new svg.Element.RenderedElementBase;
 
1777
                
 
1778
                // tspan 
 
1779
                svg.Element.tspan = function(node) {
 
1780
                        this.base = svg.Element.TextElementBase;
 
1781
                        this.base(node);
 
1782
                        
 
1783
                        //                                                               TEXT                     ELEMENT
 
1784
                        this.text = node.nodeType == 3 ? node.nodeValue : node.childNodes[0].nodeValue;
 
1785
                        this.getText = function() {
 
1786
                                return this.text;
 
1787
                        }
 
1788
                }
 
1789
                svg.Element.tspan.prototype = new svg.Element.TextElementBase;
 
1790
                
 
1791
                // tref
 
1792
                svg.Element.tref = function(node) {
 
1793
                        this.base = svg.Element.TextElementBase;
 
1794
                        this.base(node);
 
1795
                        
 
1796
                        this.getText = function() {
 
1797
                                var element = this.attribute('xlink:href').Definition.getDefinition();
 
1798
                                if (element != null) return element.children[0].getText();
 
1799
                        }
 
1800
                }
 
1801
                svg.Element.tref.prototype = new svg.Element.TextElementBase;           
 
1802
                
 
1803
                // a element
 
1804
                svg.Element.a = function(node) {
 
1805
                        this.base = svg.Element.TextElementBase;
 
1806
                        this.base(node);
 
1807
                        
 
1808
                        this.hasText = true;
 
1809
                        for (var i=0; i<node.childNodes.length; i++) {
 
1810
                                if (node.childNodes[i].nodeType != 3) this.hasText = false;
 
1811
                        }
 
1812
                        
 
1813
                        // this might contain text
 
1814
                        this.text = this.hasText ? node.childNodes[0].nodeValue : '';
 
1815
                        this.getText = function() {
 
1816
                                return this.text;
 
1817
                        }               
 
1818
 
 
1819
                        this.baseRenderChildren = this.renderChildren;
 
1820
                        this.renderChildren = function(ctx) {
 
1821
                                if (this.hasText) {
 
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));                                  
 
1826
                                }
 
1827
                                else {
 
1828
                                        // render as temporary group
 
1829
                                        var g = new svg.Element.g();
 
1830
                                        g.children = this.children;
 
1831
                                        g.parent = this;
 
1832
                                        g.render(ctx);
 
1833
                                }
 
1834
                        }
 
1835
                        
 
1836
                        this.onclick = function() {
 
1837
                                window.open(this.attribute('xlink:href').value);
 
1838
                        }
 
1839
                        
 
1840
                        this.onmousemove = function() {
 
1841
                                svg.ctx.canvas.style.cursor = 'pointer';
 
1842
                        }
 
1843
                }
 
1844
                svg.Element.a.prototype = new svg.Element.TextElementBase;              
 
1845
                
 
1846
                // image element
 
1847
                svg.Element.image = function(node) {
 
1848
                        this.base = svg.Element.RenderedElementBase;
 
1849
                        this.base(node);
 
1850
                        
 
1851
                        svg.Images.push(this);
 
1852
                        this.img = document.createElement('img');
 
1853
                        this.loaded = false;
 
1854
                        var that = this;
 
1855
                        this.img.onload = function() { that.loaded = true; }
 
1856
                        this.img.src = this.attribute('xlink:href').value;
 
1857
                        
 
1858
                        this.renderChildren = function(ctx) {
 
1859
                                var x = this.attribute('x').Length.toPixels('x');
 
1860
                                var y = this.attribute('y').Length.toPixels('y');
 
1861
                                
 
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;
 
1865
                        
 
1866
                                ctx.save();
 
1867
                                ctx.translate(x, y);
 
1868
                                svg.AspectRatio(ctx,
 
1869
                                                                this.attribute('preserveAspectRatio').value,
 
1870
                                                                width,
 
1871
                                                                this.img.width,
 
1872
                                                                height,
 
1873
                                                                this.img.height,
 
1874
                                                                0,
 
1875
                                                                0);     
 
1876
                                ctx.drawImage(this.img, 0, 0);                  
 
1877
                                ctx.restore();
 
1878
                        }
 
1879
                }
 
1880
                svg.Element.image.prototype = new svg.Element.RenderedElementBase;
 
1881
                
 
1882
                // group element
 
1883
                svg.Element.g = function(node) {
 
1884
                        this.base = svg.Element.RenderedElementBase;
 
1885
                        this.base(node);
 
1886
                        
 
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());
 
1891
                                }
 
1892
                                return bb;
 
1893
                        };
 
1894
                }
 
1895
                svg.Element.g.prototype = new svg.Element.RenderedElementBase;
 
1896
 
 
1897
                // symbol element
 
1898
                svg.Element.symbol = function(node) {
 
1899
                        this.base = svg.Element.RenderedElementBase;
 
1900
                        this.base(node);
 
1901
                        
 
1902
                        this.baseSetContext = this.setContext;
 
1903
                        this.setContext = function(ctx) {               
 
1904
                                this.baseSetContext(ctx);
 
1905
                                
 
1906
                                // viewbox
 
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];
 
1911
                                        width = viewBox[2];
 
1912
                                        height = viewBox[3];
 
1913
                                        
 
1914
                                        svg.AspectRatio(ctx,
 
1915
                                                                        this.attribute('preserveAspectRatio').value, 
 
1916
                                                                        this.attribute('width').Length.toPixels('x'),
 
1917
                                                                        width,
 
1918
                                                                        this.attribute('height').Length.toPixels('y'),
 
1919
                                                                        height,
 
1920
                                                                        minX,
 
1921
                                                                        minY);
 
1922
 
 
1923
                                        svg.ViewPort.SetCurrent(viewBox[2], viewBox[3]);                                                
 
1924
                                }
 
1925
                        }                       
 
1926
                }
 
1927
                svg.Element.symbol.prototype = new svg.Element.RenderedElementBase;             
 
1928
                        
 
1929
                // style element
 
1930
                svg.Element.style = function(node) { 
 
1931
                        this.base = svg.Element.ElementBase;
 
1932
                        this.base(node);
 
1933
                        
 
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 != '') {
 
1946
                                                        var props = {};
 
1947
                                                        for (var k=0; k<cssProps.length; k++) {
 
1948
                                                                var prop = cssProps[k].split(':');
 
1949
                                                                var name = prop[0];
 
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]));
 
1953
                                                                }
 
1954
                                                        }
 
1955
                                                        svg.Styles[cssClass] = props;
 
1956
                                                }
 
1957
                                        }
 
1958
                                }
 
1959
                        }
 
1960
                }
 
1961
                svg.Element.style.prototype = new svg.Element.ElementBase;
 
1962
                
 
1963
                // use element 
 
1964
                svg.Element.use = function(node) {
 
1965
                        this.base = svg.Element.RenderedElementBase;
 
1966
                        this.base(node);
 
1967
                        
 
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'));
 
1973
                        }
 
1974
                        
 
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;
 
1979
                                return element;
 
1980
                        }
 
1981
                        
 
1982
                        this.path = function(ctx) {
 
1983
                                var element = this.getDefinition();
 
1984
                                if (element != null) element.path(ctx);
 
1985
                        }
 
1986
                        
 
1987
                        this.renderChildren = function(ctx) {
 
1988
                                var element = this.getDefinition();
 
1989
                                if (element != null) element.render(ctx);
 
1990
                        }
 
1991
                }
 
1992
                svg.Element.use.prototype = new svg.Element.RenderedElementBase;
 
1993
                
 
1994
                // clip element
 
1995
                svg.Element.clipPath = function(node) {
 
1996
                        this.base = svg.Element.ElementBase;
 
1997
                        this.base(node);
 
1998
                        
 
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);
 
2003
                                                ctx.clip();
 
2004
                                        }
 
2005
                                }
 
2006
                        }
 
2007
                }
 
2008
                svg.Element.clipPath.prototype = new svg.Element.ElementBase;
 
2009
 
 
2010
                // title element, do nothing
 
2011
                svg.Element.title = function(node) {
 
2012
                }
 
2013
                svg.Element.title.prototype = new svg.Element.ElementBase;
 
2014
 
 
2015
                // desc element, do nothing
 
2016
                svg.Element.desc = function(node) {
 
2017
                }
 
2018
                svg.Element.desc.prototype = new svg.Element.ElementBase;               
 
2019
                
 
2020
                svg.Element.MISSING = function(node) {
 
2021
                        console.log('ERROR: Element \'' + node.nodeName + '\' not yet implemented.');
 
2022
                }
 
2023
                svg.Element.MISSING.prototype = new svg.Element.ElementBase;
 
2024
                
 
2025
                // element factory
 
2026
                svg.CreateElement = function(node) {    
 
2027
                        var className = node.nodeName.replace(/^[^:]+:/,'');
 
2028
                        var e = null;
 
2029
                        if (typeof(svg.Element[className]) != 'undefined') {
 
2030
                                e = new svg.Element[className](node);
 
2031
                        }
 
2032
                        else {
 
2033
                                e = new svg.Element.MISSING(node);
 
2034
                        }
 
2035
 
 
2036
                        e.type = node.nodeName;
 
2037
                        return e;
 
2038
                }
 
2039
                                
 
2040
                // load from url
 
2041
                svg.load = function(ctx, url) {
 
2042
                        svg.loadXml(ctx, svg.ajax(url));
 
2043
                }
 
2044
                
 
2045
                // load from xml
 
2046
                svg.loadXml = function(ctx, xml) {
 
2047
                        svg.init(ctx);
 
2048
                        
 
2049
                        var mapXY = function(p) {
 
2050
                                var e = ctx.canvas;
 
2051
                                while (e) {
 
2052
                                        p.x -= e.offsetLeft;
 
2053
                                        p.y -= e.offsetTop;
 
2054
                                        e = e.offsetParent;
 
2055
                                }
 
2056
                                if (window.scrollX) p.x += window.scrollX;
 
2057
                                if (window.scrollY) p.y += window.scrollY;
 
2058
                                return p;
 
2059
                        }
 
2060
                        
 
2061
                        // bind mouse
 
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);
 
2066
                                };
 
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);
 
2070
                                };
 
2071
                        }
 
2072
                
 
2073
                        var dom = svg.parseXml(xml);
 
2074
                        var e = svg.CreateElement(dom.documentElement);
 
2075
                                        
 
2076
                        // render loop
 
2077
                        var isFirstRender = true;
 
2078
                        var draw = function() {
 
2079
                                if (svg.opts == null || svg.opts['ignoreDimensions'] != true) {
 
2080
                                        // set canvas size
 
2081
                                        if (e.style('width').hasValue()) {
 
2082
                                                ctx.canvas.width = e.style('width').Length.toPixels(ctx.canvas.parentNode.clientWidth);
 
2083
                                        }
 
2084
                                        if (e.style('height').hasValue()) {
 
2085
                                                ctx.canvas.height = e.style('height').Length.toPixels(ctx.canvas.parentNode.clientHeight);
 
2086
                                        }
 
2087
                                }
 
2088
                                svg.ViewPort.SetCurrent(ctx.canvas.clientWidth, ctx.canvas.clientHeight);               
 
2089
                                
 
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';
 
2097
                                }
 
2098
                        
 
2099
                                // clear and render
 
2100
                                if (svg.opts == null || svg.opts['ignoreClear'] != true) {
 
2101
                                        ctx.clearRect(0, 0, ctx.canvas.clientWidth, ctx.canvas.clientHeight);
 
2102
                                }
 
2103
                                e.render(ctx);
 
2104
                                if (isFirstRender) {
 
2105
                                        isFirstRender = false;
 
2106
                                        if (svg.opts != null && typeof(svg.opts['renderCallback']) == 'function') svg.opts['renderCallback']();
 
2107
                                }                       
 
2108
                        }
 
2109
                        
 
2110
                        var waitingForImages = true;
 
2111
                        if (svg.ImagesLoaded()) {
 
2112
                                waitingForImages = false;
 
2113
                                draw();
 
2114
                        }
 
2115
                        svg.intervalID = setInterval(function() { 
 
2116
                                var needUpdate = false;
 
2117
                                
 
2118
                                if (waitingForImages && svg.ImagesLoaded()) {
 
2119
                                        waitingForImages = false;
 
2120
                                        needUpdate = true;
 
2121
                                }
 
2122
                        
 
2123
                                // need update from mouse events?
 
2124
                                if (svg.opts == null || svg.opts['ignoreMouse'] != true) {
 
2125
                                        needUpdate = needUpdate | svg.Mouse.hasEvents();
 
2126
                                }
 
2127
                        
 
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);
 
2132
                                        }
 
2133
                                }
 
2134
                                
 
2135
                                // need update from redraw?
 
2136
                                if (svg.opts != null && typeof(svg.opts['forceRedraw']) == 'function') {
 
2137
                                        if (svg.opts['forceRedraw']() == true) needUpdate = true;
 
2138
                                }
 
2139
                                
 
2140
                                // render if needed
 
2141
                                if (needUpdate) {
 
2142
                                        draw();                         
 
2143
                                        svg.Mouse.runEvents(); // run and clear our events
 
2144
                                }
 
2145
                        }, 1000 / svg.FRAMERATE);
 
2146
                }
 
2147
                
 
2148
                svg.stop = function() {
 
2149
                        if (svg.intervalID) {
 
2150
                                clearInterval(svg.intervalID);
 
2151
                        }
 
2152
                }
 
2153
                
 
2154
                svg.Mouse = new (function() {
 
2155
                        this.events = [];
 
2156
                        this.hasEvents = function() { return this.events.length != 0; }
 
2157
                
 
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(); }
 
2161
                                });
 
2162
                        }
 
2163
                        
 
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(); }
 
2167
                                });
 
2168
                        }                       
 
2169
                        
 
2170
                        this.eventElements = [];
 
2171
                        
 
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;
 
2176
                                }
 
2177
                        }
 
2178
                        
 
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;
 
2183
                                }                       
 
2184
                        }
 
2185
                        
 
2186
                        this.runEvents = function() {
 
2187
                                svg.ctx.canvas.style.cursor = '';
 
2188
                                
 
2189
                                for (var i=0; i<this.events.length; i++) {
 
2190
                                        var e = this.events[i];
 
2191
                                        var element = this.eventElements[i];
 
2192
                                        while (element) {
 
2193
                                                e.run(element);
 
2194
                                                element = element.parent;
 
2195
                                        }
 
2196
                                }               
 
2197
                        
 
2198
                                // done running, clear
 
2199
                                this.events = []; 
 
2200
                                this.eventElements = [];
 
2201
                        }
 
2202
                });
 
2203
                
 
2204
                return svg;
 
2205
        }
 
2206
})();
 
2207
 
 
2208
if (CanvasRenderingContext2D) {
 
2209
        CanvasRenderingContext2D.prototype.drawSvg = function(s, dx, dy, dw, dh) {
 
2210
                canvg(this.canvas, s, { 
 
2211
                        ignoreMouse: true, 
 
2212
                        ignoreAnimation: true, 
 
2213
                        ignoreDimensions: true, 
 
2214
                        ignoreClear: true, 
 
2215
                        offsetX: dx, 
 
2216
                        offsetY: dy, 
 
2217
                        scaleWidth: dw, 
 
2218
                        scaleHeight: dh
 
2219
                });
 
2220
        }
 
2221
}
 
2222
 
 
2223
/**
 
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
 
2228
 */
 
2229
function RGBColor(color_string)
 
2230
{
 
2231
    this.ok = false;
 
2232
 
 
2233
    // strip any leading #
 
2234
    if (color_string.charAt(0) == '#') { // remove # if any
 
2235
        color_string = color_string.substr(1,6);
 
2236
    }
 
2237
 
 
2238
    color_string = color_string.replace(/ /g,'');
 
2239
    color_string = color_string.toLowerCase();
 
2240
 
 
2241
    // before getting into regexps, try simple matches
 
2242
    // and overwrite the input
 
2243
    var simple_colors = {
 
2244
        aliceblue: 'f0f8ff',
 
2245
        antiquewhite: 'faebd7',
 
2246
        aqua: '00ffff',
 
2247
        aquamarine: '7fffd4',
 
2248
        azure: 'f0ffff',
 
2249
        beige: 'f5f5dc',
 
2250
        bisque: 'ffe4c4',
 
2251
        black: '000000',
 
2252
        blanchedalmond: 'ffebcd',
 
2253
        blue: '0000ff',
 
2254
        blueviolet: '8a2be2',
 
2255
        brown: 'a52a2a',
 
2256
        burlywood: 'deb887',
 
2257
        cadetblue: '5f9ea0',
 
2258
        chartreuse: '7fff00',
 
2259
        chocolate: 'd2691e',
 
2260
        coral: 'ff7f50',
 
2261
        cornflowerblue: '6495ed',
 
2262
        cornsilk: 'fff8dc',
 
2263
        crimson: 'dc143c',
 
2264
        cyan: '00ffff',
 
2265
        darkblue: '00008b',
 
2266
        darkcyan: '008b8b',
 
2267
        darkgoldenrod: 'b8860b',
 
2268
        darkgray: 'a9a9a9',
 
2269
        darkgreen: '006400',
 
2270
        darkkhaki: 'bdb76b',
 
2271
        darkmagenta: '8b008b',
 
2272
        darkolivegreen: '556b2f',
 
2273
        darkorange: 'ff8c00',
 
2274
        darkorchid: '9932cc',
 
2275
        darkred: '8b0000',
 
2276
        darksalmon: 'e9967a',
 
2277
        darkseagreen: '8fbc8f',
 
2278
        darkslateblue: '483d8b',
 
2279
        darkslategray: '2f4f4f',
 
2280
        darkturquoise: '00ced1',
 
2281
        darkviolet: '9400d3',
 
2282
        deeppink: 'ff1493',
 
2283
        deepskyblue: '00bfff',
 
2284
        dimgray: '696969',
 
2285
        dodgerblue: '1e90ff',
 
2286
        feldspar: 'd19275',
 
2287
        firebrick: 'b22222',
 
2288
        floralwhite: 'fffaf0',
 
2289
        forestgreen: '228b22',
 
2290
        fuchsia: 'ff00ff',
 
2291
        gainsboro: 'dcdcdc',
 
2292
        ghostwhite: 'f8f8ff',
 
2293
        gold: 'ffd700',
 
2294
        goldenrod: 'daa520',
 
2295
        gray: '808080',
 
2296
        green: '008000',
 
2297
        greenyellow: 'adff2f',
 
2298
        honeydew: 'f0fff0',
 
2299
        hotpink: 'ff69b4',
 
2300
        indianred : 'cd5c5c',
 
2301
        indigo : '4b0082',
 
2302
        ivory: 'fffff0',
 
2303
        khaki: 'f0e68c',
 
2304
        lavender: 'e6e6fa',
 
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',
 
2322
        lime: '00ff00',
 
2323
        limegreen: '32cd32',
 
2324
        linen: 'faf0e6',
 
2325
        magenta: 'ff00ff',
 
2326
        maroon: '800000',
 
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',
 
2339
        moccasin: 'ffe4b5',
 
2340
        navajowhite: 'ffdead',
 
2341
        navy: '000080',
 
2342
        oldlace: 'fdf5e6',
 
2343
        olive: '808000',
 
2344
        olivedrab: '6b8e23',
 
2345
        orange: 'ffa500',
 
2346
        orangered: 'ff4500',
 
2347
        orchid: 'da70d6',
 
2348
        palegoldenrod: 'eee8aa',
 
2349
        palegreen: '98fb98',
 
2350
        paleturquoise: 'afeeee',
 
2351
        palevioletred: 'd87093',
 
2352
        papayawhip: 'ffefd5',
 
2353
        peachpuff: 'ffdab9',
 
2354
        peru: 'cd853f',
 
2355
        pink: 'ffc0cb',
 
2356
        plum: 'dda0dd',
 
2357
        powderblue: 'b0e0e6',
 
2358
        purple: '800080',
 
2359
        red: 'ff0000',
 
2360
        rosybrown: 'bc8f8f',
 
2361
        royalblue: '4169e1',
 
2362
        saddlebrown: '8b4513',
 
2363
        salmon: 'fa8072',
 
2364
        sandybrown: 'f4a460',
 
2365
        seagreen: '2e8b57',
 
2366
        seashell: 'fff5ee',
 
2367
        sienna: 'a0522d',
 
2368
        silver: 'c0c0c0',
 
2369
        skyblue: '87ceeb',
 
2370
        slateblue: '6a5acd',
 
2371
        slategray: '708090',
 
2372
        snow: 'fffafa',
 
2373
        springgreen: '00ff7f',
 
2374
        steelblue: '4682b4',
 
2375
        tan: 'd2b48c',
 
2376
        teal: '008080',
 
2377
        thistle: 'd8bfd8',
 
2378
        tomato: 'ff6347',
 
2379
        turquoise: '40e0d0',
 
2380
        violet: 'ee82ee',
 
2381
        violetred: 'd02090',
 
2382
        wheat: 'f5deb3',
 
2383
        white: 'ffffff',
 
2384
        whitesmoke: 'f5f5f5',
 
2385
        yellow: 'ffff00',
 
2386
        yellowgreen: '9acd32'
 
2387
    };
 
2388
    for (var key in simple_colors) {
 
2389
        if (color_string == key) {
 
2390
            color_string = simple_colors[key];
 
2391
        }
 
2392
    }
 
2393
    // emd of simple type-in colors
 
2394
 
 
2395
    // array of color definition objects
 
2396
    var color_defs = [
 
2397
        {
 
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){
 
2401
                return [
 
2402
                    parseInt(bits[1]),
 
2403
                    parseInt(bits[2]),
 
2404
                    parseInt(bits[3])
 
2405
                ];
 
2406
            }
 
2407
        },
 
2408
        {
 
2409
            re: /^(\w{2})(\w{2})(\w{2})$/,
 
2410
            example: ['#00ff00', '336699'],
 
2411
            process: function (bits){
 
2412
                return [
 
2413
                    parseInt(bits[1], 16),
 
2414
                    parseInt(bits[2], 16),
 
2415
                    parseInt(bits[3], 16)
 
2416
                ];
 
2417
            }
 
2418
        },
 
2419
        {
 
2420
            re: /^(\w{1})(\w{1})(\w{1})$/,
 
2421
            example: ['#fb0', 'f0f'],
 
2422
            process: function (bits){
 
2423
                return [
 
2424
                    parseInt(bits[1] + bits[1], 16),
 
2425
                    parseInt(bits[2] + bits[2], 16),
 
2426
                    parseInt(bits[3] + bits[3], 16)
 
2427
                ];
 
2428
            }
 
2429
        }
 
2430
    ];
 
2431
 
 
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);
 
2437
        if (bits) {
 
2438
            channels = processor(bits);
 
2439
            this.r = channels[0];
 
2440
            this.g = channels[1];
 
2441
            this.b = channels[2];
 
2442
            this.ok = true;
 
2443
        }
 
2444
 
 
2445
    }
 
2446
 
 
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);
 
2451
 
 
2452
    // some getters
 
2453
    this.toRGB = function () {
 
2454
        return 'rgb(' + this.r + ', ' + this.g + ', ' + this.b + ')';
 
2455
    }
 
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;
 
2464
    }
 
2465
 
 
2466
    // help
 
2467
    this.getHelpXML = function () {
 
2468
 
 
2469
        var examples = new Array();
 
2470
        // add regexps
 
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];
 
2475
            }
 
2476
        }
 
2477
        // add type-in colors
 
2478
        for (var sc in simple_colors) {
 
2479
            examples[examples.length] = sc;
 
2480
        }
 
2481
 
 
2482
        var xml = document.createElement('ul');
 
2483
        xml.setAttribute('id', 'rgbcolor-examples');
 
2484
        for (var i = 0; i < examples.length; i++) {
 
2485
            try {
 
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 =
 
2490
                        'margin: 3px; '
 
2491
                        + 'border: 1px solid black; '
 
2492
                        + 'background:' + list_color.toHex() + '; '
 
2493
                        + 'color:' + list_color.toHex()
 
2494
                ;
 
2495
                example_div.appendChild(document.createTextNode('test'));
 
2496
                var list_item_value = document.createTextNode(
 
2497
                    ' ' + examples[i] + ' -> ' + list_color.toRGB() + ' -> ' + list_color.toHex()
 
2498
                );
 
2499
                list_item.appendChild(example_div);
 
2500
                list_item.appendChild(list_item_value);
 
2501
                xml.appendChild(list_item);
 
2502
 
 
2503
            } catch(e){}
 
2504
        }
 
2505
        return xml;
 
2506
 
 
2507
    }
 
2508
 
 
2509
}
 
 
b'\\ No newline at end of file'