Merge pull request #9250 from ahocevar/clear-refresh

Clearer behaviour of clear() and refresh() on sources
This commit is contained in:
Andreas Hocevar
2019-02-21 17:12:26 +01:00
committed by GitHub
7 changed files with 224 additions and 14 deletions
+6
View File
@@ -124,6 +124,12 @@ The removed classes and components are:
Following the removal of the experimental WebGL renderer, the AtlasManager has been removed as well. The atlas was only used by this renderer. Following the removal of the experimental WebGL renderer, the AtlasManager has been removed as well. The atlas was only used by this renderer.
The non API `getChecksum` functions of the style is also removed. The non API `getChecksum` functions of the style is also removed.
##### Change of the behavior of the vector source's clear() and refresh() methods
The `ol/source/Vector#clear()` method no longer triggers a reload of the data from the server. If you were previously using `clear()` to refetch from the server, you now have to use `refresh()`.
The `ol/source/Vector#refresh()` method now removes all features from the source and triggers a reload of the data from the server. If you were previously using the `refresh()` method to re-render a vector layer, you should instead call `ol/layer/Vector#changed()`.
#### Other changes #### Other changes
##### Allow declutter in image render mode ##### Allow declutter in image render mode
+1 -1
View File
@@ -145,7 +145,7 @@ class Source extends BaseObject {
} }
/** /**
* Refreshes the source and finally dispatches a 'change' event. * Refreshes the source. The source will be cleared, and data from the server will be reloaded.
* @api * @api
*/ */
refresh() { refresh() {
+10 -2
View File
@@ -300,12 +300,20 @@ class TileSource extends Source {
return withinExtentAndZ(tileCoord, tileGrid) ? tileCoord : null; return withinExtentAndZ(tileCoord, tileGrid) ? tileCoord : null;
} }
/**
* Remove all cached tiles from the source. The next render cycle will fetch new tiles.
* @api
*/
clear() {
this.tileCache.clear();
}
/** /**
* @inheritDoc * @inheritDoc
*/ */
refresh() { refresh() {
this.tileCache.clear(); this.clear();
this.changed(); super.refresh();
} }
/** /**
+20 -2
View File
@@ -498,7 +498,6 @@ class VectorSource extends Source {
if (this.featuresRtree_) { if (this.featuresRtree_) {
this.featuresRtree_.clear(); this.featuresRtree_.clear();
} }
this.loadedExtentsRtree_.clear();
this.nullGeometryFeatures_ = {}; this.nullGeometryFeatures_ = {};
const clearEvent = new VectorSourceEvent(VectorEventType.CLEAR); const clearEvent = new VectorSourceEvent(VectorEventType.CLEAR);
@@ -894,6 +893,15 @@ class VectorSource extends Source {
} }
} }
/**
* @inheritDoc
*/
refresh() {
this.clear(true);
this.loadedExtentsRtree_.clear();
super.refresh();
}
/** /**
* Remove an extent from the list of loaded extents. * Remove an extent from the list of loaded extents.
@@ -977,7 +985,7 @@ class VectorSource extends Source {
/** /**
* Set the new loader of the source. The next loadFeatures call will use the * Set the new loader of the source. The next render cycle will use the
* new loader. * new loader.
* @param {import("../featureloader.js").FeatureLoader} loader The loader to set. * @param {import("../featureloader.js").FeatureLoader} loader The loader to set.
* @api * @api
@@ -986,6 +994,16 @@ class VectorSource extends Source {
this.loader_ = loader; this.loader_ = loader;
} }
/**
* Points the source to a new url. The next render cycle will use the new url.
* @param {string|import("../featureloader.js").FeatureUrlFunction} url Url.
* @api
*/
setUrl(url) {
assert(this.format_, 7); // `format` must be set when `url` is set
this.setLoader(xhr(url, this.format_));
}
} }
+51
View File
@@ -1,6 +1,10 @@
import ImageWMS from '../../../../src/ol/source/ImageWMS.js'; import ImageWMS from '../../../../src/ol/source/ImageWMS.js';
import Image from '../../../../src/ol/layer/Image.js';
import {get as getProjection} from '../../../../src/ol/proj.js'; import {get as getProjection} from '../../../../src/ol/proj.js';
import {getWidth, getHeight} from '../../../../src/ol/extent.js'; import {getWidth, getHeight} from '../../../../src/ol/extent.js';
import View from '../../../../src/ol/View.js';
import Map from '../../../../src/ol/Map.js';
import ImageState from '../../../../src/ol/ImageState.js';
describe('ol.source.ImageWMS', function() { describe('ol.source.ImageWMS', function() {
@@ -326,4 +330,51 @@ describe('ol.source.ImageWMS', function() {
}); });
}); });
describe('#refresh()', function() {
let map, source;
let callCount = 0;
beforeEach(function(done) {
source = new ImageWMS(options);
source.setImageLoadFunction(function(image) {
++callCount;
image.state = ImageState.LOADED;
source.loading = false;
});
const target = document.createElement('div');
target.style.width = target.style.height = '100px';
document.body.appendChild(target);
map = new Map({
target: target,
layers: [
new Image({
source: source
})
],
view: new View({
center: [0, 0],
zoom: 0
})
});
map.once('rendercomplete', function() {
callCount = 0;
done();
});
});
afterEach(function() {
document.body.removeChild(map.getTargetElement());
map.setTarget(null);
});
it('reloads from server', function(done) {
map.once('rendercomplete', function() {
expect(callCount).to.be(1);
done();
});
source.refresh();
});
});
}); });
+75 -9
View File
@@ -9,6 +9,7 @@ import VectorLayer from '../../../../src/ol/layer/Vector.js';
import {bbox as bboxStrategy} from '../../../../src/ol/loadingstrategy.js'; import {bbox as bboxStrategy} from '../../../../src/ol/loadingstrategy.js';
import {get as getProjection, transformExtent, fromLonLat} from '../../../../src/ol/proj.js'; import {get as getProjection, transformExtent, fromLonLat} from '../../../../src/ol/proj.js';
import VectorSource from '../../../../src/ol/source/Vector.js'; import VectorSource from '../../../../src/ol/source/Vector.js';
import GeoJSON from '../../../../src/ol/format/GeoJSON.js';
describe('ol.source.Vector', function() { describe('ol.source.Vector', function() {
@@ -147,6 +148,79 @@ describe('ol.source.Vector', function() {
}); });
describe('clear and refresh', function() {
let map, source, spy;
beforeEach(function(done) {
source = new VectorSource({
format: new GeoJSON(),
url: 'spec/ol/source/vectorsource/single-feature.json'
});
const target = document.createElement('div');
target.style.width = target.style.height = '100px';
document.body.appendChild(target);
map = new Map({
target: target,
layers: [
new VectorLayer({
source: source
})
],
view: new View({
center: [0, 0],
zoom: 0
})
});
map.once('rendercomplete', function() {
spy = sinon.spy(source, 'loader_');
done();
});
});
afterEach(function() {
if (spy) {
source.loader_.restore();
}
document.body.removeChild(map.getTargetElement());
map.setTarget(null);
});
it('#refresh() reloads from server', function(done) {
expect(source.getFeatures()).to.have.length(1);
map.once('rendercomplete', function() {
expect(source.getFeatures()).to.have.length(1);
expect(spy.callCount).to.be(1);
done();
});
source.refresh();
});
it('#clear() removes all features from the source', function(done) {
expect(source.getFeatures()).to.have.length(1);
map.once('rendercomplete', function() {
expect(source.getFeatures()).to.have.length(0);
expect(spy.callCount).to.be(0);
done();
});
source.clear();
});
it('After #setUrl(), refresh() loads from the new url', function(done) {
source.loader_.restore();
spy = undefined;
expect(source.getFeatures()).to.have.length(1);
const oldCoordinates = source.getFeatures()[0].getGeometry().getCoordinates();
map.on('rendercomplete', function() {
expect(source.getFeatures()).to.have.length(1);
const newCoordinates = source.getFeatures()[0].getGeometry().getCoordinates();
expect(newCoordinates).to.not.eql(oldCoordinates);
done();
});
source.setUrl('spec/ol/data/point.json');
source.refresh();
});
});
describe('when populated with 10 random points and a null', function() { describe('when populated with 10 random points and a null', function() {
let features; let features;
@@ -167,8 +241,6 @@ describe('ol.source.Vector', function() {
describe('#clear', function() { describe('#clear', function() {
it('removes all features using fast path', function() { it('removes all features using fast path', function() {
const changeSpy = sinon.spy();
listen(vectorSource, 'change', changeSpy);
const removeFeatureSpy = sinon.spy(); const removeFeatureSpy = sinon.spy();
listen(vectorSource, 'removefeature', removeFeatureSpy); listen(vectorSource, 'removefeature', removeFeatureSpy);
const clearSourceSpy = sinon.spy(); const clearSourceSpy = sinon.spy();
@@ -176,8 +248,6 @@ describe('ol.source.Vector', function() {
vectorSource.clear(true); vectorSource.clear(true);
expect(vectorSource.getFeatures()).to.eql([]); expect(vectorSource.getFeatures()).to.eql([]);
expect(vectorSource.isEmpty()).to.be(true); 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).not.to.be.called();
expect(removeFeatureSpy.callCount).to.be(0); expect(removeFeatureSpy.callCount).to.be(0);
expect(clearSourceSpy).to.be.called(); expect(clearSourceSpy).to.be.called();
@@ -185,8 +255,6 @@ describe('ol.source.Vector', function() {
}); });
it('removes all features using slow path', function() { it('removes all features using slow path', function() {
const changeSpy = sinon.spy();
listen(vectorSource, 'change', changeSpy);
const removeFeatureSpy = sinon.spy(); const removeFeatureSpy = sinon.spy();
listen(vectorSource, 'removefeature', removeFeatureSpy); listen(vectorSource, 'removefeature', removeFeatureSpy);
const clearSourceSpy = sinon.spy(); const clearSourceSpy = sinon.spy();
@@ -194,8 +262,6 @@ describe('ol.source.Vector', function() {
vectorSource.clear(); vectorSource.clear();
expect(vectorSource.getFeatures()).to.eql([]); expect(vectorSource.getFeatures()).to.eql([]);
expect(vectorSource.isEmpty()).to.be(true); expect(vectorSource.isEmpty()).to.be(true);
expect(changeSpy).to.be.called();
expect(changeSpy.callCount).to.be(1);
expect(removeFeatureSpy).to.be.called(); expect(removeFeatureSpy).to.be.called();
expect(removeFeatureSpy.callCount).to.be(features.length); expect(removeFeatureSpy.callCount).to.be(features.length);
expect(clearSourceSpy).to.be.called(); expect(clearSourceSpy).to.be.called();
@@ -521,7 +587,7 @@ describe('ol.source.Vector', function() {
source.loadFeatures([-10000, -10000, 10000, 10000], 1, source.loadFeatures([-10000, -10000, 10000, 10000], 1,
getProjection('EPSG:3857')); getProjection('EPSG:3857'));
source.setLoader(loader2); source.setLoader(loader2);
source.clear(); source.refresh();
source.loadFeatures([-10000, -10000, 10000, 10000], 1, source.loadFeatures([-10000, -10000, 10000, 10000], 1,
getProjection('EPSG:3857')); getProjection('EPSG:3857'));
expect(count1).to.eql(1); expect(count1).to.eql(1);
+61
View File
@@ -1,8 +1,11 @@
import TileSource from '../../../../src/ol/source/Tile.js'; import TileSource from '../../../../src/ol/source/Tile.js';
import TileLayer from '../../../../src/ol/layer/Tile.js';
import TileImage from '../../../../src/ol/source/TileImage.js'; import TileImage from '../../../../src/ol/source/TileImage.js';
import UrlTile from '../../../../src/ol/source/UrlTile.js'; import UrlTile from '../../../../src/ol/source/UrlTile.js';
import XYZ from '../../../../src/ol/source/XYZ.js'; import XYZ from '../../../../src/ol/source/XYZ.js';
import {createXYZ} from '../../../../src/ol/tilegrid.js'; import {createXYZ} from '../../../../src/ol/tilegrid.js';
import View from '../../../../src/ol/View.js';
import Map from '../../../../src/ol/Map.js';
describe('ol.source.XYZ', function() { describe('ol.source.XYZ', function() {
@@ -183,4 +186,62 @@ describe('ol.source.XYZ', function() {
}); });
describe('clear and refresh', function() {
let map, source;
let callCount = 0;
beforeEach(function(done) {
source = new XYZ({
url: 'spec/ol/data/osm-{z}-{x}-{y}.png',
tileLoadFunction: function(image, src) {
++callCount;
image.getImage().src = src;
}
});
const target = document.createElement('div');
target.style.width = target.style.height = '100px';
document.body.appendChild(target);
map = new Map({
target: target,
layers: [
new TileLayer({
source: source
})
],
view: new View({
center: [0, 0],
zoom: 0
})
});
map.once('rendercomplete', function() {
callCount = 0;
done();
});
});
afterEach(function() {
document.body.removeChild(map.getTargetElement());
map.setTarget(null);
});
it('#refresh() reloads from server', function(done) {
map.once('rendercomplete', function() {
expect(callCount).to.be(1);
done();
});
source.refresh();
});
it('#clear() clears the tile cache', function(done) {
map.once('rendercomplete', function() {
done(new Error('should not re-render'));
});
source.clear();
setTimeout(function() {
done();
}, 1000);
});
});
}); });