307 lines
10 KiB
JavaScript
307 lines
10 KiB
JavaScript
//>>built
|
|
define("dojox/gfx/utils", ["dojo/_base/kernel","dojo/_base/lang","./_base", "dojo/_base/html","dojo/_base/array", "dojo/_base/window", "dojo/_base/json",
|
|
"dojo/_base/Deferred", "dojo/_base/sniff", "require","dojo/_base/config"],
|
|
function(kernel, lang, g, html, arr, win, jsonLib, Deferred, has, require, config){
|
|
var gu = g.utils = {};
|
|
/*===== g= dojox.gfx; gu = dojox.gfx.utils; =====*/
|
|
|
|
lang.mixin(gu, {
|
|
forEach: function(
|
|
/*dojox.gfx.Surface|dojox.gfx.Shape*/ object,
|
|
/*Function|String|Array*/ f, /*Object?*/ o
|
|
){
|
|
// summary:
|
|
// Takes a shape or a surface and applies a function "f" to in the context of "o"
|
|
// (or global, if missing). If "shape" was a surface or a group, it applies the same
|
|
// function to all children recursively effectively visiting all shapes of the underlying scene graph.
|
|
// object : The gfx container to iterate.
|
|
// f : The function to apply.
|
|
// o : The scope.
|
|
o = o || win.global;
|
|
f.call(o, object);
|
|
if(object instanceof g.Surface || object instanceof g.Group){
|
|
arr.forEach(object.children, function(shape){
|
|
gu.forEach(shape, f, o);
|
|
});
|
|
}
|
|
},
|
|
|
|
serialize: function(
|
|
/* dojox.gfx.Surface|dojox.gfx.Shape */ object
|
|
){
|
|
// summary:
|
|
// Takes a shape or a surface and returns a DOM object, which describes underlying shapes.
|
|
var t = {}, v, isSurface = object instanceof g.Surface;
|
|
if(isSurface || object instanceof g.Group){
|
|
t.children = arr.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
|
|
){
|
|
// summary:
|
|
// Works just like serialize() but returns a JSON string. If prettyPrint is true, the string is pretty-printed to make it more human-readable.
|
|
return jsonLib.toJson(gu.serialize(object), prettyPrint); // String
|
|
},
|
|
|
|
deserialize: function(
|
|
/* dojox.gfx.Surface|dojox.gfx.Shape */ parent,
|
|
/* dojox.gfx.Shape|Array */ object
|
|
){
|
|
// summary:
|
|
// Takes a surface or a shape and populates it with an object produced by serialize().
|
|
if(object instanceof Array){
|
|
return arr.map(object, lang.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){
|
|
arr.forEach(object.children, lang.hitch(null, gu.deserialize, shape));
|
|
}
|
|
return shape; // dojox.gfx.Shape
|
|
},
|
|
|
|
fromJson: function(
|
|
/* dojox.gfx.Surface|dojox.gfx.Shape */ parent,
|
|
/* String */ json){
|
|
// summary:
|
|
// Works just like deserialize() but takes a JSON representation of the object.
|
|
return gu.deserialize(parent, jsonLib.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 Deferred();
|
|
|
|
if(g.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 = gu.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.
|
|
win.withDoc(gu._gfxSvgProxy.document, function() {
|
|
html.style(node, "width", width);
|
|
html.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 Deferred();
|
|
var f = win.doc.createElement("iframe");
|
|
html.style(f, {
|
|
display: "none",
|
|
position: "absolute",
|
|
width: "1em",
|
|
height: "1em",
|
|
top: "-10000px"
|
|
});
|
|
var intv;
|
|
if(has("ie")){
|
|
f.onreadystatechange = function(){
|
|
if(f.contentWindow.document.readyState == "complete"){
|
|
f.onreadystatechange = function() {};
|
|
intv = setInterval(function() {
|
|
if(f.contentWindow[kernel.scopeMap["dojo"][1]._scopeName] &&
|
|
f.contentWindow[kernel.scopeMap["dojox"][1]._scopeName].gfx &&
|
|
f.contentWindow[kernel.scopeMap["dojox"][1]._scopeName].gfx.utils){
|
|
clearInterval(intv);
|
|
f.contentWindow.parent[kernel.scopeMap["dojox"][1]._scopeName].gfx.utils._gfxSvgProxy = f.contentWindow;
|
|
f.contentWindow.parent[kernel.scopeMap["dojox"][1]._scopeName].gfx.utils._svgSerializerInitialized();
|
|
}
|
|
}, 50);
|
|
}
|
|
};
|
|
}else{
|
|
f.onload = function(){
|
|
f.onload = function() {};
|
|
intv = setInterval(function() {
|
|
if(f.contentWindow[kernel.scopeMap["dojo"][1]._scopeName] &&
|
|
f.contentWindow[kernel.scopeMap["dojox"][1]._scopeName].gfx &&
|
|
f.contentWindow[kernel.scopeMap["dojox"][1]._scopeName].gfx.utils){
|
|
clearInterval(intv);
|
|
f.contentWindow.parent[kernel.scopeMap["dojox"][1]._scopeName].gfx.utils._gfxSvgProxy = f.contentWindow;
|
|
f.contentWindow.parent[kernel.scopeMap["dojox"][1]._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 = (config["dojoxGfxSvgProxyFrameUrl"]||require.toUrl("dojox/gfx/resources/gfxSvgProxyFrame.html"));
|
|
f.setAttribute("src", uri.toString());
|
|
win.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;
|
|
}
|
|
//Same for xmlns:xlink (missing in Chrome and Safari)
|
|
if(svg.indexOf("xmlns:xlink=\"http://www.w3.org/1999/xlink\"") == -1){
|
|
svg = svg.substring(4, svg.length);
|
|
svg = "<svg xmlns:xlink=\"http://www.w3.org/1999/xlink\"" + svg;
|
|
}
|
|
//and add namespace to href attribute if not done yet
|
|
//(FF 5+ adds xlink:href but not the xmlns def)
|
|
if(svg.indexOf("xlink:href") === -1){
|
|
svg = svg.replace(/href\s*=/g, "xlink:href=");
|
|
}
|
|
//Do some other cleanup, like stripping out the
|
|
//dojoGfx attributes and quoting ids.
|
|
svg = svg.replace(/\bdojoGfx\w*\s*=\s*(['"])\w*\1/g, "");
|
|
svg = svg.replace(/\b__gfxObject__\s*=\s*(['"])\w*\1/g, "");
|
|
svg = svg.replace(/[=]([^"']+?)(\s|>)/g,'="$1"$2');
|
|
}
|
|
return svg; //Cleaned SVG text.
|
|
}
|
|
});
|
|
|
|
return gu;
|
|
});
|