diff --git a/src/symbol/placement.js b/src/symbol/placement.js index fc996d57627..ce645c8e45f 100644 --- a/src/symbol/placement.js +++ b/src/symbol/placement.js @@ -366,9 +366,16 @@ export class Placement { const layout = bucket.layers[0].layout; const duplicateOpacityState = new JointOpacityState(null, 0, false, false, true); + const textAllowOverlap = layout.get('text-allow-overlap'); + const iconAllowOverlap = layout.get('icon-allow-overlap'); + // If allow-overlap is true, we can show symbols before placement runs on them + // But we have to wait for placement if we potentially depend on a paired icon/text + // with allow-overlap: false. + // See https://github.com/mapbox/mapbox-gl-js/issues/7032 const defaultOpacityState = new JointOpacityState(null, 0, - layout.get('text-allow-overlap'), - layout.get('icon-allow-overlap'), true); + textAllowOverlap && (iconAllowOverlap || !bucket.hasIconData() || layout.get('icon-optional')), + iconAllowOverlap && (textAllowOverlap || !bucket.hasTextData() || layout.get('text-optional')), + true); for (let s = 0; s < bucket.symbolInstances.length; s++) { const symbolInstance = bucket.symbolInstances[s]; diff --git a/test/integration/render-tests/regressions/mapbox-gl-js#7032/expected.png b/test/integration/render-tests/regressions/mapbox-gl-js#7032/expected.png new file mode 100644 index 00000000000..73a3a03a124 Binary files /dev/null and b/test/integration/render-tests/regressions/mapbox-gl-js#7032/expected.png differ diff --git a/test/integration/render-tests/regressions/mapbox-gl-js#7032/style.json b/test/integration/render-tests/regressions/mapbox-gl-js#7032/style.json new file mode 100644 index 00000000000..e9859c4d43c --- /dev/null +++ b/test/integration/render-tests/regressions/mapbox-gl-js#7032/style.json @@ -0,0 +1,75 @@ +{ + "version": 8, + "metadata": { + "test": { + "height": 128, + "width": 128, + "description": "This test renders before the first placement happens, to exercise default opacities. Before fixing #7032, the restaurant icon would incorrectly appear even though its matched text hadn't been placed.", + "fadeDuration": 100, + "operations": [ + ["wait"], + ["wait", 50] + ] + } + }, + "center": [ 0, 0 ], + "zoom": 0, + "sources": { + "point": { + "type": "geojson", + "data": { + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [ 0, 0 ] + } + } + ] + } + } + }, + "glyphs": "local://glyphs/{fontstack}/{range}.pbf", + "sprite": "local://sprites/sprite", + "layers": [ + { + "id": "background", + "type": "background", + "paint": { + "background-color": "white" + } + }, + { + "id": "text", + "type": "symbol", + "source": "point", + "layout": { + "text-field": "Needs Placement", + "icon-image": "restaurant-12", + "text-allow-overlap": false, + "icon-allow-overlap": true, + "text-optional": false, + "text-font": [ + "Open Sans Semibold", + "Arial Unicode MS Bold" + ] + } + }, + { + "id": "label", + "type": "symbol", + "source": "point", + "layout": { + "text-field": "Shows w/o Placement", + "text-allow-overlap": true, + "text-font": [ + "Open Sans Semibold", + "Arial Unicode MS Bold" + ] + } + } + ] +}