Add a canvas source
Replicates the MapLibre example Add a canvas source. A canvas source has no YAML form — its content is drawn by page JS every frame, so a declarative description would describe nothing. The YAML holds the map; the page animates bouncing circles on a hidden <canvas> and, once mapReady() resolves, adds a canvas source pinned to four corners plus a raster layer to draw it.
The YAML half
Section titled “The YAML half”# 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-canvas-source/# The YAML half: the map and its camera limits. A `canvas` source has no# YAML form — its content is drawn by page JS every frame anyway — so the# source and its raster layer are added in add-a-canvas-source.js.type: mapid: add-a-canvas-sourceconfig: center: [95.899147, 18.088694] zoom: 5 minZoom: 4 mapStyle: "https://demotiles.maplibre.org/style.json"The page half
Section titled “The page half”This markup goes inside <ml-map>; children with a slot ride its corner system.
<!-- Not slotted: the drawing surface stays hidden inside <ml-map>. --><canvas data-canvas-source width="400" height="400" hidden></canvas>The JavaScript half
Section titled “The JavaScript half”// The JavaScript half: a `canvas` source, added through mapReady(). The page// animates bouncing circles on a hidden <canvas>; MapLibre re-reads it// every frame (animate: true) and drapes it over four corner coordinates.const mapEl = document.querySelector("ml-map");const canvas = document.querySelector("[data-canvas-source]");const ctx = canvas.getContext("2d");const size = canvas.width;const radius = 20;
const circles = Array.from({ length: 5 }, () => ({ x: Math.random() * (size - radius * 2) + radius, y: Math.random() * (size - radius * 2) + radius, dx: (Math.random() - 0.5) * 4, dy: (Math.random() - 0.5) * 4, color: `hsl(${Math.floor(Math.random() * 360)} 80% 45%)`,}));
function animate() { ctx.clearRect(0, 0, size, size); for (const c of circles) { if (c.x + radius > size || c.x - radius < 0) c.dx = -c.dx; if (c.y + radius > size || c.y - radius < 0) c.dy = -c.dy; c.x += c.dx; c.y += c.dy; ctx.beginPath(); ctx.arc(c.x, c.y, radius, 0, Math.PI * 2); ctx.lineWidth = 3; ctx.strokeStyle = c.color; ctx.stroke(); } requestAnimationFrame(animate);}animate();
mapEl.mapReady().then((map) => { map.addSource("canvas-source", { type: "canvas", canvas, coordinates: [ [91.4461, 21.5006], [100.3541, 21.5006], [100.3541, 13.9706], [91.4461, 13.9706], ], animate: true, // static canvases should say false: it saves a re-upload per frame }); map.addLayer({ id: "canvas-layer", type: "raster", source: "canvas-source" });});What to notice
Section titled “What to notice”animate: truemakes MapLibre re-read the canvas every frame; set it tofalsefor a static canvas to save the upload.- The
<canvas>sits inside<ml-map>without aslot, so the element leaves it where it is — hidden — while the map reads it. - Sources added by page JS live outside the document, so
mlym emitwon’t see them.