Converting control to an interaction
To dispatch events, the interaction base class now inherits from goog.events.EventTarget.
This commit is contained in:
@@ -9,52 +9,6 @@
|
|||||||
<link rel="stylesheet" href="../resources/layout.css" type="text/css">
|
<link rel="stylesheet" href="../resources/layout.css" type="text/css">
|
||||||
<link rel="stylesheet" href="../resources/bootstrap/css/bootstrap-responsive.min.css" type="text/css">
|
<link rel="stylesheet" href="../resources/bootstrap/css/bootstrap-responsive.min.css" type="text/css">
|
||||||
<title>Select features example</title>
|
<title>Select features example</title>
|
||||||
<style type="text/css">
|
|
||||||
/* TODO: remove this after css/button refactoring */
|
|
||||||
.ol-select {
|
|
||||||
position: absolute;
|
|
||||||
background: rgba(255,255,255,0.4);
|
|
||||||
border-radius: 4px;
|
|
||||||
left: 8px;
|
|
||||||
padding: 2px;
|
|
||||||
top: 65px;
|
|
||||||
}
|
|
||||||
@media print {
|
|
||||||
.ol-select {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.ol-select a {
|
|
||||||
display: block;
|
|
||||||
margin: 1px;
|
|
||||||
padding: 0;
|
|
||||||
color: white;
|
|
||||||
font-size: 16px;
|
|
||||||
font-family: 'Lucida Grande',Verdana,Geneva,Lucida,Arial,Helvetica,sans-serif;
|
|
||||||
font-weight: bold;
|
|
||||||
text-decoration: none;
|
|
||||||
text-align: center;
|
|
||||||
height: 22px;
|
|
||||||
width: 22px;
|
|
||||||
background-color: rgba(0, 60, 136, 0.2);
|
|
||||||
border-radius: 2px;
|
|
||||||
}
|
|
||||||
.ol-touch .ol-select a {
|
|
||||||
font-size: 20px;
|
|
||||||
height: 30px;
|
|
||||||
width: 30px;
|
|
||||||
line-height: 26px;
|
|
||||||
}
|
|
||||||
.ol-select.active a {
|
|
||||||
background-color: rgba(0, 60, 136, 0.6);
|
|
||||||
}
|
|
||||||
.ol-select a:hover {
|
|
||||||
background-color: rgba(0, 60, 136, 0.7);
|
|
||||||
}
|
|
||||||
.ol-select a:after {
|
|
||||||
content: "S";
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
@@ -84,7 +38,7 @@
|
|||||||
|
|
||||||
<div class="span12">
|
<div class="span12">
|
||||||
<h4 id="title">Select features example</h4>
|
<h4 id="title">Select features example</h4>
|
||||||
<p id="shortdesc">Example of using the Select control. Select features by clicking polygons. Hold the Shift-key to add to the selection. Click the 'S' button to toggle the control's active state.</p>
|
<p id="shortdesc">Example of using the Select interaction. Select features by clicking polygons. Hold the Shift-key to add to the selection.</p>
|
||||||
<div id="docs">
|
<div id="docs">
|
||||||
<p>See the <a href="select-features.js" target="_blank">select-features.js source</a> to see how this is done.</p>
|
<p>See the <a href="select-features.js" target="_blank">select-features.js source</a> to see how this is done.</p>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
goog.require('ol.Map');
|
goog.require('ol.Map');
|
||||||
goog.require('ol.RendererHint');
|
goog.require('ol.RendererHint');
|
||||||
goog.require('ol.View2D');
|
goog.require('ol.View2D');
|
||||||
goog.require('ol.control.Select');
|
goog.require('ol.interaction.Select');
|
||||||
goog.require('ol.control.defaults');
|
goog.require('ol.interaction.defaults');
|
||||||
goog.require('ol.layer.TileLayer');
|
goog.require('ol.layer.TileLayer');
|
||||||
goog.require('ol.layer.Vector');
|
goog.require('ol.layer.Vector');
|
||||||
goog.require('ol.parser.ogc.GML_v3');
|
goog.require('ol.parser.ogc.GML_v3');
|
||||||
@@ -46,12 +46,12 @@ var vector = new ol.layer.Vector({
|
|||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
var selectControl = new ol.control.Select({
|
var selectInteraction = new ol.interaction.Select({
|
||||||
layerFilter: function(layer) { return layer === vector; }
|
layerFilter: function(layer) { return layer === vector; }
|
||||||
});
|
});
|
||||||
|
|
||||||
var map = new ol.Map({
|
var map = new ol.Map({
|
||||||
controls: ol.control.defaults().extend([selectControl]),
|
interactions: ol.interaction.defaults().extend([selectInteraction]),
|
||||||
layers: [raster, vector],
|
layers: [raster, vector],
|
||||||
renderer: ol.RendererHint.CANVAS,
|
renderer: ol.RendererHint.CANVAS,
|
||||||
target: 'map',
|
target: 'map',
|
||||||
@@ -60,5 +60,3 @@ var map = new ol.Map({
|
|||||||
zoom: 4
|
zoom: 4
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
selectControl.activate();
|
|
||||||
|
|||||||
@@ -201,16 +201,6 @@
|
|||||||
* Default is '' (empty string).
|
* Default is '' (empty string).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
|
||||||
* @typedef {Object} ol.control.SelectOptions
|
|
||||||
* @property {string|undefined} className CSS class name. Default is 'ol-select'.
|
|
||||||
* @property {Element|undefined} element Element.
|
|
||||||
* @property {undefined|function(ol.layer.Layer):boolean} layerFilter Filter
|
|
||||||
* function to restrict selection to a subset of layers.
|
|
||||||
* @property {ol.Map|undefined} map Map.
|
|
||||||
* @property {Element|undefined} target Target.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {Object} ol.control.ScaleLineOptions
|
* @typedef {Object} ol.control.ScaleLineOptions
|
||||||
* @property {string|undefined} className CSS Class name. Default is 'ol-scale-line'.
|
* @property {string|undefined} className CSS Class name. Default is 'ol-scale-line'.
|
||||||
@@ -305,6 +295,12 @@
|
|||||||
* @property {number|undefined} delta Delta.
|
* @property {number|undefined} delta Delta.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {Object} ol.interaction.SelectOptions
|
||||||
|
* @property {undefined|function(ol.layer.Layer):boolean} layerFilter Filter
|
||||||
|
* function to restrict selection to a subset of layers.
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {Object} ol.interaction.TouchPanOptions
|
* @typedef {Object} ol.interaction.TouchPanOptions
|
||||||
* @property {ol.Kinetic|undefined} kinetic Kinetic.
|
* @property {ol.Kinetic|undefined} kinetic Kinetic.
|
||||||
|
|||||||
@@ -1,3 +0,0 @@
|
|||||||
@exportClass ol.control.Select ol.control.SelectOptions
|
|
||||||
@exportProperty ol.control.Select.prototype.activate
|
|
||||||
@exportProperty ol.control.Select.prototype.deactivate
|
|
||||||
@@ -1,235 +0,0 @@
|
|||||||
goog.provide('ol.control.Select');
|
|
||||||
|
|
||||||
goog.require('goog.array');
|
|
||||||
goog.require('goog.dom');
|
|
||||||
goog.require('goog.dom.TagName');
|
|
||||||
goog.require('goog.dom.classes');
|
|
||||||
goog.require('goog.events');
|
|
||||||
goog.require('goog.events.EventType');
|
|
||||||
goog.require('ol.MapBrowserEvent.EventType');
|
|
||||||
goog.require('ol.control.Control');
|
|
||||||
goog.require('ol.css');
|
|
||||||
goog.require('ol.interaction.condition');
|
|
||||||
goog.require('ol.layer.Vector');
|
|
||||||
goog.require('ol.layer.VectorLayerRenderIntent');
|
|
||||||
goog.require('ol.source.Vector');
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @typedef {{layer: ol.layer.Layer,
|
|
||||||
* selected: (Array.<ol.Feature>|undefined),
|
|
||||||
* type: goog.events.EventType,
|
|
||||||
* unselected: (Array.<ol.Feature>|undefined)}}
|
|
||||||
*/
|
|
||||||
ol.control.SelectEventObject;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @constructor
|
|
||||||
* @extends {ol.control.Control}
|
|
||||||
* @param {ol.control.SelectOptions=} opt_options Options.
|
|
||||||
*/
|
|
||||||
ol.control.Select = function(opt_options) {
|
|
||||||
var options = goog.isDef(opt_options) ? opt_options : {};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @type {boolean}
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
this.active_ = false;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Mapping between original features and cloned features on selection layers.
|
|
||||||
* @type {Object.<*,Object.<string,ol.Feature>>}
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
this.featureMap_ = {};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Mapping between original layers and selection layers.
|
|
||||||
* @type {Object.<*,ol.layer.Vector>}
|
|
||||||
* @protected
|
|
||||||
*/
|
|
||||||
this.selectionLayers = {};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @type {null|function(ol.layer.Layer):boolean}
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
this.layerFilter_ = goog.isDef(options.layerFilter) ?
|
|
||||||
options.layerFilter : null;
|
|
||||||
|
|
||||||
// TODO: css/button refactoring
|
|
||||||
var className = goog.isDef(options.className) ? options.className :
|
|
||||||
'ol-select';
|
|
||||||
|
|
||||||
var element = goog.dom.createDom(goog.dom.TagName.DIV, {
|
|
||||||
'class': className + ' ' + ol.css.CLASS_UNSELECTABLE
|
|
||||||
});
|
|
||||||
var button = goog.dom.createDom(goog.dom.TagName.A, {
|
|
||||||
'href': '#Select'
|
|
||||||
});
|
|
||||||
goog.dom.appendChild(element, button);
|
|
||||||
|
|
||||||
goog.events.listen(element, [
|
|
||||||
goog.events.EventType.TOUCHEND,
|
|
||||||
goog.events.EventType.CLICK
|
|
||||||
], this.toggleActive_, false, this);
|
|
||||||
|
|
||||||
goog.base(this, {
|
|
||||||
element: element,
|
|
||||||
map: options.map,
|
|
||||||
target: options.target
|
|
||||||
});
|
|
||||||
};
|
|
||||||
goog.inherits(ol.control.Select, ol.control.Control);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {goog.events.BrowserEvent} browserEvent Browser event.
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
ol.control.Select.prototype.toggleActive_ = function(browserEvent) {
|
|
||||||
// prevent #Select anchor from getting appended to the url
|
|
||||||
browserEvent.preventDefault();
|
|
||||||
if (this.active_) {
|
|
||||||
this.deactivate();
|
|
||||||
} else {
|
|
||||||
this.activate();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Activate the control.
|
|
||||||
*/
|
|
||||||
ol.control.Select.prototype.activate = function() {
|
|
||||||
if (!this.active_) {
|
|
||||||
this.active_ = true;
|
|
||||||
goog.dom.classes.add(this.element, 'active');
|
|
||||||
var map = this.getMap();
|
|
||||||
for (var i in this.selectionLayers) {
|
|
||||||
map.addLayer(this.selectionLayers[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Implement box selection
|
|
||||||
this.listenerKeys.push(
|
|
||||||
goog.events.listen(map, ol.MapBrowserEvent.EventType.CLICK,
|
|
||||||
this.handleClick, true, this));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Dectivate the control.
|
|
||||||
*/
|
|
||||||
ol.control.Select.prototype.deactivate = function() {
|
|
||||||
if (this.active_) {
|
|
||||||
if (!goog.array.isEmpty(this.listenerKeys)) {
|
|
||||||
goog.array.forEach(this.listenerKeys, goog.events.unlistenByKey);
|
|
||||||
this.listenerKeys.length = 0;
|
|
||||||
}
|
|
||||||
var map = this.getMap();
|
|
||||||
for (var i in this.selectionLayers) {
|
|
||||||
map.removeLayer(this.selectionLayers[i]);
|
|
||||||
}
|
|
||||||
goog.dom.classes.remove(this.element, 'active');
|
|
||||||
this.active_ = false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {ol.MapBrowserEvent} evt Event.
|
|
||||||
*/
|
|
||||||
ol.control.Select.prototype.handleClick = function(evt) {
|
|
||||||
var map = this.getMap();
|
|
||||||
var layers = map.getLayerGroup().getLayersArray();
|
|
||||||
if (!goog.isNull(this.layerFilter_)) {
|
|
||||||
layers = goog.array.filter(layers, this.layerFilter_);
|
|
||||||
}
|
|
||||||
var clear = !ol.interaction.condition.shiftKeyOnly(evt.browserEvent);
|
|
||||||
|
|
||||||
function select(featuresByLayer) {
|
|
||||||
this.select(featuresByLayer, layers, clear);
|
|
||||||
}
|
|
||||||
|
|
||||||
map.getFeatures({
|
|
||||||
layers: layers,
|
|
||||||
pixel: evt.getPixel(),
|
|
||||||
success: goog.bind(select, this)
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {Array.<Array.<ol.Feature>>} featuresByLayer Features by layer.
|
|
||||||
* @param {Array.<ol.layer.Layer>} layers The queried layers.
|
|
||||||
* @param {boolean} clear Whether the current layer content should be cleared.
|
|
||||||
*/
|
|
||||||
ol.control.Select.prototype.select = function(featuresByLayer, layers, clear) {
|
|
||||||
for (var i = 0, ii = featuresByLayer.length; i < ii; ++i) {
|
|
||||||
var layer = layers[i];
|
|
||||||
var layerId = goog.getUid(layer);
|
|
||||||
var selectionLayer = this.selectionLayers[layerId];
|
|
||||||
if (!goog.isDef(selectionLayer)) {
|
|
||||||
selectionLayer = new ol.layer.Vector({
|
|
||||||
source: new ol.source.Vector({parser: null}),
|
|
||||||
style: layer.getStyle()
|
|
||||||
});
|
|
||||||
selectionLayer.setTemporary(true);
|
|
||||||
this.getMap().addLayer(selectionLayer);
|
|
||||||
this.selectionLayers[layerId] = selectionLayer;
|
|
||||||
this.featureMap_[layerId] = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
var features = featuresByLayer[i];
|
|
||||||
var numFeatures = features.length;
|
|
||||||
var selectedFeatures = [];
|
|
||||||
var featuresToAdd = [];
|
|
||||||
var unselectedFeatures = [];
|
|
||||||
var featuresToRemove = [];
|
|
||||||
var featureMap = this.featureMap_[layerId];
|
|
||||||
for (var j = 0; j < numFeatures; ++j) {
|
|
||||||
var feature = features[j];
|
|
||||||
var featureId = goog.getUid(feature);
|
|
||||||
var clone = featureMap[featureId];
|
|
||||||
if (clone) {
|
|
||||||
// TODO: make toggle configurable
|
|
||||||
unselectedFeatures.push(feature);
|
|
||||||
featuresToRemove.push(clone);
|
|
||||||
delete featureMap[featureId];
|
|
||||||
}
|
|
||||||
if (clear) {
|
|
||||||
for (var f in featureMap) {
|
|
||||||
unselectedFeatures.push(layer.getFeatureWithUid(f));
|
|
||||||
featuresToRemove.push(featureMap[f]);
|
|
||||||
}
|
|
||||||
featureMap = {};
|
|
||||||
this.featureMap_[layerId] = featureMap;
|
|
||||||
}
|
|
||||||
if (!clone) {
|
|
||||||
clone = feature.clone();
|
|
||||||
featureMap[featureId] = clone;
|
|
||||||
clone.renderIntent = ol.layer.VectorLayerRenderIntent.SELECTED;
|
|
||||||
selectedFeatures.push(feature);
|
|
||||||
featuresToAdd.push(clone);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (goog.isFunction(layer.setRenderIntent)) {
|
|
||||||
layer.setRenderIntent(ol.layer.VectorLayerRenderIntent.HIDDEN,
|
|
||||||
selectedFeatures);
|
|
||||||
layer.setRenderIntent(ol.layer.VectorLayerRenderIntent.DEFAULT,
|
|
||||||
unselectedFeatures);
|
|
||||||
}
|
|
||||||
selectionLayer.removeFeatures(featuresToRemove);
|
|
||||||
selectionLayer.addFeatures(featuresToAdd);
|
|
||||||
this.dispatchEvent(/** @type {ol.control.SelectEventObject} */ ({
|
|
||||||
layer: layer,
|
|
||||||
selected: selectedFeatures,
|
|
||||||
type: goog.events.EventType.CHANGE,
|
|
||||||
unselected: unselectedFeatures
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
goog.provide('ol.interaction.Interaction');
|
goog.provide('ol.interaction.Interaction');
|
||||||
|
|
||||||
|
goog.require('goog.events.EventTarget');
|
||||||
goog.require('ol.MapBrowserEvent');
|
goog.require('ol.MapBrowserEvent');
|
||||||
goog.require('ol.animation.pan');
|
goog.require('ol.animation.pan');
|
||||||
goog.require('ol.animation.rotate');
|
goog.require('ol.animation.rotate');
|
||||||
@@ -12,9 +13,12 @@ goog.require('ol.easing');
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @constructor
|
* @constructor
|
||||||
|
* @extends {goog.events.EventTarget}
|
||||||
*/
|
*/
|
||||||
ol.interaction.Interaction = function() {
|
ol.interaction.Interaction = function() {
|
||||||
|
goog.base(this);
|
||||||
};
|
};
|
||||||
|
goog.inherits(ol.interaction.Interaction, goog.events.EventTarget);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
2
src/ol/interaction/selectinteraction.exports
Normal file
2
src/ol/interaction/selectinteraction.exports
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
@exportClass ol.interaction.Select ol.interaction.SelectOptions
|
||||||
|
@exportProperty ol.interaction.Select.prototype.dispose
|
||||||
180
src/ol/interaction/selectinteraction.js
Normal file
180
src/ol/interaction/selectinteraction.js
Normal file
@@ -0,0 +1,180 @@
|
|||||||
|
goog.provide('ol.interaction.Select');
|
||||||
|
|
||||||
|
goog.require('goog.array');
|
||||||
|
goog.require('goog.asserts');
|
||||||
|
goog.require('goog.events');
|
||||||
|
goog.require('goog.events.EventType');
|
||||||
|
goog.require('ol.MapBrowserEvent.EventType');
|
||||||
|
goog.require('ol.interaction.Interaction');
|
||||||
|
goog.require('ol.interaction.condition');
|
||||||
|
goog.require('ol.layer.Vector');
|
||||||
|
goog.require('ol.layer.VectorLayerRenderIntent');
|
||||||
|
goog.require('ol.source.Vector');
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {{layer: ol.layer.Layer,
|
||||||
|
* map: ol.Map,
|
||||||
|
* selected: (Array.<ol.Feature>|undefined),
|
||||||
|
* type: goog.events.EventType,
|
||||||
|
* unselected: (Array.<ol.Feature>|undefined)}}
|
||||||
|
*/
|
||||||
|
ol.interaction.SelectEventObject;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @constructor
|
||||||
|
* @extends {ol.interaction.Interaction}
|
||||||
|
* @param {ol.interaction.SelectOptions=} opt_options Options.
|
||||||
|
*/
|
||||||
|
ol.interaction.Select = function(opt_options) {
|
||||||
|
var options = goog.isDef(opt_options) ? opt_options : {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mapping between original features and cloned features on selection layers.
|
||||||
|
* @type {Object.<*,Object.<*,ol.Feature>>}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
this.featureMap_ = {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mapping between original layers and selection layers, by map.
|
||||||
|
* @type {Object.<*,{map:ol.Map,layers:Object.<*,ol.layer.Vector>}>}
|
||||||
|
* @protected
|
||||||
|
*/
|
||||||
|
this.selectionLayers = {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {null|function(ol.layer.Layer):boolean}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
this.layerFilter_ = goog.isDef(options.layerFilter) ?
|
||||||
|
options.layerFilter : null;
|
||||||
|
|
||||||
|
goog.base(this);
|
||||||
|
};
|
||||||
|
goog.inherits(ol.interaction.Select, ol.interaction.Interaction);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
ol.interaction.Select.prototype.disposeInternal = function() {
|
||||||
|
for (var m in this.selectionLayers) {
|
||||||
|
var selectionLayers = this.selectionLayers[m].layers;
|
||||||
|
var map = this.selectionLayers[m].map;
|
||||||
|
for (var l in selectionLayers) {
|
||||||
|
map.removeLayer(selectionLayers[l]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
goog.base(this, 'disposeInternal');
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc.
|
||||||
|
*/
|
||||||
|
ol.interaction.Select.prototype.handleMapBrowserEvent = function(evt) {
|
||||||
|
if (evt.type === ol.MapBrowserEvent.EventType.CLICK) {
|
||||||
|
var map = evt.map;
|
||||||
|
var layers = map.getLayerGroup().getLayersArray();
|
||||||
|
if (!goog.isNull(this.layerFilter_)) {
|
||||||
|
layers = goog.array.filter(layers, this.layerFilter_);
|
||||||
|
}
|
||||||
|
var clear = !ol.interaction.condition.shiftKeyOnly(evt.browserEvent);
|
||||||
|
|
||||||
|
var select = function(featuresByLayer) {
|
||||||
|
this.select(map, featuresByLayer, layers, clear);
|
||||||
|
};
|
||||||
|
|
||||||
|
map.getFeatures({
|
||||||
|
layers: layers,
|
||||||
|
pixel: evt.getPixel(),
|
||||||
|
success: goog.bind(select, this)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// TODO: Implement box selection
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {ol.Map} map The map where the selction event originated.
|
||||||
|
* @param {Array.<Array.<ol.Feature>>} featuresByLayer Features by layer.
|
||||||
|
* @param {Array.<ol.layer.Layer>} layers The queried layers.
|
||||||
|
* @param {boolean} clear Whether the current layer content should be cleared.
|
||||||
|
*/
|
||||||
|
ol.interaction.Select.prototype.select =
|
||||||
|
function(map, featuresByLayer, layers, clear) {
|
||||||
|
var mapId = goog.getUid(map);
|
||||||
|
for (var i = 0, ii = featuresByLayer.length; i < ii; ++i) {
|
||||||
|
var layer = layers[i];
|
||||||
|
var layerId = goog.getUid(layer);
|
||||||
|
if (!(mapId in this.selectionLayers)) {
|
||||||
|
this.selectionLayers[mapId] = {map: map, layers: {}};
|
||||||
|
}
|
||||||
|
var selectionLayer = this.selectionLayers[mapId].layers[layerId];
|
||||||
|
if (!goog.isDef(selectionLayer)) {
|
||||||
|
goog.asserts.assertFunction(layer.getStyle,
|
||||||
|
'At least one of the layers has no "getStyle()" function.');
|
||||||
|
selectionLayer = new ol.layer.Vector({
|
||||||
|
source: new ol.source.Vector({parser: null}),
|
||||||
|
style: layer.getStyle()
|
||||||
|
});
|
||||||
|
selectionLayer.setTemporary(true);
|
||||||
|
map.addLayer(selectionLayer);
|
||||||
|
this.selectionLayers[mapId].layers[layerId] = selectionLayer;
|
||||||
|
this.featureMap_[layerId] = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
var features = featuresByLayer[i];
|
||||||
|
var numFeatures = features.length;
|
||||||
|
var selectedFeatures = [];
|
||||||
|
var featuresToAdd = [];
|
||||||
|
var unselectedFeatures = [];
|
||||||
|
var featuresToRemove = [];
|
||||||
|
var featureMap = this.featureMap_[layerId];
|
||||||
|
var oldFeatureMap = featureMap;
|
||||||
|
if (clear) {
|
||||||
|
for (var f in featureMap) {
|
||||||
|
unselectedFeatures.push(layer.getFeatureWithUid(f));
|
||||||
|
featuresToRemove.push(featureMap[f]);
|
||||||
|
}
|
||||||
|
featureMap = {};
|
||||||
|
this.featureMap_[layerId] = featureMap;
|
||||||
|
}
|
||||||
|
for (var j = 0; j < numFeatures; ++j) {
|
||||||
|
var feature = features[j];
|
||||||
|
var featureId = goog.getUid(feature);
|
||||||
|
var clone = featureMap[featureId];
|
||||||
|
if (clone) {
|
||||||
|
// TODO: make toggle configurable
|
||||||
|
unselectedFeatures.push(feature);
|
||||||
|
featuresToRemove.push(clone);
|
||||||
|
delete featureMap[featureId];
|
||||||
|
} else if (!(featureId in oldFeatureMap)) {
|
||||||
|
clone = feature.clone();
|
||||||
|
featureMap[featureId] = clone;
|
||||||
|
clone.renderIntent = ol.layer.VectorLayerRenderIntent.SELECTED;
|
||||||
|
selectedFeatures.push(feature);
|
||||||
|
featuresToAdd.push(clone);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (goog.isFunction(layer.setRenderIntent)) {
|
||||||
|
layer.setRenderIntent(ol.layer.VectorLayerRenderIntent.HIDDEN,
|
||||||
|
selectedFeatures);
|
||||||
|
layer.setRenderIntent(ol.layer.VectorLayerRenderIntent.DEFAULT,
|
||||||
|
unselectedFeatures);
|
||||||
|
}
|
||||||
|
selectionLayer.removeFeatures(featuresToRemove);
|
||||||
|
selectionLayer.addFeatures(featuresToAdd);
|
||||||
|
this.dispatchEvent(/** @type {ol.interaction.SelectEventObject} */ ({
|
||||||
|
layer: layer,
|
||||||
|
map: map,
|
||||||
|
selected: selectedFeatures,
|
||||||
|
type: goog.events.EventType.CHANGE,
|
||||||
|
unselected: unselectedFeatures
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -1,137 +0,0 @@
|
|||||||
goog.provide('ol.test.control.Select');
|
|
||||||
|
|
||||||
describe('ol.control.Select', function() {
|
|
||||||
var map, target, select, vector, features;
|
|
||||||
|
|
||||||
beforeEach(function() {
|
|
||||||
target = document.createElement('div');
|
|
||||||
target.style.width = '256px';
|
|
||||||
target.style.height = '256px';
|
|
||||||
document.body.appendChild(target);
|
|
||||||
map = new ol.Map({
|
|
||||||
target: target
|
|
||||||
});
|
|
||||||
features = ol.parser.GeoJSON.read(JSON.stringify({
|
|
||||||
'type': 'FeatureCollection',
|
|
||||||
'features': [{
|
|
||||||
'type': 'Feature',
|
|
||||||
'geometry': {
|
|
||||||
'type': 'Point',
|
|
||||||
'coordinates': [-1, 1]
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
'type': 'Feature',
|
|
||||||
'geometry': {
|
|
||||||
'type': 'Point',
|
|
||||||
'coordinates': [1, -1]
|
|
||||||
}
|
|
||||||
}]
|
|
||||||
}));
|
|
||||||
vector = new ol.layer.Vector({source: new ol.source.Vector({})});
|
|
||||||
vector.addFeatures(features);
|
|
||||||
select = new ol.control.Select({
|
|
||||||
layerFilter: function(layer) { return layer === vector; },
|
|
||||||
map: map
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(function() {
|
|
||||||
goog.dispose(select);
|
|
||||||
goog.dispose(map);
|
|
||||||
document.body.removeChild(target);
|
|
||||||
select = null;
|
|
||||||
map = null;
|
|
||||||
target = null;
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('DOM creation', function() {
|
|
||||||
|
|
||||||
it('creates the expected DOM elements', function() {
|
|
||||||
var selectButtons = goog.dom.getElementsByClass('ol-select', target),
|
|
||||||
selectButton = selectButtons[0],
|
|
||||||
hasUnselectableCls;
|
|
||||||
|
|
||||||
expect(selectButtons.length).to.be(1);
|
|
||||||
|
|
||||||
hasUnselectableCls = goog.dom.classes.has(selectButton,
|
|
||||||
'ol-unselectable');
|
|
||||||
expect(hasUnselectableCls).to.be(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('has an .active class only when activated', function() {
|
|
||||||
var selectButton = goog.dom.getElementsByClass('ol-select', target)[0];
|
|
||||||
select.activate();
|
|
||||||
expect(goog.dom.classes.has(selectButton, 'active')).to.be(true);
|
|
||||||
select.deactivate();
|
|
||||||
expect(goog.dom.classes.has(selectButton, 'active')).to.be(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('#activate and #deactivate', function() {
|
|
||||||
it('adds a temp layer to the map only when active and in use', function() {
|
|
||||||
expect(map.getLayers().getLength()).to.be(0);
|
|
||||||
select.activate();
|
|
||||||
expect(map.getLayers().getLength()).to.be(0);
|
|
||||||
select.select([features[0]], [vector]);
|
|
||||||
expect(map.getLayers().getLength()).to.be(1);
|
|
||||||
expect(map.getLayers().getAt(0).getTemporary()).to.be(true);
|
|
||||||
select.deactivate();
|
|
||||||
expect(map.getLayers().getLength()).to.be(0);
|
|
||||||
});
|
|
||||||
it('has a private property so it knows if it is active', function() {
|
|
||||||
expect(select.active_).to.be(false);
|
|
||||||
select.activate();
|
|
||||||
expect(select.active_).to.be(true);
|
|
||||||
select.deactivate();
|
|
||||||
expect(select.active_).to.be(false);
|
|
||||||
});
|
|
||||||
it('toggles active state on click', function() {
|
|
||||||
var selectButton = goog.dom.getElementsByClass('ol-select', target)[0];
|
|
||||||
var event = new goog.events.BrowserEvent({type: 'click'});
|
|
||||||
goog.events.fireListeners(selectButton, event.type, false, event);
|
|
||||||
expect(select.active_).to.be(true);
|
|
||||||
goog.events.fireListeners(selectButton, event.type, false, event);
|
|
||||||
expect(select.active_).to.be(false);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('#select', function() {
|
|
||||||
|
|
||||||
it('toggles selection of features', function() {
|
|
||||||
select.select([features], [vector]);
|
|
||||||
var layer = select.selectionLayers[goog.getUid(vector)];
|
|
||||||
expect(goog.object.getCount(layer.featureCache_.idLookup_)).to.be(2);
|
|
||||||
select.select([features], [vector]);
|
|
||||||
expect(goog.object.getCount(layer.featureCache_.idLookup_)).to.be(0);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('can append features to an existing selection', function() {
|
|
||||||
select.select([[features[0]]], [vector]);
|
|
||||||
select.select([[features[1]]], [vector]);
|
|
||||||
var layer = select.selectionLayers[goog.getUid(vector)];
|
|
||||||
expect(goog.object.getCount(layer.featureCache_.idLookup_)).to.be(2);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('can clear a selection before selecting new features', function() {
|
|
||||||
select.select([[features[0]]], [vector], true);
|
|
||||||
select.select([[features[1]]], [vector], true);
|
|
||||||
var layer = select.selectionLayers[goog.getUid(vector)];
|
|
||||||
expect(goog.object.getCount(layer.featureCache_.idLookup_)).to.be(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
goog.require('goog.dispose');
|
|
||||||
goog.require('goog.dom');
|
|
||||||
goog.require('goog.dom.classes');
|
|
||||||
goog.require('goog.events');
|
|
||||||
goog.require('goog.events.BrowserEvent');
|
|
||||||
goog.require('goog.object');
|
|
||||||
goog.require('ol.Map');
|
|
||||||
goog.require('ol.control.Select');
|
|
||||||
goog.require('ol.layer.Vector');
|
|
||||||
goog.require('ol.parser.GeoJSON');
|
|
||||||
goog.require('ol.source.Vector');
|
|
||||||
84
test/spec/ol/interaction/selectinteraction.test.js
Normal file
84
test/spec/ol/interaction/selectinteraction.test.js
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
goog.provide('ol.test.interaction.Select');
|
||||||
|
|
||||||
|
describe('ol.interaction.Select', function() {
|
||||||
|
var map, target, select, vector, features;
|
||||||
|
|
||||||
|
beforeEach(function() {
|
||||||
|
target = document.createElement('div');
|
||||||
|
target.style.width = '256px';
|
||||||
|
target.style.height = '256px';
|
||||||
|
document.body.appendChild(target);
|
||||||
|
map = new ol.Map({
|
||||||
|
target: target
|
||||||
|
});
|
||||||
|
features = ol.parser.GeoJSON.read(JSON.stringify({
|
||||||
|
'type': 'FeatureCollection',
|
||||||
|
'features': [{
|
||||||
|
'type': 'Feature',
|
||||||
|
'geometry': {
|
||||||
|
'type': 'Point',
|
||||||
|
'coordinates': [-1, 1]
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
'type': 'Feature',
|
||||||
|
'geometry': {
|
||||||
|
'type': 'Point',
|
||||||
|
'coordinates': [1, -1]
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
}));
|
||||||
|
vector = new ol.layer.Vector({source: new ol.source.Vector({})});
|
||||||
|
vector.addFeatures(features);
|
||||||
|
select = new ol.interaction.Select({
|
||||||
|
layerFilter: function(layer) { return layer === vector; }
|
||||||
|
});
|
||||||
|
map.getInteractions().push(select);
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(function() {
|
||||||
|
goog.dispose(select);
|
||||||
|
goog.dispose(map);
|
||||||
|
document.body.removeChild(target);
|
||||||
|
select = null;
|
||||||
|
map = null;
|
||||||
|
target = null;
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('#select', function() {
|
||||||
|
|
||||||
|
it('toggles selection of features', function() {
|
||||||
|
select.select(map, [features], [vector]);
|
||||||
|
var layer = select.selectionLayers[goog.getUid(map)]
|
||||||
|
.layers[goog.getUid(vector)];
|
||||||
|
expect(goog.object.getCount(layer.featureCache_.idLookup_)).to.be(2);
|
||||||
|
select.select(map, [features], [vector]);
|
||||||
|
expect(goog.object.getCount(layer.featureCache_.idLookup_)).to.be(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can append features to an existing selection', function() {
|
||||||
|
select.select(map, [[features[0]]], [vector]);
|
||||||
|
select.select(map, [[features[1]]], [vector]);
|
||||||
|
var layer = select.selectionLayers[goog.getUid(map)]
|
||||||
|
.layers[goog.getUid(vector)];
|
||||||
|
expect(goog.object.getCount(layer.featureCache_.idLookup_)).to.be(2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can clear a selection before selecting new features', function() {
|
||||||
|
select.select(map, [[features[0]]], [vector], true);
|
||||||
|
select.select(map, [[features[1]]], [vector], true);
|
||||||
|
var layer = select.selectionLayers[goog.getUid(map)]
|
||||||
|
.layers[goog.getUid(vector)];
|
||||||
|
expect(goog.object.getCount(layer.featureCache_.idLookup_)).to.be(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
goog.require('goog.dispose');
|
||||||
|
goog.require('goog.object');
|
||||||
|
goog.require('ol.Map');
|
||||||
|
goog.require('ol.interaction.Select');
|
||||||
|
goog.require('ol.layer.Vector');
|
||||||
|
goog.require('ol.parser.GeoJSON');
|
||||||
|
goog.require('ol.source.Vector');
|
||||||
Reference in New Issue
Block a user