Skip to content

Generate and add a missing icon to the map

Replicates the MapLibre example Generate and add a missing icon to the map. The points and their data-driven icon name (square-rgb-<r,g,b>) are YAML. No image by those names exists anywhere: the page answers MapLibre’s request for each one by painting a square in the colour the name spells out: through map.setMissingStyleImageResolver() on maplibre-gl 6, which MapLibre awaits before treating the icon as missing, and through the styleimagemissing event on 4 and 5. The layer starts hidden so the handler is listening before the first icon request.

Three squares, each painted the moment MapLibre asked for it
generate-and-add-a-missing-icon-to-the-map.yaml
# yaml-language-server: $schema=https://docs.maplibre-yaml.org/schema/latest/map.schema.json
# Gallery twin of https://maplibre.org/maplibre-gl-js/docs/examples/generate-and-add-a-missing-icon-to-the-map/
# The YAML half: three points whose icon NAME is computed from data
# (`square-rgb-<r,g,b>`). No image by those names exists anywhere; the
# page answers MapLibre's styleimagemissing event by painting one on
# demand — see generate-and-add-a-missing-icon-to-the-map.js. The layer
# starts hidden so the handler is listening before the first request.
type: map
id: generate-and-add-a-missing-icon-to-the-map
config:
center: [0, 0]
zoom: 1
mapStyle: "https://demotiles.maplibre.org/style.json"
layers:
- id: points
type: symbol
visible: false
source:
type: geojson
data:
type: FeatureCollection
features:
- { type: Feature, geometry: { type: Point, coordinates: [0, 0] }, properties: { color: "255,0,0" } }
- { type: Feature, geometry: { type: Point, coordinates: [50, 0] }, properties: { color: "255,209,28" } }
- { type: Feature, geometry: { type: Point, coordinates: [-50, 0] }, properties: { color: "242,127,32" } }
layout:
icon-image: ["concat", "square-rgb-", ["get", "color"]]
generate-and-add-a-missing-icon-to-the-map.js
// The JavaScript half: MapLibre asks the page for an image it doesn't have,
// and the page paints it. The colour is parsed from the requested name
// itself, so any `square-rgb-r,g,b` works.
//
// maplibre-gl 6 asks through map.setMissingStyleImageResolver(), which it
// awaits before the icon counts as missing; an image added from the old
// `styleimagemissing` event arrives too late there. maplibre-gl 4 and 5
// only have the event, where a synchronous addImage() is in time.
const mapEl = document.querySelector("ml-map");
const prefix = "square-rgb-";
function paint(map, id) {
if (!id.startsWith(prefix)) return; // not one this page can make
const rgb = id.slice(prefix.length).split(",").map(Number);
const width = 64;
const data = new Uint8Array(width * width * 4);
for (let i = 0; i < width * width; i++) {
data.set([rgb[0], rgb[1], rgb[2], 255], i * 4);
}
map.addImage(id, { width, height: width, data });
}
mapEl.mapReady().then((map) => {
if (typeof map.setMissingStyleImageResolver === "function") {
map.setMissingStyleImageResolver((id) => paint(map, id));
} else {
map.on("styleimagemissing", ({ id }) => paint(map, id));
}
// Listening now — let the layer request its icons.
mapEl.setLayerVisibility("points", true);
});
  • The handler must call addImage synchronously; MapLibre re-checks for the image as soon as the event returns.
  • maplibre-yaml’s own missing-image warning defers to page handlers: an image supplied this way is never reported as missing.