/*!! * Canvas 2 Svg v1.0.4 * A low level canvas to SVG converter. Uses a mock canvas context to build an SVG document. * * Licensed under the MIT license: * http://www.opensource.org/licenses/mit-license.php * * Author: * Kerry Liu * * Copyright (c) 2014 Gliffy Inc. */ ;(function() { "use strict"; var STYLES, ctx, CanvasGradient, CanvasPattern, namedEntities; //helper function to format a string function format(str, args) { var keys = Object.keys(args), i; for (i=0; i 1) { options = defaultOptions; options.width = arguments[0]; options.height = arguments[1]; } else if( !o ) { options = defaultOptions; } else { options = o; } if(!(this instanceof ctx)) { //did someone call this without new? return new ctx(options); } //setup options this.width = options.width || defaultOptions.width; this.height = options.height || defaultOptions.height; this.enableMirroring = options.enableMirroring !== undefined ? options.enableMirroring : defaultOptions.enableMirroring; this.canvas = this; ///point back to this instance! this.__canvas = document.createElement("canvas"); this.__ctx = this.__canvas.getContext("2d"); this.__setDefaultStyles(); this.__stack = [this.__getStyleState()]; this.__groupStack = []; //the root svg element this.__root = document.createElementNS("http://www.w3.org/2000/svg", "svg"); this.__root.setAttribute("version", 1.1); this.__root.setAttribute("xmlns", "http://www.w3.org/2000/svg"); this.__root.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:xlink", "http://www.w3.org/1999/xlink"); this.__root.setAttribute("width", this.width); this.__root.setAttribute("height", this.height); //make sure we don't generate the same ids in defs this.__ids = {}; //defs tag this.__defs = document.createElementNS("http://www.w3.org/2000/svg", "defs"); this.__root.appendChild(this.__defs); //also add a group child. the svg element can't use the transform attribute this.__currentElement = document.createElementNS("http://www.w3.org/2000/svg", "g"); this.__root.appendChild(this.__currentElement); }; /** * Creates the specified svg element * @private */ ctx.prototype.__createElement = function(elementName, properties, resetFill) { var element = document.createElementNS("http://www.w3.org/2000/svg", elementName), keys = Object.keys(properties), i, key; if(resetFill) { //if fill or stroke is not specified, the svg element should not display. By default SVG's fill is black. element.setAttribute("fill", "none"); element.setAttribute("stroke", "none"); } for(i=0; i Math.PI ? 0 : 1; } else { largeArcFlag = diff > Math.PI ? 1 : 0; } this.moveTo(startX, startY); this.__addPathCommand(format("A {rx} {ry} {xAxisRotation} {largeArcFlag} {sweepFlag} {endX} {endY}", {rx:radius, ry:radius, xAxisRotation:0, largeArcFlag:largeArcFlag, sweepFlag:sweepFlag, endX:endX, endY:endY})); }; /** * Generates a ClipPath from the clip command. */ ctx.prototype.clip = function(){ var group = this.__closestGroupOrSvg(), clipPath = document.createElementNS("http://www.w3.org/2000/svg", "clipPath"), id = randomString(this.__ids), newGroup = document.createElementNS("http://www.w3.org/2000/svg", "g"); group.removeChild(this.__currentElement); clipPath.setAttribute("id", id); clipPath.appendChild(this.__currentElement); this.__defs.appendChild(clipPath); //set the clip path to this group group.setAttribute("clip-path", format("url(#{id})", {id:id})); //clip paths can be scaled and transformed, we need to add another wrapper group to avoid later transformations // to this path group.appendChild(newGroup); this.__currentElement = newGroup; }; /** * Draws a canvas, image or mock context to this canvas. * Note that all svg dom manipulation uses node.childNodes rather than node.children for IE support. * http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html#dom-context-2d-drawimage */ ctx.prototype.drawImage = function(){ //convert arguments to a real array var args = Array.prototype.slice.call(arguments), image=args[0], dx, dy, dw, dh, sx=0, sy=0, sw, sh, parent, svg, defs, group, currentElement, svgImage, canvas, context, id; if(args.length === 3) { dx = args[1]; dy = args[2]; sw = image.width; sh = image.height; dw = sw; dh = sh; } else if(args.length === 5) { dx = args[1]; dy = args[2]; dw = args[3]; dh = args[4]; sw = image.width; sh = image.height; } else if(args.length === 9) { sx = args[1]; sy = args[2]; sw = args[3]; sh = args[4]; dx = args[5]; dy = args[6]; dw = args[7]; dh = args[8]; } else { throw new Error("Inavlid number of arguments passed to drawImage: " + arguments.length); } parent = this.__closestGroupOrSvg(); currentElement = this.__currentElement; if(image instanceof ctx) { //canvas2svg mock canvas context. In the future we may want to clone nodes instead. //also I'm currently ignoring dw, dh, sw, sh, sx, sy for a mock context. svg = image.getSvg(); defs = svg.childNodes[0]; while(defs.childNodes.length) { id = defs.childNodes[0].getAttribute("id"); this.__ids[id] = id; this.__defs.appendChild(defs.childNodes[0]); } group = svg.childNodes[1]; parent.appendChild(group); this.__currentElement = group; this.translate(dx, dy); this.__currentElement = currentElement; } else if(image.nodeName === "CANVAS" || image.nodeName === "IMG") { //canvas or image svgImage = document.createElementNS("http://www.w3.org/2000/svg", "image"); svgImage.setAttribute("width", dw); svgImage.setAttribute("height", dh); svgImage.setAttribute("preserveAspectRatio", "none"); if(sx || sy || sw !== image.width || sh !== image.height) { //crop the image using a temporary canvas canvas = document.createElement("canvas"); canvas.width = dw; canvas.height = dh; context = canvas.getContext("2d"); context.drawImage(image, sx, sy, sw, sh, 0, 0, dw, dh); image = canvas; } svgImage.setAttributeNS("http://www.w3.org/1999/xlink", "xlink:href", image.nodeName === "CANVAS" ? image.toDataURL() : image.getAttribute("src")); parent.appendChild(svgImage); this.__currentElement = svgImage; this.translate(dx, dy); this.__currentElement = currentElement; } }; /** * Generates a pattern tag */ ctx.prototype.createPattern = function(image, repetition){ var pattern = document.createElementNS("http://www.w3.org/2000/svg", "pattern"), id = randomString(this.__ids), img; pattern.setAttribute("id", id); pattern.setAttribute("width", image.width); pattern.setAttribute("height", image.height); if(image.nodeName === "CANVAS" || image.nodeName === "IMG") { img = document.createElementNS("http://www.w3.org/2000/svg", "image"); img.setAttribute("width", image.width); img.setAttribute("height", image.height); img.setAttributeNS("http://www.w3.org/1999/xlink", "xlink:href", image.nodeName === "CANVAS" ? image.toDataURL() : image.getAttribute("src")); pattern.appendChild(img); this.__defs.appendChild(pattern); } else if(image instanceof ctx) { pattern.appendChild(image.__root.childNodes[1]); this.__defs.appendChild(pattern); } return new CanvasPattern(pattern, this); }; /** * Not yet implemented */ ctx.prototype.drawFocusRing = function(){}; ctx.prototype.createImageData = function(){}; ctx.prototype.getImageData = function(){}; ctx.prototype.putImageData = function(){}; ctx.prototype.globalCompositeOperation = function(){}; ctx.prototype.arcTo = function(){}; ctx.prototype.setTransform = function(){}; //add options for alternative namespace window.C2S = ctx; }());