diff --git a/debug/3895.html b/debug/3895.html
new file mode 100644
index 00000000000..1b38f88e156
--- /dev/null
+++ b/debug/3895.html
@@ -0,0 +1,52 @@
+
+
+
+ Mapbox GL JS debug page
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/js/style/style.js b/js/style/style.js
index 47a4a38f8e0..44096b33f2b 100644
--- a/js/style/style.js
+++ b/js/style/style.js
@@ -455,13 +455,15 @@ class Style extends Evented {
if (this._removedLayers[id] && layer.source) {
// If, in the current batch, we have already removed this layer
- // and we are now re-adding it, then we need to clear (rather
- // than just reload) the underyling source's tiles.
- // Otherwise, tiles marked 'reloading' will have buffers that are
- // set up for the _previous_ version of this layer, confusing
+ // and we are now re-adding it with a different `type`, then we
+ // need to clear (rather than just reload) the underyling source's
+ // tiles. Otherwise, tiles marked 'reloading' will have buckets /
+ // buffers that are set up for the _previous_ version of this
+ // layer, causing, e.g.:
// https://github.com/mapbox/mapbox-gl-js/issues/3633
+ const removed = this._removedLayers[id];
delete this._removedLayers[id];
- this._updatedSources[layer.source] = 'clear';
+ this._updatedSources[layer.source] = removed.type !== layer.type ? 'clear' : 'reload';
}
this._updateLayer(layer);
@@ -536,7 +538,7 @@ class Style extends Evented {
}
this._changed = true;
- this._removedLayers[id] = true;
+ this._removedLayers[id] = layer;
delete this._layers[id];
delete this._updatedLayers[id];
delete this._updatedPaintProps[id];
diff --git a/test/js/style/style.test.js b/test/js/style/style.test.js
index ce6a6b23a46..7411755c3f4 100644
--- a/test/js/style/style.test.js
+++ b/test/js/style/style.test.js
@@ -625,6 +625,72 @@ test('Style#addLayer', (t) => {
});
});
+ t.test('#3895 reloads source (instead of clearing) if adding this layer with the same type, immediately after removing it', (t) => {
+ const style = new Style(util.extend(createStyleJSON(), {
+ "sources": {
+ "mapbox": {
+ "type": "vector",
+ "tiles": []
+ }
+ },
+ layers: [{
+ "id": "my-layer",
+ "type": "symbol",
+ "source": "mapbox",
+ "source-layer": "boxmap",
+ "filter": ["==", "id", 0]
+ }]
+ }));
+
+ const layer = {
+ "id": "my-layer",
+ "type": "symbol",
+ "source": "mapbox",
+ "source-layer": "boxmap"
+ };
+
+ style.on('style.load', () => {
+ style.sourceCaches['mapbox'].reload = t.end;
+ style.sourceCaches['mapbox'].clearTiles = t.fail;
+ style.removeLayer('my-layer');
+ style.addLayer(layer);
+ style.update();
+ });
+ });
+
+ t.test('clears source (instead of reloading) if adding this layer with a different type, immediately after removing it', (t) => {
+ const style = new Style(util.extend(createStyleJSON(), {
+ "sources": {
+ "mapbox": {
+ "type": "vector",
+ "tiles": []
+ }
+ },
+ layers: [{
+ "id": "my-layer",
+ "type": "symbol",
+ "source": "mapbox",
+ "source-layer": "boxmap",
+ "filter": ["==", "id", 0]
+ }]
+ }));
+
+ const layer = {
+ "id": "my-layer",
+ "type": "circle",
+ "source": "mapbox",
+ "source-layer": "boxmap"
+ };
+
+ style.on('style.load', () => {
+ style.sourceCaches['mapbox'].reload = t.fail;
+ style.sourceCaches['mapbox'].clearTiles = t.end;
+ style.removeLayer('my-layer');
+ style.addLayer(layer);
+ style.update();
+ });
+ });
+
t.test('fires "data" event', (t) => {
const style = new Style(createStyleJSON()),
layer = {id: 'background', type: 'background'};