Provide a method for retrieving features by id
This commit is contained in:
@@ -69,6 +69,20 @@ ol.source.Vector = function(opt_options) {
|
|||||||
*/
|
*/
|
||||||
this.nullGeometryFeatures_ = {};
|
this.nullGeometryFeatures_ = {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A lookup of features by id (the return from feature.getId()).
|
||||||
|
* @private
|
||||||
|
* @type {Object.<string, ol.Feature>}
|
||||||
|
*/
|
||||||
|
this.idIndex_ = {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A lookup of features without id (keyed by goog.getUid(feature)).
|
||||||
|
* @private
|
||||||
|
* @type {Object.<string, ol.Feature>}
|
||||||
|
*/
|
||||||
|
this.undefIdIndex_ = {};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
* @type {Object.<string, Array.<goog.events.Key>>}
|
* @type {Object.<string, Array.<goog.events.Key>>}
|
||||||
@@ -116,6 +130,14 @@ ol.source.Vector.prototype.addFeatureInternal = function(feature) {
|
|||||||
} else {
|
} else {
|
||||||
this.nullGeometryFeatures_[goog.getUid(feature).toString()] = feature;
|
this.nullGeometryFeatures_[goog.getUid(feature).toString()] = feature;
|
||||||
}
|
}
|
||||||
|
var id = feature.getId();
|
||||||
|
if (goog.isDef(id)) {
|
||||||
|
var sid = id.toString();
|
||||||
|
goog.asserts.assert(!(goog.isDef(this.idIndex_[sid])));
|
||||||
|
this.idIndex_[sid] = feature;
|
||||||
|
} else {
|
||||||
|
this.undefIdIndex_[goog.getUid(feature).toString()] = feature;
|
||||||
|
}
|
||||||
this.dispatchEvent(
|
this.dispatchEvent(
|
||||||
new ol.source.VectorEvent(ol.source.VectorEventType.ADDFEATURE, feature));
|
new ol.source.VectorEvent(ol.source.VectorEventType.ADDFEATURE, feature));
|
||||||
};
|
};
|
||||||
@@ -314,6 +336,20 @@ ol.source.Vector.prototype.getExtent = function() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a feature by its identifier (the value returned by feature.getId()).
|
||||||
|
* Note that the index treats string and numeric identifiers as the same. So
|
||||||
|
* `source.getFeatureById(2)` will return a feature with id `'2'` or `2`.
|
||||||
|
*
|
||||||
|
* @param {string|number} id Feature identifier.
|
||||||
|
* @return {ol.Feature} The feature (or `null` if not found).
|
||||||
|
*/
|
||||||
|
ol.source.Vector.prototype.getFeatureById = function(id) {
|
||||||
|
var feature = this.idIndex_[id.toString()];
|
||||||
|
return goog.isDef(feature) ? feature : null;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {goog.events.Event} event Event.
|
* @param {goog.events.Event} event Event.
|
||||||
* @private
|
* @private
|
||||||
@@ -336,6 +372,35 @@ ol.source.Vector.prototype.handleFeatureChange_ = function(event) {
|
|||||||
this.rBush_.update(extent, feature);
|
this.rBush_.update(extent, feature);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
var id = feature.getId();
|
||||||
|
var removed;
|
||||||
|
if (goog.isDef(id)) {
|
||||||
|
var sid = id.toString();
|
||||||
|
if (featureKey in this.undefIdIndex_) {
|
||||||
|
delete this.undefIdIndex_[featureKey];
|
||||||
|
goog.asserts.assert(!goog.isDef(this.idIndex_[sid]),
|
||||||
|
'Duplicate feature id: ' + id);
|
||||||
|
this.idIndex_[sid] = feature;
|
||||||
|
} else {
|
||||||
|
if (this.idIndex_[sid] !== feature) {
|
||||||
|
removed = this.removeFromIdIndex_(feature);
|
||||||
|
goog.asserts.assert(removed,
|
||||||
|
'Expected feature to be removed from index');
|
||||||
|
goog.asserts.assert(!(sid in this.idIndex_),
|
||||||
|
'Duplicate feature id: ' + id);
|
||||||
|
this.idIndex_[sid] = feature;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!(featureKey in this.undefIdIndex_)) {
|
||||||
|
removed = this.removeFromIdIndex_(feature);
|
||||||
|
goog.asserts.assert(removed,
|
||||||
|
'Expected feature to be removed from index');
|
||||||
|
this.undefIdIndex_[featureKey] = feature;
|
||||||
|
} else {
|
||||||
|
goog.asserts.assert(this.undefIdIndex_[featureKey] === feature);
|
||||||
|
}
|
||||||
|
}
|
||||||
this.dispatchChangeEvent();
|
this.dispatchChangeEvent();
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -384,11 +449,37 @@ ol.source.Vector.prototype.removeFeatureInternal = function(feature) {
|
|||||||
goog.array.forEach(this.featureChangeKeys_[featureKey],
|
goog.array.forEach(this.featureChangeKeys_[featureKey],
|
||||||
goog.events.unlistenByKey);
|
goog.events.unlistenByKey);
|
||||||
delete this.featureChangeKeys_[featureKey];
|
delete this.featureChangeKeys_[featureKey];
|
||||||
|
var id = feature.getId();
|
||||||
|
if (goog.isDef(id)) {
|
||||||
|
delete this.idIndex_[id.toString()];
|
||||||
|
} else {
|
||||||
|
delete this.undefIdIndex_[featureKey];
|
||||||
|
}
|
||||||
this.dispatchEvent(new ol.source.VectorEvent(
|
this.dispatchEvent(new ol.source.VectorEvent(
|
||||||
ol.source.VectorEventType.REMOVEFEATURE, feature));
|
ol.source.VectorEventType.REMOVEFEATURE, feature));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a feature from the id index. Called internally when the feature id
|
||||||
|
* may have changed.
|
||||||
|
* @param {ol.Feature} feature The feature.
|
||||||
|
* @return {boolean} Removed the feature from the index.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
ol.source.Vector.prototype.removeFromIdIndex_ = function(feature) {
|
||||||
|
var removed = false;
|
||||||
|
for (var id in this.idIndex_) {
|
||||||
|
if (this.idIndex_[id] === feature) {
|
||||||
|
delete this.idIndex_[id];
|
||||||
|
removed = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return removed;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @constructor
|
* @constructor
|
||||||
|
|||||||
@@ -244,6 +244,125 @@ describe('ol.source.Vector', function() {
|
|||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('#getFeatureById()', function() {
|
||||||
|
var source;
|
||||||
|
beforeEach(function() {
|
||||||
|
source = new ol.source.Vector();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns a feature by id', function() {
|
||||||
|
var feature = new ol.Feature();
|
||||||
|
feature.setId('foo');
|
||||||
|
source.addFeature(feature);
|
||||||
|
expect(source.getFeatureById('foo')).to.be(feature);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns a feature by id (set after add)', function() {
|
||||||
|
var feature = new ol.Feature();
|
||||||
|
source.addFeature(feature);
|
||||||
|
expect(source.getFeatureById('foo')).to.be(null);
|
||||||
|
feature.setId('foo');
|
||||||
|
expect(source.getFeatureById('foo')).to.be(feature);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns null when no feature is found', function() {
|
||||||
|
var feature = new ol.Feature();
|
||||||
|
feature.setId('foo');
|
||||||
|
source.addFeature(feature);
|
||||||
|
expect(source.getFeatureById('bar')).to.be(null);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns null after removing feature', function() {
|
||||||
|
var feature = new ol.Feature();
|
||||||
|
feature.setId('foo');
|
||||||
|
source.addFeature(feature);
|
||||||
|
expect(source.getFeatureById('foo')).to.be(feature);
|
||||||
|
source.removeFeature(feature);
|
||||||
|
expect(source.getFeatureById('foo')).to.be(null);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns null after unsetting id', function() {
|
||||||
|
var feature = new ol.Feature();
|
||||||
|
feature.setId('foo');
|
||||||
|
source.addFeature(feature);
|
||||||
|
expect(source.getFeatureById('foo')).to.be(feature);
|
||||||
|
feature.setId(undefined);
|
||||||
|
expect(source.getFeatureById('foo')).to.be(null);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns null after clear', function() {
|
||||||
|
var feature = new ol.Feature();
|
||||||
|
feature.setId('foo');
|
||||||
|
source.addFeature(feature);
|
||||||
|
expect(source.getFeatureById('foo')).to.be(feature);
|
||||||
|
source.clear();
|
||||||
|
expect(source.getFeatureById('foo')).to.be(null);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns null when no features are indexed', function() {
|
||||||
|
expect(source.getFeatureById('foo')).to.be(null);
|
||||||
|
source.addFeature(new ol.Feature());
|
||||||
|
expect(source.getFeatureById('foo')).to.be(null);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns correct feature after add/remove/add', function() {
|
||||||
|
expect(source.getFeatureById('foo')).to.be(null);
|
||||||
|
var first = new ol.Feature();
|
||||||
|
first.setId('foo');
|
||||||
|
source.addFeature(first);
|
||||||
|
expect(source.getFeatureById('foo')).to.be(first);
|
||||||
|
source.removeFeature(first);
|
||||||
|
expect(source.getFeatureById('foo')).to.be(null);
|
||||||
|
var second = new ol.Feature();
|
||||||
|
second.setId('foo');
|
||||||
|
source.addFeature(second);
|
||||||
|
expect(source.getFeatureById('foo')).to.be(second);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns correct feature after add/change', function() {
|
||||||
|
expect(source.getFeatureById('foo')).to.be(null);
|
||||||
|
var feature = new ol.Feature();
|
||||||
|
feature.setId('foo');
|
||||||
|
source.addFeature(feature);
|
||||||
|
expect(source.getFeatureById('foo')).to.be(feature);
|
||||||
|
feature.setId('bar');
|
||||||
|
expect(source.getFeatureById('foo')).to.be(null);
|
||||||
|
expect(source.getFeatureById('bar')).to.be(feature);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('the feature id index', function() {
|
||||||
|
var source;
|
||||||
|
beforeEach(function() {
|
||||||
|
source = new ol.source.Vector();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('enforces a uniqueness constraint (on add)', function() {
|
||||||
|
var feature = new ol.Feature();
|
||||||
|
feature.setId('foo');
|
||||||
|
source.addFeature(feature);
|
||||||
|
var dupe = new ol.Feature();
|
||||||
|
dupe.setId('foo');
|
||||||
|
expect(function() {
|
||||||
|
source.addFeature(dupe);
|
||||||
|
}).to.throwException();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('enforces a uniqueness constraint (on change)', function() {
|
||||||
|
var foo = new ol.Feature();
|
||||||
|
foo.setId('foo');
|
||||||
|
source.addFeature(foo);
|
||||||
|
var bar = new ol.Feature();
|
||||||
|
bar.setId('bar');
|
||||||
|
source.addFeature(bar);
|
||||||
|
expect(function() {
|
||||||
|
bar.setId('foo');
|
||||||
|
}).to.throwException();
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user