Skip to content

Add a Canvas Source in Maptoolkit Maps JS

A canvas source lets you use a standard HTML canvas element as a raster layer on your map, with updates reflected in real time. You draw onto the canvas with the 2D API and call source.play() to keep the animation running continuously on the map surface. Use this technique to overlay animated overlays, custom data visualizations, or procedurally generated graphics at specific geographic bounds.

const API_KEY = 'YOUR_API_KEY';

    const canvas = document.getElementById('canvas');
    const ctx = canvas.getContext('2d');

    let phase = 0;
    function animate() {
        ctx.clearRect(0, 0, 400, 400);
        for (let i = 0; i < 6; i++) {
            const x = 200 + Math.cos(phase + i * Math.PI / 3) * 120;
            const y = 200 + Math.sin(phase + i * Math.PI / 3) * 120;
            const r = 30 + Math.sin(phase * 2 + i) * 15;
            ctx.beginPath();
            ctx.arc(x, y, r, 0, Math.PI * 2);
            ctx.fillStyle = `hsla(${(phase * 60 + i * 60) % 360}, 80%, 55%, 0.7)`;
            ctx.fill();
        }
        phase += 0.02;
        requestAnimationFrame(animate);
    }
    animate();

    const map = new maptoolkit.Map({
        container: 'map',
        apiKey: API_KEY,
        style: `https://styles.maptoolkit.net/maptoolkit/maptoolkit.summer.json?api_key=${API_KEY}`,
        center: [13.5, 47.5],
        zoom: 6,
        attributionControl: { compact: false }
    });

    map.addControl(new maptoolkit.NavigationControl(), 'top-right');

    map.on('load', () => {
        map.addSource('canvas-source', {
            type: 'canvas',
            canvas: 'canvas',
            coordinates: [
                [9.5, 49.1],
                [17.2, 49.1],
                [17.2, 46.4],
                [9.5, 46.4]
            ],
            animate: true
        });

        map.addLayer({
            id: 'canvas-layer',
            type: 'raster',
            source: 'canvas-source',
            paint: { 'raster-opacity': 0.85 }
        });
    });
<!DOCTYPE html>
<html lang="en">
<head>
    <title>Add a Canvas Source - Maptoolkit Maps JS</title>
    <meta property="og:description" content="Use an animated HTML canvas as a map source to draw dynamic content." />
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <script src="https://unpkg.com/@maptoolkit/maps@11.0.0-beta.3/dist/maptoolkit.js"></script>
    <link rel="stylesheet" href="https://unpkg.com/@maptoolkit/maps@11.0.0-beta.3/dist/maptoolkit.css" />
    <style>
        html, body { width: 100%; height: 100%; margin: 0; padding: 0; }
        #map { width: 100%; height: 100%; }
    </style>
</head>
<body>
<div id="map"></div>
<canvas id="canvas" style="display:none;" width="400" height="400"></canvas>
<script>
    const API_KEY = 'YOUR_API_KEY';

    const canvas = document.getElementById('canvas');
    const ctx = canvas.getContext('2d');

    let phase = 0;
    function animate() {
        ctx.clearRect(0, 0, 400, 400);
        for (let i = 0; i < 6; i++) {
            const x = 200 + Math.cos(phase + i * Math.PI / 3) * 120;
            const y = 200 + Math.sin(phase + i * Math.PI / 3) * 120;
            const r = 30 + Math.sin(phase * 2 + i) * 15;
            ctx.beginPath();
            ctx.arc(x, y, r, 0, Math.PI * 2);
            ctx.fillStyle = `hsla(${(phase * 60 + i * 60) % 360}, 80%, 55%, 0.7)`;
            ctx.fill();
        }
        phase += 0.02;
        requestAnimationFrame(animate);
    }
    animate();

    const map = new maptoolkit.Map({
        container: 'map',
        apiKey: API_KEY,
        style: `https://styles.maptoolkit.net/maptoolkit/maptoolkit.summer.json?api_key=${API_KEY}`,
        center: [13.5, 47.5],
        zoom: 6,
        attributionControl: { compact: false }
    });

    map.addControl(new maptoolkit.NavigationControl(), 'top-right');

    map.on('load', () => {
        map.addSource('canvas-source', {
            type: 'canvas',
            canvas: 'canvas',
            coordinates: [
                [9.5, 49.1],
                [17.2, 49.1],
                [17.2, 46.4],
                [9.5, 46.4]
            ],
            animate: true
        });

        map.addLayer({
            id: 'canvas-layer',
            type: 'raster',
            source: 'canvas-source',
            paint: { 'raster-opacity': 0.85 }
        });
    });
</script>
</body>
</html>

Use the prompt below with any LLM to get the same result. Make sure the Maptoolkit MCP server is connected first — check out AI Integration & MCP to get started.

Use the Maptoolkit Connector. Create an interactive map with zoom level 6, centered around [13.5, 47.5]. Add an animated HTML canvas source displaying rotating colorful circles, overlaid on the bounds of Austria.

How it works

A canvas source turns an HTML canvas into a map layer. The renderer re-reads the canvas each frame, so whatever you draw appears on the map without any explicit update call.

coordinates pins the four corners of the canvas to four geographic positions, in the order top-left, top-right, bottom-right, bottom-left. Getting the order wrong mirrors or twists the image rather than erroring.

animate: true is what makes it re-read continuously. For a canvas you draw once, leave it off and the texture is uploaded a single time, which is much cheaper.

The canvas element has to be in the DOM, though it can be hidden with CSS.

Because the corners are fixed, the drawing stretches with the projection: the further it is from the equator and the larger it is, the more Web Mercator distorts it.

Next steps

The reason to draw on a canvas is usually data that does not fit the style spec: a wind field, a live sensor sweep, a rendered gradient. The next step is drawing from real values rather than a pattern, which is where the technique earns itself.

If the drawing turns out to be points, lines or polygons after all, a GeoJSON source and a normal layer will be faster and easier to style than anything you paint by hand.