1 | define(["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 | }); |
---|