[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 | /** |
---|
| 8 | * @requires OpenLayers/Handler.js |
---|
| 9 | * @requires OpenLayers/Geometry/Point.js |
---|
| 10 | */ |
---|
| 11 | |
---|
| 12 | /** |
---|
| 13 | * Class: OpenLayers.Handler.Point |
---|
| 14 | * Handler to draw a point on the map. Point is displayed on mouse down, |
---|
| 15 | * moves on mouse move, and is finished on mouse up. The handler triggers |
---|
| 16 | * callbacks for 'done', 'cancel', and 'modify'. The modify callback is |
---|
| 17 | * called with each change in the sketch and will receive the latest point |
---|
| 18 | * drawn. Create a new instance with the <OpenLayers.Handler.Point> |
---|
| 19 | * constructor. |
---|
| 20 | * |
---|
| 21 | * Inherits from: |
---|
| 22 | * - <OpenLayers.Handler> |
---|
| 23 | */ |
---|
| 24 | OpenLayers.Handler.Point = OpenLayers.Class(OpenLayers.Handler, { |
---|
| 25 | |
---|
| 26 | /** |
---|
| 27 | * Property: point |
---|
| 28 | * {<OpenLayers.Feature.Vector>} The currently drawn point |
---|
| 29 | */ |
---|
| 30 | point: null, |
---|
| 31 | |
---|
| 32 | /** |
---|
| 33 | * Property: layer |
---|
| 34 | * {<OpenLayers.Layer.Vector>} The temporary drawing layer |
---|
| 35 | */ |
---|
| 36 | layer: null, |
---|
| 37 | |
---|
| 38 | /** |
---|
| 39 | * APIProperty: multi |
---|
| 40 | * {Boolean} Cast features to multi-part geometries before passing to the |
---|
| 41 | * layer. Default is false. |
---|
| 42 | */ |
---|
| 43 | multi: false, |
---|
| 44 | |
---|
| 45 | /** |
---|
| 46 | * Property: drawing |
---|
| 47 | * {Boolean} A point is being drawn |
---|
| 48 | */ |
---|
| 49 | drawing: false, |
---|
| 50 | |
---|
| 51 | /** |
---|
| 52 | * Property: mouseDown |
---|
| 53 | * {Boolean} The mouse is down |
---|
| 54 | */ |
---|
| 55 | mouseDown: false, |
---|
| 56 | |
---|
| 57 | /** |
---|
| 58 | * Property: lastDown |
---|
| 59 | * {<OpenLayers.Pixel>} Location of the last mouse down |
---|
| 60 | */ |
---|
| 61 | lastDown: null, |
---|
| 62 | |
---|
| 63 | /** |
---|
| 64 | * Property: lastUp |
---|
| 65 | * {<OpenLayers.Pixel>} |
---|
| 66 | */ |
---|
| 67 | lastUp: null, |
---|
| 68 | |
---|
| 69 | /** |
---|
| 70 | * APIProperty: persist |
---|
| 71 | * {Boolean} Leave the feature rendered until destroyFeature is called. |
---|
| 72 | * Default is false. If set to true, the feature remains rendered until |
---|
| 73 | * destroyFeature is called, typically by deactivating the handler or |
---|
| 74 | * starting another drawing. |
---|
| 75 | */ |
---|
| 76 | persist: false, |
---|
| 77 | |
---|
| 78 | /** |
---|
| 79 | * Property: layerOptions |
---|
| 80 | * {Object} Any optional properties to be set on the sketch layer. |
---|
| 81 | */ |
---|
| 82 | layerOptions: null, |
---|
| 83 | |
---|
| 84 | /** |
---|
| 85 | * Constructor: OpenLayers.Handler.Point |
---|
| 86 | * Create a new point handler. |
---|
| 87 | * |
---|
| 88 | * Parameters: |
---|
| 89 | * control - {<OpenLayers.Control>} The control that owns this handler |
---|
| 90 | * callbacks - {Object} An object with a properties whose values are |
---|
| 91 | * functions. Various callbacks described below. |
---|
| 92 | * options - {Object} An optional object with properties to be set on the |
---|
| 93 | * handler |
---|
| 94 | * |
---|
| 95 | * Named callbacks: |
---|
| 96 | * create - Called when a sketch is first created. Callback called with |
---|
| 97 | * the creation point geometry and sketch feature. |
---|
| 98 | * modify - Called with each move of a vertex with the vertex (point) |
---|
| 99 | * geometry and the sketch feature. |
---|
| 100 | * done - Called when the point drawing is finished. The callback will |
---|
| 101 | * recieve a single argument, the point geometry. |
---|
| 102 | * cancel - Called when the handler is deactivated while drawing. The |
---|
| 103 | * cancel callback will receive a geometry. |
---|
| 104 | */ |
---|
| 105 | initialize: function(control, callbacks, options) { |
---|
| 106 | if(!(options && options.layerOptions && options.layerOptions.styleMap)) { |
---|
| 107 | this.style = OpenLayers.Util.extend(OpenLayers.Feature.Vector.style['default'], {}); |
---|
| 108 | } |
---|
| 109 | |
---|
| 110 | OpenLayers.Handler.prototype.initialize.apply(this, arguments); |
---|
| 111 | }, |
---|
| 112 | |
---|
| 113 | /** |
---|
| 114 | * APIMethod: activate |
---|
| 115 | * turn on the handler |
---|
| 116 | */ |
---|
| 117 | activate: function() { |
---|
| 118 | if(!OpenLayers.Handler.prototype.activate.apply(this, arguments)) { |
---|
| 119 | return false; |
---|
| 120 | } |
---|
| 121 | // create temporary vector layer for rendering geometry sketch |
---|
| 122 | // TBD: this could be moved to initialize/destroy - setting visibility here |
---|
| 123 | var options = OpenLayers.Util.extend({ |
---|
| 124 | displayInLayerSwitcher: false, |
---|
| 125 | // indicate that the temp vector layer will never be out of range |
---|
| 126 | // without this, resolution properties must be specified at the |
---|
| 127 | // map-level for this temporary layer to init its resolutions |
---|
| 128 | // correctly |
---|
| 129 | calculateInRange: OpenLayers.Function.True |
---|
| 130 | }, this.layerOptions); |
---|
| 131 | this.layer = new OpenLayers.Layer.Vector(this.CLASS_NAME, options); |
---|
| 132 | this.map.addLayer(this.layer); |
---|
| 133 | return true; |
---|
| 134 | }, |
---|
| 135 | |
---|
| 136 | /** |
---|
| 137 | * Method: createFeature |
---|
| 138 | * Add temporary features |
---|
| 139 | * |
---|
| 140 | * Parameters: |
---|
| 141 | * pixel - {<OpenLayers.Pixel>} A pixel location on the map. |
---|
| 142 | */ |
---|
| 143 | createFeature: function(pixel) { |
---|
| 144 | var lonlat = this.map.getLonLatFromPixel(pixel); |
---|
| 145 | this.point = new OpenLayers.Feature.Vector( |
---|
| 146 | new OpenLayers.Geometry.Point(lonlat.lon, lonlat.lat) |
---|
| 147 | ); |
---|
| 148 | this.callback("create", [this.point.geometry, this.point]); |
---|
| 149 | this.point.geometry.clearBounds(); |
---|
| 150 | this.layer.addFeatures([this.point], {silent: true}); |
---|
| 151 | }, |
---|
| 152 | |
---|
| 153 | /** |
---|
| 154 | * APIMethod: deactivate |
---|
| 155 | * turn off the handler |
---|
| 156 | */ |
---|
| 157 | deactivate: function() { |
---|
| 158 | if(!OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) { |
---|
| 159 | return false; |
---|
| 160 | } |
---|
| 161 | // call the cancel callback if mid-drawing |
---|
| 162 | if(this.drawing) { |
---|
| 163 | this.cancel(); |
---|
| 164 | } |
---|
| 165 | this.destroyFeature(); |
---|
| 166 | // If a layer's map property is set to null, it means that that layer |
---|
| 167 | // isn't added to the map. Since we ourself added the layer to the map |
---|
| 168 | // in activate(), we can assume that if this.layer.map is null it means |
---|
| 169 | // that the layer has been destroyed (as a result of map.destroy() for |
---|
| 170 | // example. |
---|
| 171 | if (this.layer.map != null) { |
---|
| 172 | this.layer.destroy(false); |
---|
| 173 | } |
---|
| 174 | this.layer = null; |
---|
| 175 | return true; |
---|
| 176 | }, |
---|
| 177 | |
---|
| 178 | /** |
---|
| 179 | * Method: destroyFeature |
---|
| 180 | * Destroy the temporary geometries |
---|
| 181 | */ |
---|
| 182 | destroyFeature: function() { |
---|
| 183 | if(this.layer) { |
---|
| 184 | this.layer.destroyFeatures(); |
---|
| 185 | } |
---|
| 186 | this.point = null; |
---|
| 187 | }, |
---|
| 188 | |
---|
| 189 | /** |
---|
| 190 | * Method: finalize |
---|
| 191 | * Finish the geometry and call the "done" callback. |
---|
| 192 | * |
---|
| 193 | * Parameters: |
---|
| 194 | * cancel - {Boolean} Call cancel instead of done callback. Default is |
---|
| 195 | * false. |
---|
| 196 | */ |
---|
| 197 | finalize: function(cancel) { |
---|
| 198 | var key = cancel ? "cancel" : "done"; |
---|
| 199 | this.drawing = false; |
---|
| 200 | this.mouseDown = false; |
---|
| 201 | this.lastDown = null; |
---|
| 202 | this.lastUp = null; |
---|
| 203 | this.callback(key, [this.geometryClone()]); |
---|
| 204 | if(cancel || !this.persist) { |
---|
| 205 | this.destroyFeature(); |
---|
| 206 | } |
---|
| 207 | }, |
---|
| 208 | |
---|
| 209 | /** |
---|
| 210 | * APIMethod: cancel |
---|
| 211 | * Finish the geometry and call the "cancel" callback. |
---|
| 212 | */ |
---|
| 213 | cancel: function() { |
---|
| 214 | this.finalize(true); |
---|
| 215 | }, |
---|
| 216 | |
---|
| 217 | /** |
---|
| 218 | * Method: click |
---|
| 219 | * Handle clicks. Clicks are stopped from propagating to other listeners |
---|
| 220 | * on map.events or other dom elements. |
---|
| 221 | * |
---|
| 222 | * Parameters: |
---|
| 223 | * evt - {Event} The browser event |
---|
| 224 | * |
---|
| 225 | * Returns: |
---|
| 226 | * {Boolean} Allow event propagation |
---|
| 227 | */ |
---|
| 228 | click: function(evt) { |
---|
| 229 | OpenLayers.Event.stop(evt); |
---|
| 230 | return false; |
---|
| 231 | }, |
---|
| 232 | |
---|
| 233 | /** |
---|
| 234 | * Method: dblclick |
---|
| 235 | * Handle double-clicks. Double-clicks are stopped from propagating to other |
---|
| 236 | * listeners on map.events or other dom elements. |
---|
| 237 | * |
---|
| 238 | * Parameters: |
---|
| 239 | * evt - {Event} The browser event |
---|
| 240 | * |
---|
| 241 | * Returns: |
---|
| 242 | * {Boolean} Allow event propagation |
---|
| 243 | */ |
---|
| 244 | dblclick: function(evt) { |
---|
| 245 | OpenLayers.Event.stop(evt); |
---|
| 246 | return false; |
---|
| 247 | }, |
---|
| 248 | |
---|
| 249 | /** |
---|
| 250 | * Method: modifyFeature |
---|
| 251 | * Modify the existing geometry given a pixel location. |
---|
| 252 | * |
---|
| 253 | * Parameters: |
---|
| 254 | * pixel - {<OpenLayers.Pixel>} A pixel location on the map. |
---|
| 255 | */ |
---|
| 256 | modifyFeature: function(pixel) { |
---|
| 257 | var lonlat = this.map.getLonLatFromPixel(pixel); |
---|
| 258 | this.point.geometry.x = lonlat.lon; |
---|
| 259 | this.point.geometry.y = lonlat.lat; |
---|
| 260 | this.callback("modify", [this.point.geometry, this.point]); |
---|
| 261 | this.point.geometry.clearBounds(); |
---|
| 262 | this.drawFeature(); |
---|
| 263 | }, |
---|
| 264 | |
---|
| 265 | /** |
---|
| 266 | * Method: drawFeature |
---|
| 267 | * Render features on the temporary layer. |
---|
| 268 | */ |
---|
| 269 | drawFeature: function() { |
---|
| 270 | this.layer.drawFeature(this.point, this.style); |
---|
| 271 | }, |
---|
| 272 | |
---|
| 273 | /** |
---|
| 274 | * Method: getGeometry |
---|
| 275 | * Return the sketch geometry. If <multi> is true, this will return |
---|
| 276 | * a multi-part geometry. |
---|
| 277 | * |
---|
| 278 | * Returns: |
---|
| 279 | * {<OpenLayers.Geometry.Point>} |
---|
| 280 | */ |
---|
| 281 | getGeometry: function() { |
---|
| 282 | var geometry = this.point && this.point.geometry; |
---|
| 283 | if(geometry && this.multi) { |
---|
| 284 | geometry = new OpenLayers.Geometry.MultiPoint([geometry]); |
---|
| 285 | } |
---|
| 286 | return geometry; |
---|
| 287 | }, |
---|
| 288 | |
---|
| 289 | /** |
---|
| 290 | * Method: geometryClone |
---|
| 291 | * Return a clone of the relevant geometry. |
---|
| 292 | * |
---|
| 293 | * Returns: |
---|
| 294 | * {<OpenLayers.Geometry>} |
---|
| 295 | */ |
---|
| 296 | geometryClone: function() { |
---|
| 297 | var geom = this.getGeometry(); |
---|
| 298 | return geom && geom.clone(); |
---|
| 299 | }, |
---|
| 300 | |
---|
| 301 | /** |
---|
| 302 | * Method: mousedown |
---|
| 303 | * Handle mouse down. Adjust the geometry and redraw. |
---|
| 304 | * Return determines whether to propagate the event on the map. |
---|
| 305 | * |
---|
| 306 | * Parameters: |
---|
| 307 | * evt - {Event} The browser event |
---|
| 308 | * |
---|
| 309 | * Returns: |
---|
| 310 | * {Boolean} Allow event propagation |
---|
| 311 | */ |
---|
| 312 | mousedown: function(evt) { |
---|
| 313 | // check keyboard modifiers |
---|
| 314 | if(!this.checkModifiers(evt)) { |
---|
| 315 | return true; |
---|
| 316 | } |
---|
| 317 | // ignore double-clicks |
---|
| 318 | if(this.lastDown && this.lastDown.equals(evt.xy)) { |
---|
| 319 | return true; |
---|
| 320 | } |
---|
| 321 | this.drawing = true; |
---|
| 322 | if(this.lastDown == null) { |
---|
| 323 | if(this.persist) { |
---|
| 324 | this.destroyFeature(); |
---|
| 325 | } |
---|
| 326 | this.createFeature(evt.xy); |
---|
| 327 | } else { |
---|
| 328 | this.modifyFeature(evt.xy); |
---|
| 329 | } |
---|
| 330 | this.lastDown = evt.xy; |
---|
| 331 | return false; |
---|
| 332 | }, |
---|
| 333 | |
---|
| 334 | /** |
---|
| 335 | * Method: mousemove |
---|
| 336 | * Handle mouse move. Adjust the geometry and redraw. |
---|
| 337 | * Return determines whether to propagate the event on the map. |
---|
| 338 | * |
---|
| 339 | * Parameters: |
---|
| 340 | * evt - {Event} The browser event |
---|
| 341 | * |
---|
| 342 | * Returns: |
---|
| 343 | * {Boolean} Allow event propagation |
---|
| 344 | */ |
---|
| 345 | mousemove: function (evt) { |
---|
| 346 | if(this.drawing) { |
---|
| 347 | this.modifyFeature(evt.xy); |
---|
| 348 | } |
---|
| 349 | return true; |
---|
| 350 | }, |
---|
| 351 | |
---|
| 352 | /** |
---|
| 353 | * Method: mouseup |
---|
| 354 | * Handle mouse up. Send the latest point in the geometry to the control. |
---|
| 355 | * Return determines whether to propagate the event on the map. |
---|
| 356 | * |
---|
| 357 | * Parameters: |
---|
| 358 | * evt - {Event} The browser event |
---|
| 359 | * |
---|
| 360 | * Returns: |
---|
| 361 | * {Boolean} Allow event propagation |
---|
| 362 | */ |
---|
| 363 | mouseup: function (evt) { |
---|
| 364 | if(this.drawing) { |
---|
| 365 | this.finalize(); |
---|
| 366 | return false; |
---|
| 367 | } else { |
---|
| 368 | return true; |
---|
| 369 | } |
---|
| 370 | }, |
---|
| 371 | |
---|
| 372 | CLASS_NAME: "OpenLayers.Handler.Point" |
---|
| 373 | }); |
---|