mapbox / mapbox-gl-native

Interactive, thoroughly customizable maps in native Android, iOS, macOS, Node.js, and Qt applications, powered by vector tiles and OpenGL
https://mapbox.com/mobile
Other
4.36k stars 1.33k forks source link

symbolSortKey does not equally sort icon and text #15964

Closed johnnewman closed 4 years ago

johnnewman commented 4 years ago

When using MGLSymbolStyleLayer's symbolSortKey expression with textAllowsOverlap as false, text collisions cause the lower-sort features to take priority. Features with a lower sort will draw their text and cause features of a higher sort to hide theirs.

Steps to reproduce

  1. Draw two features on the map that overlap.
  2. Ensure they both have valid icon and text properties.
  3. Set textOptional to true, iconAllowsOverlap to true, and textAllowsOverlap to false.

Expected behavior

When the features collide:

Actual behavior

The icons are at the correct z-level, but the lower-sort feature's text has caused the higher-sort feature's text to hide.

The attached zip contains a sample Xcode project that demonstrates this issue. You'll just need to run a pod install and supply an API token in the app delegate. The output of the project is captured in the screenshot below. The red feature has a higher sort value, but its text is hidden.

TextLayeringProject.zip

Screen Shot 2019-11-22 at 5 25 32 PM

If I reverse the sort values by multiplying them all by -1, then the red icon appears with its text, but both the text and the icon are drawn below the now higher blue icon:

Screen Shot 2019-11-22 at 5 28 10 PM

Configuration

Mapbox SDK versions: 5.4.0 iOS/macOS versions: 13.2.2 Device/simulator models: 11 Xcode version: 11.2.1

chloekraw commented 4 years ago

Thanks for the report @johnnewman. This probably has the same root cause as https://github.com/mapbox/mapbox-gl-js/issues/8896.

cc @ansis @ahk @asheemmamoowala

johnnewman commented 4 years ago

@ansis @chloekraw I am still able to reproduce this issue using the sample project with the Mapbox iOS SDK v5.5.1.

For the two features in the sample, the only way I can get the red feature's text to draw above the blue feature is by setting the symbolZOrder to viewport-y. But this means we lose the finer-grained control that we hope to gain by using auto for symbolZOrder and specifying a sort value for symbolSortKey.

My goal is for both the icon and text to be prioritized based upon the symbolSortKey for that feature.

symbolZOrder = viewport-y; symbolSortKey = nil symbolZOrder = auto; symbolSortKey = sort symbolZOrder = auto; symbolSortKey = sort * -1
viewport-y sort sort * -1

Configuration

Mapbox SDK versions: 5.5.1 iOS/macOS versions: 13.3 Device/simulator models: 11 Xcode version: 11.3

chloekraw commented 4 years ago

@johnnewman thanks for the comment.

For the two features in the sample, the only way I can get the red feature's text to draw above the blue feature is by setting the symbolZOrder to viewport-y. But this means we lose the finer-grained control that we hope to gain by using auto for symbolZOrder and specifying a sort value for symbolSortKey.

I'm not sure if you misspoke here, but symbolSortKey has no effect when symbolZOrder is set to viewport-y. It must be set to auto in order for sort keys to be taken into consideration.

A few follow-up questions:

johnnewman commented 4 years ago

@chloekraw Thank you for your quick response.

Getting the red feature's text to draw over the blue feature with viewport-y was a lucky coincidence. I recognize that doing this will totally drop any sort control that the client has, because symbolSortKey will be ignored. In my tests, viewport-y was the only way to guarantee that text will never draw underneath an icon within the same layer.

chloekraw commented 4 years ago

@johnnewman I see. Unfortunately, symbolSortKey is not currently supported for your use case. The documentation means that when iconAllowOverlap or textAllowOverlap is enabled, a higher sort-key reflects higher priority. When *AllowOverlap is disabled, a lower sort-key reflects higher priority.

This is because when symbols are not allowed to overlap, symbols placed first cause subsequent symbols to be hidden due to collision detection. In contrast, symbols placed first when overlap is enabled are underneath symbols placed later. This is a reflection of how the renderer behaves and we understand it's suboptimal; however, it cannot be easily changed. We would like to investigate rewriting our shaders, placement logic, etc. in a way that may enable a future refactor of symbolSortKey to have consistent sorting based on priority, but this is a very large lift and not prioritized at the moment.

johnnewman commented 4 years ago

Thank you for the insight @chloekraw. Even though this refactor isn't prioritized at the moment, would it be possible to reopen this ticket so that we have something to track?

chloekraw commented 4 years ago

@johnnewman sure, I've opened a ticket here to track: https://github.com/mapbox/mapbox-gl-js/issues/9368