diff --git a/examples/select-feature.html b/examples/select-feature.html index c4cf04da56..1548e980d1 100644 --- a/examples/select-feature.html +++ b/examples/select-feature.html @@ -19,22 +19,18 @@ var wmsLayer = new OpenLayers.Layer.WMS( "OpenLayers WMS", "http://labs.metacarta.com/wms/vmap0?", {layers: 'basic'}); - var pointLayer = new OpenLayers.Layer.Vector("Point Layer"); - var lineLayer = new OpenLayers.Layer.Vector("Line Layer"); var polygonLayer = new OpenLayers.Layer.Vector("Polygon Layer"); - map.addLayers([wmsLayer, pointLayer, lineLayer, polygonLayer]); + map.addLayers([wmsLayer, polygonLayer]); map.addControl(new OpenLayers.Control.LayerSwitcher()); map.addControl(new OpenLayers.Control.MousePosition()); drawControls = { - point: new OpenLayers.Control.DrawFeature(pointLayer, - OpenLayers.Handler.Point), - line: new OpenLayers.Control.DrawFeature(lineLayer, - OpenLayers.Handler.Path), polygon: new OpenLayers.Control.DrawFeature(polygonLayer, OpenLayers.Handler.Polygon), - select: new OpenLayers.Control.SelectFeature(polygonLayer) + select: new OpenLayers.Control.SelectFeature(polygonLayer), + hover: new OpenLayers.Control.SelectFeature(polygonLayer, + {hover: true}) }; for(var key in drawControls) { @@ -67,20 +63,19 @@
  • - - -
  • -
  • - - -
  • -
  • - +
  • - - + + +
  • +
  • + +
  • diff --git a/lib/OpenLayers.js b/lib/OpenLayers.js index 9a55fb2e97..ca93bb0904 100644 --- a/lib/OpenLayers.js +++ b/lib/OpenLayers.js @@ -96,7 +96,7 @@ if (typeof(_OPENLAYERS_SFL_) == "undefined") { "OpenLayers/Handler/Point.js", "OpenLayers/Handler/Path.js", "OpenLayers/Handler/Polygon.js", - "OpenLayers/Handler/Select.js", + "OpenLayers/Handler/Feature.js", "OpenLayers/Handler/Drag.js", "OpenLayers/Handler/Box.js", "OpenLayers/Handler/MouseWheel.js", diff --git a/lib/OpenLayers/Control/SelectFeature.js b/lib/OpenLayers/Control/SelectFeature.js index 0b740ffb0b..3ea8db341f 100644 --- a/lib/OpenLayers/Control/SelectFeature.js +++ b/lib/OpenLayers/Control/SelectFeature.js @@ -14,15 +14,21 @@ OpenLayers.Control.SelectFeature = OpenLayers.Class.create(); OpenLayers.Control.SelectFeature.prototype = OpenLayers.Class.inherit(OpenLayers.Control, { + /** + * @type {Boolean} Allow selection of multiple geometries + */ + multiple: false, + + /** + * @type {Boolean} Select on mouse over and deselect on mouse out. If + * true, this ignores clicks and only listens to mouse moves. + */ + hover: false, + /** * @type {OpenLayers.Layer.Vector} */ layer: null, - - /** - * @type {OpenLayers.Handler.Select} - */ - handler: null, /** * @type {Object} The functions that are sent to the handler for callback @@ -35,15 +41,10 @@ OpenLayers.Control.SelectFeature.prototype = selectStyle: OpenLayers.Feature.Vector.style['select'], /** - * @type {Object} Hash of styles + * @type {OpenLayers.Handler.Feature} * @private */ - originalStyle: null, - - /** - * @type {Boolean} Allow selection of multiple geometries - */ - multiple: false, + handler: null, /** * @param {OpenLayers.Layer.Vector} layer @@ -52,16 +53,26 @@ OpenLayers.Control.SelectFeature.prototype = */ initialize: function(layer, options) { OpenLayers.Control.prototype.initialize.apply(this, [options]); - this.callbacks = OpenLayers.Util.extend({down: this.downFeature}, - this.callbacks); + this.callbacks = OpenLayers.Util.extend({ + down: this.downFeature, + over: this.overFeature, + out: this.outFeature + }, this.callbacks); this.layer = layer; - this.handler = new OpenLayers.Handler.Select(this, layer, this.callbacks); + this.handler = new OpenLayers.Handler.Feature(this, layer, this.callbacks); }, /** - * + * Called when the feature handler detects a mouse-down on a feature + * @param {OpenLayers.Geometry} */ downFeature: function(geometry) { + if(this.hover) { + return; + } + if(geometry.parent) { + geometry = geometry.parent; + } // Store feature style for restoration later if(geometry.feature.originalStyle == null) { geometry.feature.originalStyle = geometry.feature.style; @@ -69,20 +80,26 @@ OpenLayers.Control.SelectFeature.prototype = if (this.multiple) { if(OpenLayers.Util.indexOf(this.layer.selectedFeatures, geometry.feature) > -1) { - this.layer.renderer.drawGeometry(geometry, geometry.feature.originalStyle); - OpenLayers.Util.removeItem(this.layer.selectedFeatures, geometry.feature); + this.layer.renderer.drawGeometry(geometry, + geometry.feature.originalStyle); + OpenLayers.Util.removeItem(this.layer.selectedFeatures, + geometry.feature); } else { this.layer.selectedFeatures.push(geometry.feature); this.layer.renderer.drawGeometry(geometry, this.selectStyle); } } else { if(OpenLayers.Util.indexOf(this.layer.selectedFeatures, geometry.feature) > -1) { - this.layer.renderer.drawGeometry(geometry, geometry.feature.originalStyle); - OpenLayers.Util.removeItem(this.layer.selectedFeatures, geometry.feature); + this.layer.renderer.drawGeometry(geometry, + geometry.feature.originalStyle); + OpenLayers.Util.removeItem(this.layer.selectedFeatures, + geometry.feature); } else { if (this.layer.selectedFeatures) { for (var i = 0; i < this.layer.selectedFeatures.length; i++) { - this.layer.renderer.drawGeometry(this.layer.selectedFeatures[i].geometry, this.layer.selectedFeatures[i].originalStyle); + this.layer.renderer.drawGeometry( + this.layer.selectedFeatures[i].geometry, + this.layer.selectedFeatures[i].originalStyle); } OpenLayers.Util.clearArray(this.layer.selectedFeatures); } @@ -92,6 +109,45 @@ OpenLayers.Control.SelectFeature.prototype = } }, + /** + * Called when the feature handler detects a mouse-over on a feature. + * Only responds if this.hover is true. + * @param {OpenLayers.Geometry} + */ + overFeature: function(geometry) { + if(!this.hover) { + return; + } + if(geometry.parent) { + geometry = geometry.parent; + } + // Store feature style for restoration later + if(geometry.feature.originalStyle == null) { + geometry.feature.originalStyle = geometry.feature.style; + } + + if(!(OpenLayers.Util.indexOf(this.layer.selectedFeatures, geometry.feature) > -1)) { + this.layer.selectedFeatures.push(geometry.feature); + this.layer.renderer.drawGeometry(geometry, this.selectStyle); + } + }, + + /** + * Called when the feature handler detects a mouse-out on a feature. + * Only responds if this.hover is true. + * @param {OpenLayers.Geometry} + */ + outFeature: function(geometry) { + if(!this.hover) { + return; + } + if(geometry.parent) { + geometry = geometry.parent; + } + this.layer.renderer.drawGeometry(geometry, geometry.feature.originalStyle); + OpenLayers.Util.removeItem(this.layer.selectedFeatures, geometry.feature); + }, + /** Set the map property for the control. * * @param {OpenLayers.Map} map diff --git a/lib/OpenLayers/Handler/Select.js b/lib/OpenLayers/Handler/Feature.js similarity index 55% rename from lib/OpenLayers/Handler/Select.js rename to lib/OpenLayers/Handler/Feature.js index 8e137b6bff..dbf5a35a2d 100644 --- a/lib/OpenLayers/Handler/Select.js +++ b/lib/OpenLayers/Handler/Feature.js @@ -4,14 +4,15 @@ /** - * Handler to draw a path on the map. Polygon is displayed on mouse down, - * moves on mouse move, and is finished on mouse up. + * Handler to respond to mouse events related to a drawn feature. + * Callbacks will be called for over, move, out, up, and down (corresponding + * to the equivalent mouse events). * * @class * @requires OpenLayers/Handler.js */ -OpenLayers.Handler.Select = OpenLayers.Class.create(); -OpenLayers.Handler.Select.prototype = +OpenLayers.Handler.Feature = OpenLayers.Class.create(); +OpenLayers.Handler.Feature.prototype = OpenLayers.Class.inherit(OpenLayers.Handler, { /** @@ -19,6 +20,11 @@ OpenLayers.Handler.Select.prototype = */ layerIndex: null, + /** + * @type {OpenLayers.Geometry} + */ + geometry: null, + /** * @constructor * @@ -36,16 +42,19 @@ OpenLayers.Handler.Select.prototype = }, /** - * Handle mouse down. Call the "up" callback if down on a feature. + * Handle mouse down. Call the "down" callback if down on a feature. * * @param {Event} evt */ mousedown: function(evt) { - return this.select('down', evt); + var selected = this.select('down', evt); + return !selected; // stop event propagation if selected }, /** - * Handle mouse moves. Call the "over" callback if over a feature. + * Handle mouse moves. Call the "move" callback if moving over a feature. + * Call the "over" callback if moving over a feature for the first time. + * Call the "out" callback if moving off of a feature. * * @param {Event} evt */ @@ -55,37 +64,57 @@ OpenLayers.Handler.Select.prototype = }, /** - * Handle mouse moves. Call the "down" callback if up on a feature. + * Handle mouse moves. Call the "up" callback if up on a feature. * * @param {Event} evt */ mouseup: function(evt) { - return this.select('up', evt); + var selected = this.select('up', evt); + return !selected; // stop event propagation if selected }, /** - * Capture double-clicks. + * Capture double-clicks. Let the event continue propagating if the + * double-click doesn't hit a geometry. Otherwise call the dblclick + * callback. * + * @param {Event} evt */ dblclick: function(evt) { - return false; + var selected = this.select('dblclick', evt); + return !selected; // stop event propagation if selected }, /** * Trigger the appropriate callback if a feature is under the mouse. * * @param {String} type Callback key + * @type {Boolean} A feature was selected */ select: function(type, evt) { var geometry = this.layer.renderer.getGeometryFromEvent(evt); if(geometry) { - if (geometry.parent) { - geometry = geometry.parent; - } + // three cases: + // over a new, out of the last and over a new, or still on the last + if(!this.geometry) { + // over a new geometry + this.callback('over', [geometry]); + } else if(this.geometry != geometry) { + // out of the last and over a new + this.callback('out', [this.geometry]); + this.callback('over', [geometry]); + } + this.geometry = geometry; this.callback(type, [geometry]); - return false; // stop event propagation + return true; + } else { + if(this.geometry) { + // out of the last + this.callback('out', [this.geometry]); + this.geometry = null; + } + return false; } - return true; }, /** @@ -118,5 +147,5 @@ OpenLayers.Handler.Select.prototype = }, /** @final @type String */ - CLASS_NAME: "OpenLayers.Handler.Select" + CLASS_NAME: "OpenLayers.Handler.Feature" });