Skip to content

Add a stretchable image to the map

Replicates the MapLibre example Add a stretchable image to the map. The labels and icon-text-fit: both are YAML. Which pixels of the background image may stretch — stretchX, stretchY — and the box the text must fit inside (content) are addImage options the images: block doesn’t carry yet, so the page loads the two images and registers them with those zones. The layers wait hidden until then.

Bubbles stretch around one, two or three lines; the plain image sits below
add-a-stretchable-image-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/add-a-stretchable-image-to-the-map/
# The YAML half: four labels whose background image stretches to fit
# (`icon-text-fit: both`), plus the original image for comparison. The
# stretch zones (stretchX/stretchY/content) are addImage options with no
# `images:` field yet, so the page registers the two images — see
# add-a-stretchable-image-to-the-map.js — and the layers wait hidden.
type: map
id: add-a-stretchable-image-to-the-map
config:
center: [0, 0]
zoom: 0.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: [40, -30] }, properties: { image-name: popup-debug, name: "Line 1\nLine 2\nLine 3" } }
- { type: Feature, geometry: { type: Point, coordinates: [40, 30] }, properties: { image-name: popup, name: "Line 1\nLine 2\nLine 3" } }
- { type: Feature, geometry: { type: Point, coordinates: [-40, -30] }, properties: { image-name: popup-debug, name: One longer line } }
- { type: Feature, geometry: { type: Point, coordinates: [-40, 30] }, properties: { image-name: popup, name: One longer line } }
layout:
text-field: ["get", "name"]
text-font: ["Noto Sans Regular"]
icon-text-fit: both
icon-image: ["get", "image-name"]
icon-overlap: always
text-overlap: always
- id: original
type: symbol
visible: false
source:
type: geojson
location:
coordinates: [0, -70]
layout:
text-field: non-stretched image
text-font: ["Noto Sans Regular"]
icon-image: popup-debug
icon-overlap: always
text-overlap: always
add-a-stretchable-image-to-the-map.js
// The JavaScript half: addImage() options the `images:` block doesn't carry.
// stretchX/stretchY name the pixel columns and rows that may stretch (the
// blue and red bands of the debug image); `content` is the box the text
// must fit inside. Then the two layers the YAML declared hidden appear.
const mapEl = document.querySelector("ml-map");
const stretch = {
stretchX: [[25, 55], [85, 115]], // two horizontally stretchable column bands
stretchY: [[25, 100]], // one vertically stretchable row band
content: [25, 25, 115, 100], // [x1, y1, x2, y2] the text sits inside
pixelRatio: 2, // a high-dpi image
};
mapEl.mapReady().then(async (map) => {
const [debugPopup, popup] = await Promise.all([
map.loadImage("/gallery-assets/popup_debug.png"),
map.loadImage("/gallery-assets/popup.png"),
]);
map.addImage("popup-debug", debugPopup.data, stretch);
map.addImage("popup", popup.data, stretch);
mapEl.setLayerVisibility("points", true);
mapEl.setLayerVisibility("original", true);
});
  • In the debug image, blue columns are the horizontal stretch zones and the red row is the vertical one; everything else keeps its shape.
  • The plain original layer shows the unstretched image for comparison.
  • Images: the upstream example’s assets, served locally.