Anchors.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468
  1. // wrapped by build app
  2. define("dojox/drawing/manager/Anchors", ["dijit","dojo","dojox"], function(dijit,dojo,dojox){
  3. dojo.provide("dojox.drawing.manager.Anchors");
  4. dojox.drawing.manager.Anchors = dojox.drawing.util.oo.declare(
  5. // summary:
  6. // Creates and manages the anchor points that are attached to
  7. // (usually) the corners of a Stencil.
  8. // description:
  9. // Used internally, but there are some things that should be known:
  10. // Anchors attach to a Stencil's 'points' (See stencil.points)
  11. // To not display an anchor on a certain point, add noAnchor:true
  12. // to the point.
  13. function(/* dojox.__stencilArgs */options){
  14. // arguments: See stencil._Base
  15. this.mouse = options.mouse;
  16. this.undo = options.undo;
  17. this.util = options.util;
  18. this.drawing = options.drawing;
  19. this.items = {};
  20. },
  21. {
  22. onAddAnchor: function(/*Anchor*/anchor){
  23. // summary:
  24. // Event fires when anchor is created
  25. },
  26. onReset: function(/*Stencil*/stencil){
  27. // summary:
  28. // Event fires when an anchor's reset method is called
  29. //
  30. // a desperate hack in order to get the anchor point to reset.
  31. // FIXME: Is this still used? I think its item.deselect();item.select();
  32. var st = this.util.byId("drawing").stencils;
  33. st.onDeselect(stencil);
  34. st.onSelect(stencil);
  35. },
  36. onRenderStencil: function(){
  37. // summary:
  38. // Event fires when an anchor calls a Stencil's render method
  39. //
  40. for(var nm in this.items){
  41. dojo.forEach(this.items[nm].anchors, function(a){
  42. a.shape.moveToFront();
  43. });
  44. }
  45. },
  46. onTransformPoint: function(/*Anchor*/anchor){
  47. // summary:
  48. // Event fired on anchor drag
  49. //
  50. // If anchors are a "group", it's corresponding anchor
  51. // is set. All anchors then moved to front.
  52. var anchors = this.items[anchor.stencil.id].anchors;
  53. var item = this.items[anchor.stencil.id].item;
  54. var pts = [];
  55. dojo.forEach(anchors, function(a, i){
  56. if(anchor.id == a.id || anchor.stencil.anchorType!="group"){
  57. // nothing
  58. }else{
  59. if(anchor.org.y == a.org.y){
  60. a.setPoint({
  61. dx: 0,
  62. dy: anchor.shape.getTransform().dy - a.shape.getTransform().dy
  63. });
  64. }else if(anchor.org.x == a.org.x){
  65. a.setPoint({
  66. dx: anchor.shape.getTransform().dx - a.shape.getTransform().dx,
  67. dy: 0
  68. });
  69. }
  70. a.shape.moveToFront();
  71. }
  72. var mx = a.shape.getTransform();
  73. pts.push({x:mx.dx + a.org.x, y:mx.dy+ a.org.y});
  74. if(a.point.t){
  75. pts[pts.length-1].t = a.point.t;
  76. }
  77. }, this);
  78. item.setPoints(pts);
  79. item.onTransform(anchor);
  80. this.onRenderStencil();
  81. },
  82. onAnchorUp: function(/*Anchor*/anchor){
  83. // summary:
  84. // Event fired on anchor mouseup
  85. },
  86. onAnchorDown: function(/*Anchor*/anchor){
  87. // summary:
  88. // Event fired on anchor mousedown
  89. },
  90. onAnchorDrag: function(/*Anchor*/anchor){
  91. // summary:
  92. // Event fired when anchor is moved
  93. },
  94. onChangeStyle: function(/*Object*/stencil){
  95. // summary:
  96. // if the Stencil changes color while were's selected
  97. // this moves the anchors to the back. Fix it.
  98. for(var nm in this.items){
  99. dojo.forEach(this.items[nm].anchors, function(a){
  100. a.shape.moveToFront();
  101. });
  102. }
  103. },
  104. add: function(/*Stencil*/item){
  105. // summary:
  106. // Creates anchor points on a Stencil, based on the
  107. // Stencil's points.
  108. //
  109. this.items[item.id] = {
  110. item:item,
  111. anchors:[]
  112. };
  113. if(item.anchorType=="none"){ return; }
  114. var pts = item.points;
  115. dojo.forEach(pts, function(p, i){
  116. if(p.noAnchor){ return; }
  117. if(i==0 || i == item.points.length-1){
  118. console.log("ITEM TYPE:", item.type, item.shortType);
  119. }
  120. var a = new dojox.drawing.manager.Anchor({stencil:item, point:p, pointIdx:i, mouse:this.mouse, util:this.util});
  121. this.items[item.id]._cons = [
  122. dojo.connect(a, "onRenderStencil", this, "onRenderStencil"),
  123. dojo.connect(a, "reset", this, "onReset"),
  124. dojo.connect(a, "onAnchorUp", this, "onAnchorUp"),
  125. dojo.connect(a, "onAnchorDown", this, "onAnchorDown"),
  126. dojo.connect(a, "onAnchorDrag", this, "onAnchorDrag"),
  127. dojo.connect(a, "onTransformPoint", this, "onTransformPoint"),
  128. // FIXME: this will fire for each anchor. yech.
  129. dojo.connect(item, "onChangeStyle", this, "onChangeStyle")
  130. ];
  131. this.items[item.id].anchors.push(a);
  132. this.onAddAnchor(a);
  133. }, this);
  134. if(item.shortType=="path"){
  135. // check if we have a double-point of a closed-curve-path
  136. var f = pts[0], l = pts[pts.length-1], a = this.items[item.id].anchors;
  137. if(f.x ==l.x && f.y==l.y){
  138. console.warn("LINK ANVHROS", a[0], a[a.length-1]);
  139. a[0].linkedAnchor = a[a.length-1];
  140. a[a.length-1].linkedAnchor = a[0];
  141. }
  142. }
  143. if(item.anchorType=="group"){
  144. dojo.forEach(this.items[item.id].anchors, function(anchor){
  145. dojo.forEach(this.items[item.id].anchors, function(a){
  146. if(anchor.id != a.id){
  147. if(anchor.org.y == a.org.y){
  148. anchor.x_anchor = a;
  149. }else if(anchor.org.x == a.org.x){
  150. anchor.y_anchor = a;
  151. }
  152. }
  153. },this);
  154. },this);
  155. }
  156. },
  157. remove: function(/*Stencil*/item){
  158. // summary:
  159. // Destroys the anchor points for a Stencil.
  160. //
  161. if(!this.items[item.id]){
  162. return;
  163. }
  164. dojo.forEach(this.items[item.id].anchors, function(a){
  165. a.destroy();
  166. });
  167. dojo.forEach(this.items[item.id]._cons, dojo.disconnect, dojo);
  168. this.items[item.id].anchors = null;
  169. delete this.items[item.id];
  170. }
  171. }
  172. );
  173. dojox.drawing.manager.Anchor = dojox.drawing.util.oo.declare(
  174. // summary:
  175. // An anchor point that is attached to (usually) one of the
  176. // corners of a Stencil.
  177. // Used internally.
  178. function(/* Object */options){
  179. // summary:
  180. // constructor.
  181. // arguments:
  182. // dojox.__stencilArgs plus some additional
  183. // data, like which point this is (pointIdx)
  184. //
  185. this.defaults = dojox.drawing.defaults.copy();
  186. this.mouse = options.mouse;
  187. this.point = options.point;
  188. this.pointIdx = options.pointIdx;
  189. this.util = options.util;
  190. this.id = options.id || this.util.uid("anchor");
  191. this.org = dojo.mixin({}, this.point);
  192. this.stencil = options.stencil;
  193. if(this.stencil.anchorPositionCheck){
  194. this.anchorPositionCheck = dojo.hitch(this.stencil, this.stencil.anchorPositionCheck);
  195. }
  196. if(this.stencil.anchorConstrain){
  197. this.anchorConstrain = dojo.hitch(this.stencil, this.stencil.anchorConstrain);
  198. }
  199. this._zCon = dojo.connect(this.mouse, "setZoom", this, "render");
  200. this.render();
  201. this.connectMouse();
  202. },
  203. {
  204. y_anchor:null,
  205. x_anchor:null,
  206. render: function(){
  207. // summary:
  208. // Creates the anchor point. Unlike most render methods
  209. // in Drawing, this is only called once.
  210. //
  211. this.shape && this.shape.removeShape();
  212. var d = this.defaults.anchors,
  213. z = this.mouse.zoom,
  214. b = d.width * z,
  215. s = d.size * z,
  216. p = s/2,
  217. line = {
  218. width:b,
  219. style:d.style,
  220. color:d.color,
  221. cap:d.cap
  222. };
  223. var _r = {
  224. x: this.point.x-p,
  225. y: this.point.y-p,
  226. width: s,
  227. height: s
  228. };
  229. this.shape = this.stencil.container.createRect(_r)
  230. .setStroke(line)
  231. .setFill(d.fill);
  232. this.shape.setTransform({dx:0, dy:0});
  233. this.util.attr(this, "drawingType", "anchor");
  234. this.util.attr(this, "id", this.id);
  235. },
  236. onRenderStencil: function(/*Anchor*/anchor){
  237. // summary:
  238. // Event fires when an anchor calls a Stencil's render method
  239. },
  240. onTransformPoint: function(/*Anchor*/anchor){
  241. // summary:
  242. // Event fires when an anchor changes the points of a Stencil
  243. },
  244. onAnchorDown: function(/*Mouse.EventObject*/obj){
  245. // summary:
  246. // Event fires for mousedown on anchor
  247. this.selected = obj.id == this.id;
  248. },
  249. onAnchorUp: function(/*Mouse.EventObject*/obj){
  250. // summary:
  251. // Event fires for mouseup on anchor
  252. this.selected = false;
  253. this.stencil.onTransformEnd(this);
  254. },
  255. onAnchorDrag: function(/*Mouse.EventObject*/obj){
  256. // summary:
  257. // Event fires for on dragging of an anchor
  258. if(this.selected){
  259. // mx is the original transform from when the anchor
  260. // was created. It does not change
  261. var mx = this.shape.getTransform();
  262. var pmx = this.shape.getParent().getParent().getTransform();
  263. var marginZero = this.defaults.anchors.marginZero;
  264. var orgx = pmx.dx + this.org.x,
  265. orgy = pmx.dy + this.org.y,
  266. x = obj.x - orgx,
  267. y = obj.y - orgy,
  268. s = this.defaults.anchors.minSize;
  269. var conL, conR, conT, conB;
  270. var chk = this.anchorPositionCheck(x, y, this);
  271. if(chk.x<0){
  272. console.warn("X<0 Shift");
  273. while(this.anchorPositionCheck(x, y, this).x<0){
  274. this.shape.getParent().getParent().applyTransform({dx:2, dy:0});
  275. }
  276. }
  277. if(chk.y<0){
  278. console.warn("Y<0 Shift");
  279. while(this.anchorPositionCheck(x, y, this).y<0){
  280. this.shape.getParent().getParent().applyTransform({dx:0, dy:2});
  281. }
  282. }
  283. if(this.y_anchor){
  284. // prevent y overlap of opposite anchor
  285. if(this.org.y > this.y_anchor.org.y){
  286. // bottom anchor
  287. conT = this.y_anchor.point.y + s - this.org.y;
  288. conB = Infinity;
  289. if(y < conT){
  290. // overlapping other anchor
  291. y = conT;
  292. }
  293. }else{
  294. // top anchor
  295. conT = -orgy + marginZero;
  296. conB = this.y_anchor.point.y - s - this.org.y;
  297. if(y < conT){
  298. // less than zero
  299. y = conT;
  300. }else if(y > conB){
  301. // overlapping other anchor
  302. y = conB;
  303. }
  304. }
  305. }else{
  306. // Lines - check for zero
  307. conT = -orgy + marginZero;
  308. if(y < conT){
  309. // less than zero
  310. y = conT;
  311. }
  312. }
  313. if(this.x_anchor){
  314. // prevent x overlap of opposite anchor
  315. if(this.org.x>this.x_anchor.org.x){
  316. // right anchor
  317. conL = this.x_anchor.point.x + s - this.org.x;
  318. conR = Infinity;
  319. if(x < conL){
  320. // overlapping other anchor
  321. x = conL;
  322. }
  323. }else{
  324. // left anchor
  325. conL = -orgx + marginZero;
  326. conR = this.x_anchor.point.x - s - this.org.x;
  327. if(x < conL){
  328. x = conL;
  329. }else if(x > conR){
  330. // overlapping other anchor
  331. x = conR;
  332. }
  333. }
  334. }else{
  335. // Lines check for zero
  336. conL = -orgx + marginZero;
  337. if(x < conL){
  338. x = conL;
  339. }
  340. }
  341. //Constrains anchor point, returns null if not overwritten by stencil
  342. var constrained = this.anchorConstrain(x, y);
  343. if(constrained != null){
  344. x=constrained.x;
  345. y=constrained.y;
  346. }
  347. this.shape.setTransform({
  348. dx:x,
  349. dy:y
  350. });
  351. if(this.linkedAnchor){
  352. // first and last points of a closed-curve-path
  353. this.linkedAnchor.shape.setTransform({
  354. dx:x,
  355. dy:y
  356. });
  357. }
  358. this.onTransformPoint(this);
  359. }
  360. },
  361. anchorConstrain: function(/* Number */x,/* Number */ y){
  362. // summary:
  363. // To be over written by tool!
  364. // Add an anchorConstrain method to the tool
  365. // and it will automatically overwrite this stub.
  366. // Should return a constrained x & y value.
  367. return null;
  368. },
  369. anchorPositionCheck: function(/* Number */x,/* Number */ y, /* Anchor */anchor){
  370. // summary:
  371. // To be over written by tool!
  372. // Add a anchorPositionCheck method to the tool
  373. // and it will automatically overwrite this stub.
  374. // Should return x and y coords. Success is both
  375. // being greater than zero, fail is if one or both
  376. // are less than zero.
  377. return {x:1, y:1};
  378. },
  379. setPoint: function(mx){
  380. // summary:
  381. // Internal. Sets the Stencil's point
  382. this.shape.applyTransform(mx);
  383. },
  384. connectMouse: function(){
  385. // summary:
  386. // Internal. Connects anchor to manager.mouse
  387. this._mouseHandle = this.mouse.register(this);
  388. },
  389. disconnectMouse: function(){
  390. // summary:
  391. // Internal. Disconnects anchor to manager.mouse
  392. this.mouse.unregister(this._mouseHandle);
  393. },
  394. reset: function(stencil){
  395. // summary:
  396. // Called (usually) from a Stencil when that Stencil
  397. // needed to make modifications to the position of the
  398. // point. Basically used when teh anchor causes a
  399. // less than zero condition.
  400. },
  401. destroy: function(){
  402. // summary:
  403. // Destroys anchor.
  404. dojo.disconnect(this._zCon);
  405. this.disconnectMouse();
  406. this.shape.removeShape();
  407. }
  408. }
  409. );
  410. });