Add a Generated Icon to the Map
Create a custom icon programmatically using the Canvas 2D API and register it with map.addImage().
Generate an Icon with Canvas API
javascript
function generateIcon(color) {
const size = 48;
const canvas = document.createElement('canvas');
canvas.width = size;
canvas.height = size;
const ctx = canvas.getContext('2d');
// Draw a circle
ctx.fillStyle = color;
ctx.beginPath();
ctx.arc(size / 2, size / 2, size / 2 - 2, 0, Math.PI * 2);
ctx.fill();
// White border
ctx.strokeStyle = '#ffffff';
ctx.lineWidth = 3;
ctx.stroke();
return ctx.getImageData(0, 0, size, size);
}Register and Use the Icon
javascript
map.on('load', () => {
const iconData = generateIcon('#3b82f6');
// Register with map
map.addImage('generated-icon', iconData);
// Use in a symbol layer
map.addLayer({
id: 'icons',
type: 'symbol',
source: 'my-source',
layout: {
'icon-image': 'generated-icon',
'icon-size': 1.0,
'icon-allow-overlap': true,
}
});
});Switch Icon at Runtime
javascript
// Update which image is used for the layer
map.setLayoutProperty('icons', 'icon-image', 'new-icon-name');Complete Example
html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<link href="https://cdn.mapmetrics-atlas.net/versions/latest/mapmetrics-gl.css" rel="stylesheet" />
<script src="https://cdn.mapmetrics-atlas.net/versions/latest/mapmetrics-gl.js"></script>
<style>#map { height: 500px; width: 100%; }</style>
</head>
<body>
<div id="map"></div>
<script>
const map = new mapmetricsgl.Map({
container: 'map',
style: '<StyleFile_URL_with_Token>',
center: [10, 30],
zoom: 1.5
});
function makeCircleIcon(color, size = 40) {
const canvas = document.createElement('canvas');
canvas.width = size; canvas.height = size;
const ctx = canvas.getContext('2d');
ctx.fillStyle = color;
ctx.beginPath();
ctx.arc(size / 2, size / 2, size / 2 - 2, 0, Math.PI * 2);
ctx.fill();
ctx.strokeStyle = '#fff';
ctx.lineWidth = 3;
ctx.stroke();
return ctx.getImageData(0, 0, size, size);
}
map.on('load', () => {
map.addImage('blue-dot', makeCircleIcon('#3b82f6'));
map.addImage('red-dot', makeCircleIcon('#ef4444'));
map.addSource('points', {
type: 'geojson',
data: {
type: 'FeatureCollection',
features: [
{ type: 'Feature', geometry: { type: 'Point', coordinates: [-74, 40.7] }, properties: {} },
{ type: 'Feature', geometry: { type: 'Point', coordinates: [2.35, 48.85] }, properties: {} },
]
}
});
map.addLayer({
id: 'icons',
type: 'symbol',
source: 'points',
layout: { 'icon-image': 'blue-dot', 'icon-size': 0.8, 'icon-allow-overlap': true }
});
});
</script>
</body>
</html>jsx
import React, { useEffect, useRef } from 'react';
import mapmetricsgl from '@mapmetrics/mapmetrics-gl';
import '@mapmetrics/mapmetrics-gl/dist/mapmetrics-gl.css';
function makeCircleIcon(color, size = 40) {
const canvas = document.createElement('canvas');
canvas.width = size; canvas.height = size;
const ctx = canvas.getContext('2d');
ctx.fillStyle = color;
ctx.beginPath();
ctx.arc(size / 2, size / 2, size / 2 - 2, 0, Math.PI * 2);
ctx.fill();
ctx.strokeStyle = '#fff';
ctx.lineWidth = 3;
ctx.stroke();
return ctx.getImageData(0, 0, size, size);
}
const pointsData = {
type: 'FeatureCollection',
features: [
{ type: 'Feature', geometry: { type: 'Point', coordinates: [-74, 40.7] }, properties: {} },
{ type: 'Feature', geometry: { type: 'Point', coordinates: [2.35, 48.85] }, properties: {} },
{ type: 'Feature', geometry: { type: 'Point', coordinates: [139.7, 35.7] }, properties: {} },
]
};
const AddGeneratedIcon = () => {
const mapContainer = useRef(null);
const map = useRef(null);
useEffect(() => {
if (map.current) return;
map.current = new mapmetricsgl.Map({
container: mapContainer.current,
style: '<StyleFile_URL_with_Token>',
center: [10, 30],
zoom: 1.5
});
map.current.on('load', () => {
map.current.addImage('blue-dot', makeCircleIcon('#3b82f6'));
map.current.addSource('points', { type: 'geojson', data: pointsData });
map.current.addLayer({
id: 'icons',
type: 'symbol',
source: 'points',
layout: { 'icon-image': 'blue-dot', 'icon-size': 0.8, 'icon-allow-overlap': true }
});
});
return () => { map.current?.remove(); map.current = null; };
}, []);
return <div ref={mapContainer} style={{ height: '500px', width: '100%' }} />;
};
export default AddGeneratedIcon;For more information, visit the MapMetrics GitHub repository.