source: Dev/branches/rest-dojo-ui/client/dojox/gfx/utils.js @ 256

Last change on this file since 256 was 256, checked in by hendrikvanantwerpen, 13 years ago

Reworked project structure based on REST interaction and Dojo library. As
soon as this is stable, the old jQueryUI branch can be removed (it's
kept for reference).

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