/*! * Canvas 2 Svg * 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 Math.PI ? 0 : 1; } else { largeArcFlag = Math.abs(endAngle - startAngle) > 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; }());