diff --git a/src/ol/source/vectorsource.js b/src/ol/source/vectorsource.js index 6b223026a0..de1783e130 100644 --- a/src/ol/source/vectorsource.js +++ b/src/ol/source/vectorsource.js @@ -36,8 +36,16 @@ ol.source.VectorEventType = { */ CHANGEFEATURE: 'changefeature', + /** + * Triggered when the clear method is called on the source. + * @event ol.source.VectorEvent#clear + * @api + */ + CLEAR: 'clear', + /** * Triggered when a feature is removed from the source. + * See {@link ol.source.Vector#clear source.clear()} for exceptions. * @event ol.source.VectorEvent#removefeature * @api stable */ @@ -227,15 +235,32 @@ ol.source.Vector.prototype.addFeaturesInternal = function(features) { /** * Remove all features from the source. + * @param {boolean=} opt_fast Skip dispatching of {@link removefeature} events. * @api stable */ -ol.source.Vector.prototype.clear = function() { - this.rBush_.forEach(this.removeFeatureInternal, this); +ol.source.Vector.prototype.clear = function(opt_fast) { + if (opt_fast) { + for (var featureId in this.featureChangeKeys_) { + var keys = this.featureChangeKeys_[featureId]; + goog.array.forEach(keys, goog.events.unlistenByKey); + } + this.featureChangeKeys_ = {}; + this.idIndex_ = {}; + this.undefIdIndex_ = {}; + } else { + var rmFeatureInternal = this.removeFeatureInternal; + this.rBush_.forEach(rmFeatureInternal, this); + goog.object.forEach(this.nullGeometryFeatures_, rmFeatureInternal, this); + goog.asserts.assert(goog.object.isEmpty(this.featureChangeKeys_)); + goog.asserts.assert(goog.object.isEmpty(this.idIndex_)); + goog.asserts.assert(goog.object.isEmpty(this.undefIdIndex_)); + } + this.rBush_.clear(); - goog.object.forEach( - this.nullGeometryFeatures_, this.removeFeatureInternal, this); - goog.object.clear(this.nullGeometryFeatures_); - goog.asserts.assert(goog.object.isEmpty(this.featureChangeKeys_)); + this.nullGeometryFeatures_ = {}; + + var clearEvent = new ol.source.VectorEvent(ol.source.VectorEventType.CLEAR); + this.dispatchEvent(clearEvent); this.changed(); }; diff --git a/src/ol/structs/rbush.js b/src/ol/structs/rbush.js index baa0e3a1f1..a9c5cce5d9 100644 --- a/src/ol/structs/rbush.js +++ b/src/ol/structs/rbush.js @@ -74,7 +74,7 @@ ol.structs.RBush.prototype.load = function(extents, values) { } goog.asserts.assert(extents.length === values.length); - var items = []; + var items = new Array(values.length); for (var i = 0, l = values.length; i < l; i++) { var extent = extents[i]; var value = values[i]; @@ -86,7 +86,7 @@ ol.structs.RBush.prototype.load = function(extents, values) { extent[3], value ]; - items.push(item); + items[i] = item; goog.object.add(this.items_, goog.getUid(value).toString(), item); } this.rbush_.load(items); @@ -228,7 +228,7 @@ ol.structs.RBush.prototype.isEmpty = function() { */ ol.structs.RBush.prototype.clear = function() { this.rbush_.clear(); - goog.object.clear(this.items_); + this.items_ = {}; }; diff --git a/test/spec/ol/source/vectorsource.test.js b/test/spec/ol/source/vectorsource.test.js index 1ec5803a2c..558cd725e8 100644 --- a/test/spec/ol/source/vectorsource.test.js +++ b/test/spec/ol/source/vectorsource.test.js @@ -85,11 +85,31 @@ describe('ol.source.Vector', function() { describe('#clear', function() { - it('removes all features', function() { + it('removes all features using fast path', function() { var changeSpy = sinon.spy(); goog.events.listen(vectorSource, 'change', changeSpy); var removeFeatureSpy = sinon.spy(); goog.events.listen(vectorSource, 'removefeature', removeFeatureSpy); + var clearSourceSpy = sinon.spy(); + goog.events.listen(vectorSource, 'clear', clearSourceSpy); + vectorSource.clear(true); + expect(vectorSource.getFeatures()).to.eql([]); + expect(vectorSource.isEmpty()).to.be(true); + expect(changeSpy).to.be.called(); + expect(changeSpy.callCount).to.be(1); + expect(removeFeatureSpy).not.to.be.called(); + expect(removeFeatureSpy.callCount).to.be(0); + expect(clearSourceSpy).to.be.called(); + expect(clearSourceSpy.callCount).to.be(1); + }); + + it('removes all features using slow path', function() { + var changeSpy = sinon.spy(); + goog.events.listen(vectorSource, 'change', changeSpy); + var removeFeatureSpy = sinon.spy(); + goog.events.listen(vectorSource, 'removefeature', removeFeatureSpy); + var clearSourceSpy = sinon.spy(); + goog.events.listen(vectorSource, 'clear', clearSourceSpy); vectorSource.clear(); expect(vectorSource.getFeatures()).to.eql([]); expect(vectorSource.isEmpty()).to.be(true); @@ -97,6 +117,8 @@ describe('ol.source.Vector', function() { expect(changeSpy.callCount).to.be(1); expect(removeFeatureSpy).to.be.called(); expect(removeFeatureSpy.callCount).to.be(features.length); + expect(clearSourceSpy).to.be.called(); + expect(clearSourceSpy.callCount).to.be(1); }); });