MouseZoomAndPan.js 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. define("dojox/charting/action2d/MouseZoomAndPan", ["dojo/_base/html", "dojo/_base/declare", "dojo/_base/window", "dojo/_base/array", "dojo/_base/event",
  2. "dojo/_base/connect", "./ChartAction", "dojo/_base/sniff", "dojo/dom-prop", "dojo/keys"],
  3. function(html, declare, win, arr, eventUtil, connect, ChartAction, has, domProp, keys){
  4. /*=====
  5. dojo.declare("dojox.charting.action2d.__MouseZoomAndPanCtorArgs", null, {
  6. // summary:
  7. // Additional arguments for mouse zoom and pan actions.
  8. // axis: String?
  9. // Target axis name for this action. Default is "x".
  10. axis: "x",
  11. // scaleFactor: Number?
  12. // The scale factor applied on mouse wheel zoom. Default is 1.2.
  13. scaleFactor: 1.2,
  14. // maxScale: Number?
  15. // The max scale factor accepted by this chart action. Default is 100.
  16. maxScale: 100,
  17. // enableScroll: Boolean?
  18. // Whether mouse drag gesture should scroll the chart. Default is true.
  19. enableScroll: true,
  20. // enableDoubleClickZoom: Boolean?
  21. // Whether a double click gesture should toggle between fit and zoom on the chart. Default is true.
  22. enableDoubleClickZoom: true,
  23. // enableKeyZoom: Boolean?
  24. // Whether a keyZoomModifier + + or keyZoomModifier + - key press should zoom in our out on the chart. Default is true.
  25. enableKeyZoom: true,
  26. // keyZoomModifier: String?
  27. // Which keyboard modifier should used for keyboard zoom in and out. This should be one of "alt", "ctrl", "shift" or "none" for no modifier. Default is "ctrl".
  28. keyZoomModifier: "ctrl"
  29. });
  30. var ChartAction = dojox.charting.action2d.ChartAction;
  31. =====*/
  32. var sUnit = has("mozilla") ? -3 : 120;
  33. var keyTests = {
  34. none: function(event){
  35. return !event.ctrlKey && !event.altKey && !event.shiftKey;
  36. },
  37. ctrl: function(event){
  38. return event.ctrlKey && !event.altKey && !event.shiftKey;
  39. },
  40. alt: function(event){
  41. return !event.ctrlKey && event.altKey && !event.shiftKey;
  42. },
  43. shift: function(event){
  44. return !event.ctrlKey && !event.altKey && event.shiftKey;
  45. }
  46. };
  47. return declare("dojox.charting.action2d.MouseZoomAndPan", ChartAction, {
  48. // summary:
  49. // Create an mouse zoom and pan action.
  50. // You can zoom in or out the data window with mouse wheel. You can scroll using mouse drag gesture.
  51. // You can toggle between zoom and fit view using double click on the chart.
  52. // the data description block for the widget parser
  53. defaultParams: {
  54. axis: "x",
  55. scaleFactor: 1.2,
  56. maxScale: 100,
  57. enableScroll: true,
  58. enableDoubleClickZoom: true,
  59. enableKeyZoom: true,
  60. keyZoomModifier: "ctrl"
  61. },
  62. optionalParams: {}, // no optional parameters
  63. constructor: function(chart, plot, kwArgs){
  64. // summary:
  65. // Create an mouse zoom and pan action and connect it.
  66. // chart: dojox.charting.Chart
  67. // The chart this action applies to.
  68. // kwArgs: dojox.charting.action2d.__MouseZoomAndPanCtorArgs?
  69. // Optional arguments for the chart action.
  70. this._listeners = [{eventName: !has("mozilla") ? "onmousewheel" : "DOMMouseScroll", methodName: "onMouseWheel"}];
  71. if(!kwArgs){ kwArgs = {}; }
  72. this.axis = kwArgs.axis ? kwArgs.axis : "x";
  73. this.scaleFactor = kwArgs.scaleFactor ? kwArgs.scaleFactor : 1.2;
  74. this.maxScale = kwArgs.maxScale ? kwArgs.maxScale : 100;
  75. this.enableScroll = kwArgs.enableScroll != undefined ? kwArgs.enableScroll : true;
  76. this.enableDoubleClickZoom = kwArgs.enableDoubleClickZoom != undefined ? kwArgs.enableDoubleClickZoom : true;
  77. this.enableKeyZoom = kwArgs.enableKeyZoom != undefined ? kwArgs.enableKeyZoom : true;
  78. this.keyZoomModifier = kwArgs.keyZoomModifier ? kwArgs.keyZoomModifier : "ctrl";
  79. if(this.enableScroll){
  80. this._listeners.push({eventName: "onmousedown", methodName: "onMouseDown"});
  81. }
  82. if(this.enableDoubleClickZoom){
  83. this._listeners.push({eventName: "ondblclick", methodName: "onDoubleClick"});
  84. }
  85. if(this.enableKeyZoom){
  86. this._listeners.push({eventName: "keypress", methodName: "onKeyPress"});
  87. }
  88. this._handles = [];
  89. this.connect();
  90. },
  91. _disconnectHandles: function(){
  92. if(has("ie")){
  93. this.chart.node.releaseCapture();
  94. }
  95. arr.forEach(this._handles, connect.disconnect);
  96. this._handles = [];
  97. },
  98. connect: function(){
  99. // summary:
  100. // Connect this action to the chart.
  101. this.inherited(arguments);
  102. if(this.enableKeyZoom){
  103. // we want to be able to get focus to receive key events
  104. domProp.set(this.chart.node, "tabindex", "0");
  105. // if one doesn't want a focus border he can do something like
  106. // dojo.style(this.chart.node, "outline", "none");
  107. }
  108. },
  109. disconnect: function(){
  110. // summary:
  111. // Disconnect this action from the chart.
  112. this.inherited(arguments);
  113. if(this.enableKeyZoom){
  114. // we don't need anymore to be able to get focus to receive key events
  115. domProp.set(this.chart.node, "tabindex", "-1");
  116. }
  117. // in case we disconnect before the end of the action
  118. this._disconnectHandles();
  119. },
  120. onMouseDown: function(event){
  121. // summary:
  122. // Called when mouse is down on the chart.
  123. var chart = this.chart, axis = chart.getAxis(this.axis);
  124. if(!axis.vertical){
  125. this._startCoord = event.pageX;
  126. }else{
  127. this._startCoord = event.pageY;
  128. }
  129. this._startOffset = axis.getWindowOffset();
  130. this._isPanning = true;
  131. // we now want to capture mouse move events everywhere to avoid
  132. // stop scrolling when going out of the chart window
  133. if(has("ie")){
  134. this._handles.push(connect.connect(this.chart.node, "onmousemove", this, "onMouseMove"));
  135. this._handles.push(connect.connect(this.chart.node, "onmouseup", this, "onMouseUp"));
  136. this.chart.node.setCapture();
  137. }else{
  138. this._handles.push(connect.connect(win.doc, "onmousemove", this, "onMouseMove"));
  139. this._handles.push(connect.connect(win.doc, "onmouseup", this, "onMouseUp"));
  140. }
  141. chart.node.focus();
  142. // prevent the browser from trying the drag on the "image"
  143. eventUtil.stop(event);
  144. },
  145. onMouseMove: function(event){
  146. // summary:
  147. // Called when mouse is moved on the chart.
  148. if(this._isPanning){
  149. var chart = this.chart, axis = chart.getAxis(this.axis);
  150. var delta = axis.vertical?(this._startCoord- event.pageY):(event.pageX - this._startCoord);
  151. var bounds = axis.getScaler().bounds,
  152. s = bounds.span / (bounds.upper - bounds.lower);
  153. var scale = axis.getWindowScale();
  154. chart.setAxisWindow(this.axis, scale, this._startOffset - delta / s / scale);
  155. chart.render();
  156. }
  157. },
  158. onMouseUp: function(event){
  159. // summary:
  160. // Called when mouse is up on the chart.
  161. this._isPanning = false;
  162. this._disconnectHandles();
  163. },
  164. onMouseWheel: function(event){
  165. // summary:
  166. // Called when mouse wheel is used on the chart.
  167. var scroll = event[(has("mozilla") ? "detail" : "wheelDelta")] / sUnit;
  168. // on Mozilla the sUnit might actually not always be 3
  169. // make sure we never have -1 < scroll < 1
  170. if(scroll > -1 && scroll < 0){
  171. scroll = -1;
  172. }else if(scroll > 0 && scroll < 1){
  173. scroll = 1;
  174. }
  175. this._onZoom(scroll, event);
  176. },
  177. onKeyPress: function(event){
  178. // summary:
  179. // Called when a key is pressed on the chart.
  180. if(keyTests[this.keyZoomModifier](event)){
  181. if(event.keyChar == "+" || event.keyCode == keys.NUMPAD_PLUS){
  182. this._onZoom(1, event);
  183. }else if(event.keyChar == "-" || event.keyCode == keys.NUMPAD_MINUS){
  184. this._onZoom(-1, event);
  185. }
  186. }
  187. },
  188. onDoubleClick: function(event){
  189. // summary:
  190. // Called when the mouse is double is double clicked on the chart. Toggle between zoom and fit chart.
  191. var chart = this.chart, axis = chart.getAxis(this.axis);
  192. var scale = 1 / this.scaleFactor;
  193. // are we fit?
  194. if(axis.getWindowScale()==1){
  195. // fit => zoom
  196. var scaler = axis.getScaler(), start = scaler.bounds.from, end = scaler.bounds.to,
  197. oldMiddle = (start + end) / 2, newMiddle = this.plot.toData({x: event.pageX, y: event.pageY})[this.axis],
  198. newStart = scale * (start - oldMiddle) + newMiddle, newEnd = scale * (end - oldMiddle) + newMiddle;
  199. chart.zoomIn(this.axis, [newStart, newEnd]);
  200. }else{
  201. // non fit => fit
  202. chart.setAxisWindow(this.axis, 1, 0);
  203. chart.render();
  204. }
  205. eventUtil.stop(event);
  206. },
  207. _onZoom: function(scroll, event){
  208. var scale = (scroll < 0 ? Math.abs(scroll)*this.scaleFactor :
  209. 1 / (Math.abs(scroll)*this.scaleFactor));
  210. var chart = this.chart, axis = chart.getAxis(this.axis);
  211. // after wheel reset event position exactly if we could start a new scroll action
  212. var cscale = axis.getWindowScale();
  213. if(cscale / scale > this.maxScale){
  214. return;
  215. }
  216. var scaler = axis.getScaler(), start = scaler.bounds.from, end = scaler.bounds.to;
  217. // keep mouse pointer as transformation center if available otherwise center
  218. var middle = (event.type == "keypress") ? (start + end) / 2 :
  219. this.plot.toData({x: event.pageX, y: event.pageY})[this.axis];
  220. var newStart = scale * (start - middle) + middle, newEnd = scale * (end - middle) + middle;
  221. chart.zoomIn(this.axis, [newStart, newEnd]);
  222. // do not scroll browser
  223. eventUtil.stop(event);
  224. }
  225. });
  226. });