1
/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
2
* license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
3
* full text of the license. */
7
* @requires OpenLayers/Control.js
8
* @requires OpenLayers/Feature/Vector.js
9
* @requires OpenLayers/Handler/Feature.js
13
* Class: OpenLayers.Control.SelectFeature
14
* Selects vector features from a given layer on click or hover.
17
* - <OpenLayers.Control>
19
OpenLayers.Control.SelectFeature = OpenLayers.Class(OpenLayers.Control, {
22
* Property: multipleKey
23
* {String} An event modifier ('altKey' or 'shiftKey') that temporarily sets
24
* the <multiple> property to true. Default is null.
30
* {String} An event modifier ('altKey' or 'shiftKey') that temporarily sets
31
* the <toggle> property to true. Default is null.
36
* APIProperty: multiple
37
* {Boolean} Allow selection of multiple geometries. Default is false.
42
* APIProperty: clickout
43
* {Boolean} Unselect features when clicking outside any feature.
50
* {Boolean} Unselect a selected feature on click. Default is false. Only
51
* has meaning if hover is false.
57
* {Boolean} Select on mouse over and deselect on mouse out. If true, this
58
* ignores clicks and only listens to mouse moves.
64
* {Boolean} Allow feature selection by drawing a box.
69
* Property: onBeforeSelect
70
* {Function} Optional function to be called before a feature is selected.
71
* The function should expect to be called with a feature.
73
onBeforeSelect: function() {},
76
* APIProperty: onSelect
77
* {Function} Optional function to be called when a feature is selected.
78
* The function should expect to be called with a feature.
80
onSelect: function() {},
83
* APIProperty: onUnselect
84
* {Function} Optional function to be called when a feature is unselected.
85
* The function should expect to be called with a feature.
87
onUnselect: function() {},
91
* {Object} The scope to use with the onBeforeSelect, onSelect, onUnselect
92
* callbacks. If null the scope will be this control.
97
* APIProperty: geometryTypes
98
* {Array(String)} To restrict selecting to a limited set of geometry types,
99
* send a list of strings corresponding to the geometry class names.
105
* {<OpenLayers.Layer.Vector>}
110
* APIProperty: callbacks
111
* {Object} The functions that are sent to the handlers.feature for callback
116
* APIProperty: selectStyle
117
* {Object} Hash of styles
122
* Property: renderIntent
123
* {String} key used to retrieve the select style from the layer's
126
renderIntent: "select",
130
* {Object} Object with references to multiple <OpenLayers.Handler>
136
* Constructor: <OpenLayers.Control.SelectFeature>
139
* layer - {<OpenLayers.Layer.Vector>}
142
initialize: function(layer, options) {
143
OpenLayers.Control.prototype.initialize.apply(this, [options]);
146
click: this.clickFeature,
147
clickout: this.clickoutFeature
150
callbacks.over = this.overFeature;
151
callbacks.out = this.outFeature;
154
this.callbacks = OpenLayers.Util.extend(callbacks, this.callbacks);
156
feature: new OpenLayers.Handler.Feature(
157
this, layer, this.callbacks, {geometryTypes: this.geometryTypes}
162
this.handlers.box = new OpenLayers.Handler.Box(
163
this, {done: this.selectBox},
164
{boxDivClassName: "olHandlerBoxSelectFeature"}
171
* Activates the control.
174
* {Boolean} The control was effectively activated.
176
activate: function () {
178
this.handlers.feature.activate();
179
if(this.box && this.handlers.box) {
180
this.handlers.box.activate();
183
return OpenLayers.Control.prototype.activate.apply(
190
* Deactivates the control.
193
* {Boolean} The control was effectively deactivated.
195
deactivate: function () {
197
this.handlers.feature.deactivate();
198
if(this.handlers.box) {
199
this.handlers.box.deactivate();
202
return OpenLayers.Control.prototype.deactivate.apply(
208
* Method: unselectAll
209
* Unselect all selected features. To unselect all except for a single
210
* feature, set the options.except property to the feature.
213
* options - {Object} Optional configuration object.
215
unselectAll: function(options) {
216
// we'll want an option to supress notification here
218
for(var i=this.layer.selectedFeatures.length-1; i>=0; --i) {
219
feature = this.layer.selectedFeatures[i];
220
if(!options || options.except != feature) {
221
this.unselect(feature);
227
* Method: clickFeature
228
* Called on click in a feature
229
* Only responds if this.hover is false.
232
* feature - {<OpenLayers.Feature.Vector>}
234
clickFeature: function(feature) {
236
var selected = (OpenLayers.Util.indexOf(this.layer.selectedFeatures,
239
if(this.toggleSelect()) {
240
this.unselect(feature);
241
} else if(!this.multipleSelect()) {
242
this.unselectAll({except: feature});
245
if(!this.multipleSelect()) {
246
this.unselectAll({except: feature});
248
this.select(feature);
254
* Method: multipleSelect
255
* Allow for multiple selected features based on <multiple> property and
256
* <multipleKey> event modifier.
259
* {Boolean} Allow for multiple selected features.
261
multipleSelect: function() {
262
return this.multiple || this.handlers.feature.evt[this.multipleKey];
266
* Method: toggleSelect
267
* Event should toggle the selected state of a feature based on <toggle>
268
* property and <toggleKey> event modifier.
271
* {Boolean} Toggle the selected state of a feature.
273
toggleSelect: function() {
274
return this.toggle || this.handlers.feature.evt[this.toggleKey];
278
* Method: clickoutFeature
279
* Called on click outside a previously clicked (selected) feature.
280
* Only responds if this.hover is false.
283
* feature - {<OpenLayers.Vector.Feature>}
285
clickoutFeature: function(feature) {
286
if(!this.hover && this.clickout) {
292
* Method: overFeature
293
* Called on over a feature.
294
* Only responds if this.hover is true.
297
* feature - {<OpenLayers.Feature.Vector>}
299
overFeature: function(feature) {
301
(OpenLayers.Util.indexOf(this.layer.selectedFeatures, feature) == -1)) {
302
this.select(feature);
308
* Called on out of a selected feature.
309
* Only responds if this.hover is true.
312
* feature - {<OpenLayers.Feature.Vector>}
314
outFeature: function(feature) {
316
this.unselect(feature);
322
* Add feature to the layer's selectedFeature array, render the feature as
323
* selected, and call the onSelect function.
326
* feature - {<OpenLayers.Feature.Vector>}
328
select: function(feature) {
329
var cont = this.onBeforeSelect.call(this.scope, feature);
331
cont = this.layer.events.triggerEvent("beforefeatureselected", {
335
this.layer.selectedFeatures.push(feature);
337
var selectStyle = this.selectStyle || this.renderIntent;
339
this.layer.drawFeature(feature, selectStyle);
340
this.layer.events.triggerEvent("featureselected", {feature: feature});
341
this.onSelect.call(this.scope, feature);
348
* Remove feature from the layer's selectedFeature array, render the feature as
349
* normal, and call the onUnselect function.
352
* feature - {<OpenLayers.Feature.Vector>}
354
unselect: function(feature) {
355
// Store feature style for restoration later
356
this.layer.drawFeature(feature, "default");
357
OpenLayers.Util.removeItem(this.layer.selectedFeatures, feature);
358
this.layer.events.triggerEvent("featureunselected", {feature: feature});
359
this.onUnselect.call(this.scope, feature);
364
* Callback from the handlers.box set up when <box> selection is true
368
* position - {<OpenLayers.Bounds> || <OpenLayers.Pixel> }
370
selectBox: function(position) {
371
if (position instanceof OpenLayers.Bounds) {
372
var minXY = this.map.getLonLatFromPixel(
373
new OpenLayers.Pixel(position.left, position.bottom)
375
var maxXY = this.map.getLonLatFromPixel(
376
new OpenLayers.Pixel(position.right, position.top)
378
var bounds = new OpenLayers.Bounds(
379
minXY.lon, minXY.lat, maxXY.lon, maxXY.lat
382
// if multiple is false, first deselect currently selected features
383
if (!this.multipleSelect()) {
387
// because we're using a box, we consider we want multiple selection
388
var prevMultiple = this.multiple;
389
this.multiple = true;
390
for(var i=0, len = this.layer.features.length; i<len; ++i) {
391
var feature = this.layer.features[i];
392
if (this.geometryTypes == null || OpenLayers.Util.indexOf(
393
this.geometryTypes, feature.geometry.CLASS_NAME) > -1) {
394
if (bounds.toGeometry().intersects(feature.geometry)) {
395
if (OpenLayers.Util.indexOf(this.layer.selectedFeatures, feature) == -1) {
396
this.select(feature);
401
this.multiple = prevMultiple;
407
* Set the map property for the control.
410
* map - {<OpenLayers.Map>}
412
setMap: function(map) {
413
this.handlers.feature.setMap(map);
415
this.handlers.box.setMap(map);
417
OpenLayers.Control.prototype.setMap.apply(this, arguments);
420
CLASS_NAME: "OpenLayers.Control.SelectFeature"