utils.js 8.7 KB

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