Mouse.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518
  1. // wrapped by build app
  2. define("dojox/drawing/manager/Mouse", ["dijit","dojo","dojox"], function(dijit,dojo,dojox){
  3. dojo.provide("dojox.drawing.manager.Mouse");
  4. dojox.drawing.manager.Mouse = dojox.drawing.util.oo.declare(
  5. // summary:
  6. // Master object (instance) that tracks mouse
  7. // events. A new instance is created for each
  8. // Drawing object.
  9. // description:
  10. // You could connect to any method or event in this
  11. // class, but it is designed to have the object
  12. // 'registered'. All objects with the current event
  13. // will be called directly.
  14. //
  15. // Custom events are used often. In addition to
  16. // standard events onDown, onUp, onDrag, etc, if
  17. // a certain object is clicked upon (or dragged, etc),
  18. // that object's drawingType will create the custom event,
  19. // such as onAnchorDown, or onStencilDown.
  20. //
  21. function(/* Object */options){
  22. this.util = options.util;
  23. this.keys = options.keys;
  24. this.id = options.id || this.util.uid("mouse");
  25. this.currentNodeId = "";
  26. this.registered = {};
  27. },
  28. {
  29. // doublClickSpeed: Number
  30. // Milliseconds between clicks to
  31. // register as for onDoubleClick
  32. doublClickSpeed:400,
  33. // private properties
  34. _lastx:0,
  35. _lasty:0,
  36. __reg:0,
  37. _downOnCanvas:false,
  38. /*=====
  39. CustomEventMethod: function(){
  40. // summary:
  41. // The custom event method that an Object that has
  42. // registered with manager.Mouse can receive.
  43. // Can contain any or all of the following methods
  44. // and they will be called as mouse events. All events
  45. // will be sent a EventObject event object.
  46. // NOTE:
  47. // Events happen anywhere in the document unless
  48. // otherwise noted.
  49. //
  50. // onMove
  51. // Fires on mousemove when mouse is up
  52. // onDown
  53. // Fires on mousedown *on the canvas*
  54. // onDrag
  55. // Fires on mousemove when mouse is down
  56. // onUp
  57. // Fires on mouseup, anywhere in the document
  58. // onStencilDown
  59. // Fired on mousedown on a Stencil
  60. // onStencilDrag
  61. // Fired when mouse moves and mose is down on a Stencil
  62. // onStencilUp
  63. // Fired on mouseup off of a Stencil
  64. // on[Custom]Up|Down|Move
  65. // Custom events can bet set and fired by setting a
  66. // different drawingType on a Stencil, or by calling
  67. // setEventMode(customEventName)
  68. },
  69. EventObject: function(){
  70. // summary:
  71. // The custom event object that is sent to registered objects
  72. // and their respective methods.
  73. // NOTE: Most event objects are the same with the exception
  74. // of the onDown events, which have fewer.
  75. //
  76. // All event properties included onDown:
  77. //
  78. // id: String
  79. // Id of the focused object
  80. // pageX: Number
  81. // The X coordinate of the mouse from the left side of
  82. // the document.
  83. // pageY: Number
  84. // The Y coordinate of the mouse from the top of
  85. // the document.
  86. // x: Number
  87. // The X coordinate of the mouse from the left side
  88. // of the canvas
  89. // y: Number
  90. // The Y coordinate of the mouse from the top
  91. // of the canvas
  92. //
  93. // These event properties are *not* in onDown:
  94. //
  95. // last: Object
  96. // The x and y coordinates of the last mousemove
  97. // relative to the canvas
  98. // move: Object
  99. // The x and y amounts the mouse moved since the last event
  100. // orgX: Number
  101. // The left side of the canvas from the side of the document
  102. // orgY: Number
  103. // The top of the canvas from the top of the document
  104. // scroll: Object
  105. // The 'top' and 'left' scroll amounts of the canvas.
  106. // start: Object
  107. // The x and y coordinates of the mousedown event
  108. // withinCanvas: Boolean
  109. // Whether the event happened within the Canvas or not
  110. },
  111. =====*/
  112. init: function(/* HTMLNode*/node){
  113. // summary:
  114. // Internal. Initializes mouse.
  115. //
  116. this.container = node;
  117. this.setCanvas();
  118. var c;
  119. var _isDown = false;
  120. dojo.connect(this.container, "rightclick", this, function(evt){
  121. console.warn("RIGHTCLICK")
  122. });
  123. dojo.connect(document.body, "mousedown", this, function(evt){
  124. //evt.preventDefault();
  125. //dojo.stopEvent(evt);
  126. });
  127. dojo.connect(this.container, "mousedown", this, function(evt){
  128. this.down(evt);
  129. // Right click shouldn't trigger drag
  130. if(evt.button != dojo.mouseButtons.RIGHT){
  131. _isDown = true;
  132. c = dojo.connect(document, "mousemove", this, "drag");
  133. }
  134. });
  135. dojo.connect(document, "mouseup", this, function(evt){
  136. dojo.disconnect(c);
  137. _isDown = false;
  138. this.up(evt);
  139. });
  140. dojo.connect(document, "mousemove", this, function(evt){
  141. if(!_isDown){
  142. this.move(evt);
  143. }
  144. });
  145. dojo.connect(this.keys, "onEsc", this, function(evt){
  146. this._dragged = false;
  147. });
  148. },
  149. setCanvas: function(){
  150. // summary:
  151. // Internal. Sets canvas position
  152. var pos = dojo.coords(this.container.parentNode);
  153. this.origin = dojo.clone(pos);
  154. },
  155. scrollOffset: function(){
  156. // summary:
  157. // Gets scroll offset of canvas
  158. return {
  159. top:this.container.parentNode.scrollTop,
  160. left:this.container.parentNode.scrollLeft
  161. }; // Object
  162. },
  163. resize: function(width,height){
  164. if(this.origin){
  165. this.origin.w=width;
  166. this.origin.h=height;
  167. }
  168. },
  169. register: function(/* Object*/scope){
  170. // summary:
  171. // All objects (Stencils) should register here if they
  172. // use mouse events. When registering, the object will
  173. // be called if it has that method.
  174. // argument:
  175. // The object to be called
  176. // Returns: handle
  177. // Keep the handle to be used for disconnection.
  178. // See: CustomEventMethod and EventObject
  179. //
  180. var handle = scope.id || "reg_"+(this.__reg++);
  181. if(!this.registered[handle]){ this.registered[handle] = scope; }
  182. return handle; // String
  183. },
  184. unregister: function(handle){
  185. // summary:
  186. // Disconnects object. Mouse events are no longer
  187. // called for it.
  188. if(!this.registered[handle]){ return; }
  189. delete this.registered[handle];
  190. },
  191. _broadcastEvent:function(strEvt, obj){
  192. // summary:
  193. // Fire events to all registered objects.
  194. //
  195. //console.log("mouse.broadcast:", strEvt, obj)
  196. for(var nm in this.registered){
  197. if(this.registered[nm][strEvt]) this.registered[nm][strEvt](obj);
  198. }
  199. },
  200. onDown: function(obj){
  201. // summary:
  202. // Create on[xx]Down event and send to broadcaster.
  203. // Could be connected to.
  204. //console.info("onDown:", this.eventName("down"))
  205. this._broadcastEvent(this.eventName("down"), obj);
  206. },
  207. onDrag: function(obj){
  208. // summary:
  209. // Create on[xx]Drag event and send to broadcaster.
  210. // Could be connected to.
  211. //
  212. var nm = this.eventName("drag");
  213. if(this._selected && nm == "onDrag"){
  214. nm = "onStencilDrag"
  215. }
  216. this._broadcastEvent(nm, obj);
  217. },
  218. onMove: function(obj){
  219. // summary:
  220. // Create onMove event and send to broadcaster.
  221. // Could be connected to.
  222. // Note: onMove never uses a custom event
  223. // Note: onMove is currently not enabled in the app.
  224. //
  225. this._broadcastEvent("onMove", obj);
  226. },
  227. overName: function(obj,evt){
  228. var nm = obj.id.split(".");
  229. evt = evt.charAt(0).toUpperCase() + evt.substring(1);
  230. if(nm[0] == "dojox" && (dojox.drawing.defaults.clickable || !dojox.drawing.defaults.clickMode)){
  231. return "onStencil"+evt;
  232. }else{
  233. return "on"+evt;
  234. }
  235. },
  236. onOver: function(obj){
  237. // summary:
  238. //
  239. this._broadcastEvent(this.overName(obj,"over"), obj);
  240. },
  241. onOut: function(obj){
  242. // summary:
  243. //
  244. this._broadcastEvent(this.overName(obj,"out"), obj);
  245. },
  246. onUp: function(obj){
  247. // summary:
  248. // Create on[xx]Up event and send to broadcaster.
  249. // Could be connected to.
  250. //
  251. // blocking first click-off (deselect), largely for TextBlock
  252. // TODO: should have param to make this optional?
  253. var nm = this.eventName("up");
  254. if(nm == "onStencilUp"){
  255. this._selected = true;
  256. }else if(this._selected && nm == "onUp"){ //////////////////////////////////////////
  257. nm = "onStencilUp";
  258. this._selected = false;
  259. }
  260. console.info("Up Event:", this.id, nm, "id:", obj.id);
  261. this._broadcastEvent(nm, obj);
  262. // Silverlight double-click handled in Silverlight class
  263. if(dojox.gfx.renderer == "silverlight"){ return; }
  264. // Check Double Click
  265. // If a double click is detected, the onDoubleClick event fires,
  266. // but does not replace the normal event. They both fire.
  267. this._clickTime = new Date().getTime();
  268. if(this._lastClickTime){
  269. if(this._clickTime-this._lastClickTime<this.doublClickSpeed){
  270. var dnm = this.eventName("doubleClick");
  271. console.warn("DOUBLE CLICK", dnm, obj);
  272. this._broadcastEvent(dnm, obj);
  273. }else{
  274. //console.log(" slow:", this._clickTime-this._lastClickTime)
  275. }
  276. }
  277. this._lastClickTime = this._clickTime;
  278. },
  279. zoom: 1,
  280. setZoom: function(zoom){
  281. // summary:
  282. // Internal. Sets the mouse zoom percentage to
  283. // that of the canvas
  284. this.zoom = 1/zoom;
  285. },
  286. setEventMode: function(mode){
  287. // summary:
  288. // Sets the mouse mode s that custom events can be called.
  289. // Also can 'disable' events by using a bogus mode:
  290. // | mouse.setEventMode("DISABLED")
  291. // (unless any object subscribes to this event,
  292. // it is effectively disabled)
  293. //
  294. this.mode = mode ? "on" + mode.charAt(0).toUpperCase() + mode.substring(1) : "";
  295. },
  296. eventName: function(name){
  297. // summary:
  298. // Internal. Determine the event name
  299. //
  300. name = name.charAt(0).toUpperCase() + name.substring(1);
  301. if(this.mode){
  302. if(this.mode == "onPathEdit"){
  303. return "on"+name;
  304. }
  305. if(this.mode == "onUI"){
  306. //return "on"+name;
  307. }
  308. return this.mode + name;
  309. }else{
  310. //Allow a mode where stencils aren't clickable
  311. if(!dojox.drawing.defaults.clickable && dojox.drawing.defaults.clickMode){return "on"+name;}
  312. var dt = !this.drawingType || this.drawingType=="surface" || this.drawingType=="canvas" ? "" : this.drawingType;
  313. var t = !dt ? "" : dt.charAt(0).toUpperCase() + dt.substring(1);
  314. return "on"+t+name;
  315. }
  316. },
  317. up: function(evt){
  318. // summary:
  319. // Internal. Create onUp event
  320. //
  321. this.onUp(this.create(evt));
  322. },
  323. down: function(evt){
  324. // summary:
  325. // Internal. Create onDown event
  326. //
  327. this._downOnCanvas = true;
  328. var sc = this.scrollOffset();
  329. var dim = this._getXY(evt);
  330. this._lastpagex = dim.x;
  331. this._lastpagey = dim.y;
  332. var o = this.origin;
  333. var x = dim.x - o.x + sc.left;
  334. var y = dim.y - o.y + sc.top;
  335. var withinCanvas = x>=0 && y>=0 && x<=o.w && y<=o.h;
  336. x*= this.zoom;
  337. y*= this.zoom;
  338. o.startx = x;
  339. o.starty = y;
  340. this._lastx = x;
  341. this._lasty = y;
  342. this.drawingType = this.util.attr(evt, "drawingType") || "";
  343. var id = this._getId(evt);
  344. //console.log("DOWN:", this.id, id, withinCanvas);
  345. //console.log("this.drawingType:", this.drawingType);
  346. if(evt.button == dojo.mouseButtons.RIGHT && this.id == "mse"){
  347. //Allow right click events to bubble for context menus
  348. }else{
  349. evt.preventDefault();
  350. dojo.stopEvent(evt);
  351. }
  352. this.onDown({
  353. mid:this.id,
  354. x:x,
  355. y:y,
  356. pageX:dim.x,
  357. pageY:dim.y,
  358. withinCanvas:withinCanvas,
  359. id:id
  360. });
  361. },
  362. over: function(obj){
  363. // summary:
  364. // Internal.
  365. //
  366. this.onOver(obj);
  367. },
  368. out: function(obj){
  369. // summary:
  370. // Internal.
  371. //
  372. this.onOut(obj);
  373. },
  374. move: function(evt){
  375. // summary:
  376. // Internal.
  377. //
  378. var obj = this.create(evt);
  379. if(this.id=="MUI"){
  380. //console.log("obj.id:", obj.id, "was:", this.currentNodeId)
  381. }
  382. if(obj.id != this.currentNodeId){
  383. // TODO: I wonder if an ID is good enough
  384. // that would avoid the mixin
  385. var outObj = {};
  386. for(var nm in obj){
  387. outObj[nm] = obj[nm];
  388. }
  389. outObj.id = this.currentNodeId;
  390. this.currentNodeId && this.out(outObj);
  391. obj.id && this.over(obj);
  392. this.currentNodeId = obj.id;
  393. }
  394. this.onMove(obj);
  395. },
  396. drag: function(evt){
  397. // summary:
  398. // Internal. Create onDrag event
  399. this.onDrag(this.create(evt, true));
  400. },
  401. create: function(evt, squelchErrors){
  402. // summary:
  403. // Internal. Create EventObject
  404. //
  405. var sc = this.scrollOffset();
  406. var dim = this._getXY(evt);
  407. var pagex = dim.x;
  408. var pagey = dim.y;
  409. var o = this.origin;
  410. var x = dim.x - o.x + sc.left;
  411. var y = dim.y - o.y + sc.top;
  412. var withinCanvas = x>=0 && y>=0 && x<=o.w && y<=o.h;
  413. x*= this.zoom;
  414. y*= this.zoom;
  415. var id = withinCanvas ? this._getId(evt, squelchErrors) : "";
  416. var ret = {
  417. mid:this.id,
  418. x:x,
  419. y:y,
  420. pageX:dim.x,
  421. pageY:dim.y,
  422. page:{
  423. x:dim.x,
  424. y:dim.y
  425. },
  426. orgX:o.x,
  427. orgY:o.y,
  428. last:{
  429. x: this._lastx,
  430. y: this._lasty
  431. },
  432. start:{
  433. x: this.origin.startx, //+ sc.left,
  434. y: this.origin.starty //+ sc.top
  435. },
  436. move:{
  437. x:pagex - this._lastpagex,
  438. y:pagey - this._lastpagey
  439. },
  440. scroll:sc,
  441. id:id,
  442. withinCanvas:withinCanvas
  443. };
  444. //console.warn("MSE LAST:", x-this._lastx, y-this._lasty)
  445. this._lastx = x;
  446. this._lasty = y;
  447. this._lastpagex = pagex;
  448. this._lastpagey = pagey;
  449. dojo.stopEvent(evt);
  450. return ret; //Object
  451. },
  452. _getId: function(evt, squelchErrors){
  453. // summary:
  454. // Internal. Gets ID of focused node.
  455. return this.util.attr(evt, "id", null, squelchErrors); // String
  456. },
  457. _getXY: function(evt){
  458. // summary:
  459. // Internal. Gets mouse coords to page.
  460. return {x:evt.pageX, y:evt.pageY}; // Object
  461. },
  462. setCursor: function(cursor,/* HTMLNode*/node){
  463. // summary:
  464. // Sets the cursor for a given node. If no
  465. // node is specified the containing node is used.
  466. if(!node){
  467. dojo.style(this.container, "cursor", cursor);
  468. }else{
  469. dojo.style(node, "cursor", cursor);
  470. }
  471. }
  472. }
  473. );
  474. });