Symbol Layer
A symbol layer renders icons, text labels, or both at point locations from a GeoJSON source. It's the style-layer equivalent of addSymbol(), but scales to any number of features and supports data-driven styling.
Ten European cities with custom marker icons and text labels, rendered from a GeoJSON source.
Add sources and layers after the style loads
Every call below needs a loaded style. Run them from onStyleLoadedCallback,
not from onMapCreated, and run them there again after a style change: a new
style discards every source and layer you added. See
Constraints and gotchas.
Basic setup
// 1. Register a custom icon
final bytes = await rootBundle.load('assets/marker.png');
await controller.addImage('my-marker', bytes.buffer.asUint8List());
// 2. Add a GeoJSON source with point features
await controller.addGeoJsonSource('cities', {
'type': 'FeatureCollection',
'features': [
{
'type': 'Feature',
'properties': {'name': 'Paris'},
'geometry': {'type': 'Point', 'coordinates': [2.3522, 48.8566]},
},
],
});
// 3. Add a symbol layer referencing the source
await controller.addSymbolLayer(
'cities',
'cities-layer',
const SymbolLayerProperties(
iconImage: 'my-marker',
iconSize: 1.0,
iconAnchor: 'bottom',
iconAllowOverlap: true,
textField: [Expressions.get, 'name'],
textSize: 13,
textOffset: [0, 1.2],
textAnchor: 'top',
textHaloColor: '#ffffff',
textHaloWidth: 2,
),
);
Data-driven icon and text
SymbolLayerProperties(
// Different icon per category
iconImage: [
Expressions.match,
[Expressions.get, 'type'],
'restaurant', 'restaurant-icon',
'hotel', 'hotel-icon',
'default-icon', // fallback
],
// Text from a property
textField: [Expressions.get, 'name'],
// Text size driven by a rank property
textSize: [
Expressions.interpolate, ['linear'],
[Expressions.get, 'rank'],
1, 16.0, // rank 1 -> 16px
5, 10.0, // rank 5 -> 10px
],
)
Collision behavior
Symbols automatically avoid each other. Control this:
SymbolLayerProperties(
iconAllowOverlap: true, // icons always show, even if overlapping
iconIgnorePlacement: false, // icons consider others' space
textAllowOverlap: false, // labels hide if they overlap
symbolAvoidEdges: true, // keep symbols away from map edges
)
Text layout
SymbolLayerProperties(
textField: [Expressions.get, 'name'],
textSize: 13,
textAnchor: 'top', // relative to the symbol point
textJustify: 'center', // left, center, right
textOffset: [0, 1.5], // [x, y] in ems
textRotate: 0, // degrees
textMaxWidth: 8, // wrap at 8 ems
textLetterSpacing: 0.05,
)
Raise symbols above the map (web)
On web, symbolHeightOffset places icons and text the given number of meters above their anchor, for labels that float over 3D buildings or terrain:
Android and iOS ignore it.
Update layer properties
await controller.setLayerProperties(
'cities-layer',
const SymbolLayerProperties(
textSize: 16,
iconSize: 1.5,
),
);
Filter by property
await controller.addSymbolLayer(
'cities', 'major-cities',
SymbolLayerProperties(...),
filter: ['>=', ['get', 'population'], 1000000], // only cities with pop >= 1M
);
Symbols that update often
MapLibre fades symbols in as it places them. With a layer you update often, such as live vehicles, this makes updated symbols flicker. Turning placement transitions off places symbols at once, without fading. It applies to every symbol on the map, the style's labels included.
Off for the whole map
Best when your data updates every second or more often.
The base map's labels also stop fading while zooming and panning.
Off only during an update
Keeps the base map's fades.
await controller.setSymbolPlacementTransitionsEnabled(false);
await controller.setGeoJsonSource('vehicles', data);
await controller.setSymbolPlacementTransitionsEnabled(true);
Android
If your style declares no transition, symbols stop fading after the first update. Add "transition": {"duration": 300, "delay": 0} to the style to keep them.
See Live Symbols (Placement Transitions) in the example app.
Key SymbolLayerProperties fields
| Property | Description |
|---|---|
iconImage |
Icon name (registered via addImage) |
iconSize |
Scale factor (1.0 = original) |
iconAnchor |
Which part of icon touches the point |
iconOffset |
[x, y] pixel offset |
iconColor |
Tint color (SDF icons only) |
iconAllowOverlap |
Show even if overlapping other icons |
textField |
Label text (string or expression) |
textSize |
Font size in pixels |
textColor |
Label color |
textHaloColor / textHaloWidth |
Outline around text |
textAnchor |
Anchor relative to point |
textOffset |
[x, y] offset in ems |
symbolPlacement |
point or line |