Axes.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576
  1. // wrapped by build app
  2. define("dojox/drawing/tools/custom/Axes", ["dijit","dojo","dojox","dojo/require!dojox/drawing/stencil/Path"], function(dijit,dojo,dojox){
  3. dojo.provide("dojox.drawing.tools.custom.Axes");
  4. dojo.require("dojox.drawing.stencil.Path");
  5. dojox.drawing.tools.custom.Axes = dojox.drawing.util.oo.declare(
  6. // summary:
  7. // Draws a right-angle Axes (shaped like an L, not a +)
  8. // description:
  9. // This Stencil is created with a Path so that the L shape
  10. // is one continuous piece. Arrow heads are placed at the end
  11. // of each axis. The Axes can be rotated. There are custom
  12. // label methods.
  13. //
  14. dojox.drawing.stencil.Path,
  15. function(options){
  16. this.closePath = false;
  17. this.xArrow = new dojox.drawing.annotations.Arrow({stencil:this, idx1:0, idx2:1});
  18. this.yArrow = new dojox.drawing.annotations.Arrow({stencil:this, idx1:2, idx2:1});
  19. if(options.data){
  20. //Allows import of z-axis in non-enabled canvas and xy-axis in
  21. //enabled canvas
  22. this.style.zAxisEnabled = options.data.cosphi == 1 ? true : false;
  23. this.setData(options.data);
  24. }
  25. if(this.style.zAxisEnabled){
  26. // If the z-axis is enabled, all axes will be created with a z-axis on the canvas.
  27. // there is no switching back and forth for the axis, only for vectors.
  28. this.data.cosphi = 1;
  29. var ops = {};
  30. dojo.mixin(ops,options);
  31. dojo.mixin(ops,{
  32. container:this.container.createGroup(),
  33. style: this.style,
  34. showAngle: false,
  35. label: null
  36. });
  37. if(options.data && (!ops.data.radius || !ops.data.angle)){
  38. ops.data.x2 = ops.data.x4;
  39. ops.data.y2 = ops.data.y4;
  40. }
  41. ops.style.zAxis = true;
  42. this.zAxis = new dojox.drawing.tools.custom.Vector(ops);
  43. this.zAxis.minimumSize = 5;
  44. //console.log("-----constructing axes: ",this.zAxis);
  45. this.connectMult([
  46. [this, "onChangeStyle", this.zAxis, "onChangeStyle"],
  47. [this, "select", this.zAxis, "select"],
  48. [this, "deselect", this.zAxis, "deselect"],
  49. [this, "onDelete", this.zAxis, "destroy"],
  50. [this, "onDrag", this, "zSet"],
  51. [this, "onTransform", this, "zSet"],
  52. [this.zAxis, "onBeforeRender", this, "zSet"],
  53. [this, "_onPostRender", this.zAxis, "render"]
  54. ]);
  55. }
  56. if(this.points && this.points.length){
  57. this.setPoints = this._postSetPoints;
  58. // render isn't called yet because baseRender is false
  59. // instead it is called here
  60. this.render();
  61. options.label && this.setLabel(options.label);
  62. options.shadow && this.addShadow(options.shadow);
  63. }
  64. },
  65. {
  66. draws:true,
  67. type:"dojox.drawing.tools.custom.Axes",
  68. minimumSize:30,
  69. showAngle:true,
  70. closePath:false,
  71. baseRender:false,
  72. zScale:.5,
  73. zPoint: function(obj){
  74. // summary:
  75. // Finds the point for the z axis.
  76. obj.radius = this.util.length(obj);
  77. var pt = this.util.pointOnCircle(obj.start.x, obj.start.y, obj.radius*this.zScale, this.style.zAngle);
  78. return {x:pt.x, y:pt.y, skip:true, noAnchor:true};
  79. },
  80. zSet: function(){
  81. if(!this.zAxis){ return; };
  82. var c = this.points[1];
  83. var z = this.points[3];
  84. var p = [
  85. {x:c.x, y:c.y},
  86. {x:z.x, y:z.y}
  87. ];
  88. var len = this.util.length({start:{x:c.x, y:c.y}, x:z.x, y:z.y});
  89. len > this.zAxis.minimumSize ? this.zAxis.setPoints(p) : false;
  90. this.zAxis.cosphi = 1;
  91. },
  92. createLabels: function(){
  93. // summary:
  94. // Creates the label for each axis.
  95. //
  96. // NOTE: Not passing style into text because it's changing it
  97. var props = {align:"middle", valign:"middle", util:this.util, annotation:true, container:this.container, mouse:this.mouse, stencil:this};
  98. this.labelX = new dojox.drawing.annotations.Label(dojo.mixin(props,{
  99. labelPosition:this.setLabelX
  100. }));
  101. this.labelY = new dojox.drawing.annotations.Label(dojo.mixin(props,{
  102. labelPosition:this.setLabelY
  103. }));
  104. if(this.style.zAxisEnabled){
  105. this.labelZ = new dojox.drawing.annotations.Label(dojo.mixin(props,{
  106. labelPosition:this.setLabelZ
  107. }));
  108. }
  109. },
  110. setLabelX: function(){
  111. // summary:
  112. // Custom placement for x-axis label
  113. //
  114. var ax = this.points[0];
  115. var c = this.points[1];
  116. var dist = 40;
  117. var offdist = 20;
  118. var pt, px, py, pt2;
  119. pt = this.util.lineSub(c.x, c.y, ax.x, ax.y, dist);
  120. px = pt.x + (pt.y -ax.y);
  121. py = pt.y + (ax.x - pt.x);
  122. pt2 = this.util.lineSub(pt.x, pt.y, px, py, (dist-offdist));
  123. return {
  124. x: pt2.x,
  125. y: pt2.y,
  126. width:20
  127. };
  128. },
  129. setLabelY: function(){
  130. // summary:
  131. // Custom placement for y-axis label
  132. //
  133. var c = this.points[1];
  134. var ay = this.points[2];
  135. var dist = 40;
  136. var offdist = 20;
  137. var pt, px, py, pt2;
  138. pt = this.util.lineSub(c.x, c.y, ay.x, ay.y, dist);
  139. px = pt.x + (ay.y - pt.y);
  140. py = pt.y + (pt.x - ay.x);
  141. pt2 = this.util.lineSub(pt.x, pt.y, px, py, (dist-offdist));
  142. return {
  143. x: pt2.x,
  144. y: pt2.y,
  145. width:20
  146. };
  147. },
  148. setLabelZ: function(){
  149. // summary:
  150. // Custom placement for z-axis label
  151. //
  152. var c = this.points[1];
  153. var z = this.points[3];
  154. var dist = 40;
  155. var offdist = 20;
  156. var pt, px, py, pt2;
  157. pt = this.util.lineSub(c.x, c.y, z.x, z.y, dist);
  158. px = pt.x + (pt.y - z.y);
  159. py = pt.y + (z.x - pt.x);
  160. pt2 = this.util.lineSub(pt.x, pt.y, px, py, (dist-offdist));
  161. return {
  162. x:pt2.x,
  163. y:pt2.y,
  164. width:20
  165. }
  166. },
  167. setLabel: function(/* ? String*/value){
  168. // summary:
  169. // Set the text of the labels. The text would be
  170. // broken up into the two labels.
  171. // arguments:
  172. // value: [optional] String
  173. // If no argument is passed, defaults to two labels
  174. // 'x' and 'y'. If an argument is passed, that
  175. // text will be split on the word 'and' to determine
  176. // the two labels.
  177. //
  178. if(this._labelsCreated){ return; }
  179. !this.labelX && this.createLabels();
  180. var x = "x";
  181. var y = "y";
  182. var z = "z";
  183. if(value){
  184. // match first "and" or "&" and trim whitespace.
  185. // Non-greedy matches are not supported in older
  186. // browsers such as Netscape Navigator 4 or
  187. // Microsoft Internet Explorer 5.0.
  188. if(this.labelZ){
  189. var lbls = value.match(/(.*?)(and|&)(.*?)(and|&)(.*)/i);
  190. if(lbls.length>4){
  191. x = lbls[1].replace(/^\s+/,"").replace(/\s+$/,"");
  192. y = lbls[3].replace(/^\s+/,"").replace(/\s+$/,"");
  193. z = lbls[5].replace(/^\s+/,"").replace(/\s+$/,"");
  194. }
  195. }else{
  196. var lbls = value.match(/(.*?)(and|&)(.*)/i);
  197. if(lbls.length>2){
  198. x = lbls[1].replace(/^\s+/,"").replace(/\s+$/,"");
  199. y = lbls[3].replace(/^\s+/,"").replace(/\s+$/,"");
  200. }
  201. }
  202. }
  203. this.labelX.setLabel(x);
  204. this.labelY.setLabel(y);
  205. if(this.labelZ){
  206. this.labelZ.setLabel(z);
  207. }
  208. this._labelsCreated = true;
  209. },
  210. getLabel: function(){
  211. // summary:
  212. // Getter for the labels. returns an object.
  213. //
  214. if(!this.labelX){ return null; }
  215. return {
  216. x:this.labelX.getText(),
  217. y:this.labelY.getText(),
  218. z:this.labelZ?this.labelZ.getText():null
  219. }; // Object
  220. },
  221. anchorPositionCheck: function(/*Number*/x, /*Number*/y, /*manager.Anchor*/anchor){
  222. // summary:
  223. // Gets called from anchor to check if its current
  224. // position is ok. If not, its x or y transform will
  225. // be changed until this passes.
  226. //
  227. var pm = this.container.getParent().getTransform();
  228. var am = anchor.shape.getTransform();
  229. // the xaxis point has changed and is not yet set as a point
  230. // - but the center should be good (except for the transform).
  231. // Now check the yaxis point.
  232. var p = this.points;
  233. var o = {x:am.dx+anchor.org.x+pm.dx, y:am.dy+anchor.org.y+pm.dy};
  234. var c = {x:p[1].x+pm.dx, y:p[1].y+pm.dy};
  235. var ox = c.x - (c.y - o.y);
  236. var oy = c.y - (o.x - c.x);
  237. return {x:ox, y:oy};
  238. },
  239. onTransformBegin: function(/*manager.Anchor*/anchor){
  240. // summary:
  241. // Overwrites _Base.onTransformBegin
  242. //
  243. // called from anchor point up mouse down
  244. this._isBeingModified = true;
  245. },
  246. onTransformEnd: function(/*manager.Anchor*/anchor){
  247. // summary:
  248. // Overwrites _Base.onTransformEnd
  249. //
  250. // Gets called on anchor mouseup
  251. // also gets called by checkBounds - we don't want that.
  252. if(!anchor){ return; }
  253. // tell anchor to go to prev point if wrong
  254. // called from anchor point up mouse up
  255. this._isBeingModified = false;
  256. //this.deselect();
  257. this._toggleSelected();
  258. console.log("before:", Math.ceil(this.points[1].x), " x ", Math.ceil(this.points[1].y))
  259. var o = this.points[0];
  260. var c = this.points[1];
  261. var obj = {start:{x:c.x,y:c.y},x:o.x, y:o.y};
  262. var pt = this.util.constrainAngle(obj, 0, 89);
  263. var zpt = this.style.zAxisEnabled ? this.zPoint(obj) : null;
  264. if(pt.x==o.x && pt.y == o.y){
  265. // we're within the constraint, so now we snap
  266. pt = this.util.snapAngle(obj, this.angleSnap/180);
  267. obj.x = pt.x;
  268. obj.y = pt.y;
  269. var ox = obj.start.x - (obj.start.y - obj.y);
  270. var oy = obj.start.y - (obj.x - obj.start.x);
  271. if(ox<0 || oy<0){
  272. console.warn("AXES ERROR LESS THAN ZERO - ABORT");
  273. return;
  274. }
  275. this.points = [{x:obj.x, y:obj.y}, {x:obj.start.x, y:obj.start.y, noAnchor:true}];
  276. this.points.push({x:ox, y:oy, noAnchor:true});
  277. if(zpt){ this.points.push(zpt);}
  278. this.setPoints(this.points);
  279. //this.select();
  280. this.onModify(this);
  281. return;
  282. }
  283. // we're outside of the constraint. Set to the low or high.
  284. this.points[0].x = pt.x
  285. this.points[0].y = pt.y;
  286. o = this.points[0];
  287. var ox = c.x - (c.y - o.y);
  288. var oy = c.y - (o.x - c.x);
  289. this.points[2] = {x:ox, y:oy, noAnchor:true};
  290. if(zpt){ this.points.push(zpt); }
  291. this.setPoints(this.points);
  292. // reset handles render
  293. //anchor.reset(this);
  294. this.labelX.setLabel();
  295. this.labelY.setLabel();
  296. if(this.labelZ){
  297. this.labelZ.setLabel();
  298. }
  299. //this.select();
  300. this.onModify(this);
  301. },
  302. getBounds: function(/*Boolean*/absolute){
  303. // summary:
  304. // Custom getBounds overwrites _Base.getBounds
  305. //
  306. var px = this.points[0],
  307. pc = this.points[1],
  308. py = this.points[2];
  309. if(this.style.zAxisEnabled){ var pz = this.points[3]; }
  310. if(absolute){
  311. var bounds = {
  312. x:pc.x,
  313. y:pc.y,
  314. x1:pc.x,
  315. y1:pc.y,
  316. x2:px.x,
  317. y2:px.y,
  318. x3:py.x,
  319. y3:py.y
  320. };
  321. if(this.style.zAxisEnabled){
  322. bounds.x4 = pz.x;
  323. bounds.y4 = pz.y;
  324. }
  325. return bounds;
  326. }
  327. var x1 = this.style.zAxisEnabled ? (py.x < pz.x ? py.x : pz.x) : py.x;
  328. y1 = py.y < px.y ? py.y : px.y,
  329. x2 = px.x,
  330. y2 = this.style.zAxisEnabled ? pz.y : pc.y;
  331. return {
  332. x1:x1,
  333. y1:y1,
  334. x2:x2,
  335. y2:y2,
  336. x:x1,
  337. y:y1,
  338. w:x2-x1,
  339. h:y2-y1
  340. };
  341. },
  342. _postSetPoints: function(/*Array*/pts){
  343. // summary:
  344. // Because Axes only has one anchor,
  345. // we substitute a special setPoints method
  346. //
  347. this.points[0] = pts[0];
  348. if(this.pointsToData){
  349. this.data = this.pointsToData();
  350. }
  351. },
  352. onTransform: function(/*Number*/anchor){
  353. // summary:
  354. // Overwrites _Base.onTransform
  355. //
  356. // the xaxis point has changed - the center will not.
  357. // need to find the yaxis point.
  358. var o = this.points[0];
  359. var c = this.points[1];
  360. var ox = c.x - (c.y - o.y);
  361. var oy = c.y - (o.x - c.x);
  362. // 'noAnchor' on a point indicates an anchor should
  363. // not be rendered. This is the Y point being set.
  364. this.points[2] = {x:ox, y:oy, noAnchor:true};
  365. if(this.style.zAxisEnabled){
  366. this.points[3] = this.zPoint({start:{x:c.x, y:c.y}, x:o.x, y:o.y});
  367. }
  368. this.setPoints(this.points);
  369. if(!this._isBeingModified){
  370. this.onTransformBegin();
  371. }
  372. this.render();
  373. },
  374. pointsToData: function(){
  375. //summary:
  376. // Converts points to data.
  377. var p = this.points;
  378. var d = {
  379. x1:p[1].x,
  380. y1:p[1].y,
  381. x2:p[0].x,
  382. y2:p[0].y,
  383. x3:p[2].x,
  384. y3:p[2].y
  385. }
  386. if(this.style.zAxisEnabled){
  387. d.x4 = p[3].x;
  388. d.y4 = p[3].y;
  389. d.cosphi = 1;
  390. }
  391. return d;
  392. },
  393. getRadius: function(){
  394. //summary:
  395. // Possibility of z-axis makes bounds unreliable.
  396. // Use these points instead.
  397. var p = this.points;
  398. var line = {start:{x:p[1].x, y:p[1].y}, x:p[0].x, y:p[0].y};
  399. return this.util.length(line);
  400. },
  401. dataToPoints: function(/* ? Object*/o){
  402. //summary:
  403. // Converts data to points.
  404. o = o || this.data;
  405. if(o.radius || o.angle){
  406. // instead of using x1,x2,y1,y1,
  407. // it's been set as x,y,angle,radius
  408. var pt = this.util.pointOnCircle(o.x,o.y,o.radius,o.angle), zpt;
  409. var ox = o.x - (o.y - pt.y);
  410. var oy = o.y - (pt.x - o.x);
  411. if((o.cosphi && o.cosphi==1) || this.style.zAxisEnabled){
  412. this.style.zAxisEnabled = true;
  413. zpt = this.util.pointOnCircle(o.x, o.y, o.radius*this.zScale, this.style.zAngle);
  414. }
  415. this.data = o = {
  416. x1:o.x,
  417. y1:o.y,
  418. x2:pt.x,
  419. y2:pt.y,
  420. x3:ox,
  421. y3:oy
  422. }
  423. if(this.style.zAxisEnabled){
  424. this.data.x4 = o.x4 = zpt.x;
  425. this.data.y4 = o.y4 = zpt.y;
  426. this.data.cosphi = 1;
  427. }
  428. }
  429. this.points = [
  430. {x:o.x2, y:o.y2},
  431. {x:o.x1, y:o.y1, noAnchor:true},
  432. {x:o.x3, y:o.y3, noAnchor:true}
  433. ];
  434. if(this.style.zAxisEnabled){ this.points.push({x:o.x4, y:o.y4, skip:true, noAnchor:true}); }
  435. return this.points;
  436. },
  437. onDrag: function(/*EventObject*/obj){
  438. // summary: See stencil._Base.onDrag
  439. //
  440. var pt = this.util.constrainAngle(obj, 0, 89);
  441. obj.x = pt.x;
  442. obj.y = pt.y;
  443. var ox = obj.start.x - (obj.start.y - obj.y);
  444. var oy = obj.start.y - (obj.x - obj.start.x);
  445. if(ox<0 || oy<0){
  446. return;
  447. }
  448. this.points = [{x:obj.x, y:obj.y}, {x:obj.start.x, y:obj.start.y, noAnchor:true}];
  449. this.points.push({x:ox, y:oy, noAnchor:true});
  450. if(this.style.zAxisEnabled){
  451. var zpt = this.zPoint(obj);
  452. this.points.push(zpt);
  453. }
  454. this.render();
  455. },
  456. onUp: function(/*EventObject*/obj){
  457. // summary: See stencil._Base.onUp
  458. //
  459. if(!this._downOnCanvas){ return; }
  460. this._downOnCanvas = false;
  461. var p = this.points;
  462. if(!p.length){
  463. var s = obj.start, d = 100;
  464. this.points = [
  465. {x:s.x+d, y:s.y+d},
  466. {x:s.x, y:s.y+d, noAnchor:true},
  467. {x:s.x, y:s.y, noAnchor:true}
  468. ];
  469. if(this.style.zAxisEnabled){
  470. var zpt = this.zPoint({start:{x:s.x, y:s.y+d}, x:s.x+d, y:s.y+d});
  471. this.points.push(zpt);
  472. }
  473. this.setPoints = this._postSetPoints;
  474. this.pointsToData();
  475. this.render();
  476. this.onRender(this);
  477. return;
  478. }
  479. var len = this.util.distance(p[1].x ,p[1].y ,p[0].x ,p[0].y );
  480. if(!p || !p.length){
  481. return;
  482. }else if(len < this.minimumSize){
  483. this.remove(this.shape, this.hit);
  484. this.xArrow.remove(this.xArrow.shape, this.xArrow.hit);
  485. this.yArrow.remove(this.yArrow.shape, this.yArrow.hit);
  486. if(this.zArrow){
  487. this.zArrow.remove(this.zArrow.shape, this.zArrow.hit);
  488. }
  489. return;
  490. }
  491. var o = p[0];
  492. var c = p[1];
  493. obj = {start:{x:c.x,y:c.y},x:o.x,y:o.y};
  494. var pt = this.util.snapAngle(obj, this.angleSnap/180);
  495. obj.x = pt.x;
  496. obj.y = pt.y;
  497. var ox = obj.start.x - (obj.start.y - obj.y);
  498. var oy = obj.start.y - (obj.x - obj.start.x);
  499. if(ox<0 || oy<0){
  500. return;
  501. }
  502. this.points = [{x:obj.x, y:obj.y}, {x:obj.start.x, y:obj.start.y, noAnchor:true}];
  503. this.points.push({x:ox, y:oy, noAnchor:true});
  504. if(this.style.zAxisEnabled){ this.points.push(this.zPoint(obj)); }
  505. this.onRender(this);
  506. this.setPoints = this._postSetPoints;
  507. }
  508. }
  509. );
  510. dojox.drawing.tools.custom.Axes.setup = {
  511. // summary: See stencil._Base ToolsSetup
  512. //
  513. name:"dojox.drawing.tools.custom.Axes",
  514. tooltip:"Axes Tool",
  515. iconClass:"iconAxes"
  516. };
  517. dojox.drawing.register(dojox.drawing.tools.custom.Axes.setup, "tool");
  518. });