diff --git a/src/style/style.js b/src/style/style.js index 977fa39361f..e9d20e764e1 100644 --- a/src/style/style.js +++ b/src/style/style.js @@ -345,6 +345,7 @@ class Style extends Evented { return; } + const changed = this._changed; if (this._changed) { const updatedIds = Object.keys(this._updatedLayers); const removedIds = Object.keys(this._removedLayers); @@ -369,8 +370,6 @@ class Style extends Evented { this.light.updateTransitions(parameters); this._resetUpdates(); - - this.fire(new Event('data', {dataType: 'style'})); } for (const sourceId in this.sourceCaches) { @@ -388,6 +387,11 @@ class Style extends Evented { this.light.recalculate(parameters); this.z = parameters.zoom; + + if (changed) { + this.fire(new Event('data', {dataType: 'style'})); + } + } _updateWorkerLayers(updatedIds: Array, removedIds: Array) { diff --git a/src/ui/control/attribution_control.js b/src/ui/control/attribution_control.js index 5f2b83944db..133945a7c1d 100644 --- a/src/ui/control/attribution_control.js +++ b/src/ui/control/attribution_control.js @@ -59,6 +59,7 @@ class AttributionControl { this._updateAttributions(); this._updateEditLink(); + this._map.on('styledata', this._updateData); this._map.on('sourcedata', this._updateData); this._map.on('moveend', this._updateEditLink); @@ -73,6 +74,7 @@ class AttributionControl { onRemove() { DOM.remove(this._container); + this._map.off('styledata', this._updateData); this._map.off('sourcedata', this._updateData); this._map.off('moveend', this._updateEditLink); this._map.off('resize', this._updateCompact); @@ -104,7 +106,7 @@ class AttributionControl { } _updateData(e: any) { - if (e && e.sourceDataType === 'metadata') { + if (e && (e.sourceDataType === 'metadata' || e.dataType === 'style')) { this._updateAttributions(); this._updateEditLink(); } @@ -129,9 +131,12 @@ class AttributionControl { const sourceCaches = this._map.style.sourceCaches; for (const id in sourceCaches) { - const source = sourceCaches[id].getSource(); - if (source.attribution && attributions.indexOf(source.attribution) < 0) { - attributions.push(source.attribution); + const sourceCache = sourceCaches[id]; + if (sourceCache.used) { + const source = sourceCache.getSource(); + if (source.attribution && attributions.indexOf(source.attribution) < 0) { + attributions.push(source.attribution); + } } } diff --git a/test/unit/ui/control/attribution.test.js b/test/unit/ui/control/attribution.test.js index 01611cd4e1f..cf4a7f68fe3 100644 --- a/test/unit/ui/control/attribution.test.js +++ b/test/unit/ui/control/attribution.test.js @@ -81,14 +81,20 @@ test('AttributionControl dedupes attributions that are substrings of others', (t map.addControl(attribution); map.on('load', () => { - map.addSource('1', { type: 'vector', attribution: 'World' }); - map.addSource('2', { type: 'vector', attribution: 'Hello World' }); - map.addSource('3', { type: 'vector', attribution: 'Another Source' }); - map.addSource('4', { type: 'vector', attribution: 'Hello' }); - map.addSource('5', { type: 'vector', attribution: 'Hello World' }); + map.addSource('1', { type: 'geojson', data: { type: 'FeatureCollection', features: [] }, attribution: 'World' }); + map.addSource('2', { type: 'geojson', data: { type: 'FeatureCollection', features: [] }, attribution: 'Hello World' }); + map.addSource('3', { type: 'geojson', data: { type: 'FeatureCollection', features: [] }, attribution: 'Another Source' }); + map.addSource('4', { type: 'geojson', data: { type: 'FeatureCollection', features: [] }, attribution: 'Hello' }); + map.addSource('5', { type: 'geojson', data: { type: 'FeatureCollection', features: [] }, attribution: 'Hello World' }); map.addSource('6', { type: 'geojson', data: { type: 'FeatureCollection', features: [] }, attribution: 'Hello World' }); map.addSource('7', { type: 'geojson', data: { type: 'FeatureCollection', features: [] }, attribution: 'GeoJSON Source' }); - + map.addLayer({ id: '1', type: 'fill', source: '1' }); + map.addLayer({ id: '2', type: 'fill', source: '2' }); + map.addLayer({ id: '3', type: 'fill', source: '3' }); + map.addLayer({ id: '4', type: 'fill', source: '4' }); + map.addLayer({ id: '5', type: 'fill', source: '5' }); + map.addLayer({ id: '6', type: 'fill', source: '6' }); + map.addLayer({ id: '7', type: 'fill', source: '7' }); }); let times = 0; @@ -107,7 +113,8 @@ test('AttributionControl has the correct edit map link', (t) => { const attribution = new AttributionControl(); map.addControl(attribution); map.on('load', () => { - map.addSource('1', {type: 'vector', attribution: 'Improve this map'}); + map.addSource('1', { type: 'geojson', data: { type: 'FeatureCollection', features: [] }, attribution: 'Improve this map'}); + map.addLayer({ id: '1', type: 'fill', source: '1' }); map.on('data', (e) => { if (e.dataType === 'source' && e.sourceDataType === 'metadata') { t.equal(attribution._editLink.href, 'https://www.mapbox.com/feedback/?owner=mapbox&id=streets-v10&access_token=pk.123#/0/0/0', 'edit link contains map location data'); @@ -124,7 +131,8 @@ test('AttributionControl is hidden if empty', (t) => { const attribution = new AttributionControl(); map.addControl(attribution); map.on('load', () => { - map.addSource('1', { type: 'vector' }); + map.addSource('1', { type: 'geojson', data: { type: 'FeatureCollection', features: [] }}); + map.addLayer({ id: '1', type: 'fill', source: '1' }); }); const container = map.getContainer(); @@ -133,7 +141,8 @@ test('AttributionControl is hidden if empty', (t) => { t.equal(attribution._container.innerHTML, ''); t.equal(container.querySelectorAll('.mapboxgl-attrib-empty').length, 1, 'includes empty class when no attribution strings are provided'); - map.addSource('2', { type: 'vector', attribution: 'Hello World' }); + map.addSource('2', { type: 'geojson', data: { type: 'FeatureCollection', features: [] }, attribution: 'Hello World'}); + map.addLayer({ id: '2', type: 'fill', source: '2' }); }; const checkNotEmptyLater = () => { @@ -179,3 +188,27 @@ test('AttributionControl shows all custom attributions if customAttribution arra ); t.end(); }); + +test('AttributionControl hides attributions for sources that are not currently visible', (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.addSource('2', { type: 'geojson', data: { type: 'FeatureCollection', features: [] }, attribution: 'Not used' }); + map.addSource('3', { type: 'geojson', data: { type: 'FeatureCollection', features: [] }, attribution: 'Vibility none' }); + map.addLayer({ id: '1', type: 'fill', source: '1' }); + map.addLayer({ id: '3', type: 'fill', source: '3', layout: { visibility: 'none' } }); + }); + + let times = 0; + map.on('data', (e) => { + if (e.dataType === 'source' && e.sourceDataType === 'metadata') { + if (++times === 3) { + t.equal(attribution._container.innerHTML, 'Used'); + t.end(); + } + } + }); +});