#

API Documentation for: NEXT
Show: Inherited Protected Private Deprecated

# File:SVGExporter.js

    /*
    * SVGExporter
    * Visit http://gskinner.com/ for documentation, updates & examples.
    *
    * Copyright ©2014 gskinner.com, inc.
    *
    * Permission is hereby granted, free of charge, to any person
    * obtaining a copy of this software and associated documentation
    * files (the "Software"), to deal in the Software without
    * restriction, including without limitation the rights to use,
    * copy, modify, merge, publish, distribute, sublicense, and/or sell
    * copies of the Software, and to permit persons to whom the
    * Software is furnished to do so, subject to the following
    * conditions:
    *
    * The above copyright notice and this permission notice shall be
    * included in all copies or substantial portions of the Software.
    *
    * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
    * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
    * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
    * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
    * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
    * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
    * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
    * OTHER DEALINGS IN THE SOFTWARE.
    */

    // http://tutorials.jenkov.com/svg/svg-transformation.html

    (function () {
    	"use strict";

    	/**
    	 * Description
    	 * @class SVGExporter
    	 * @constructor
    	 **/
    	var SVGExporter = function (stage) {
    		this.initialize(stage);
    	};
    	var p = SVGExporter.prototype;

    // shortcuts:
    	var c = createjs;

    	var att = function(el, attr, value) {
    		el.setAttribute(attr, value);
    		return el;
    	};

    	var atts = function(el, o) {
    		for (var n in o) {
    			el.setAttribute(n, o[n]);
    		}
    		return el;
    	};

    	var create = function(name, o) {
    		return atts(document.createElementNS(SVGExporter.SVG_NS, name), o);
    	};

    	var add = function(parent, child) {
    		if (!child) { return; }
    		parent.appendChild(child);
    		return child;
    	};

    	var mtx = null;

    // static:
    	SVGExporter.SVG_NS = "http://www.w3.org/2000/svg";
    	SVGExporter.XLINK_NS = "http://www.w3.org/1999/xlink";
    	SVGExporter.BLEND_MAP = {multiply:1, screen:1, overlay:1, darken:1, lighten:1, "color-dodge":1, "color-burn":1, "hard-light":1, "soft-light":1, difference:1, exclusion:1, hue:1, saturation:1, color:1, luminosity:1};

    // properties:
    	p.svg = null;
    	p.stage = null;
    	p.defs = null;
    	p.uids = {};

    // initialization:
    	/**
    	 * Initialization method.
    	 * @method initialize
    	 * @protected
    	 **/
    	p.initialize = function (stage) {
    		this.stage = stage;
    		mtx = stage.getMatrix();
    		var svg = this.svg = create("svg");
    		svg.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:xlink", SVGExporter.XLINK_NS);
    		atts(svg, {width:stage.canvas.width, height:stage.canvas.height, style:"border: 1px solid black; overflow: hidden;"});
    		add(svg, this.defs = create("defs"));
    		add(svg, this.exportContainer(stage));
    	};

    // public properties:

    // private properties:

    // public methods:
    	p.getUID = function(id) {
    		if (this.uids[id] == null) {
    			this.uids[id] = 0;
    			return id;
    		}
    		return id+"_"+(++this.uids[id]);
    	};

    	// makes it easy to override this to add unsupported types:
    	p.exportElement = function(o) {
    		if (o instanceof c.Container) { return this.exportContainer(o); }
    		if (o instanceof c.Bitmap) { return this.exportBitmap(o); }
    		if (o instanceof c.Sprite) { return this.exportSprite(o); }
    		if (o instanceof c.Shape) { return this.exportShape(o); }
    	};

    	p.exportContainer = function(o) {
    		var group = this.addTransform(create("g"), o);
    		for (var i= 0, l=o.getNumChildren(); i<l; i++) {
    			add(group, this.exportElement(o.getChildAt(i)));
    		}
    		return group;
    	};

    	p.exportBitmap = function(o) {
    		return this.addTransform(this._getImage(o.image), o);
    	};

    	p.exportSprite = function(o) {
    		var ss = o.spriteSheet;
    		var frame = ss.getFrame(o.currentFrame);
    		var r = frame.rect;
    		var sprite = this.addTransform(this._getImage(frame.image), o, -r.x - frame.regX, -r.y - frame.regY);
    		var id = this.getUID(sprite.id+"_mask");
    		var mask = create("clipPath", {id:id});
    		add(mask, create("rect", {x: r.x, y: r.y, width: r.width, height: r.height}));
    		add(this.defs, mask);
    		att(sprite, "clip-path", "url(#"+id+")");
    		return sprite;
    	};

    	p.exportShape = function(o) {
    		var shape = this.addTransform(create("g"), o), G = c.Graphics;

    		var q = o.graphics.getInstructions();
    		var active = [], fill=null, stroke=null, strokeStyle=null, closed = false;

    		for (var i= 0, l= q.length; i<l; i++) {
    			var cmd = q[i], isStrokeOrPath = false;

    			if (cmd instanceof G.Fill) {
    				fill = cmd;
    				isStrokeOrPath = closed = true;
    			} else if (cmd instanceof G.Stroke) {
    				stroke = cmd;
    				isStrokeOrPath = closed = true;
    			} else if (cmd instanceof G.StrokeStyle) {
    				strokeStyle = cmd;
    				isStrokeOrPath = closed = true;
    			}
    			if ((closed && !isStrokeOrPath) || i == l-1) {
    				this.exportPath(active, this.getFillAndStroke(fill, stroke, strokeStyle), shape);
    				active.length = 0;
    				closed = false;
    			}
    			if (!isStrokeOrPath) {
    				active.push(cmd);
    			}
    		}

    		return shape;
    	};

    	p.exportPath = function(arr, style, parent) {
    		var o, G = c.Graphics;
    		for (var i= 0, l=arr.length; i<l; i++) {
    			var cmd = arr[i];
    			if (cmd instanceof G.Rect) { o = create("rect", {x:cmd.x, y:cmd.y, width:cmd.w, height:cmd.h}); }
    			else if (cmd instanceof G.Circle) { o = create("circle", {cx:cmd.x, cy:cmd.y, r:cmd.radius}); }
    			else if (cmd instanceof G.Ellipse) { o = create("ellipse", {cx:cmd.x+cmd.w/2, cy:cmd.y+cmd.h/2, rx:cmd.w/2, ry:cmd.h/2}); }
    			else if (cmd instanceof G.RoundRect) {
    				if (cmd.radiusTL == cmd.radiusTR && cmd.radiusTL == cmd.radiusBR && cmd.radiusTL == cmd.radiusBL) { o = create("rect", {x:cmd.x, y:cmd.y, width:cmd.w, height:cmd.h, rx:cmd.radiusTL}); }
    				else { /* TODO: complex drawRoundRect */ }
    			}

    			if (o) {
    				if (parent) { add(parent, o); }
    				if (style) { att(o, "style", style); }
    			}
    		}
    	};

    	p.getFillAndStroke = function(fill, stroke, strokeStyle) {
    		var style = "";
    		if (fill) { style += "fill:"+fill.style+";"; }
    		if (stroke) { style += "stroke:"+stroke.style+";"; }
    		if (strokeStyle) {
    			if (strokeStyle.width != 1) { style += "stroke-width:"+strokeStyle.width+";"; }
    			var caps = strokeStyle.caps == null ? "butt" : strokeStyle.caps;
    			if (caps != "none") { style += "stroke-linecap:"+caps+";" }
    			if (strokeStyle.joints && strokeStyle.joints != "miter") { style += "stroke-linejoin:"+strokeStyle.joints+";"; }
    			else if (strokeStyle.miterLimit != 4) { style += "stroke-miterlimit:"+(strokeStyle.miterLimit?strokeStyle.miterLimit:10)+";"; }

    		}
    		return style;
    	};

    	p._getImage = function(image) {
    		var bmp = create("image");
    		bmp.setAttributeNS(SVGExporter.XLINK_NS, "xlink:href", image.src);
    		atts(bmp, {width: image.width, height: image.height});
    		return bmp;
    	};

    	p.addTransform = function(el, o, x, y) {
    		if (o.alpha != 1) { att(el, "opacity", o.alpha.toFixed(4)); }
    		if (!o.visible) { att(el, "display", "none"); }
    		att(el, "id", this.getUID(o.name||"element"));
    		var blend = SVGExporter.BLEND_MAP[o.compositeOperation];
    		if (blend) {
    			console.log(o.compositeOperation);
    			att(el, "style", "mix-blend-mode:"+ o.compositeOperation);
    		}

    		mtx = o.getMatrix(mtx);
    		if (x && y) { mtx.append(1,0,0,1,x,y); }
    		if (mtx.isIdentity()) { return el; }
    		att(el, "transform", "matrix("+[mtx.a.toFixed(4), mtx.b.toFixed(4), mtx.c.toFixed(4), mtx.d.toFixed(4), mtx.tx.toFixed(4), mtx.ty.toFixed(2)]+")");
    		return el;
    	};

    // private methods:

    	window.SVGExporter = SVGExporter;
    })();