/*
Copyright (c) 2004-2011, The Dojo Foundation All Rights Reserved.
Available via Academic Free License >= 2.1 OR the modified BSD license.
see: http://dojotoolkit.org/license for details
*/
if(!dojo._hasResource["dojox.gfx.utils"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojox.gfx.utils"] = true;
dojo.provide("dojox.gfx.utils");
dojo.require("dojox.gfx");
(function(){
var d = dojo, g = dojox.gfx, gu = g.utils;
dojo.mixin(gu, {
forEach: function(
/* dojox.gfx.Surface || dojox.gfx.Shape */ object,
/*Function|String|Array*/ f, /*Object?*/ o
){
o = o || d.global;
f.call(o, object);
if(object instanceof g.Surface || object instanceof g.Group){
d.forEach(object.children, function(shape){
gu.forEach(shape, f, o);
});
}
},
serialize: function(
/* dojox.gfx.Surface || dojox.gfx.Shape */ object
){
var t = {}, v, isSurface = object instanceof g.Surface;
if(isSurface || object instanceof g.Group){
t.children = d.map(object.children, gu.serialize);
if(isSurface){
return t.children; // Array
}
}else{
t.shape = object.getShape();
}
if(object.getTransform){
v = object.getTransform();
if(v){ t.transform = v; }
}
if(object.getStroke){
v = object.getStroke();
if(v){ t.stroke = v; }
}
if(object.getFill){
v = object.getFill();
if(v){ t.fill = v; }
}
if(object.getFont){
v = object.getFont();
if(v){ t.font = v; }
}
return t; // Object
},
toJson: function(
/* dojox.gfx.Surface || dojox.gfx.Shape */ object,
/* Boolean? */ prettyPrint
){
return d.toJson(gu.serialize(object), prettyPrint); // String
},
deserialize: function(
/* dojox.gfx.Surface || dojox.gfx.Shape */ parent,
/* dojox.gfx.Shape || Array */ object
){
if(object instanceof Array){
return d.map(object, d.hitch(null, gu.deserialize, parent)); // Array
}
var shape = ("shape" in object) ? parent.createShape(object.shape) : parent.createGroup();
if("transform" in object){
shape.setTransform(object.transform);
}
if("stroke" in object){
shape.setStroke(object.stroke);
}
if("fill" in object){
shape.setFill(object.fill);
}
if("font" in object){
shape.setFont(object.font);
}
if("children" in object){
d.forEach(object.children, d.hitch(null, gu.deserialize, shape));
}
return shape; // dojox.gfx.Shape
},
fromJson: function(
/* dojox.gfx.Surface || dojox.gfx.Shape */ parent,
/* String */ json){
return gu.deserialize(parent, d.fromJson(json)); // Array || dojox.gfx.Shape
},
toSvg: function(/*GFX object*/surface){
// summary:
// Function to serialize a GFX surface to SVG text.
// description:
// Function to serialize a GFX surface to SVG text. The value of this output
// is that there are numerous serverside parser libraries that can render
// SVG into images in various formats. This provides a way that GFX objects
// can be captured in a known format and sent serverside for serialization
// into an image.
// surface:
// The GFX surface to serialize.
// returns:
// Deferred object that will be called when SVG serialization is complete.
//Since the init and even surface creation can be async, we need to
//return a deferred that will be called when content has serialized.
var deferred = new dojo.Deferred();
if(dojox.gfx.renderer === "svg"){
//If we're already in SVG mode, this is easy and quick.
try{
var svg = gu._cleanSvg(gu._innerXML(surface.rawNode));
deferred.callback(svg);
}catch(e){
deferred.errback(e);
}
}else{
//Okay, now we have to get creative with hidden iframes and the like to
//serialize SVG.
if (!gu._initSvgSerializerDeferred) {
gu._initSvgSerializer();
}
var jsonForm = dojox.gfx.utils.toJson(surface);
var serializer = function(){
try{
var sDim = surface.getDimensions();
var width = sDim.width;
var height = sDim.height;
//Create an attach point in the iframe for the contents.
var node = gu._gfxSvgProxy.document.createElement("div");
gu._gfxSvgProxy.document.body.appendChild(node);
//Set the node scaling.
dojo.withDoc(gu._gfxSvgProxy.document, function() {
dojo.style(node, "width", width);
dojo.style(node, "height", height);
}, this);
//Create temp surface to render object to and render.
var ts = gu._gfxSvgProxy[dojox._scopeName].gfx.createSurface(node, width, height);
//It's apparently possible that a suface creation is async, so we need to use
//the whenLoaded function. Probably not needed for SVG, but making it common
var draw = function(surface) {
try{
gu._gfxSvgProxy[dojox._scopeName].gfx.utils.fromJson(surface, jsonForm);
//Get contents and remove temp surface.
var svg = gu._cleanSvg(node.innerHTML);
surface.clear();
surface.destroy();
gu._gfxSvgProxy.document.body.removeChild(node);
deferred.callback(svg);
}catch(e){
deferred.errback(e);
}
};
ts.whenLoaded(null,draw);
}catch (ex) {
deferred.errback(ex);
}
};
//See if we can call it directly or pass it to the deferred to be
//called on initialization.
if(gu._initSvgSerializerDeferred.fired > 0){
serializer();
}else{
gu._initSvgSerializerDeferred.addCallback(serializer);
}
}
return deferred; //dojo.Deferred that will be called when serialization finishes.
},
//iFrame document used for handling SVG serialization.
_gfxSvgProxy: null,
//Serializer loaded.
_initSvgSerializerDeferred: null,
_svgSerializerInitialized: function() {
// summary:
// Internal function to call when the serializer init completed.
// tags:
// private
gu._initSvgSerializerDeferred.callback(true);
},
_initSvgSerializer: function(){
// summary:
// Internal function to initialize the hidden iframe where SVG rendering
// will occur.
// tags:
// private
if(!gu._initSvgSerializerDeferred){
gu._initSvgSerializerDeferred = new dojo.Deferred();
var f = dojo.doc.createElement("iframe");
dojo.style(f, {
display: "none",
position: "absolute",
width: "1em",
height: "1em",
top: "-10000px"
});
var intv;
if(dojo.isIE){
f.onreadystatechange = function(){
if(f.contentWindow.document.readyState == "complete"){
f.onreadystatechange = function() {};
intv = setInterval(function() {
if(f.contentWindow[dojo._scopeName] &&
f.contentWindow[dojox._scopeName].gfx &&
f.contentWindow[dojox._scopeName].gfx.utils){
clearInterval(intv);
f.contentWindow.parent[dojox._scopeName].gfx.utils._gfxSvgProxy = f.contentWindow;
f.contentWindow.parent[dojox._scopeName].gfx.utils._svgSerializerInitialized();
}
}, 50);
}
};
}else{
f.onload = function(){
f.onload = function() {};
intv = setInterval(function() {
if(f.contentWindow[dojo._scopeName] &&
f.contentWindow[dojox._scopeName].gfx &&
f.contentWindow[dojox._scopeName].gfx.utils){
clearInterval(intv);
f.contentWindow.parent[dojox._scopeName].gfx.utils._gfxSvgProxy = f.contentWindow;
f.contentWindow.parent[dojox._scopeName].gfx.utils._svgSerializerInitialized();
}
}, 50);
};
}
//We have to load the GFX SVG proxy frame. Default is to use the one packaged in dojox.
var uri = (dojo.config["dojoxGfxSvgProxyFrameUrl"]||dojo.moduleUrl("dojox", "gfx/resources/gfxSvgProxyFrame.html"));
f.setAttribute("src", uri);
dojo.body().appendChild(f);
}
},
_innerXML: function(/*Node*/node){
// summary:
// Implementation of MS's innerXML function, borrowed from dojox.xml.parser.
// node:
// The node from which to generate the XML text representation.
// tags:
// private
if(node.innerXML){
return node.innerXML; //String
}else if(node.xml){
return node.xml; //String
}else if(typeof XMLSerializer != "undefined"){
return (new XMLSerializer()).serializeToString(node); //String
}
return null;
},
_cleanSvg: function(svg) {
// summary:
// Internal function that cleans up artifacts in extracted SVG content.
// tags:
// private
if(svg){
//Make sure the namespace is set.
if(svg.indexOf("xmlns=\"http://www.w3.org/2000/svg\"") == -1){
svg = svg.substring(4, svg.length);
svg = "<svg xmlns=\"http://www.w3.org/2000/svg\"" + svg;
}
//Do some other cleanup, like stripping out the
//dojoGfx attributes.
svg = svg.replace(/\bdojoGfx\w*\s*=\s*(['"])\w*\1/g, "");
}
return svg; //Cleaned SVG text.
}
});
})();
}