gfx.js.uncompressed.js 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928
  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. /*
  7. This is an optimized version of Dojo, built for deployment and not for
  8. development. To get sources and documentation, please visit:
  9. http://dojotoolkit.org
  10. */
  11. if(!dojo._hasResource["dojox.gfx.matrix"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  12. dojo._hasResource["dojox.gfx.matrix"] = true;
  13. dojo.provide("dojox.gfx.matrix");
  14. (function(){
  15. var m = dojox.gfx.matrix;
  16. // candidates for dojox.math:
  17. var _degToRadCache = {};
  18. m._degToRad = function(degree){
  19. return _degToRadCache[degree] || (_degToRadCache[degree] = (Math.PI * degree / 180));
  20. };
  21. m._radToDeg = function(radian){ return radian / Math.PI * 180; };
  22. m.Matrix2D = function(arg){
  23. // summary: a 2D matrix object
  24. // description: Normalizes a 2D matrix-like object. If arrays is passed,
  25. // all objects of the array are normalized and multiplied sequentially.
  26. // arg: Object
  27. // a 2D matrix-like object, a number, or an array of such objects
  28. if(arg){
  29. if(typeof arg == "number"){
  30. this.xx = this.yy = arg;
  31. }else if(arg instanceof Array){
  32. if(arg.length > 0){
  33. var matrix = m.normalize(arg[0]);
  34. // combine matrices
  35. for(var i = 1; i < arg.length; ++i){
  36. var l = matrix, r = dojox.gfx.matrix.normalize(arg[i]);
  37. matrix = new m.Matrix2D();
  38. matrix.xx = l.xx * r.xx + l.xy * r.yx;
  39. matrix.xy = l.xx * r.xy + l.xy * r.yy;
  40. matrix.yx = l.yx * r.xx + l.yy * r.yx;
  41. matrix.yy = l.yx * r.xy + l.yy * r.yy;
  42. matrix.dx = l.xx * r.dx + l.xy * r.dy + l.dx;
  43. matrix.dy = l.yx * r.dx + l.yy * r.dy + l.dy;
  44. }
  45. dojo.mixin(this, matrix);
  46. }
  47. }else{
  48. dojo.mixin(this, arg);
  49. }
  50. }
  51. };
  52. // the default (identity) matrix, which is used to fill in missing values
  53. dojo.extend(m.Matrix2D, {xx: 1, xy: 0, yx: 0, yy: 1, dx: 0, dy: 0});
  54. dojo.mixin(m, {
  55. // summary: class constants, and methods of dojox.gfx.matrix
  56. // matrix constants
  57. // identity: dojox.gfx.matrix.Matrix2D
  58. // an identity matrix constant: identity * (x, y) == (x, y)
  59. identity: new m.Matrix2D(),
  60. // flipX: dojox.gfx.matrix.Matrix2D
  61. // a matrix, which reflects points at x = 0 line: flipX * (x, y) == (-x, y)
  62. flipX: new m.Matrix2D({xx: -1}),
  63. // flipY: dojox.gfx.matrix.Matrix2D
  64. // a matrix, which reflects points at y = 0 line: flipY * (x, y) == (x, -y)
  65. flipY: new m.Matrix2D({yy: -1}),
  66. // flipXY: dojox.gfx.matrix.Matrix2D
  67. // a matrix, which reflects points at the origin of coordinates: flipXY * (x, y) == (-x, -y)
  68. flipXY: new m.Matrix2D({xx: -1, yy: -1}),
  69. // matrix creators
  70. translate: function(a, b){
  71. // summary: forms a translation matrix
  72. // description: The resulting matrix is used to translate (move) points by specified offsets.
  73. // a: Number: an x coordinate value
  74. // b: Number: a y coordinate value
  75. if(arguments.length > 1){
  76. return new m.Matrix2D({dx: a, dy: b}); // dojox.gfx.matrix.Matrix2D
  77. }
  78. // branch
  79. // a: dojox.gfx.Point: a point-like object, which specifies offsets for both dimensions
  80. // b: null
  81. return new m.Matrix2D({dx: a.x, dy: a.y}); // dojox.gfx.matrix.Matrix2D
  82. },
  83. scale: function(a, b){
  84. // summary: forms a scaling matrix
  85. // description: The resulting matrix is used to scale (magnify) points by specified offsets.
  86. // a: Number: a scaling factor used for the x coordinate
  87. // b: Number: a scaling factor used for the y coordinate
  88. if(arguments.length > 1){
  89. return new m.Matrix2D({xx: a, yy: b}); // dojox.gfx.matrix.Matrix2D
  90. }
  91. if(typeof a == "number"){
  92. // branch
  93. // a: Number: a uniform scaling factor used for the both coordinates
  94. // b: null
  95. return new m.Matrix2D({xx: a, yy: a}); // dojox.gfx.matrix.Matrix2D
  96. }
  97. // branch
  98. // a: dojox.gfx.Point: a point-like object, which specifies scale factors for both dimensions
  99. // b: null
  100. return new m.Matrix2D({xx: a.x, yy: a.y}); // dojox.gfx.matrix.Matrix2D
  101. },
  102. rotate: function(angle){
  103. // summary: forms a rotating matrix
  104. // description: The resulting matrix is used to rotate points
  105. // around the origin of coordinates (0, 0) by specified angle.
  106. // angle: Number: an angle of rotation in radians (>0 for CW)
  107. var c = Math.cos(angle);
  108. var s = Math.sin(angle);
  109. return new m.Matrix2D({xx: c, xy: -s, yx: s, yy: c}); // dojox.gfx.matrix.Matrix2D
  110. },
  111. rotateg: function(degree){
  112. // summary: forms a rotating matrix
  113. // description: The resulting matrix is used to rotate points
  114. // around the origin of coordinates (0, 0) by specified degree.
  115. // See dojox.gfx.matrix.rotate() for comparison.
  116. // degree: Number: an angle of rotation in degrees (>0 for CW)
  117. return m.rotate(m._degToRad(degree)); // dojox.gfx.matrix.Matrix2D
  118. },
  119. skewX: function(angle) {
  120. // summary: forms an x skewing matrix
  121. // description: The resulting matrix is used to skew points in the x dimension
  122. // around the origin of coordinates (0, 0) by specified angle.
  123. // angle: Number: an skewing angle in radians
  124. return new m.Matrix2D({xy: Math.tan(angle)}); // dojox.gfx.matrix.Matrix2D
  125. },
  126. skewXg: function(degree){
  127. // summary: forms an x skewing matrix
  128. // description: The resulting matrix is used to skew points in the x dimension
  129. // around the origin of coordinates (0, 0) by specified degree.
  130. // See dojox.gfx.matrix.skewX() for comparison.
  131. // degree: Number: an skewing angle in degrees
  132. return m.skewX(m._degToRad(degree)); // dojox.gfx.matrix.Matrix2D
  133. },
  134. skewY: function(angle){
  135. // summary: forms a y skewing matrix
  136. // description: The resulting matrix is used to skew points in the y dimension
  137. // around the origin of coordinates (0, 0) by specified angle.
  138. // angle: Number: an skewing angle in radians
  139. return new m.Matrix2D({yx: Math.tan(angle)}); // dojox.gfx.matrix.Matrix2D
  140. },
  141. skewYg: function(degree){
  142. // summary: forms a y skewing matrix
  143. // description: The resulting matrix is used to skew points in the y dimension
  144. // around the origin of coordinates (0, 0) by specified degree.
  145. // See dojox.gfx.matrix.skewY() for comparison.
  146. // degree: Number: an skewing angle in degrees
  147. return m.skewY(m._degToRad(degree)); // dojox.gfx.matrix.Matrix2D
  148. },
  149. reflect: function(a, b){
  150. // summary: forms a reflection matrix
  151. // description: The resulting matrix is used to reflect points around a vector,
  152. // which goes through the origin.
  153. // a: dojox.gfx.Point: a point-like object, which specifies a vector of reflection
  154. // b: null
  155. if(arguments.length == 1){
  156. b = a.y;
  157. a = a.x;
  158. }
  159. // branch
  160. // a: Number: an x coordinate value
  161. // b: Number: a y coordinate value
  162. // make a unit vector
  163. var a2 = a * a, b2 = b * b, n2 = a2 + b2, xy = 2 * a * b / n2;
  164. return new m.Matrix2D({xx: 2 * a2 / n2 - 1, xy: xy, yx: xy, yy: 2 * b2 / n2 - 1}); // dojox.gfx.matrix.Matrix2D
  165. },
  166. project: function(a, b){
  167. // summary: forms an orthogonal projection matrix
  168. // description: The resulting matrix is used to project points orthogonally on a vector,
  169. // which goes through the origin.
  170. // a: dojox.gfx.Point: a point-like object, which specifies a vector of projection
  171. // b: null
  172. if(arguments.length == 1){
  173. b = a.y;
  174. a = a.x;
  175. }
  176. // branch
  177. // a: Number: an x coordinate value
  178. // b: Number: a y coordinate value
  179. // make a unit vector
  180. var a2 = a * a, b2 = b * b, n2 = a2 + b2, xy = a * b / n2;
  181. return new m.Matrix2D({xx: a2 / n2, xy: xy, yx: xy, yy: b2 / n2}); // dojox.gfx.matrix.Matrix2D
  182. },
  183. // ensure matrix 2D conformance
  184. normalize: function(matrix){
  185. // summary: converts an object to a matrix, if necessary
  186. // description: Converts any 2D matrix-like object or an array of
  187. // such objects to a valid dojox.gfx.matrix.Matrix2D object.
  188. // matrix: Object: an object, which is converted to a matrix, if necessary
  189. return (matrix instanceof m.Matrix2D) ? matrix : new m.Matrix2D(matrix); // dojox.gfx.matrix.Matrix2D
  190. },
  191. // common operations
  192. clone: function(matrix){
  193. // summary: creates a copy of a 2D matrix
  194. // matrix: dojox.gfx.matrix.Matrix2D: a 2D matrix-like object to be cloned
  195. var obj = new m.Matrix2D();
  196. for(var i in matrix){
  197. if(typeof(matrix[i]) == "number" && typeof(obj[i]) == "number" && obj[i] != matrix[i]) obj[i] = matrix[i];
  198. }
  199. return obj; // dojox.gfx.matrix.Matrix2D
  200. },
  201. invert: function(matrix){
  202. // summary: inverts a 2D matrix
  203. // matrix: dojox.gfx.matrix.Matrix2D: a 2D matrix-like object to be inverted
  204. var M = m.normalize(matrix),
  205. D = M.xx * M.yy - M.xy * M.yx,
  206. M = new m.Matrix2D({
  207. xx: M.yy/D, xy: -M.xy/D,
  208. yx: -M.yx/D, yy: M.xx/D,
  209. dx: (M.xy * M.dy - M.yy * M.dx) / D,
  210. dy: (M.yx * M.dx - M.xx * M.dy) / D
  211. });
  212. return M; // dojox.gfx.matrix.Matrix2D
  213. },
  214. _multiplyPoint: function(matrix, x, y){
  215. // summary: applies a matrix to a point
  216. // matrix: dojox.gfx.matrix.Matrix2D: a 2D matrix object to be applied
  217. // x: Number: an x coordinate of a point
  218. // y: Number: a y coordinate of a point
  219. return {x: matrix.xx * x + matrix.xy * y + matrix.dx, y: matrix.yx * x + matrix.yy * y + matrix.dy}; // dojox.gfx.Point
  220. },
  221. multiplyPoint: function(matrix, /* Number||Point */ a, /* Number, optional */ b){
  222. // summary: applies a matrix to a point
  223. // matrix: dojox.gfx.matrix.Matrix2D: a 2D matrix object to be applied
  224. // a: Number: an x coordinate of a point
  225. // b: Number: a y coordinate of a point
  226. var M = m.normalize(matrix);
  227. if(typeof a == "number" && typeof b == "number"){
  228. return m._multiplyPoint(M, a, b); // dojox.gfx.Point
  229. }
  230. // branch
  231. // matrix: dojox.gfx.matrix.Matrix2D: a 2D matrix object to be applied
  232. // a: dojox.gfx.Point: a point
  233. // b: null
  234. return m._multiplyPoint(M, a.x, a.y); // dojox.gfx.Point
  235. },
  236. multiply: function(matrix){
  237. // summary: combines matrices by multiplying them sequentially in the given order
  238. // matrix: dojox.gfx.matrix.Matrix2D...: a 2D matrix-like object,
  239. // all subsequent arguments are matrix-like objects too
  240. var M = m.normalize(matrix);
  241. // combine matrices
  242. for(var i = 1; i < arguments.length; ++i){
  243. var l = M, r = m.normalize(arguments[i]);
  244. M = new m.Matrix2D();
  245. M.xx = l.xx * r.xx + l.xy * r.yx;
  246. M.xy = l.xx * r.xy + l.xy * r.yy;
  247. M.yx = l.yx * r.xx + l.yy * r.yx;
  248. M.yy = l.yx * r.xy + l.yy * r.yy;
  249. M.dx = l.xx * r.dx + l.xy * r.dy + l.dx;
  250. M.dy = l.yx * r.dx + l.yy * r.dy + l.dy;
  251. }
  252. return M; // dojox.gfx.matrix.Matrix2D
  253. },
  254. // high level operations
  255. _sandwich: function(matrix, x, y){
  256. // summary: applies a matrix at a centrtal point
  257. // matrix: dojox.gfx.matrix.Matrix2D: a 2D matrix-like object, which is applied at a central point
  258. // x: Number: an x component of the central point
  259. // y: Number: a y component of the central point
  260. return m.multiply(m.translate(x, y), matrix, m.translate(-x, -y)); // dojox.gfx.matrix.Matrix2D
  261. },
  262. scaleAt: function(a, b, c, d){
  263. // summary: scales a picture using a specified point as a center of scaling
  264. // description: Compare with dojox.gfx.matrix.scale().
  265. // a: Number: a scaling factor used for the x coordinate
  266. // b: Number: a scaling factor used for the y coordinate
  267. // c: Number: an x component of a central point
  268. // d: Number: a y component of a central point
  269. // accepts several signatures:
  270. // 1) uniform scale factor, Point
  271. // 2) uniform scale factor, x, y
  272. // 3) x scale, y scale, Point
  273. // 4) x scale, y scale, x, y
  274. switch(arguments.length){
  275. case 4:
  276. // a and b are scale factor components, c and d are components of a point
  277. return m._sandwich(m.scale(a, b), c, d); // dojox.gfx.matrix.Matrix2D
  278. case 3:
  279. if(typeof c == "number"){
  280. // branch
  281. // a: Number: a uniform scaling factor used for both coordinates
  282. // b: Number: an x component of a central point
  283. // c: Number: a y component of a central point
  284. // d: null
  285. return m._sandwich(m.scale(a), b, c); // dojox.gfx.matrix.Matrix2D
  286. }
  287. // branch
  288. // a: Number: a scaling factor used for the x coordinate
  289. // b: Number: a scaling factor used for the y coordinate
  290. // c: dojox.gfx.Point: a central point
  291. // d: null
  292. return m._sandwich(m.scale(a, b), c.x, c.y); // dojox.gfx.matrix.Matrix2D
  293. }
  294. // branch
  295. // a: Number: a uniform scaling factor used for both coordinates
  296. // b: dojox.gfx.Point: a central point
  297. // c: null
  298. // d: null
  299. return m._sandwich(m.scale(a), b.x, b.y); // dojox.gfx.matrix.Matrix2D
  300. },
  301. rotateAt: function(angle, a, b){
  302. // summary: rotates a picture using a specified point as a center of rotation
  303. // description: Compare with dojox.gfx.matrix.rotate().
  304. // angle: Number: an angle of rotation in radians (>0 for CW)
  305. // a: Number: an x component of a central point
  306. // b: Number: a y component of a central point
  307. // accepts several signatures:
  308. // 1) rotation angle in radians, Point
  309. // 2) rotation angle in radians, x, y
  310. if(arguments.length > 2){
  311. return m._sandwich(m.rotate(angle), a, b); // dojox.gfx.matrix.Matrix2D
  312. }
  313. // branch
  314. // angle: Number: an angle of rotation in radians (>0 for CCW)
  315. // a: dojox.gfx.Point: a central point
  316. // b: null
  317. return m._sandwich(m.rotate(angle), a.x, a.y); // dojox.gfx.matrix.Matrix2D
  318. },
  319. rotategAt: function(degree, a, b){
  320. // summary: rotates a picture using a specified point as a center of rotation
  321. // description: Compare with dojox.gfx.matrix.rotateg().
  322. // degree: Number: an angle of rotation in degrees (>0 for CW)
  323. // a: Number: an x component of a central point
  324. // b: Number: a y component of a central point
  325. // accepts several signatures:
  326. // 1) rotation angle in degrees, Point
  327. // 2) rotation angle in degrees, x, y
  328. if(arguments.length > 2){
  329. return m._sandwich(m.rotateg(degree), a, b); // dojox.gfx.matrix.Matrix2D
  330. }
  331. // branch
  332. // degree: Number: an angle of rotation in degrees (>0 for CCW)
  333. // a: dojox.gfx.Point: a central point
  334. // b: null
  335. return m._sandwich(m.rotateg(degree), a.x, a.y); // dojox.gfx.matrix.Matrix2D
  336. },
  337. skewXAt: function(angle, a, b){
  338. // summary: skews a picture along the x axis using a specified point as a center of skewing
  339. // description: Compare with dojox.gfx.matrix.skewX().
  340. // angle: Number: an skewing angle in radians
  341. // a: Number: an x component of a central point
  342. // b: Number: a y component of a central point
  343. // accepts several signatures:
  344. // 1) skew angle in radians, Point
  345. // 2) skew angle in radians, x, y
  346. if(arguments.length > 2){
  347. return m._sandwich(m.skewX(angle), a, b); // dojox.gfx.matrix.Matrix2D
  348. }
  349. // branch
  350. // angle: Number: an skewing angle in radians
  351. // a: dojox.gfx.Point: a central point
  352. // b: null
  353. return m._sandwich(m.skewX(angle), a.x, a.y); // dojox.gfx.matrix.Matrix2D
  354. },
  355. skewXgAt: function(degree, a, b){
  356. // summary: skews a picture along the x axis using a specified point as a center of skewing
  357. // description: Compare with dojox.gfx.matrix.skewXg().
  358. // degree: Number: an skewing angle in degrees
  359. // a: Number: an x component of a central point
  360. // b: Number: a y component of a central point
  361. // accepts several signatures:
  362. // 1) skew angle in degrees, Point
  363. // 2) skew angle in degrees, x, y
  364. if(arguments.length > 2){
  365. return m._sandwich(m.skewXg(degree), a, b); // dojox.gfx.matrix.Matrix2D
  366. }
  367. // branch
  368. // degree: Number: an skewing angle in degrees
  369. // a: dojox.gfx.Point: a central point
  370. // b: null
  371. return m._sandwich(m.skewXg(degree), a.x, a.y); // dojox.gfx.matrix.Matrix2D
  372. },
  373. skewYAt: function(angle, a, b){
  374. // summary: skews a picture along the y axis using a specified point as a center of skewing
  375. // description: Compare with dojox.gfx.matrix.skewY().
  376. // angle: Number: an skewing angle in radians
  377. // a: Number: an x component of a central point
  378. // b: Number: a y component of a central point
  379. // accepts several signatures:
  380. // 1) skew angle in radians, Point
  381. // 2) skew angle in radians, x, y
  382. if(arguments.length > 2){
  383. return m._sandwich(m.skewY(angle), a, b); // dojox.gfx.matrix.Matrix2D
  384. }
  385. // branch
  386. // angle: Number: an skewing angle in radians
  387. // a: dojox.gfx.Point: a central point
  388. // b: null
  389. return m._sandwich(m.skewY(angle), a.x, a.y); // dojox.gfx.matrix.Matrix2D
  390. },
  391. skewYgAt: function(/* Number */ degree, /* Number||Point */ a, /* Number, optional */ b){
  392. // summary: skews a picture along the y axis using a specified point as a center of skewing
  393. // description: Compare with dojox.gfx.matrix.skewYg().
  394. // degree: Number: an skewing angle in degrees
  395. // a: Number: an x component of a central point
  396. // b: Number: a y component of a central point
  397. // accepts several signatures:
  398. // 1) skew angle in degrees, Point
  399. // 2) skew angle in degrees, x, y
  400. if(arguments.length > 2){
  401. return m._sandwich(m.skewYg(degree), a, b); // dojox.gfx.matrix.Matrix2D
  402. }
  403. // branch
  404. // degree: Number: an skewing angle in degrees
  405. // a: dojox.gfx.Point: a central point
  406. // b: null
  407. return m._sandwich(m.skewYg(degree), a.x, a.y); // dojox.gfx.matrix.Matrix2D
  408. }
  409. //TODO: rect-to-rect mapping, scale-to-fit (isotropic and anisotropic versions)
  410. });
  411. })();
  412. // propagate Matrix2D up
  413. dojox.gfx.Matrix2D = dojox.gfx.matrix.Matrix2D;
  414. }
  415. if(!dojo._hasResource["dojox.gfx._base"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  416. dojo._hasResource["dojox.gfx._base"] = true;
  417. dojo.provide("dojox.gfx._base");
  418. (function(){
  419. var g = dojox.gfx, b = g._base;
  420. // candidates for dojox.style (work on VML and SVG nodes)
  421. g._hasClass = function(/*DomNode*/node, /*String*/classStr){
  422. // summary:
  423. // Returns whether or not the specified classes are a portion of the
  424. // class list currently applied to the node.
  425. // return (new RegExp('(^|\\s+)'+classStr+'(\\s+|$)')).test(node.className) // Boolean
  426. var cls = node.getAttribute("className");
  427. return cls && (" " + cls + " ").indexOf(" " + classStr + " ") >= 0; // Boolean
  428. };
  429. g._addClass = function(/*DomNode*/node, /*String*/classStr){
  430. // summary:
  431. // Adds the specified classes to the end of the class list on the
  432. // passed node.
  433. var cls = node.getAttribute("className") || "";
  434. if(!cls || (" " + cls + " ").indexOf(" " + classStr + " ") < 0){
  435. node.setAttribute("className", cls + (cls ? " " : "") + classStr);
  436. }
  437. };
  438. g._removeClass = function(/*DomNode*/node, /*String*/classStr){
  439. // summary: Removes classes from node.
  440. var cls = node.getAttribute("className");
  441. if(cls){
  442. node.setAttribute(
  443. "className",
  444. cls.replace(new RegExp('(^|\\s+)' + classStr + '(\\s+|$)'), "$1$2")
  445. );
  446. }
  447. };
  448. // candidate for dojox.html.metrics (dynamic font resize handler is not implemented here)
  449. // derived from Morris John's emResized measurer
  450. b._getFontMeasurements = function(){
  451. // summary:
  452. // Returns an object that has pixel equivilents of standard font
  453. // size values.
  454. var heights = {
  455. '1em': 0, '1ex': 0, '100%': 0, '12pt': 0, '16px': 0, 'xx-small': 0,
  456. 'x-small': 0, 'small': 0, 'medium': 0, 'large': 0, 'x-large': 0,
  457. 'xx-large': 0
  458. };
  459. if(dojo.isIE){
  460. // we do a font-size fix if and only if one isn't applied already.
  461. // NOTE: If someone set the fontSize on the HTML Element, this will kill it.
  462. dojo.doc.documentElement.style.fontSize="100%";
  463. }
  464. // set up the measuring node.
  465. var div = dojo.create("div", {style: {
  466. position: "absolute",
  467. left: "0",
  468. top: "-100px",
  469. width: "30px",
  470. height: "1000em",
  471. borderWidth: "0",
  472. margin: "0",
  473. padding: "0",
  474. outline: "none",
  475. lineHeight: "1",
  476. overflow: "hidden"
  477. }}, dojo.body());
  478. // do the measurements.
  479. for(var p in heights){
  480. div.style.fontSize = p;
  481. heights[p] = Math.round(div.offsetHeight * 12/16) * 16/12 / 1000;
  482. }
  483. dojo.body().removeChild(div);
  484. return heights; // object
  485. };
  486. var fontMeasurements = null;
  487. b._getCachedFontMeasurements = function(recalculate){
  488. if(recalculate || !fontMeasurements){
  489. fontMeasurements = b._getFontMeasurements();
  490. }
  491. return fontMeasurements;
  492. };
  493. // candidate for dojox.html.metrics
  494. var measuringNode = null, empty = {};
  495. b._getTextBox = function( /*String*/ text,
  496. /*Object*/ style,
  497. /*String?*/ className){
  498. var m, s, al = arguments.length;
  499. if(!measuringNode){
  500. measuringNode = dojo.create("div", {style: {
  501. position: "absolute",
  502. top: "-10000px",
  503. left: "0"
  504. }}, dojo.body());
  505. }
  506. m = measuringNode;
  507. // reset styles
  508. m.className = "";
  509. s = m.style;
  510. s.borderWidth = "0";
  511. s.margin = "0";
  512. s.padding = "0";
  513. s.outline = "0";
  514. // set new style
  515. if(al > 1 && style){
  516. for(var i in style){
  517. if(i in empty){ continue; }
  518. s[i] = style[i];
  519. }
  520. }
  521. // set classes
  522. if(al > 2 && className){
  523. m.className = className;
  524. }
  525. // take a measure
  526. m.innerHTML = text;
  527. if(m["getBoundingClientRect"]){
  528. var bcr = m.getBoundingClientRect();
  529. return {l: bcr.left, t: bcr.top, w: bcr.width || (bcr.right - bcr.left), h: bcr.height || (bcr.bottom - bcr.top)};
  530. }else{
  531. return dojo.marginBox(m);
  532. }
  533. };
  534. // candidate for dojo.dom
  535. var uniqueId = 0;
  536. b._getUniqueId = function(){
  537. // summary: returns a unique string for use with any DOM element
  538. var id;
  539. do{
  540. id = dojo._scopeName + "Unique" + (++uniqueId);
  541. }while(dojo.byId(id));
  542. return id;
  543. };
  544. })();
  545. dojo.mixin(dojox.gfx, {
  546. // summary:
  547. // defines constants, prototypes, and utility functions
  548. // default shapes, which are used to fill in missing parameters
  549. defaultPath: {
  550. type: "path", path: ""
  551. },
  552. defaultPolyline: {
  553. type: "polyline", points: []
  554. },
  555. defaultRect: {
  556. type: "rect", x: 0, y: 0, width: 100, height: 100, r: 0
  557. },
  558. defaultEllipse: {
  559. type: "ellipse", cx: 0, cy: 0, rx: 200, ry: 100
  560. },
  561. defaultCircle: {
  562. type: "circle", cx: 0, cy: 0, r: 100
  563. },
  564. defaultLine: {
  565. type: "line", x1: 0, y1: 0, x2: 100, y2: 100
  566. },
  567. defaultImage: {
  568. type: "image", x: 0, y: 0, width: 0, height: 0, src: ""
  569. },
  570. defaultText: {
  571. type: "text", x: 0, y: 0, text: "", align: "start",
  572. decoration: "none", rotated: false, kerning: true
  573. },
  574. defaultTextPath: {
  575. type: "textpath", text: "", align: "start",
  576. decoration: "none", rotated: false, kerning: true
  577. },
  578. // default geometric attributes
  579. defaultStroke: {
  580. type: "stroke", color: "black", style: "solid", width: 1,
  581. cap: "butt", join: 4
  582. },
  583. defaultLinearGradient: {
  584. type: "linear", x1: 0, y1: 0, x2: 100, y2: 100,
  585. colors: [
  586. { offset: 0, color: "black" }, { offset: 1, color: "white" }
  587. ]
  588. },
  589. defaultRadialGradient: {
  590. type: "radial", cx: 0, cy: 0, r: 100,
  591. colors: [
  592. { offset: 0, color: "black" }, { offset: 1, color: "white" }
  593. ]
  594. },
  595. defaultPattern: {
  596. type: "pattern", x: 0, y: 0, width: 0, height: 0, src: ""
  597. },
  598. defaultFont: {
  599. type: "font", style: "normal", variant: "normal",
  600. weight: "normal", size: "10pt", family: "serif"
  601. },
  602. getDefault: (function(){
  603. var typeCtorCache = {};
  604. // a memoized delegate()
  605. return function(/*String*/ type){
  606. var t = typeCtorCache[type];
  607. if(t){
  608. return new t();
  609. }
  610. t = typeCtorCache[type] = new Function;
  611. t.prototype = dojox.gfx[ "default" + type ];
  612. return new t();
  613. }
  614. })(),
  615. normalizeColor: function(/*Color*/ color){
  616. // summary:
  617. // converts any legal color representation to normalized
  618. // dojo.Color object
  619. return (color instanceof dojo.Color) ? color : new dojo.Color(color); // dojo.Color
  620. },
  621. normalizeParameters: function(existed, update){
  622. // summary:
  623. // updates an existing object with properties from an "update"
  624. // object
  625. // existed: Object
  626. // the "target" object to be updated
  627. // update: Object
  628. // the "update" object, whose properties will be used to update
  629. // the existed object
  630. if(update){
  631. var empty = {};
  632. for(var x in existed){
  633. if(x in update && !(x in empty)){
  634. existed[x] = update[x];
  635. }
  636. }
  637. }
  638. return existed; // Object
  639. },
  640. makeParameters: function(defaults, update){
  641. // summary:
  642. // copies the original object, and all copied properties from the
  643. // "update" object
  644. // defaults: Object
  645. // the object to be cloned before updating
  646. // update: Object
  647. // the object, which properties are to be cloned during updating
  648. if(!update){
  649. // return dojo.clone(defaults);
  650. return dojo.delegate(defaults);
  651. }
  652. var result = {};
  653. for(var i in defaults){
  654. if(!(i in result)){
  655. result[i] = dojo.clone((i in update) ? update[i] : defaults[i]);
  656. }
  657. }
  658. return result; // Object
  659. },
  660. formatNumber: function(x, addSpace){
  661. // summary: converts a number to a string using a fixed notation
  662. // x: Number: number to be converted
  663. // addSpace: Boolean?: if it is true, add a space before a positive number
  664. var val = x.toString();
  665. if(val.indexOf("e") >= 0){
  666. val = x.toFixed(4);
  667. }else{
  668. var point = val.indexOf(".");
  669. if(point >= 0 && val.length - point > 5){
  670. val = x.toFixed(4);
  671. }
  672. }
  673. if(x < 0){
  674. return val; // String
  675. }
  676. return addSpace ? " " + val : val; // String
  677. },
  678. // font operations
  679. makeFontString: function(font){
  680. // summary: converts a font object to a CSS font string
  681. // font: Object: font object (see dojox.gfx.defaultFont)
  682. return font.style + " " + font.variant + " " + font.weight + " " + font.size + " " + font.family; // Object
  683. },
  684. splitFontString: function(str){
  685. // summary:
  686. // converts a CSS font string to a font object
  687. // description:
  688. // Converts a CSS font string to a gfx font object. The CSS font
  689. // string components should follow the W3C specified order
  690. // (see http://www.w3.org/TR/CSS2/fonts.html#font-shorthand):
  691. // style, variant, weight, size, optional line height (will be
  692. // ignored), and family.
  693. // str: String
  694. // a CSS font string
  695. var font = dojox.gfx.getDefault("Font");
  696. var t = str.split(/\s+/);
  697. do{
  698. if(t.length < 5){ break; }
  699. font.style = t[0];
  700. font.variant = t[1];
  701. font.weight = t[2];
  702. var i = t[3].indexOf("/");
  703. font.size = i < 0 ? t[3] : t[3].substring(0, i);
  704. var j = 4;
  705. if(i < 0){
  706. if(t[4] == "/"){
  707. j = 6;
  708. }else if(t[4].charAt(0) == "/"){
  709. j = 5;
  710. }
  711. }
  712. if(j < t.length){
  713. font.family = t.slice(j).join(" ");
  714. }
  715. }while(false);
  716. return font; // Object
  717. },
  718. // length operations
  719. cm_in_pt: 72 / 2.54, // Number: points per centimeter
  720. mm_in_pt: 7.2 / 2.54, // Number: points per millimeter
  721. px_in_pt: function(){
  722. // summary: returns a number of pixels per point
  723. return dojox.gfx._base._getCachedFontMeasurements()["12pt"] / 12; // Number
  724. },
  725. pt2px: function(len){
  726. // summary: converts points to pixels
  727. // len: Number: a value in points
  728. return len * dojox.gfx.px_in_pt(); // Number
  729. },
  730. px2pt: function(len){
  731. // summary: converts pixels to points
  732. // len: Number: a value in pixels
  733. return len / dojox.gfx.px_in_pt(); // Number
  734. },
  735. normalizedLength: function(len) {
  736. // summary: converts any length value to pixels
  737. // len: String: a length, e.g., "12pc"
  738. if(len.length == 0) return 0;
  739. if(len.length > 2){
  740. var px_in_pt = dojox.gfx.px_in_pt();
  741. var val = parseFloat(len);
  742. switch(len.slice(-2)){
  743. case "px": return val;
  744. case "pt": return val * px_in_pt;
  745. case "in": return val * 72 * px_in_pt;
  746. case "pc": return val * 12 * px_in_pt;
  747. case "mm": return val * dojox.gfx.mm_in_pt * px_in_pt;
  748. case "cm": return val * dojox.gfx.cm_in_pt * px_in_pt;
  749. }
  750. }
  751. return parseFloat(len); // Number
  752. },
  753. // a constant used to split a SVG/VML path into primitive components
  754. pathVmlRegExp: /([A-Za-z]+)|(\d+(\.\d+)?)|(\.\d+)|(-\d+(\.\d+)?)|(-\.\d+)/g,
  755. pathSvgRegExp: /([A-Za-z])|(\d+(\.\d+)?)|(\.\d+)|(-\d+(\.\d+)?)|(-\.\d+)/g,
  756. equalSources: function(a, b){
  757. // summary: compares event sources, returns true if they are equal
  758. return a && b && a == b;
  759. },
  760. switchTo: function(renderer){
  761. var ns = dojox.gfx[renderer];
  762. if(ns){
  763. dojo.forEach(["Group", "Rect", "Ellipse", "Circle", "Line",
  764. "Polyline", "Image", "Text", "Path", "TextPath",
  765. "Surface", "createSurface"], function(name){
  766. dojox.gfx[name] = ns[name];
  767. });
  768. }
  769. }
  770. });
  771. }
  772. if(!dojo._hasResource["dojox.gfx"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  773. dojo._hasResource["dojox.gfx"] = true;
  774. dojo.provide("dojox.gfx");
  775. dojo.loadInit(function(){
  776. // Since loaderInit can be fired before any dojo.provide/require calls,
  777. // make sure the dojox.gfx object exists and only run this logic if dojox.gfx.renderer
  778. // has not been defined yet.
  779. var gfx = dojo.getObject("dojox.gfx", true), sl, flag, match;
  780. while(!gfx.renderer){
  781. // Have a way to force a GFX renderer, if so desired.
  782. // Useful for being able to serialize GFX data in a particular format.
  783. if(dojo.config.forceGfxRenderer){
  784. dojox.gfx.renderer = dojo.config.forceGfxRenderer;
  785. break;
  786. }
  787. var renderers = (typeof dojo.config.gfxRenderer == "string" ?
  788. dojo.config.gfxRenderer : "svg,vml,canvas,silverlight").split(",");
  789. for(var i = 0; i < renderers.length; ++i){
  790. switch(renderers[i]){
  791. case "svg":
  792. // the next test is from https://github.com/phiggins42/has.js
  793. if("SVGAngle" in dojo.global){
  794. dojox.gfx.renderer = "svg";
  795. }
  796. break;
  797. case "vml":
  798. if(dojo.isIE){
  799. dojox.gfx.renderer = "vml";
  800. }
  801. break;
  802. case "silverlight":
  803. try{
  804. if(dojo.isIE){
  805. sl = new ActiveXObject("AgControl.AgControl");
  806. if(sl && sl.IsVersionSupported("1.0")){
  807. flag = true;
  808. }
  809. }else{
  810. if(navigator.plugins["Silverlight Plug-In"]){
  811. flag = true;
  812. }
  813. }
  814. }catch(e){
  815. flag = false;
  816. }finally{
  817. sl = null;
  818. }
  819. if(flag){
  820. dojox.gfx.renderer = "silverlight";
  821. }
  822. break;
  823. case "canvas":
  824. if(dojo.global.CanvasRenderingContext2D){
  825. dojox.gfx.renderer = "canvas";
  826. }
  827. break;
  828. }
  829. if(gfx.renderer){
  830. break;
  831. }
  832. }
  833. break;
  834. }
  835. if(dojo.config.isDebug){
  836. console.log("gfx renderer = " + gfx.renderer);
  837. }
  838. // load & initialize renderer
  839. if(gfx[gfx.renderer]){
  840. // already loaded
  841. gfx.switchTo(gfx.renderer);
  842. }else{
  843. // load
  844. gfx.loadAndSwitch = gfx.renderer;
  845. dojo["require"]("dojox.gfx." + gfx.renderer);
  846. }
  847. });
  848. }