Closed johnnewman closed 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
@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 |
---|---|---|
Mapbox SDK versions: 5.5.1 iOS/macOS versions: 13.3 Device/simulator models: 11 Xcode version: 11.3
@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:
iconAllowOverlap
is enabled; is textAllowOverlap
disabled? It might be helpful to share the rest of your runtime styling properties as well.sort
from the second example by -1
, so the red icon actually has a lower sort key?@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.
textAllowsOverlap
property is set to false
. Here are the full properties from that sample:
layer.text = NSExpression(forKeyPath: "text")
layer.iconImageName = NSExpression(forKeyPath: "icon")
layer.textAnchor = NSExpression(forConstantValue: NSValue(mglTextAnchor: .left))
layer.textJustification = NSExpression(forConstantValue: NSValue(mglTextJustification: .left))
layer.textColor = NSExpression(forConstantValue: UIColor.black)
layer.textAllowsOverlap = NSExpression(forConstantValue: NSNumber(value: false))
layer.iconAllowsOverlap = NSExpression(forConstantValue: NSNumber(value: true))
layer.textOptional = NSExpression(forConstantValue: NSNumber(value: true))
layer.textFontSize = NSExpression(forConstantValue: NSNumber(value: 13))
layer.textOffset = NSExpression(forConstantValue: NSValue(cgVector: CGVector.init(dx: 1, dy: 0)))
layer.symbolSortKey = symbolSortKeyExpression()
Yep! The same sort integer was used in both test cases. Here is the snippet from the sample project where you can change it:
/// Our goal is to get the red pin (sort 100) to appear above the blue pin (sort 0).
/// Since the red is on top, we also want the red pin's text to draw at the same z-level.
private func symbolSortKeyExpression() -> NSExpression {
// Red icon on top; blue text appears
return NSExpression(forKeyPath: "sort")
// Blue icon on top; red text appears
// return NSExpression(forFunction: "multiply:by:", arguments: [NSExpression(forKeyPath: "sort"), NSExpression(forConstantValue: -1)])
}
auto
for symbolZOrder
and rely on symbolSortKey
to handle the z sorting. My issue is that when I do that, the text is not guaranteed to draw at the same z-level as the icon.@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.
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?
@johnnewman sure, I've opened a ticket here to track: https://github.com/mapbox/mapbox-gl-js/issues/9368
When using MGLSymbolStyleLayer's
symbolSortKey
expression withtextAllowsOverlap
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
icon
andtext
properties.textOptional
to true,iconAllowsOverlap
to true, andtextAllowsOverlap
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
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:Configuration
Mapbox SDK versions: 5.4.0 iOS/macOS versions: 13.2.2 Device/simulator models: 11 Xcode version: 11.2.1