Make Modify interaction listen to feature changes

This commit makes the Modify interaction modify its segment data when the candidate features change.
This commit is contained in:
Éric Lemoine
2015-08-18 16:39:49 +02:00
parent d042b4c277
commit 5f7e6ac61a
2 changed files with 137 additions and 20 deletions

View File

@@ -4,6 +4,7 @@ goog.require('goog.array');
goog.require('goog.asserts'); goog.require('goog.asserts');
goog.require('goog.events'); goog.require('goog.events');
goog.require('goog.events.Event'); goog.require('goog.events.Event');
goog.require('goog.events.EventType');
goog.require('goog.functions'); goog.require('goog.functions');
goog.require('ol.Collection'); goog.require('ol.Collection');
goog.require('ol.CollectionEventType'); goog.require('ol.CollectionEventType');
@@ -168,6 +169,14 @@ ol.interaction.Modify = function(options) {
*/ */
this.snappedToVertex_ = false; this.snappedToVertex_ = false;
/**
* Indicate whether the interaction is currently changing a feature's
* coordinates.
* @type {boolean}
* @private
*/
this.changingFeature_ = false;
/** /**
* @type {Array} * @type {Array}
* @private * @private
@@ -235,6 +244,48 @@ ol.interaction.Modify.prototype.addFeature_ = function(feature) {
if (!goog.isNull(map)) { if (!goog.isNull(map)) {
this.handlePointerAtPixel_(this.lastPixel_, map); this.handlePointerAtPixel_(this.lastPixel_, map);
} }
goog.events.listen(feature, goog.events.EventType.CHANGE,
this.handleFeatureChange_, false, this);
};
/**
* @param {ol.Feature} feature Feature.
* @private
*/
ol.interaction.Modify.prototype.removeFeature_ = function(feature) {
this.removeFeatureSegmentData_(feature);
// Remove the vertex feature if the collection of canditate features
// is empty.
if (!goog.isNull(this.vertexFeature_) &&
this.features_.getLength() === 0) {
this.overlay_.getSource().removeFeature(this.vertexFeature_);
this.vertexFeature_ = null;
}
goog.events.unlisten(feature, goog.events.EventType.CHANGE,
this.handleFeatureChange_, false, this);
};
/**
* @param {ol.Feature} feature Feature.
* @private
*/
ol.interaction.Modify.prototype.removeFeatureSegmentData_ = function(feature) {
var rBush = this.rBush_;
var /** @type {Array.<ol.interaction.SegmentDataType>} */ nodesToRemove = [];
rBush.forEach(
/**
* @param {ol.interaction.SegmentDataType} node RTree node.
*/
function(node) {
if (feature === node.feature) {
nodesToRemove.push(node);
}
});
for (var i = nodesToRemove.length - 1; i >= 0; --i) {
rBush.remove(nodesToRemove[i]);
}
}; };
@@ -259,28 +310,26 @@ ol.interaction.Modify.prototype.handleFeatureAdd_ = function(evt) {
}; };
/**
* @param {goog.events.Event} evt Event.
* @private
*/
ol.interaction.Modify.prototype.handleFeatureChange_ = function(evt) {
if (!this.changingFeature_) {
var feature = /** @type {ol.Feature} */ (evt.target);
this.removeFeature_(feature);
this.addFeature_(feature);
}
};
/** /**
* @param {ol.CollectionEvent} evt Event. * @param {ol.CollectionEvent} evt Event.
* @private * @private
*/ */
ol.interaction.Modify.prototype.handleFeatureRemove_ = function(evt) { ol.interaction.Modify.prototype.handleFeatureRemove_ = function(evt) {
var feature = evt.element; var feature = /** @type {ol.Feature} */ (evt.element);
var rBush = this.rBush_; this.removeFeature_(feature);
var i, nodesToRemove = [];
rBush.forEachInExtent(feature.getGeometry().getExtent(), function(node) {
if (feature === node.feature) {
nodesToRemove.push(node);
}
});
for (i = nodesToRemove.length - 1; i >= 0; --i) {
rBush.remove(nodesToRemove[i]);
}
// There remains only vertexFeature…
if (!goog.isNull(this.vertexFeature_) &&
this.features_.getLength() === 0) {
this.overlay_.getSource().removeFeature(this.vertexFeature_);
this.vertexFeature_ = null;
}
}; };
@@ -585,7 +634,7 @@ ol.interaction.Modify.handleDragEvent_ = function(evt) {
break; break;
} }
geometry.setCoordinates(coordinates); this.setGeometryCoordinates_(geometry, coordinates);
} }
this.createOrUpdateVertexFeature_(vertex); this.createOrUpdateVertexFeature_(vertex);
}; };
@@ -768,7 +817,7 @@ ol.interaction.Modify.prototype.insertVertex_ = function(segmentData, vertex) {
return; return;
} }
geometry.setCoordinates(coordinates); this.setGeometryCoordinates_(geometry, coordinates);
var rTree = this.rBush_; var rTree = this.rBush_;
goog.asserts.assert(goog.isDef(segment), 'segment should be defined'); goog.asserts.assert(goog.isDef(segment), 'segment should be defined');
rTree.remove(segmentData); rTree.remove(segmentData);
@@ -874,7 +923,7 @@ ol.interaction.Modify.prototype.removeVertex_ = function() {
if (deleted) { if (deleted) {
this.rBush_.remove(newSegment[0]); this.rBush_.remove(newSegment[0]);
this.rBush_.remove(newSegment[1]); this.rBush_.remove(newSegment[1]);
geometry.setCoordinates(coordinates); this.setGeometryCoordinates_(geometry, coordinates);
goog.asserts.assert(newIndex >= 0, 'newIndex should be larger than 0'); goog.asserts.assert(newIndex >= 0, 'newIndex should be larger than 0');
var newSegmentData = /** @type {ol.interaction.SegmentDataType} */ ({ var newSegmentData = /** @type {ol.interaction.SegmentDataType} */ ({
depth: segmentData.depth, depth: segmentData.depth,
@@ -898,6 +947,19 @@ ol.interaction.Modify.prototype.removeVertex_ = function() {
}; };
/**
* @param {ol.geom.SimpleGeometry} geometry Geometry.
* @param {Array} coordinates Coordinates.
* @private
*/
ol.interaction.Modify.prototype.setGeometryCoordinates_ =
function(geometry, coordinates) {
this.changingFeature_ = true;
geometry.setCoordinates(coordinates);
this.changingFeature_ = false;
};
/** /**
* @param {ol.geom.SimpleGeometry} geometry Geometry. * @param {ol.geom.SimpleGeometry} geometry Geometry.
* @param {number} index Index. * @param {number} index Index.

View File

@@ -262,10 +262,65 @@ describe('ol.interaction.Modify', function() {
expect(feature.getGeometry().getCoordinates()[0]).to.have.length(5); expect(feature.getGeometry().getCoordinates()[0]).to.have.length(5);
}); });
}); });
describe('handle feature change', function() {
var getListeners;
beforeEach(function() {
getListeners = function(feature, modify) {
var listeners = goog.events.getListeners(
feature, goog.events.EventType.CHANGE, false);
return goog.array.filter(listeners, function(listener) {
return listener.handler == modify;
});
};
});
it('updates the segment data', function() {
var modify = new ol.interaction.Modify({
features: new ol.Collection(features)
});
map.addInteraction(modify);
var feature = features[0];
var listeners, listener;
listeners = getListeners(feature, modify);
expect(listeners).to.have.length(1);
var firstSegmentData;
firstSegmentData = modify.rBush_.forEachInExtent([0, 0, 5, 5],
function(node) {
return node;
});
expect(firstSegmentData.segment[0]).to.eql([0, 0]);
expect(firstSegmentData.segment[1]).to.eql([10, 20]);
var coordinates = feature.getGeometry().getCoordinates();
var firstVertex = coordinates[0][0];
firstVertex[0] = 1;
firstVertex[1] = 1;
feature.getGeometry().setCoordinates(coordinates);
firstSegmentData = modify.rBush_.forEachInExtent([0, 0, 5, 5],
function(node) {
return node;
});
expect(firstSegmentData.segment[0]).to.eql([1, 1]);
expect(firstSegmentData.segment[1]).to.eql([10, 20]);
listeners = getListeners(feature, modify);
expect(listeners).to.have.length(1);
});
});
}); });
goog.require('goog.array');
goog.require('goog.dispose'); goog.require('goog.dispose');
goog.require('goog.events'); goog.require('goog.events');
goog.require('goog.events.EventType');
goog.require('goog.events.BrowserEvent'); goog.require('goog.events.BrowserEvent');
goog.require('goog.style'); goog.require('goog.style');
goog.require('ol.Collection'); goog.require('ol.Collection');