Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add symbol-sort-key style property #7678

Merged
merged 4 commits into from
Dec 12, 2018
Merged

add symbol-sort-key style property #7678

merged 4 commits into from
Dec 12, 2018

Conversation

ansis
Copy link
Contributor

@ansis ansis commented Dec 6, 2018

This property allows users to specify a sorting order for symbols. Symbols are sorted in ascending order based on the key. Symbols with lower keys will appear below symbols with higher keys when they are rendered with overlap. Symbols with lower keys will be placed before symbols with higher keys.

This fixes #7111 by defining a sort order across tile boundaries.

This also adds an auto option for symbol-z-order which will be the new default. It does not change the behavior of the default value though.

Launch Checklist

  • briefly describe the changes in this PR
  • write tests for all new functionality
  • document any changes to public APIs
  • post benchmark scores (everything passed)
  • manually test the debug page
  • tagged @mapbox/studio and/or @mapbox/maps-design if this PR includes style spec changes
  • think about adding a benchmark for symbols

features

[
    { id: 1, properties: { key: 1 }, geometry: {}},
    { id: 0, properties: { key: 0 }, geometry: {}},
    { id: 2, properties: { key: 2 }, geometry: {}},
];

With the following style you would render feature 2 above feature 1 above feature 0:

"symbol-sort-key": ["get", "key"],
"icon-allow-overlap": true

With the following style it would give feature 0 priority over other features if they collide:

"symbol-sort-key": ["get", "key"],
"icon-allow-overlap": false

@mapbox/studio @mapbox/maps-design

  • does this accomplish what you want out of sorting feature?
  • Would another name be clearer?
  • Is ascending sort order the right choice?

Sorting between layers is currently out of scope.

This property allows users to specify a sorting order for symbols.
Symbols are sorted in ascending order based on the key. Symbols
with lower keys will appear below symbols with higher keys when
they are rendered with overlap. Symbols with lower keys will be placed
before symbols with higher keys.

This also fixes #7111 by defining a sort order across tile boundaries.
@ansis ansis requested a review from ChrisLoer December 6, 2018 16:38
@ansis
Copy link
Contributor Author

ansis commented Dec 7, 2018

Tagging @kkaefer because he opened the initial proposal in #4361. This implementation adds sorting as a layout property instead of a top level property because adding layout properties seems easier. This also uses a key instead of a comparator because while it is less powerful it is a bit simpler with expressions and a bit more optimizable.

painter.transform.zoom, buffers.programConfigurations.get(layer.id),
buffers.dynamicLayoutVertexBuffer, buffers.opacityVertexBuffer);
}

function drawSymbolsSorted(painter: Painter, renderData: Array<SymbolTileRenderState>, layer, colorMode, stencilMode) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we refactor this so it's "prepare draw state per tile, then draw once per segment" whether we're sorting or not? I think it would be easier to follow that way -- we wouldn't have to deal with the ambiguous naming that drawLayerSymbols is sometimes a preparation step and sometimes an actual draw step.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think my thinking here was to avoid the extra overhead for symbol layers that don't need this but I should probably benchmark to see if this is valid. It looks like it should be pretty cheap to do what you are suggesting.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ChrisLoer I've pushed a commit to always use the preparation step. Can you review?

@kkaefer
Copy link
Contributor

kkaefer commented Dec 7, 2018

Is ascending sort order the right choice?

We could add a "symbol-sort-order": "desc" | "asc" to specify the order. Without that key, you'd have to resort to a hack like "symbol-sort-key": ["-", 100000000, ["get", "key"]] for numeric keys (and it's unclear to me what you'd use for textual keys).

uses a key instead of a comparator because while it is less powerful it is a bit simpler with expressions

We could use an expression like ["<", ["get", "key", "lhs"], ["get", "key", "rhs"]] to allow comparators. The special names lhs/rhs in get and has expressions would be the two features being compared during sorting. However, you're right in pointing out that this is more complex (and probably slower) than using a sort key.

@ansis
Copy link
Contributor Author

ansis commented Dec 10, 2018

We could add a "symbol-sort-order": "desc" | "asc"

We decided that we should leave this out and add it later if it seems useful.

We could use an expression like ["<", ["get", "key", "lhs"], ["get", "key", "rhs"]] to allow comparators.

We decided to use keys for simplicity. If we need to support tie breaking later one we can try to add arrays of keys.

@kkaefer
Copy link
Contributor

kkaefer commented Dec 11, 2018

/cc @mapbox/studio

Copy link
Member

@tristen tristen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changes LGTM. I can see this being worthwhile to account for in Studio. Especially for custom data where features may not be sorted correctly.

The original issue brought up supporting this for circle types. Curious what the timing is for that along with other layer types like line, fill?

@ChrisLoer
Copy link
Contributor

LGTM! But let's add at least one render test that exercises sorting at a tile boundary?

@ansis
Copy link
Contributor Author

ansis commented Dec 11, 2018

@ChrisLoer thanks for catching that, I forgot to commit them. The render tests test sorting at boundaries for text, icons and for text, and with placement enabled.

Copy link
Contributor

@ChrisLoer ChrisLoer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎉

@nickidlugash
Copy link

nickidlugash commented Dec 11, 2018

Is ascending sort order the right choice?

This answer is kinda hard to answer though since the hierarchy is reverse for the two styling options (overlapping or not). I could see use cases for both ascending and descending, but this seems reasonable if we have to pick one.

Would another name be clearer?

symbol-sort-key sounds fine. I guess symbol-sort-property would be the other idea that comes to mind, since we refer to data fields as property in multiple other areas of the spec.

@mapcarta
Copy link

mapcarta commented Mar 6, 2019

Could symbol-sort-key also work for text overlap? It currently only seems to work for icon overlap ('icon-allow-overlap':false). The idea could be extended to be text overlap for the following style:

[ 'icon-allow-overlap':true, 'text-allow-overlap':false ]

@aMoniker
Copy link

aMoniker commented Apr 5, 2019

@ansis

We decided that we should leave ["symbol-sort-order": "desc" | "asc"] out and add it later if it seems useful.

This was an unfortunate decision for us. We have a symbol layer rendering location names, and a circle layer rendering their points. The source is the same for both, and is sorted in descending order by our own concept of location "importance".

The top labels are rendered first, and preclude others that follow due to collision. However, the circle layer renders the least important points last, which means they occlude the more important points. This matters for us since our circles are color-coded (low importance locations are usually grey).

Our case would be solved by introducing symbol-sort-order, though it would also mean we'd have to ship an extra property for every single point which indicates its order.

More ideal would be adding another option to symbol-z-order called something like source-reversed, so we could return our source points in reverse order so circles render properly, while also using source-reversed on the symbol layer so those render properly.

It seems like either suggestion above shouldn't be too bad implement, though I can't say with certainty without knowing the codebase. Would it be possible to introduce one of the features above, or any other option that would solve this use case?

@ansis
Copy link
Contributor Author

ansis commented May 20, 2019

@aMoniker sorry, I missed this comment earlier. Would it be possible for you to add a property in the data which you could use with symbol-sort-key to reverse? I understand that a reversal property might be simpler for your use case but we need to balance supporting specific use cases with the complexity that adding new properties introduces.

@aMoniker
Copy link

@ansis No worries, I appreciate the reply. I suppose we could add a ranking property to the features shipped by our tile server for use with symbol-sort-key, though from the PR description it sounds like we'd have to ship an inverse of that property since lower values take precedence when colliding. We'd also have to reverse the order in which the features were returned, so that the circle layer renders properly.

@ansis
Copy link
Contributor Author

ansis commented May 21, 2019

You could also use expression to invert the value ["-", ["get", "my-sort-key-property"]]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Enable consistent sorting across tile boundaries
7 participants