[76] | 1 | /* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for |
---|
| 2 | * full list of contributors). Published under the Clear BSD license. |
---|
| 3 | * See http://svn.openlayers.org/trunk/openlayers/license.txt for the |
---|
| 4 | * full text of the license. */ |
---|
| 5 | |
---|
| 6 | /** |
---|
| 7 | * @requires OpenLayers/Handler.js |
---|
| 8 | */ |
---|
| 9 | |
---|
| 10 | /** |
---|
| 11 | * Class: OpenLayers.Handler.Drag |
---|
| 12 | * The drag handler is used to deal with sequences of browser events related |
---|
| 13 | * to dragging. The handler is used by controls that want to know when |
---|
| 14 | * a drag sequence begins, when a drag is happening, and when it has |
---|
| 15 | * finished. |
---|
| 16 | * |
---|
| 17 | * Controls that use the drag handler typically construct it with callbacks |
---|
| 18 | * for 'down', 'move', and 'done'. Callbacks for these keys are called |
---|
| 19 | * when the drag begins, with each move, and when the drag is done. In |
---|
| 20 | * addition, controls can have callbacks keyed to 'up' and 'out' if they |
---|
| 21 | * care to differentiate between the types of events that correspond with |
---|
| 22 | * the end of a drag sequence. If no drag actually occurs (no mouse move) |
---|
| 23 | * the 'down' and 'up' callbacks will be called, but not the 'done' |
---|
| 24 | * callback. |
---|
| 25 | * |
---|
| 26 | * Create a new drag handler with the <OpenLayers.Handler.Drag> constructor. |
---|
| 27 | * |
---|
| 28 | * Inherits from: |
---|
| 29 | * - <OpenLayers.Handler> |
---|
| 30 | */ |
---|
| 31 | OpenLayers.Handler.Drag = OpenLayers.Class(OpenLayers.Handler, { |
---|
| 32 | |
---|
| 33 | /** |
---|
| 34 | * Property: started |
---|
| 35 | * {Boolean} When a mousedown event is received, we want to record it, but |
---|
| 36 | * not set 'dragging' until the mouse moves after starting. |
---|
| 37 | */ |
---|
| 38 | started: false, |
---|
| 39 | |
---|
| 40 | /** |
---|
| 41 | * Property: stopDown |
---|
| 42 | * {Boolean} Stop propagation of mousedown events from getting to listeners |
---|
| 43 | * on the same element. Default is true. |
---|
| 44 | */ |
---|
| 45 | stopDown: true, |
---|
| 46 | |
---|
| 47 | /** |
---|
| 48 | * Property: dragging |
---|
| 49 | * {Boolean} |
---|
| 50 | */ |
---|
| 51 | dragging: false, |
---|
| 52 | |
---|
| 53 | /** |
---|
| 54 | * Property: last |
---|
| 55 | * {<OpenLayers.Pixel>} The last pixel location of the drag. |
---|
| 56 | */ |
---|
| 57 | last: null, |
---|
| 58 | |
---|
| 59 | /** |
---|
| 60 | * Property: start |
---|
| 61 | * {<OpenLayers.Pixel>} The first pixel location of the drag. |
---|
| 62 | */ |
---|
| 63 | start: null, |
---|
| 64 | |
---|
| 65 | /** |
---|
| 66 | * Property: oldOnselectstart |
---|
| 67 | * {Function} |
---|
| 68 | */ |
---|
| 69 | oldOnselectstart: null, |
---|
| 70 | |
---|
| 71 | /** |
---|
| 72 | * Property: interval |
---|
| 73 | * {Integer} In order to increase performance, an interval (in |
---|
| 74 | * milliseconds) can be set to reduce the number of drag events |
---|
| 75 | * called. If set, a new drag event will not be set until the |
---|
| 76 | * interval has passed. |
---|
| 77 | * Defaults to 0, meaning no interval. |
---|
| 78 | */ |
---|
| 79 | interval: 0, |
---|
| 80 | |
---|
| 81 | /** |
---|
| 82 | * Property: timeoutId |
---|
| 83 | * {String} The id of the timeout used for the mousedown interval. |
---|
| 84 | * This is "private", and should be left alone. |
---|
| 85 | */ |
---|
| 86 | timeoutId: null, |
---|
| 87 | |
---|
| 88 | /** |
---|
| 89 | * APIProperty: documentDrag |
---|
| 90 | * {Boolean} If set to true, the handler will also handle mouse moves when |
---|
| 91 | * the cursor has moved out of the map viewport. Default is false. |
---|
| 92 | */ |
---|
| 93 | documentDrag: false, |
---|
| 94 | |
---|
| 95 | /** |
---|
| 96 | * Property: documentEvents |
---|
| 97 | * {<OpenLayers.Events>} Event instance for observing document events. Will |
---|
| 98 | * be set on mouseout if documentDrag is set to true. |
---|
| 99 | */ |
---|
| 100 | documentEvents: null, |
---|
| 101 | |
---|
| 102 | /** |
---|
| 103 | * Constructor: OpenLayers.Handler.Drag |
---|
| 104 | * Returns OpenLayers.Handler.Drag |
---|
| 105 | * |
---|
| 106 | * Parameters: |
---|
| 107 | * control - {<OpenLayers.Control>} The control that is making use of |
---|
| 108 | * this handler. If a handler is being used without a control, the |
---|
| 109 | * handlers setMap method must be overridden to deal properly with |
---|
| 110 | * the map. |
---|
| 111 | * callbacks - {Object} An object containing a single function to be |
---|
| 112 | * called when the drag operation is finished. The callback should |
---|
| 113 | * expect to recieve a single argument, the pixel location of the event. |
---|
| 114 | * Callbacks for 'move' and 'done' are supported. You can also speficy |
---|
| 115 | * callbacks for 'down', 'up', and 'out' to respond to those events. |
---|
| 116 | * options - {Object} |
---|
| 117 | */ |
---|
| 118 | initialize: function(control, callbacks, options) { |
---|
| 119 | OpenLayers.Handler.prototype.initialize.apply(this, arguments); |
---|
| 120 | }, |
---|
| 121 | |
---|
| 122 | /** |
---|
| 123 | * The four methods below (down, move, up, and out) are used by subclasses |
---|
| 124 | * to do their own processing related to these mouse events. |
---|
| 125 | */ |
---|
| 126 | |
---|
| 127 | /** |
---|
| 128 | * Method: down |
---|
| 129 | * This method is called during the handling of the mouse down event. |
---|
| 130 | * Subclasses can do their own processing here. |
---|
| 131 | * |
---|
| 132 | * Parameters: |
---|
| 133 | * evt - {Event} The mouse down event |
---|
| 134 | */ |
---|
| 135 | down: function(evt) { |
---|
| 136 | }, |
---|
| 137 | |
---|
| 138 | /** |
---|
| 139 | * Method: move |
---|
| 140 | * This method is called during the handling of the mouse move event. |
---|
| 141 | * Subclasses can do their own processing here. |
---|
| 142 | * |
---|
| 143 | * Parameters: |
---|
| 144 | * evt - {Event} The mouse move event |
---|
| 145 | * |
---|
| 146 | */ |
---|
| 147 | move: function(evt) { |
---|
| 148 | }, |
---|
| 149 | |
---|
| 150 | /** |
---|
| 151 | * Method: up |
---|
| 152 | * This method is called during the handling of the mouse up event. |
---|
| 153 | * Subclasses can do their own processing here. |
---|
| 154 | * |
---|
| 155 | * Parameters: |
---|
| 156 | * evt - {Event} The mouse up event |
---|
| 157 | */ |
---|
| 158 | up: function(evt) { |
---|
| 159 | }, |
---|
| 160 | |
---|
| 161 | /** |
---|
| 162 | * Method: out |
---|
| 163 | * This method is called during the handling of the mouse out event. |
---|
| 164 | * Subclasses can do their own processing here. |
---|
| 165 | * |
---|
| 166 | * Parameters: |
---|
| 167 | * evt - {Event} The mouse out event |
---|
| 168 | */ |
---|
| 169 | out: function(evt) { |
---|
| 170 | }, |
---|
| 171 | |
---|
| 172 | /** |
---|
| 173 | * The methods below are part of the magic of event handling. Because |
---|
| 174 | * they are named like browser events, they are registered as listeners |
---|
| 175 | * for the events they represent. |
---|
| 176 | */ |
---|
| 177 | |
---|
| 178 | /** |
---|
| 179 | * Method: mousedown |
---|
| 180 | * Handle mousedown events |
---|
| 181 | * |
---|
| 182 | * Parameters: |
---|
| 183 | * evt - {Event} |
---|
| 184 | * |
---|
| 185 | * Returns: |
---|
| 186 | * {Boolean} Let the event propagate. |
---|
| 187 | */ |
---|
| 188 | mousedown: function (evt) { |
---|
| 189 | var propagate = true; |
---|
| 190 | this.dragging = false; |
---|
| 191 | if (this.checkModifiers(evt) && OpenLayers.Event.isLeftClick(evt)) { |
---|
| 192 | this.started = true; |
---|
| 193 | this.start = evt.xy; |
---|
| 194 | this.last = evt.xy; |
---|
| 195 | OpenLayers.Element.addClass( |
---|
| 196 | this.map.viewPortDiv, "olDragDown" |
---|
| 197 | ); |
---|
| 198 | this.down(evt); |
---|
| 199 | this.callback("down", [evt.xy]); |
---|
| 200 | OpenLayers.Event.stop(evt); |
---|
| 201 | |
---|
| 202 | if(!this.oldOnselectstart) { |
---|
| 203 | this.oldOnselectstart = (document.onselectstart) ? document.onselectstart : OpenLayers.Function.True; |
---|
| 204 | } |
---|
| 205 | document.onselectstart = OpenLayers.Function.False; |
---|
| 206 | |
---|
| 207 | propagate = !this.stopDown; |
---|
| 208 | } else { |
---|
| 209 | this.started = false; |
---|
| 210 | this.start = null; |
---|
| 211 | this.last = null; |
---|
| 212 | } |
---|
| 213 | return propagate; |
---|
| 214 | }, |
---|
| 215 | |
---|
| 216 | /** |
---|
| 217 | * Method: mousemove |
---|
| 218 | * Handle mousemove events |
---|
| 219 | * |
---|
| 220 | * Parameters: |
---|
| 221 | * evt - {Event} |
---|
| 222 | * |
---|
| 223 | * Returns: |
---|
| 224 | * {Boolean} Let the event propagate. |
---|
| 225 | */ |
---|
| 226 | mousemove: function (evt) { |
---|
| 227 | if (this.started && !this.timeoutId && (evt.xy.x != this.last.x || evt.xy.y != this.last.y)) { |
---|
| 228 | if(this.documentDrag === true && this.documentEvents) { |
---|
| 229 | if(evt.element === document) { |
---|
| 230 | this.adjustXY(evt); |
---|
| 231 | // do setEvent manually because the documentEvents are not |
---|
| 232 | // registered with the map |
---|
| 233 | this.setEvent(evt); |
---|
| 234 | } else { |
---|
| 235 | this.destroyDocumentEvents(); |
---|
| 236 | } |
---|
| 237 | } |
---|
| 238 | if (this.interval > 0) { |
---|
| 239 | this.timeoutId = setTimeout(OpenLayers.Function.bind(this.removeTimeout, this), this.interval); |
---|
| 240 | } |
---|
| 241 | this.dragging = true; |
---|
| 242 | this.move(evt); |
---|
| 243 | this.callback("move", [evt.xy]); |
---|
| 244 | if(!this.oldOnselectstart) { |
---|
| 245 | this.oldOnselectstart = document.onselectstart; |
---|
| 246 | document.onselectstart = OpenLayers.Function.False; |
---|
| 247 | } |
---|
| 248 | this.last = this.evt.xy; |
---|
| 249 | } |
---|
| 250 | return true; |
---|
| 251 | }, |
---|
| 252 | |
---|
| 253 | /** |
---|
| 254 | * Method: removeTimeout |
---|
| 255 | * Private. Called by mousemove() to remove the drag timeout. |
---|
| 256 | */ |
---|
| 257 | removeTimeout: function() { |
---|
| 258 | this.timeoutId = null; |
---|
| 259 | }, |
---|
| 260 | |
---|
| 261 | /** |
---|
| 262 | * Method: mouseup |
---|
| 263 | * Handle mouseup events |
---|
| 264 | * |
---|
| 265 | * Parameters: |
---|
| 266 | * evt - {Event} |
---|
| 267 | * |
---|
| 268 | * Returns: |
---|
| 269 | * {Boolean} Let the event propagate. |
---|
| 270 | */ |
---|
| 271 | mouseup: function (evt) { |
---|
| 272 | if (this.started) { |
---|
| 273 | if(this.documentDrag === true && this.documentEvents) { |
---|
| 274 | this.adjustXY(evt); |
---|
| 275 | this.destroyDocumentEvents(); |
---|
| 276 | } |
---|
| 277 | var dragged = (this.start != this.last); |
---|
| 278 | this.started = false; |
---|
| 279 | this.dragging = false; |
---|
| 280 | OpenLayers.Element.removeClass( |
---|
| 281 | this.map.viewPortDiv, "olDragDown" |
---|
| 282 | ); |
---|
| 283 | this.up(evt); |
---|
| 284 | this.callback("up", [evt.xy]); |
---|
| 285 | if(dragged) { |
---|
| 286 | this.callback("done", [evt.xy]); |
---|
| 287 | } |
---|
| 288 | document.onselectstart = this.oldOnselectstart; |
---|
| 289 | } |
---|
| 290 | return true; |
---|
| 291 | }, |
---|
| 292 | |
---|
| 293 | /** |
---|
| 294 | * Method: mouseout |
---|
| 295 | * Handle mouseout events |
---|
| 296 | * |
---|
| 297 | * Parameters: |
---|
| 298 | * evt - {Event} |
---|
| 299 | * |
---|
| 300 | * Returns: |
---|
| 301 | * {Boolean} Let the event propagate. |
---|
| 302 | */ |
---|
| 303 | mouseout: function (evt) { |
---|
| 304 | if (this.started && OpenLayers.Util.mouseLeft(evt, this.map.div)) { |
---|
| 305 | if(this.documentDrag === true) { |
---|
| 306 | this.documentEvents = new OpenLayers.Events(this, document, |
---|
| 307 | null, null, {includeXY: true}); |
---|
| 308 | this.documentEvents.on({ |
---|
| 309 | mousemove: this.mousemove, |
---|
| 310 | mouseup: this.mouseup |
---|
| 311 | }); |
---|
| 312 | OpenLayers.Element.addClass( |
---|
| 313 | document.body, "olDragDown" |
---|
| 314 | ); |
---|
| 315 | } else { |
---|
| 316 | var dragged = (this.start != this.last); |
---|
| 317 | this.started = false; |
---|
| 318 | this.dragging = false; |
---|
| 319 | OpenLayers.Element.removeClass( |
---|
| 320 | this.map.viewPortDiv, "olDragDown" |
---|
| 321 | ); |
---|
| 322 | this.out(evt); |
---|
| 323 | this.callback("out", []); |
---|
| 324 | if(dragged) { |
---|
| 325 | this.callback("done", [evt.xy]); |
---|
| 326 | } |
---|
| 327 | if(document.onselectstart) { |
---|
| 328 | document.onselectstart = this.oldOnselectstart; |
---|
| 329 | } |
---|
| 330 | } |
---|
| 331 | } |
---|
| 332 | return true; |
---|
| 333 | }, |
---|
| 334 | |
---|
| 335 | /** |
---|
| 336 | * Method: click |
---|
| 337 | * The drag handler captures the click event. If something else registers |
---|
| 338 | * for clicks on the same element, its listener will not be called |
---|
| 339 | * after a drag. |
---|
| 340 | * |
---|
| 341 | * Parameters: |
---|
| 342 | * evt - {Event} |
---|
| 343 | * |
---|
| 344 | * Returns: |
---|
| 345 | * {Boolean} Let the event propagate. |
---|
| 346 | */ |
---|
| 347 | click: function (evt) { |
---|
| 348 | // let the click event propagate only if the mouse moved |
---|
| 349 | return (this.start == this.last); |
---|
| 350 | }, |
---|
| 351 | |
---|
| 352 | /** |
---|
| 353 | * Method: activate |
---|
| 354 | * Activate the handler. |
---|
| 355 | * |
---|
| 356 | * Returns: |
---|
| 357 | * {Boolean} The handler was successfully activated. |
---|
| 358 | */ |
---|
| 359 | activate: function() { |
---|
| 360 | var activated = false; |
---|
| 361 | if(OpenLayers.Handler.prototype.activate.apply(this, arguments)) { |
---|
| 362 | this.dragging = false; |
---|
| 363 | activated = true; |
---|
| 364 | } |
---|
| 365 | return activated; |
---|
| 366 | }, |
---|
| 367 | |
---|
| 368 | /** |
---|
| 369 | * Method: deactivate |
---|
| 370 | * Deactivate the handler. |
---|
| 371 | * |
---|
| 372 | * Returns: |
---|
| 373 | * {Boolean} The handler was successfully deactivated. |
---|
| 374 | */ |
---|
| 375 | deactivate: function() { |
---|
| 376 | var deactivated = false; |
---|
| 377 | if(OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) { |
---|
| 378 | this.started = false; |
---|
| 379 | this.dragging = false; |
---|
| 380 | this.start = null; |
---|
| 381 | this.last = null; |
---|
| 382 | deactivated = true; |
---|
| 383 | OpenLayers.Element.removeClass( |
---|
| 384 | this.map.viewPortDiv, "olDragDown" |
---|
| 385 | ); |
---|
| 386 | } |
---|
| 387 | return deactivated; |
---|
| 388 | }, |
---|
| 389 | |
---|
| 390 | /** |
---|
| 391 | * Method: adjustXY |
---|
| 392 | * Converts event coordinates that are relative to the document body to |
---|
| 393 | * ones that are relative to the map viewport. The latter is the default in |
---|
| 394 | * OpenLayers. |
---|
| 395 | * |
---|
| 396 | * Parameters: |
---|
| 397 | * evt - {Object} |
---|
| 398 | */ |
---|
| 399 | adjustXY: function(evt) { |
---|
| 400 | var pos = OpenLayers.Util.pagePosition(this.map.div); |
---|
| 401 | evt.xy.x -= pos[0]; |
---|
| 402 | evt.xy.y -= pos[1]; |
---|
| 403 | }, |
---|
| 404 | |
---|
| 405 | /** |
---|
| 406 | * Method: destroyDocumentEvents |
---|
| 407 | * Destroys the events instance that gets added to the document body when |
---|
| 408 | * documentDrag is true and the mouse cursor leaves the map viewport while |
---|
| 409 | * dragging. |
---|
| 410 | */ |
---|
| 411 | destroyDocumentEvents: function() { |
---|
| 412 | OpenLayers.Element.removeClass( |
---|
| 413 | document.body, "olDragDown" |
---|
| 414 | ); |
---|
| 415 | this.documentEvents.destroy(); |
---|
| 416 | this.documentEvents = null; |
---|
| 417 | }, |
---|
| 418 | |
---|
| 419 | CLASS_NAME: "OpenLayers.Handler.Drag" |
---|
| 420 | }); |
---|