common.js 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  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.drawing.util.common"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  7. dojo._hasResource["dojox.drawing.util.common"] = true;
  8. dojo.provide("dojox.drawing.util.common");
  9. dojo.require("dojox.math.round");
  10. (function(){
  11. var uidMap = {};
  12. var start = 0;
  13. dojox.drawing.util.common = {
  14. // summary:
  15. // A collection of common methods used for DojoX Drawing.
  16. // This singleton is accessible in most Drawing classes
  17. // as this.util
  18. //
  19. // NOTE:
  20. // A lot of functions use a EventObject
  21. // as an argument. An attempt was made to accept
  22. // either that object or a list of numbers. That wasn't
  23. // finished (it didn't work well in all cases) but is
  24. // likely to happen in the future.
  25. // In cases where you are not sending a Mouse object,
  26. // form your argument like so:
  27. // var obj = {
  28. // start:{
  29. // x:Number, // start x
  30. // y:Number // start y
  31. // },
  32. // x: Number, // end x
  33. // y:Number // end y
  34. // }
  35. //
  36. //
  37. radToDeg: function(/*Numer*/n){
  38. // summary:
  39. // Convert the passed number to degrees.
  40. return (n*180)/Math.PI; // Number
  41. },
  42. degToRad: function(/*Numer*/n){
  43. // summary:
  44. // Convert the passed number to radians.
  45. return (n*Math.PI)/180; // Number
  46. },
  47. angle: function(/*EventObject*/obj, /* ? Float */snap){
  48. // summary:
  49. // Return angle based on mouse object
  50. // arguments:
  51. // obj: EventObject
  52. // Manager.Mouse event.
  53. // snap: Float
  54. // Returns nearest angle within snap limits
  55. //
  56. //obj = this.argsToObj.apply(this, arguments);
  57. if(snap){
  58. snap = snap/180;
  59. var radians = this.radians(obj),
  60. seg = Math.PI * snap,
  61. rnd = dojox.math.round(radians/seg),
  62. new_radian = rnd*seg;
  63. return dojox.math.round(this.radToDeg(new_radian)); // Whole Number
  64. }else{
  65. return this.radToDeg(this.radians(obj)); // Float
  66. }
  67. },
  68. oppAngle: function(/*Angle*/ang){
  69. (ang+=180) > 360 ? ang = ang - 360 : ang;
  70. return ang;
  71. },
  72. radians: function(/*EventObject*/o){
  73. // summary:
  74. // Return the radians derived from the coordinates
  75. // in the Mouse object.
  76. //
  77. //var o = this.argsToObj.apply(this, arguments);
  78. return Math.atan2(o.start.y-o.y,o.x-o.start.x);
  79. },
  80. length: function(/*EventObject*/o){
  81. // summary:
  82. // Return the length derived from the coordinates
  83. // in the Mouse object.
  84. //
  85. return Math.sqrt(Math.pow(o.start.x-o.x, 2)+Math.pow(o.start.y-o.y, 2));
  86. },
  87. lineSub: function(/*Number*/x1, /*Number*/y1, /*Number*/x2, /*Number*/y2, /*Number*/amt){
  88. // summary:
  89. // Subtract an amount from a line
  90. // description:
  91. // x1,y1,x2,y2 represents the Line. 'amt' represents the amount
  92. // to subtract from it.
  93. //
  94. var len = this.distance(this.argsToObj.apply(this, arguments));
  95. len = len < amt ? amt : len;
  96. var pc = (len-amt)/len;
  97. var x = x1 - (x1-x2) * pc;
  98. var y = y1 - (y1-y2) * pc;
  99. return {x:x, y:y}; // Object
  100. },
  101. argsToObj: function(){
  102. // summary:
  103. // Attempts to determine in a Mouse Object
  104. // was passed or indiviual numbers. Returns
  105. // an object.
  106. //
  107. var a = arguments;
  108. if(a.length < 4){ return a[0]; }
  109. return {
  110. start:{
  111. x:a[0],
  112. y:a[1]
  113. },
  114. x:a[2],
  115. y:a[3]//,
  116. //snap:a[4]
  117. }; // Object
  118. },
  119. distance: function(/*EventObject or x1,y1,x2,y2*/){
  120. // summary:
  121. // Return the length derived from the coordinates
  122. // in the Mouse object. Different from util.length
  123. // in that this always returns an absolute value.
  124. //
  125. var o = this.argsToObj.apply(this, arguments);
  126. return Math.abs(Math.sqrt(Math.pow(o.start.x-o.x, 2)+Math.pow(o.start.y-o.y, 2))); // Number
  127. },
  128. slope:function(/*Object*/p1, /*Object*/p2){
  129. // summary:
  130. // Given two poits of a line, returns the slope.
  131. if(!(p1.x-p2.x)){ return 0; }
  132. return ((p1.y-p2.y)/(p1.x-p2.x)); // Number
  133. },
  134. pointOnCircle: function(/*Number*/cx, /*Number*/cy, /*Number*/radius, /*Number*/angle){
  135. // summary:
  136. // A *very* helpful method. If you know the center
  137. // (or starting) point, length and angle, find the
  138. // x,y point at the end of that line.
  139. //
  140. var radians = angle * Math.PI / 180.0;
  141. var x = radius * Math.cos(radians);
  142. var y = radius * Math.sin(radians);
  143. return {
  144. x:cx+x,
  145. y:cy-y
  146. }; // Object
  147. },
  148. constrainAngle: function(/*EventObject*/obj, /*Number*/min, /*Number*/max){
  149. // summary:
  150. // Ensures the angle in the Mouse Object is within the
  151. // min and max limits. If not one of those limits is used.
  152. // Returns an x,y point for the angle used.
  153. //
  154. var angle = this.angle(obj);
  155. if(angle >= min && angle <= max){
  156. return obj; // Object
  157. }
  158. var radius = this.length(obj);
  159. var new_angle = angle > max ? max : min - angle < 100 ? min : max;
  160. return this.pointOnCircle(obj.start.x,obj.start.y,radius, new_angle); // Object
  161. },
  162. snapAngle: function(/*EventObject*/obj, /*Float*/ca){
  163. // summary:
  164. // Snaps a line to the nearest angle
  165. // obj: Mouse object (see dojox.drawing.Mouse)
  166. // ca: Fractional amount to snap to
  167. // A decimal number fraction of a half circle
  168. // .5 would snap to 90 degrees
  169. // .25 would snap to 45 degrees
  170. // .125 would snap to 22.5 degrees, etc.
  171. //
  172. var radians = this.radians(obj),
  173. radius = this.length(obj),
  174. seg = Math.PI * ca,
  175. rnd = Math.round(radians/seg),
  176. new_radian = rnd*seg,
  177. new_angle = this.radToDeg(new_radian),
  178. pt = this.pointOnCircle(obj.start.x,obj.start.y,radius,new_angle);
  179. return pt; // Object
  180. },
  181. // helpers
  182. idSetStart: function(num){
  183. start=num;
  184. },
  185. uid: function(/* ? String */str){
  186. // summary:
  187. // Creates a unique ID.
  188. // arguments:
  189. // str: String
  190. // If provided, kept in a map, incremented
  191. // and used in the id. Otherwise 'shape' is used.
  192. //
  193. str = str || "shape";
  194. uidMap[str] = uidMap[str]===undefined ? start : uidMap[str] + 1;
  195. return str + uidMap[str]; // String
  196. },
  197. abbr: function(type){
  198. // summary:
  199. // Converts a namespace (typically a tool or a stencil) into
  200. // an abbreviation
  201. return type.substring(type.lastIndexOf(".")+1).charAt(0).toLowerCase()
  202. + type.substring(type.lastIndexOf(".")+2);
  203. },
  204. mixin: function(o1, o2){
  205. // TODO: make faster
  206. //return dojo.mixin(dojo.clone(o1), dojo.clone(o2));
  207. },
  208. objects:{}, //private?
  209. register: function(/*Object*/obj){
  210. // summary:
  211. // Since util is the only Singleton in Drawing (besides
  212. // keys) it is used to help connect the Drawing object
  213. // the Toolbar. Since multiple drawings can be on one
  214. // page, this function serves a little more use than
  215. // on first apearance.
  216. this.objects[obj.id] = obj;
  217. },
  218. byId: function(/*String*/id){
  219. // summary:
  220. // Get an object that was registered with util.register
  221. //
  222. return this.objects[id];
  223. },
  224. attr: function(/* Object */ elem, /* property */ prop, /* ? value */ value, squelchErrors){
  225. // summary:
  226. // Helper function to attach attributes to SVG and VML raw nodes.
  227. //
  228. if(!elem){ return false; }
  229. try{
  230. // util is a crappy check, but we need to tell the diff
  231. // between a Drawing shape and a GFX shape
  232. if(elem.shape && elem.util){
  233. elem = elem.shape;
  234. }
  235. if(!value && prop=="id" && elem.target){
  236. var n = elem.target;
  237. while(!dojo.attr(n, "id")){
  238. n = n.parentNode;
  239. }
  240. return dojo.attr(n, "id");
  241. }
  242. if(elem.rawNode || elem.target){
  243. var args = Array.prototype.slice.call(arguments);
  244. args[0] = elem.rawNode || elem.target;
  245. return dojo.attr.apply(dojo, args);
  246. }
  247. return dojo.attr(elem, "id");
  248. }catch(e){
  249. if(!squelchErrors){
  250. // For debugging only. These errors actually cause errors in IE's console
  251. //console.error("BAD ATTR: prop:", prop, "el:", elem)
  252. //console.error(e)
  253. //console.trace();
  254. }
  255. return false;
  256. }
  257. }
  258. };
  259. })();
  260. }