diff --git a/src/symbol/placement.js b/src/symbol/placement.js index 607f5316844..29df64e6f21 100644 --- a/src/symbol/placement.js +++ b/src/symbol/placement.js @@ -188,6 +188,25 @@ export class Placement { const textOptional = layout.get('text-optional'); const iconOptional = layout.get('icon-optional'); + const textAllowOverlap = layout.get('text-allow-overlap'); + const iconAllowOverlap = layout.get('icon-allow-overlap'); + // This logic is similar to the "defaultOpacityState" logic below in updateBucketOpacities + // If we know a symbol is always supposed to show, force it to be marked visible even if + // it wasn't placed into the collision index (because some or all of it was outside the range + // of the collision grid). + // There is a subtle edge case here we're accepting: + // Symbol A has text-allow-overlap: true, icon-allow-overlap: true, icon-optional: false + // A's icon is outside the grid, so doesn't get placed + // A's text would be inside grid, but doesn't get placed because of icon-optional: false + // We still show A because of the allow-overlap settings. + // Symbol B has allow-overlap: false, and gets placed where A's text would be + // On panning in, there is a short period when Symbol B and Symbol A will overlap + // This is the reverse of our normal policy of "fade in on pan", but should look like any other + // collision and hopefully not be too noticeable. + // See https://github.com/mapbox/mapbox-gl-js/issues/7172 + const alwaysShowText = textAllowOverlap && (iconAllowOverlap || !bucket.hasIconData() || iconOptional); + const alwaysShowIcon = iconAllowOverlap && (textAllowOverlap || !bucket.hasTextData() || textOptional); + const collisionGroup = this.collisionGroups.get(bucket.sourceID); if (!bucket.collisionArrays && collisionBoxArray) { @@ -289,7 +308,7 @@ export class Placement { assert(symbolInstance.crossTileID !== 0); assert(bucket.bucketInstanceId !== 0); - this.placements[symbolInstance.crossTileID] = new JointPlacement(placeText, placeIcon, offscreen || bucket.justReloaded); + this.placements[symbolInstance.crossTileID] = new JointPlacement(placeText || alwaysShowText, placeIcon || alwaysShowIcon, offscreen || bucket.justReloaded); seenCrossTileIDs[symbolInstance.crossTileID] = true; } } diff --git a/test/integration/render-tests/regressions/mapbox-gl-js#7172/expected.png b/test/integration/render-tests/regressions/mapbox-gl-js#7172/expected.png new file mode 100644 index 00000000000..4926dcafb02 Binary files /dev/null and b/test/integration/render-tests/regressions/mapbox-gl-js#7172/expected.png differ diff --git a/test/integration/render-tests/regressions/mapbox-gl-js#7172/style.json b/test/integration/render-tests/regressions/mapbox-gl-js#7172/style.json new file mode 100644 index 00000000000..6fc4b20e63e --- /dev/null +++ b/test/integration/render-tests/regressions/mapbox-gl-js#7172/style.json @@ -0,0 +1,67 @@ +{ + "version": 8, + "metadata": { + "test": { + "fadeDuration": 100, + "width": 512, + "height": 512, + "description": "This test ensures that symbols with allow-overlap: true are always visible, even if they get included in a placement where they are outside of the collision grid. Before the fix, this test showed partially transparent icons in the right quarter of the viewport.", + "operations": [ + ["wait", 100], + ["wait", 100], + ["setCenter", [ + 13.428056, + 52.499167 + ]], + ["wait"], + ["wait", 100], + [ + "wait", + 50 + ] + ] + } + }, + "center": [ + 13.418056, + 52.499167 + ], + "zoom": 14, + "sources": { + "mapbox": { + "type": "vector", + "maxzoom": 14, + "tiles": [ + "local://tiles/{z}-{x}-{y}.mvt" + ] + } + }, + "sprite": "local://sprites/sprite", + "layers": [ + { + "id": "background", + "type": "background", + "paint": { + "background-color": "white" + } + }, + { + "id": "icon", + "type": "symbol", + "source": "mapbox", + "source-layer": "poi_label", + "filter": [ + "==", + "maki", + "restaurant" + ], + "layout": { + "symbol-placement": "point", + "icon-allow-overlap": true, + "icon-ignore-placement": true, + "icon-image": "{maki}-12" + }, + "paint": {} + } + ] +}