diff --git a/src/style/style.js b/src/style/style.js index 9e2c5935139..70523941871 100644 --- a/src/style/style.js +++ b/src/style/style.js @@ -412,8 +412,12 @@ class Style extends Evented { this._resetUpdates(); } + const sourcesUsedBefore = {}; + for (const sourceId in this.sourceCaches) { - this.sourceCaches[sourceId].used = false; + const sourceCache = this.sourceCaches[sourceId]; + sourcesUsedBefore[sourceId] = sourceCache.used; + sourceCache.used = false; } for (const layerId of this._order) { @@ -425,6 +429,13 @@ class Style extends Evented { } } + for (const sourceId in sourcesUsedBefore) { + const sourceCache = this.sourceCaches[sourceId]; + if (sourcesUsedBefore[sourceId] !== sourceCache.used) { + sourceCache.fire(new Event('data', {sourceDataType: 'visibility', dataType:'source', sourceId})); + } + } + this.light.recalculate(parameters); this.z = parameters.zoom; diff --git a/src/ui/control/attribution_control.js b/src/ui/control/attribution_control.js index a1664f7da2b..b057efde359 100644 --- a/src/ui/control/attribution_control.js +++ b/src/ui/control/attribution_control.js @@ -111,7 +111,7 @@ class AttributionControl { } _updateData(e: any) { - if (e && (e.sourceDataType === 'metadata' || e.dataType === 'style')) { + if (e && (e.sourceDataType === 'metadata' || e.sourceDataType === 'visibility' || e.dataType === 'style')) { this._updateAttributions(); this._updateEditLink(); } diff --git a/src/ui/events.js b/src/ui/events.js index 229818c612a..275225d61e5 100644 --- a/src/ui/events.js +++ b/src/ui/events.js @@ -264,7 +264,7 @@ export type MapBoxZoomEvent = { * @property {boolean} [isSourceLoaded] True if the event has a `dataType` of `source` and the source has no outstanding network requests. * @property {Object} [source] The [style spec representation of the source](https://www.mapbox.com/mapbox-gl-style-spec/#sources) if the event has a `dataType` of `source`. * @property {string} [sourceDataType] Included if the event has a `dataType` of `source` and the event signals - * that internal data has been received or changed. Possible values are `metadata` and `content`. + * that internal data has been received or changed. Possible values are `metadata`, `content` and `visibility`. * @property {Object} [tile] The tile being loaded or changed, if the event has a `dataType` of `source` and * the event is related to loading of a tile. * @property {Coordinate} [coord] The coordinate of the tile if the event has a `dataType` of `source` and diff --git a/test/unit/ui/control/attribution.test.js b/test/unit/ui/control/attribution.test.js index 0508f1609e4..3256110b533 100644 --- a/test/unit/ui/control/attribution.test.js +++ b/test/unit/ui/control/attribution.test.js @@ -239,3 +239,27 @@ test('AttributionControl hides attributions for sources that are not currently v } }); }); + +test('AttributionControl toggles attributions for sources whose visibility changes when zooming', (t) => { + const map = createMap(t); + const attribution = new AttributionControl(); + map.addControl(attribution); + + map.on('load', () => { + map.addSource('1', {type: 'geojson', data: {type: 'FeatureCollection', features: []}, attribution: 'Used'}); + map.addLayer({id: '1', type: 'fill', source: '1', minzoom: 12}); + }); + + map.on('data', (e) => { + if (e.dataType === 'source' && e.sourceDataType === 'metadata') { + t.equal(attribution._innerContainer.innerHTML, ''); + map.setZoom(13); + } + if (e.dataType === 'source' && e.sourceDataType === 'visibility') { + if (map.getZoom() === 13) { + t.equal(attribution._innerContainer.innerHTML, 'Used'); + t.end(); + } + } + }); +});