vml_attach.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397
  1. dojo.require("dojox.gfx.vml");
  2. dojo.experimental("dojox.gfx.vml_attach");
  3. (function() {
  4. dojox.gfx.attachNode = function(node) {
  5. // summary: creates a shape from a Node
  6. // node: Node: an VML node
  7. if (!node)
  8. return null;
  9. var s = null;
  10. switch (node.tagName.toLowerCase()) {
  11. case dojox.gfx.Rect.nodeType :
  12. s = new dojox.gfx.Rect(node);
  13. attachRect(s);
  14. break;
  15. case dojox.gfx.Ellipse.nodeType :
  16. if (node.style.width == node.style.height) {
  17. s = new dojox.gfx.Circle(node);
  18. attachCircle(s);
  19. } else {
  20. s = new dojox.gfx.Ellipse(node);
  21. attachEllipse(s);
  22. }
  23. break;
  24. case dojox.gfx.Path.nodeType :
  25. switch (node.getAttribute("dojoGfxType")) {
  26. case "line" :
  27. s = new dojox.gfx.Line(node);
  28. attachLine(s);
  29. break;
  30. case "polyline" :
  31. s = new dojox.gfx.Polyline(node);
  32. attachPolyline(s);
  33. break;
  34. case "path" :
  35. s = new dojox.gfx.Path(node);
  36. attachPath(s);
  37. break;
  38. case "text" :
  39. s = new dojox.gfx.Text(node);
  40. attachText(s);
  41. attachFont(s);
  42. attachTextTransform(s);
  43. break;
  44. case "textpath" :
  45. s = new dojox.gfx.TextPath(node);
  46. attachPath(s);
  47. attachText(s);
  48. attachFont(s);
  49. break;
  50. }
  51. break;
  52. case dojox.gfx.Image.nodeType :
  53. switch (node.getAttribute("dojoGfxType")) {
  54. case "image" :
  55. s = new dojox.gfx.Image(node);
  56. attachImage(s);
  57. attachImageTransform(s);
  58. break;
  59. }
  60. break;
  61. default :
  62. // console.debug("FATAL ERROR! tagName = " + node.tagName);
  63. return null;
  64. }
  65. if (!(s instanceof dojox.gfx.Image)) {
  66. attachFill(s);
  67. attachStroke(s);
  68. if (!(s instanceof dojox.gfx.Text)) {
  69. attachTransform(s);
  70. }
  71. }
  72. return s; // dojox.gfx.Shape
  73. };
  74. dojox.gfx.attachSurface = function(node) {
  75. // summary: creates a surface from a Node
  76. // node: Node: an VML node
  77. var s = new dojox.gfx.Surface();
  78. s.clipNode = node;
  79. var r = s.rawNode = node.firstChild;
  80. var b = r.firstChild;
  81. if (!b || b.tagName != "rect") {
  82. return null; // dojox.gfx.Surface
  83. }
  84. s.bgNode = r;
  85. return s; // dojox.gfx.Surface
  86. };
  87. var attachFill = function(object) {
  88. // summary: deduces a fill style from a node.
  89. // object: dojox.gfx.Shape: an VML shape
  90. var fillStyle = null, r = object.rawNode, fo = r.fill;
  91. if (fo.on && fo.type == "gradient") {
  92. var fillStyle = dojo.clone(dojox.gfx.defaultLinearGradient), rad = dojox.gfx.matrix
  93. ._degToRad(fo.angle);
  94. fillStyle.x2 = Math.cos(rad);
  95. fillStyle.y2 = Math.sin(rad);
  96. fillStyle.colors = [];
  97. var stops = fo.colors.value.split(";");
  98. for (var i = 0; i < stops.length; ++i) {
  99. var t = stops[i].match(/\S+/g);
  100. if (!t || t.length != 2) {
  101. continue;
  102. }
  103. fillStyle.colors.push({
  104. offset : dojox.gfx.vml._parseFloat(t[0]),
  105. color : new dojo.Color(t[1])
  106. });
  107. }
  108. } else if (fo.on && fo.type == "gradientradial") {
  109. var fillStyle = dojo.clone(dojox.gfx.defaultRadialGradient), w = parseFloat(r.style.width), h = parseFloat(r.style.height);
  110. fillStyle.cx = isNaN(w) ? 0 : fo.focusposition.x * w;
  111. fillStyle.cy = isNaN(h) ? 0 : fo.focusposition.y * h;
  112. fillStyle.r = isNaN(w) ? 1 : w / 2;
  113. fillStyle.colors = [];
  114. var stops = fo.colors.value.split(";");
  115. for (var i = stops.length - 1; i >= 0; --i) {
  116. var t = stops[i].match(/\S+/g);
  117. if (!t || t.length != 2) {
  118. continue;
  119. }
  120. fillStyle.colors.push({
  121. offset : dojox.gfx.vml._parseFloat(t[0]),
  122. color : new dojo.Color(t[1])
  123. });
  124. }
  125. } else if (fo.on && fo.type == "tile") {
  126. var fillStyle = dojo.clone(dojox.gfx.defaultPattern);
  127. fillStyle.width = dojox.gfx.pt2px(fo.size.x); // from pt
  128. fillStyle.height = dojox.gfx.pt2px(fo.size.y); // from pt
  129. fillStyle.x = fo.origin.x * fillStyle.width;
  130. fillStyle.y = fo.origin.y * fillStyle.height;
  131. fillStyle.src = fo.src;
  132. } else if (fo.on && r.fillcolor) {
  133. // a color object !
  134. fillStyle = new dojo.Color(r.fillcolor + "");
  135. fillStyle.a = fo.opacity;
  136. }
  137. object.fillStyle = fillStyle;
  138. };
  139. var attachStroke = function(object) {
  140. // summary: deduces a stroke style from a node.
  141. // object: dojox.gfx.Shape: an VML shape
  142. var r = object.rawNode;
  143. if (!r.stroked) {
  144. object.strokeStyle = null;
  145. return;
  146. }
  147. var strokeStyle = object.strokeStyle = dojo
  148. .clone(dojox.gfx.defaultStroke), rs = r.stroke;
  149. strokeStyle.color = new dojo.Color(r.strokecolor.value);
  150. strokeStyle.width = dojox.gfx.normalizedLength(r.strokeweight + "");
  151. strokeStyle.color.a = rs.opacity;
  152. strokeStyle.cap = this._translate(this._capMapReversed, rs.endcap);
  153. strokeStyle.join = rs.joinstyle == "miter"
  154. ? rs.miterlimit
  155. : rs.joinstyle;
  156. strokeStyle.style = rs.dashstyle;
  157. };
  158. var attachTransform = function(object) {
  159. // summary: deduces a transformation matrix from a node.
  160. // object: dojox.gfx.Shape: an VML shape
  161. var s = rawNode.skew, sm = s.matrix, so = s.offset;
  162. object.matrix = dojox.gfx.matrix.normalize({
  163. xx : sm.xtox,
  164. xy : sm.ytox,
  165. yx : sm.xtoy,
  166. yy : sm.ytoy,
  167. dx : dojox.gfx.pt2px(so.x),
  168. dy : dojox.gfx.pt2px(so.y)
  169. });
  170. };
  171. var attachGroup = function(object) {
  172. // summary: reconstructs all group shape parameters from a node (VML).
  173. // object: dojox.gfx.Shape: an VML shape
  174. // attach the background
  175. object.bgNode = object.rawNode.firstChild; // TODO: check it first
  176. };
  177. var attachRect = function(object) {
  178. // summary: builds a rectangle shape from a node.
  179. // object: dojox.gfx.Shape: an VML shape
  180. // a workaround for the VML's arcsize bug: cannot read arcsize of an
  181. // instantiated node
  182. var r = object.rawNode, arcsize = r.outerHTML
  183. .match(/arcsize = \"(\d*\.?\d+[%f]?)\"/)[1], style = r.style, width = parseFloat(style.width), height = parseFloat(style.height);
  184. arcsize = (arcsize.indexOf("%") >= 0)
  185. ? parseFloat(arcsize) / 100
  186. : dojox.gfx.vml._parseFloat(arcsize);
  187. // make an object
  188. object.shape = dojox.gfx.makeParameters(dojox.gfx.defaultRect, {
  189. x : parseInt(style.left),
  190. y : parseInt(style.top),
  191. width : width,
  192. height : height,
  193. r : Math.min(width, height) * arcsize
  194. });
  195. };
  196. var attachEllipse = function(object) {
  197. // summary: builds an ellipse shape from a node.
  198. // object: dojox.gfx.Shape: an VML shape
  199. var style = object.rawNode.style, rx = parseInt(style.width) / 2, ry = parseInt(style.height)
  200. / 2;
  201. object.shape = dojox.gfx.makeParameters(dojox.gfx.defaultEllipse, {
  202. cx : parseInt(style.left) + rx,
  203. cy : parseInt(style.top) + ry,
  204. rx : rx,
  205. ry : ry
  206. });
  207. };
  208. var attachCircle = function(object) {
  209. // summary: builds a circle shape from a node.
  210. // object: dojox.gfx.Shape: an VML shape
  211. var style = object.rawNode.style, r = parseInt(style.width) / 2;
  212. object.shape = dojox.gfx.makeParameters(dojox.gfx.defaultCircle, {
  213. cx : parseInt(style.left) + r,
  214. cy : parseInt(style.top) + r,
  215. r : r
  216. });
  217. };
  218. var attachLine = function(object) {
  219. // summary: builds a line shape from a node.
  220. // object: dojox.gfx.Shape: an VML shape
  221. var shape = object.shape = dojo.clone(dojox.gfx.defaultLine), p = object.rawNode.path.v
  222. .match(dojox.gfx.pathVmlRegExp);
  223. do {
  224. if (p.length < 7 || p[0] != "m" || p[3] != "l" || p[6] != "e") {
  225. break;
  226. }
  227. shape.x1 = parseInt(p[1]);
  228. shape.y1 = parseInt(p[2]);
  229. shape.x2 = parseInt(p[4]);
  230. shape.y2 = parseInt(p[5]);
  231. } while (false);
  232. };
  233. var attachPolyline = function(object) {
  234. // summary: builds a polyline/polygon shape from a node.
  235. // object: dojox.gfx.Shape: an VML shape
  236. var shape = object.shape = dojo.clone(dojox.gfx.defaultPolyline), p = object.rawNode.path.v
  237. .match(dojox.gfx.pathVmlRegExp);
  238. do {
  239. if (p.length < 3 || p[0] != "m") {
  240. break;
  241. }
  242. var x = parseInt(p[0]), y = parseInt(p[1]);
  243. if (isNaN(x) || isNaN(y)) {
  244. break;
  245. }
  246. shape.points.push({
  247. x : x,
  248. y : y
  249. });
  250. if (p.length < 6 || p[3] != "l") {
  251. break;
  252. }
  253. for (var i = 4; i < p.length; i += 2) {
  254. x = parseInt(p[i]);
  255. y = parseInt(p[i + 1]);
  256. if (isNaN(x) || isNaN(y)) {
  257. break;
  258. }
  259. shape.points.push({
  260. x : x,
  261. y : y
  262. });
  263. }
  264. } while (false);
  265. };
  266. var attachImage = function(object) {
  267. // summary: builds an image shape from a node.
  268. // object: dojox.gfx.Shape: an VML shape
  269. object.shape = dojo.clone(dojox.gfx.defaultImage);
  270. object.shape.src = object.rawNode.firstChild.src;
  271. };
  272. var attachImageTransform = function(object) {
  273. // summary: deduces a transformation matrix from a node.
  274. // object: dojox.gfx.Shape: an VML shape
  275. var m = object.rawNode.filters["DXImageTransform.Microsoft.Matrix"];
  276. object.matrix = dojox.gfx.matrix.normalize({
  277. xx : m.M11,
  278. xy : m.M12,
  279. yx : m.M21,
  280. yy : m.M22,
  281. dx : m.Dx,
  282. dy : m.Dy
  283. });
  284. };
  285. var attachText = function(object) {
  286. // summary: builds a text shape from a node.
  287. // object: dojox.gfx.Shape: an VML shape
  288. var shape = object.shape = dojo.clone(dojox.gfx.defaultText), r = object.rawNode, p = r.path.v
  289. .match(dojox.gfx.pathVmlRegExp);
  290. do {
  291. if (!p || p.length != 7) {
  292. break;
  293. }
  294. var c = r.childNodes, i = 0;
  295. for (; i < c.length && c[i].tagName != "textpath"; ++i);
  296. if (i >= c.length) {
  297. break;
  298. }
  299. var s = c[i].style;
  300. shape.text = c[i].string;
  301. switch (s["v-text-align"]) {
  302. case "left" :
  303. shape.x = parseInt(p[1]);
  304. shape.align = "start";
  305. break;
  306. case "center" :
  307. shape.x = (parseInt(p[1]) + parseInt(p[4])) / 2;
  308. shape.align = "middle";
  309. break;
  310. case "right" :
  311. shape.x = parseInt(p[4]);
  312. shape.align = "end";
  313. break;
  314. }
  315. shape.y = parseInt(p[2]);
  316. shape.decoration = s["text-decoration"];
  317. shape.rotated = s["v-rotate-letters"].toLowerCase() in dojox.gfx.vml._bool;
  318. shape.kerning = s["v-text-kern"].toLowerCase() in dojox.gfx.vml._bool;
  319. return;
  320. } while (false);
  321. object.shape = null;
  322. };
  323. var attachFont = function(object) {
  324. // summary: deduces a font style from a node.
  325. // object: dojox.gfx.Shape: an VML shape
  326. var fontStyle = object.fontStyle = dojo.clone(dojox.gfx.defaultFont), c = object.rawNode.childNodes, i = 0;
  327. for (; i < c.length && c[i].tagName == "textpath"; ++i);
  328. if (i >= c.length) {
  329. object.fontStyle = null;
  330. return;
  331. }
  332. var s = c[i].style;
  333. fontStyle.style = s.fontstyle;
  334. fontStyle.variant = s.fontvariant;
  335. fontStyle.weight = s.fontweight;
  336. fontStyle.size = s.fontsize;
  337. fontStyle.family = s.fontfamily;
  338. };
  339. var attachTextTransform = function(object) {
  340. // summary: deduces a transformation matrix from a node.
  341. // object: dojox.gfx.Shape: an VML shape
  342. attachTransform(object);
  343. var matrix = object.matrix, fs = object.fontStyle;
  344. // see comments in _getRealMatrix()
  345. if (matrix && fs) {
  346. object.matrix = dojox.gfx.matrix.multiply(matrix, {
  347. dy : dojox.gfx.normalizedLength(fs.size) * 0.35
  348. });
  349. }
  350. };
  351. var attachPath = function(object) {
  352. // summary: builds a path shape from a Node.
  353. // object: dojox.gfx.Shape: an VML shape
  354. var shape = object.shape = dojo.clone(dojox.gfx.defaultPath), p = rawNode.path.v
  355. .match(dojox.gfx.pathVmlRegExp), t = [], skip = false, map = dojox.gfx.Path._pathVmlToSvgMap;
  356. for (var i = 0; i < p.length; ++p) {
  357. var s = p[i];
  358. if (s in map) {
  359. skip = false;
  360. t.push(map[s]);
  361. } else if (!skip) {
  362. var n = parseInt(s);
  363. if (isNaN(n)) {
  364. skip = true;
  365. } else {
  366. t.push(n);
  367. }
  368. }
  369. }
  370. var l = t.length;
  371. if (l >= 4 && t[l - 1] == "" && t[l - 2] == 0 && t[l - 3] == 0
  372. && t[l - 4] == "l") {
  373. t.splice(l - 4, 4);
  374. }
  375. if (l) {
  376. shape.path = t.join(" ");
  377. }
  378. };
  379. })();