-
Notifications
You must be signed in to change notification settings - Fork 2.3k
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
Variable text placement for point labels #5038
Comments
A feature like this existed in CartoCSS (implemented by TileMill), which I used quite a lot. One tweak I would like to request is the ability to tweak the workflow:
My preference was generally that I want every label to be shown (especially important for static maps), so I want the mapping engine to try to avoid collisions, but to fallback to placing with a collision if necessary. CartoCSS only gave the ability to either avoid collisions (but maybe get no label) or allow collisions (and make no attempt to avoid them), so it'd be great to have a middle option. |
Thanks for the feedback, @stevage! I'm not sure how straightforward or difficult that ability would be to implement – @ansis or @ChrisLoer would have a better sense. It might be straightforward to attempt adding the feature one more time after all placement options fail, with the first placement option and as if |
Yeah, good thought. There are definitely use cases for having that flag on or off. General purpose maps for mass audiences probably value looking nice and avoiding any label collisions. Specialist maps for niche audiences probably value getting all the information shown one way or the other. |
@nickidlugash Can the unit of text-offset be specified in terms of the icon next to which text is being placed instead of ems? In all the examples you have included above assume that the icon is smaller than 1emx1em. The style will break, the moment one decides to use larger icons. This is an issue even today if the style uses larger icons. It would be nice if one could create robust "place text below icon layers" in the style that do not depend on icon size in ems. |
@mb12 An ideal unit for text offset is tricky because in practice, the ideal offset often needs to be relative to both the icon size and the text size (or line width and text size, for offset line labels). Currently you can use icons larger than 1emx1em since you can specify a value of larger than 1, but would require a property function value if you want to use a variety of icon sizes within a single style layer. There are definite pain points to specifying offset values right now, as you've highlighted, so if we do consider implementing a new offset property, we'll need to take this into consideration. I suggested pixels as a alternative unit with the thought that an absolute unit in conjunction with the upcoming expressions syntax might make it easier to take into account both icon/line and text size. |
This would tie in nicely with #6432 to ensure labels are drawn on screen if they would otherwise be cut offscreen. |
We have a PR up implementing this! Please check it out: #7596 @stevage the PR doesn't include the |
Implemented in #7596. 🎉 |
The purpose of this is ticket is to discuss and document our experimentation with variable text placement for point labels, and to decide if we want to implement this in Mapbox GL as an alternative option to fixed label placements.
Generally, variable label placement is the ability for the renderer to assign different placements for a label in order to improve the likelihood that the label will be visible.
Implementing viewport label placement will unblock this ability. (Caveat: we can't implement this for api-gl, as cross-tile placements would not be predictable.)
Example placement workflow:
For each label:
Benefits
Allowing variable label placements should result in label visibility that more closely matches a map designer's intent, as defined by the zoom level visibility and placement order of features in the data source + stylesheet. Specifically:
1. Improved label hierarchy
With a fixed label placement, it's common for a label that was attempted to be placed later (and therefore generally less important) to be visible while a label that was attempted to be placed earlier (and therefore generally more important) to be hidden. This is due to a collision between the label with earlier placement and another label with even earlier placement.
For example:
In this example, Label 1 is placed first. Label 2 is attempted to be placed second, but with the fixed placement, it collides with Label 1 and does not get placed. With a variable placement, using the second placement option (the right side) gives Label 2 space to be placed. Label 3 is attempted to be placed third, and with the fixed placement there is space for it to be placed since Label 2 was not placed. With the variable placement, Label 3 collides with Label 2 and does not get placed. Even though the number of labels visible is the same with fixed and variable placement in this example, variable placement improves the visibility of more important labels.
2. Improved label density
In addition, variable label placement can allow more labels overall to be visible, to more closely match the density of the data.
For example:
In this example, a fixed placement allows 2 out of 3 labels to be visible, while a variable placement allows all 3 labels to be visible.
Spec implementation
Text "placement" here refers specifically to a combination of 3 style spec layout properties:
text-anchor
text-justify
text-offset
Typical combinations of this are:

Assuming that we want to allow users to control the variable placement options (which I think is fairly necessary for this to be useful), here's a few possible spec changes to consider:
Allow array values (stacks) for the 3 relevant properties
For these 3 properties, we could allow users to specify an array of values that are treated as a stack.
These 3 properties would need to be evaluated together, i.e. each array would be required to have the same length, and the corresponding position in each array would need to be applied together.
e.g. If these
text-anchor: [left, right, top, bottom]
text-justify: [left, right, center, center]
text-offset: [[0.5, 0], [-0.5, 0], [0, 0.5], [0, -0.5]]
Then the first placement option would be:
text-anchor: left
text-justify: left
text-offset: [0.5, 0]
Add new properties for text offsets
Our current implementation of the
text-offset
property uses x/y coordinates to define the offset, which means that offset distance and direction are defined together. We may want to explore the possibility of adding new properties that separate these two variables, e.g.text-offset-distance
andtext-offset-direction
.Benefits compared to using current
text-offset
property:Implementation considerations:
text-offset
?text-offset-distance
:text-offset
unit)text-offset-direction
:text-anchor
text-anchor
values +auto
(followstext-anchor
))e.g.
text-justify: [left, right, center, center]
text-anchor: [left, right, top, bottom]
text-offset-distance: 20
text-offset-direction auto
Challenges
text-optional: true
for dense, low priority point labels (e.g. small point-of-interest like stores and restaurant in Mapbox Streets vector tiles) may help with stability, particularly during rotation.Next steps
1. Prototype
@mollymerp is working on an initial mapbox-gl-js prototype in this branch, with placement logic hardcoded in the renderer.
2. Compare prototypes to fixed placement styling
Using two sets of features in Mapbox Streets vector tiles as case studies, I plan to compare the initial prototypes to our current fixed placement styling (using the new viewport placement implementation):
City labels with data-driven placement values.
POI labels with a single placement value
3. Document more use cases
I've been mostly focused on evaluating variable label placement for use with our Mapbox Streets vector tiles. If you have a real or hypothetical use case for this, please comment below!
4. Explore options for spec implementation
I included a few initial ideas here, and will continue to round up feedback, alternatives suggestions, and important considerations.
Other variable placement options for future consideration
/cc @mollymerp @ChrisLoer @ansis @mapbox/gl-core @ajashton @ericwolfe @peterliu
(Please cc anyone else who might be interested in this topic.)
The text was updated successfully, but these errors were encountered: