Pan.js 6.6 KB

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