source: Dev/trunk/src/client/dojox/gfx/utils.js @ 529

Last change on this file since 529 was 483, checked in by hendrikvanantwerpen, 11 years ago

Added Dojo 1.9.3 release.

File size: 10.8 KB
Line 
1define(["dojo/_base/kernel","dojo/_base/lang","./_base", "dojo/_base/html","dojo/_base/array", "dojo/_base/window", "dojo/_base/json",
2        "dojo/_base/Deferred", "dojo/_base/sniff", "require","dojo/_base/config"],
3  function(kernel, lang, g, html, arr, win, jsonLib, Deferred, has, require, config){
4        var gu = g.utils = {};
5
6        lang.mixin(gu, {
7                forEach: function(
8                        /*dojox/gfx/shape.Surface|dojox/gfx/shape.Shape*/ object,
9                        /*Function|String|Array*/ f, /*Object?*/ o
10                ){
11                        // summary:
12                        //              Takes a shape or a surface and applies a function "f" to in the context of "o"
13                        //              (or global, if missing). If "shape" was a surface or a group, it applies the same
14                        //              function to all children recursively effectively visiting all shapes of the underlying scene graph.
15                        // object:
16                        //              The gfx container to iterate.
17                        // f:
18                        //              The function to apply.
19                        // o:
20                        //              The scope.
21                        o = o || kernel.global;
22                        f.call(o, object);
23                        if(object instanceof g.Surface || object instanceof g.Group){
24                                arr.forEach(object.children, function(shape){
25                                        gu.forEach(shape, f, o);
26                                });
27                        }
28                },
29
30                serialize: function(object){
31                        // summary:
32                        //              Takes a shape or a surface and returns an object, which describes underlying shapes.
33                        // object: dojox/gfx/shape.Surface|dojox/gfx/shape.Shape
34                        //              The container to serialize.
35
36                        var t = {}, v, isSurface = object instanceof g.Surface;
37                        if(isSurface || object instanceof g.Group){
38                                t.children = arr.map(object.children, gu.serialize);
39                                if(isSurface){
40                                        return t.children;      // Array
41                                }
42                        }else{
43                                t.shape = object.getShape();
44                        }
45                        if(object.getTransform){
46                                v = object.getTransform();
47                                if(v){ t.transform = v; }
48                        }
49                        if(object.getStroke){
50                                v = object.getStroke();
51                                if(v){ t.stroke = v; }
52                        }
53                        if(object.getFill){
54                                v = object.getFill();
55                                if(v){ t.fill = v; }
56                        }
57                        if(object.getFont){
58                                v = object.getFont();
59                                if(v){ t.font = v; }
60                        }
61                        return t;       // Object
62                },
63
64                toJson: function(object, prettyPrint){
65                        // summary:
66                        //              Works just like serialize() but returns a JSON string. If prettyPrint is true, the string is pretty-printed to make it more human-readable.
67                        // object: dojox/gfx/shape.Surface|dojox/gfx/shape.Shape
68                        //              The container to serialize.
69                        // prettyPrint: Boolean?
70                        //              Indicates whether the output string should be formatted.
71                        // returns: String
72                       
73                        return jsonLib.toJson(gu.serialize(object), prettyPrint);       // String
74                },
75
76                deserialize: function(parent, object){
77                        // summary:
78                        //              Takes a surface or a shape and populates it with an object produced by serialize().
79                        // parent: dojox/gfx/shape.Surface|dojox/gfx/shape.Shape
80                        //              The destination container for the deserialized shapes.
81                        // object: dojox/gfx/shape.Shape|Array
82                        //              The shapes to deserialize.
83
84                        if(object instanceof Array){
85                                return arr.map(object, lang.hitch(null, gu.deserialize, parent));       // Array
86                        }
87                        var shape = ("shape" in object) ? parent.createShape(object.shape) : parent.createGroup();
88                        if("transform" in object){
89                                shape.setTransform(object.transform);
90                        }
91                        if("stroke" in object){
92                                shape.setStroke(object.stroke);
93                        }
94                        if("fill" in object){
95                                shape.setFill(object.fill);
96                        }
97                        if("font" in object){
98                                shape.setFont(object.font);
99                        }
100                        if("children" in object){
101                                arr.forEach(object.children, lang.hitch(null, gu.deserialize, shape));
102                        }
103                        return shape;   // dojox/gfx/shape.Shape
104                },
105
106                fromJson: function(parent, json){
107                        // summary:
108                        //              Works just like deserialize() but takes a JSON representation of the object.
109                        // parent: dojox/gfx/shape.Surface|dojox/gfx/shape.Shape
110                        //              The destination container for the deserialized shapes.
111                        // json: String
112                        //              The shapes to deserialize.
113
114                        return gu.deserialize(parent, jsonLib.fromJson(json));  // Array|dojox/gfx/shape.Shape
115                },
116
117                toSvg: function(/*dojox/gfx/shape.Surface*/surface){
118                        // summary:
119                        //              Function to serialize a GFX surface to SVG text.
120                        // description:
121                        //              Function to serialize a GFX surface to SVG text.  The value of this output
122                        //              is that there are numerous serverside parser libraries that can render
123                        //              SVG into images in various formats.  This provides a way that GFX objects
124                        //              can be captured in a known format and sent serverside for serialization
125                        //              into an image.
126                        // surface:
127                        //              The GFX surface to serialize.
128                        // returns:
129                        //              Deferred object that will be called when SVG serialization is complete.
130               
131                        //Since the init and even surface creation can be async, we need to
132                        //return a deferred that will be called when content has serialized.
133                        var deferred = new Deferred();
134               
135                        if(g.renderer === "svg"){
136                                //If we're already in SVG mode, this is easy and quick.
137                                try{
138                                        var svg = gu._cleanSvg(gu._innerXML(surface.rawNode));
139                                        deferred.callback(svg);
140                                }catch(e){
141                                        deferred.errback(e);
142                                }
143                        }else{
144                                //Okay, now we have to get creative with hidden iframes and the like to
145                                //serialize SVG.
146                                if (!gu._initSvgSerializerDeferred) {
147                                        gu._initSvgSerializer();
148                                }
149                                var jsonForm = gu.toJson(surface);
150                                var serializer = function(){
151                                        try{
152                                                var sDim = surface.getDimensions();
153                                                var width = sDim.width;
154                                                var     height = sDim.height;
155
156                                                //Create an attach point in the iframe for the contents.
157                                                var node = gu._gfxSvgProxy.document.createElement("div");
158                                                gu._gfxSvgProxy.document.body.appendChild(node);
159                                                //Set the node scaling.
160                                                win.withDoc(gu._gfxSvgProxy.document, function() {
161                                                        html.style(node, "width", width);
162                                                        html.style(node, "height", height);
163                                                }, this);
164
165                                                //Create temp surface to render object to and render.
166                                                var ts = gu._gfxSvgProxy[dojox._scopeName].gfx.createSurface(node, width, height);
167
168                                                //It's apparently possible that a suface creation is async, so we need to use
169                                                //the whenLoaded function.  Probably not needed for SVG, but making it common
170                                                var draw = function(surface) {
171                                                        try{
172                                                                gu._gfxSvgProxy[dojox._scopeName].gfx.utils.fromJson(surface, jsonForm);
173
174                                                                //Get contents and remove temp surface.
175                                                                var svg = gu._cleanSvg(node.innerHTML);
176                                                                surface.clear();
177                                                                surface.destroy();
178                                                                gu._gfxSvgProxy.document.body.removeChild(node);
179                                                                deferred.callback(svg);
180                                                        }catch(e){
181                                                                deferred.errback(e);
182                                                        }
183                                                };
184                                                ts.whenLoaded(null,draw);
185                                         }catch (ex) {
186                                                deferred.errback(ex);
187                                        }
188                                };
189                                //See if we can call it directly or pass it to the deferred to be
190                                //called on initialization.
191                                if(gu._initSvgSerializerDeferred.fired > 0){
192                                        serializer();
193                                }else{
194                                        gu._initSvgSerializerDeferred.addCallback(serializer);
195                                }
196                        }
197                        return deferred; //dojo.Deferred that will be called when serialization finishes.
198                },
199
200                //iFrame document used for handling SVG serialization.
201                _gfxSvgProxy: null,
202
203                //Serializer loaded.
204                _initSvgSerializerDeferred: null,
205
206                _svgSerializerInitialized: function() {
207                        // summary:
208                        //              Internal function to call when the serializer init completed.
209                        // tags:
210                        //              private
211                        gu._initSvgSerializerDeferred.callback(true);
212                },
213
214                _initSvgSerializer: function(){
215                        // summary:
216                        //              Internal function to initialize the hidden iframe where SVG rendering
217                        //              will occur.
218                        // tags:
219                        //              private
220                        if(!gu._initSvgSerializerDeferred){
221                                gu._initSvgSerializerDeferred = new Deferred();
222                                var f = win.doc.createElement("iframe");
223                                html.style(f, {
224                                        display: "none",
225                                        position: "absolute",
226                                        width: "1em",
227                                        height: "1em",
228                                        top: "-10000px"
229                                });
230                                var intv;
231                                if(has("ie")){
232                                        f.onreadystatechange = function(){
233                                                if(f.contentWindow.document.readyState == "complete"){
234                                                        f.onreadystatechange = function() {};
235                                                        intv = setInterval(function() {
236                                                                if(f.contentWindow[kernel.scopeMap["dojo"][1]._scopeName] &&
237                                                                   f.contentWindow[kernel.scopeMap["dojox"][1]._scopeName].gfx &&
238                                                                   f.contentWindow[kernel.scopeMap["dojox"][1]._scopeName].gfx.utils){
239                                                                        clearInterval(intv);
240                                                                        f.contentWindow.parent[kernel.scopeMap["dojox"][1]._scopeName].gfx.utils._gfxSvgProxy = f.contentWindow;
241                                                                        f.contentWindow.parent[kernel.scopeMap["dojox"][1]._scopeName].gfx.utils._svgSerializerInitialized();
242                                                                }
243                                                        }, 50);
244                                                }
245                                        };
246                                }else{
247                                        f.onload = function(){
248                                                f.onload = function() {};
249                                                intv = setInterval(function() {
250                                                        if(f.contentWindow[kernel.scopeMap["dojo"][1]._scopeName] &&
251                                                           f.contentWindow[kernel.scopeMap["dojox"][1]._scopeName].gfx &&
252                                                           f.contentWindow[kernel.scopeMap["dojox"][1]._scopeName].gfx.utils){
253                                                                clearInterval(intv);
254                                                                f.contentWindow.parent[kernel.scopeMap["dojox"][1]._scopeName].gfx.utils._gfxSvgProxy = f.contentWindow;
255                                                                f.contentWindow.parent[kernel.scopeMap["dojox"][1]._scopeName].gfx.utils._svgSerializerInitialized();
256                                                        }
257                                                }, 50);
258                                        };
259                                }
260                                //We have to load the GFX SVG proxy frame.  Default is to use the one packaged in dojox.
261                                var uri = (config["dojoxGfxSvgProxyFrameUrl"]||require.toUrl("dojox/gfx/resources/gfxSvgProxyFrame.html"));
262                                f.setAttribute("src", uri.toString());
263                                win.body().appendChild(f);
264                        }
265                },
266
267                _innerXML: function(/*Node*/node){
268                        // summary:
269                        //              Implementation of MS's innerXML function, borrowed from dojox.xml.parser.
270                        // node:
271                        //              The node from which to generate the XML text representation.
272                        // tags:
273                        //              private
274                        if(node.innerXML){
275                                return node.innerXML;   //String
276                        }else if(node.xml){
277                                return node.xml;                //String
278                        }else if(typeof XMLSerializer != "undefined"){
279                                return (new XMLSerializer()).serializeToString(node);   //String
280                        }
281                        return null;
282                },
283
284                _cleanSvg: function(svg) {
285                        // summary:
286                        //              Internal function that cleans up artifacts in extracted SVG content.
287                        // tags:
288                        //              private
289                        if(svg){
290                                //Make sure the namespace is set.
291                                if(svg.indexOf("xmlns=\"http://www.w3.org/2000/svg\"") == -1){
292                                        svg = svg.substring(4, svg.length);
293                                        svg = "<svg xmlns=\"http://www.w3.org/2000/svg\"" + svg;
294                                }
295                                //Same for xmlns:xlink (missing in Chrome and Safari)
296                                if(svg.indexOf("xmlns:xlink=\"http://www.w3.org/1999/xlink\"") == -1){
297                                        svg = svg.substring(4, svg.length);
298                                        svg = "<svg xmlns:xlink=\"http://www.w3.org/1999/xlink\"" + svg;
299                                }
300                                //and add namespace to href attribute if not done yet
301                                //(FF 5+ adds xlink:href but not the xmlns def)
302                                if(svg.indexOf("xlink:href") === -1){
303                                        svg = svg.replace(/href\s*=/g, "xlink:href=");
304                                }
305                                // in IE, <image are serialized as <img>
306                                svg = svg.replace(/<img\b([^>]*)>/gi,"<image $1 />");
307                                //Do some other cleanup, like stripping out the
308                                //dojoGfx attributes and quoting ids.
309                                svg = svg.replace(/\bdojoGfx\w*\s*=\s*(['"])\w*\1/g, "");
310                                svg = svg.replace(/\b__gfxObject__\s*=\s*(['"])\w*\1/g, "");
311                                svg = svg.replace(/[=]([^"']+?)(\s|>)/g,'="$1"$2');
312                        }
313                        return svg;  //Cleaned SVG text.
314                }
315        });
316
317        return gu;
318});
Note: See TracBrowser for help on using the repository browser.