Pan.js 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  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.plugins.tools.Pan"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  7. dojo._hasResource["dojox.drawing.plugins.tools.Pan"] = true;
  8. dojo.provide("dojox.drawing.plugins.tools.Pan");
  9. dojo.require("dojox.drawing.plugins._Plugin");
  10. dojox.drawing.plugins.tools.Pan = dojox.drawing.util.oo.declare(
  11. // summary:
  12. // A plugin that allows for a scrolling canvas. An action
  13. // tool is added to the toolbar that allows for panning. Holding
  14. // the space bar is a shortcut to that action. The canvas will
  15. // only pan and scroll if there are objects out of the viewable
  16. // area.
  17. // example:
  18. // | <div dojoType="dojox.drawing.Toolbar" drawingId="drawingNode" class="drawingToolbar vertical">
  19. // | <div tool="dojox.drawing.tools.Line" selected="true">Line</div>
  20. // | <div plugin="dojox.drawing.plugins.tools.Pan" options="{}">Pan</div>
  21. // | </div>
  22. //
  23. dojox.drawing.plugins._Plugin,
  24. function(options){
  25. this.domNode = options.node;
  26. var _scrollTimeout;
  27. this.toolbar = options.scope;
  28. this.connect(this.toolbar, "onToolClick", this, function(){
  29. this.onSetPan(false)
  30. });
  31. this.connect(this.keys, "onKeyUp", this, "onKeyUp");
  32. this.connect(this.keys, "onKeyDown", this, "onKeyDown");
  33. this.connect(this.keys, "onArrow", this, "onArrow");
  34. this.connect(this.anchors, "onAnchorUp", this, "checkBounds");
  35. this.connect(this.stencils, "register", this, "checkBounds");
  36. this.connect(this.canvas, "resize", this, "checkBounds");
  37. this.connect(this.canvas, "setZoom", this, "checkBounds");
  38. this.connect(this.canvas, "onScroll", this, function(){
  39. if(this._blockScroll){
  40. this._blockScroll = false;
  41. return;
  42. }
  43. _scrollTimeout && clearTimeout(_scrollTimeout);
  44. _scrollTimeout = setTimeout(dojo.hitch(this, "checkBounds"), 200);
  45. });
  46. this._mouseHandle = this.mouse.register(this);
  47. // This HAS to be called after setting initial objects or things get screwy.
  48. //this.checkBounds();
  49. },{
  50. selected:false,
  51. keyScroll:false,
  52. type:"dojox.drawing.plugins.tools.Pan",
  53. onPanUp: function(obj){
  54. if(obj.id == this.button.id){
  55. this.onSetPan(false);
  56. }
  57. },
  58. onKeyUp: function(evt){
  59. switch(evt.keyCode){
  60. case 32:
  61. this.onSetPan(false);
  62. break;
  63. case 39: case 37: case 38: case 40:
  64. clearInterval(this._timer);
  65. break;
  66. }
  67. },
  68. onKeyDown: function(evt){
  69. if(evt.keyCode == 32){
  70. this.onSetPan(true);
  71. }
  72. },
  73. interval: 20,
  74. onArrow: function(evt){
  75. if(this._timer){ clearInterval(this._timer); }
  76. this._timer = setInterval(dojo.hitch(this,function(evt){
  77. this.canvas.domNode.parentNode.scrollLeft += evt.x*10;
  78. this.canvas.domNode.parentNode.scrollTop += evt.y*10;
  79. },evt), this.interval);
  80. },
  81. onSetPan: function(/*Boolean | Event*/ bool){
  82. if(bool === true || bool === false){
  83. this.selected = !bool;
  84. }
  85. console.log('ON SET PAN:', this.selected)
  86. if(this.selected){
  87. this.selected = false;
  88. this.button.deselect();
  89. }else{
  90. this.selected = true;
  91. this.button.select();
  92. }
  93. this.mouse.setEventMode(this.selected ? "pan" : "");
  94. },
  95. onPanDrag: function(obj){
  96. var x = obj.x - obj.last.x;
  97. var y = obj.y - obj.last.y;
  98. this.canvas.domNode.parentNode.scrollTop -= obj.move.y;
  99. this.canvas.domNode.parentNode.scrollLeft -= obj.move.x;
  100. this.canvas.onScroll();
  101. },
  102. onUp: function(obj){
  103. if(obj.withinCanvas){
  104. this.keyScroll = true;
  105. }else{
  106. this.keyScroll = false;
  107. }
  108. },
  109. onStencilUp: function(obj){
  110. // this gets called even on click-off because of the
  111. // issues with TextBlock deselection
  112. this.checkBounds();
  113. },
  114. onStencilDrag: function(obj){
  115. // this gets called even on click-off because of the
  116. // issues with TextBlock deselection
  117. //this.checkBounds();
  118. },
  119. checkBounds: function(){
  120. //watch("CHECK BOUNDS DISABLED", true); return;
  121. // summary:
  122. // Scans all items on the canvas and checks if they are out of
  123. // bounds. If so, a scroll bar (in Canvas) is shown. If the position
  124. // is left or top, the canvas is scrolled all items are relocated
  125. // the distance of the scroll. Ideally, it should look as if the
  126. // items do not move.
  127. // logging stuff here so it can be turned on and off. This method is
  128. // very high maintenance.
  129. var log = function(){
  130. //console.log.apply(console, arguments);
  131. }
  132. var warn = function(){
  133. //console.warn.apply(console, arguments);
  134. }
  135. //console.clear();
  136. //console.time("check bounds");
  137. // initialize a shot-tin of vars
  138. var t=Infinity, r=-Infinity, b=-10000, l=10000,
  139. sx=0, sy=0, dy=0, dx=0,
  140. mx = this.stencils.group ? this.stencils.group.getTransform() : {dx:0, dy:0},
  141. sc = this.mouse.scrollOffset(),
  142. // scY, scX: the scrollbar creates the need for extra dimension
  143. scY = sc.left ? 10 : 0,
  144. scX = sc.top ? 10 : 0,
  145. // ch, cw: the current size of the canvas
  146. ch = this.canvas.height,
  147. cw = this.canvas.width,
  148. z = this.canvas.zoom,
  149. // pch, pcw: the normal size of the canvas (not scrolled)
  150. // these could change if the container resizes.
  151. pch = this.canvas.parentHeight,
  152. pcw = this.canvas.parentWidth;
  153. this.stencils.withSelected(function(m){
  154. var o = m.getBounds();
  155. warn("SEL BOUNDS:", o);
  156. t = Math.min(o.y1 + mx.dy, t);
  157. r = Math.max(o.x2 + mx.dx, r);
  158. b = Math.max(o.y2 + mx.dy, b);
  159. l = Math.min(o.x1 + mx.dx, l);
  160. });
  161. this.stencils.withUnselected(function(m){
  162. var o = m.getBounds();
  163. warn("UN BOUNDS:", o);
  164. t = Math.min(o.y1, t);
  165. r = Math.max(o.x2, r);
  166. b = Math.max(o.y2, b);
  167. l = Math.min(o.x1, l);
  168. log("----------- B:", b, o.y2)
  169. });
  170. b *= z;
  171. var xscroll = 0, yscroll = 0;
  172. log("Bottom test", "b:", b, "z:", z, "ch:", ch, "pch:", pch, "top:", sc.top, "sy:", sy, "mx.dy:", mx.dy);
  173. if(b > pch || sc.top ){
  174. log("*bottom scroll*");
  175. // item off bottom
  176. ch = Math.max(b, pch + sc.top);
  177. sy = sc.top;
  178. xscroll += this.canvas.getScrollWidth();
  179. }else if(!sy && ch>pch){
  180. log("*bottom remove*");
  181. // item moved from bottom
  182. ch = pch;
  183. }
  184. r *= z;
  185. if(r > pcw || sc.left){
  186. //log("*right scroll*");
  187. // item off right
  188. cw = Math.max(r, pcw + sc.left);
  189. sx = sc.left;
  190. yscroll += this.canvas.getScrollWidth();
  191. }else if(!sx && cw>pcw){
  192. //log("*right remove*");
  193. // item moved from right
  194. cw = pcw;
  195. }
  196. // add extra space for scrollbars
  197. // double it to give some breathing room
  198. cw += xscroll*2;
  199. ch += yscroll*2;
  200. this._blockScroll = true;
  201. // selected items are not transformed. The selection itself is
  202. // and the items are on de-select
  203. this.stencils.group && this.stencils.group.applyTransform({dx:dx, dy:dy});
  204. // non-selected items are transformed
  205. this.stencils.withUnselected(function(m){
  206. m.transformPoints({dx:dx, dy:dy});
  207. });
  208. this.canvas.setDimensions(cw, ch, sx, sy);
  209. //console.timeEnd("check bounds");
  210. }
  211. }
  212. );
  213. dojox.drawing.plugins.tools.Pan.setup = {
  214. name:"dojox.drawing.plugins.tools.Pan",
  215. tooltip:"Pan Tool",
  216. iconClass:"iconPan",
  217. button:false
  218. };
  219. dojox.drawing.register(dojox.drawing.plugins.tools.Pan.setup, "plugin");
  220. }