maplibre / maplibre-style-spec

MapLibre Style Specification & Utilities
https://maplibre.org/maplibre-style-spec/
Other
69 stars 59 forks source link

Default anchor for icons #763

Open westinrm opened 1 month ago

westinrm commented 1 month ago

Design Proposal: Default anchor for icons

Motivation

Icon anchors are frequently the same for every different usage of the icons, and for dynamically created or loaded icons it is very difficult or impossible to provide them when writing the style. (https://github.com/mapbox/mapbox-gl-js/issues/5369)

Proposed Change

Add intrinsic variations to most alignment and anchor options for symbol fields that read a default value that was defined in the sprite sheet or when the sprite was added to the map.

API Modifications

Add a intrinsic option to the icon-anchor, text-anchor, and text-justify style properties.

Add a intrinsic-text-anchor: [number, number], intrinsic-icon-anchor: [number, number], and intrinsic-text-justify: [ ... ] to the sprite definition

Migration Plan and Compatibility

The new functionality is strictly additive so it should not require any changes by users. Users that use the same settings for every usage of a symbol may convert those declarations to using the intrinsic settings.

Rejected Alternatives

HarelM commented 1 month ago

Can you use some illustrations and examples to better explain the problem and solution? Generally speaking, placing something that is called "text-anchor" in sprite.json seems like a "smell" to me too be honest...

westinrm commented 1 month ago

sprite.json already has parameters for having the shape of the sprite respond to text. (stretchX, stretchY, textFitWidth, textFitHeight). Where/how to display text is part of a sprite's definition for things like highway shields.

The example I have on hand is a SDF backed magnifying glass: image I want the center of the magnifying glass on the feature, and the text next to the handle: image

I need to define:

icon-offset: [ -5, -5 ]
text-offset: [ 20, 20 ]
text-justify: 'left'

This is easy enough if the style I'm writing is using a constant image, however it is becomes difficult if I'm basing the chosen icon on a feature property:

icon-image: [ 'case', cond, 'magnifying', 'other' ]
icon-offset: [ 'case', cond, [ -5, -5 ], [ 0, 0 ] ]
text-offset: [ 'case', cond, [ 20, 20 ], [ 0, 0 ] ]
text-justify: [ 'case', cond, 'left', 'center' ]

This only works though when the entire set of icons is known at style creation time, something that isn't the case if you're using styleimagemissing to dynamically load icons.

HarelM commented 1 month ago

Shields are a very bad example of how sprite json definition got ugly, I wouldn't use it to make a point... If I could, I would have removed it from the sorite spec and create a whole separate definition just for shields. Let's try and find a better home for this new requirement...

HarelM commented 1 month ago

If you are using stylemissingimage then why bother adding a spec definition (you are not using the style.json) anyway so you can code around it.

westinrm commented 1 month ago

Unless I'm missing something I would have to:

The issue here is that I don't know all of the possible icons when creating the style, which means I can't correctly fill in the icon offset/etc expressions.

The spec definition for sprites defines the StyleImageMetadata typescript type, which is an argument to map.addImage.