Skip to content

Draw a Circle ​

Draw circles on the map using the circle layer type or as filled polygon areas.

Click the map to add a circle at that location.

Method 1: Circle Layer (Pixel-based) ​

The simplest way — uses pixel radius, so the circle size stays constant regardless of zoom level:

javascript
map.addSource('points', {
  type: 'geojson',
  data: {
    type: 'FeatureCollection',
    features: [
      { type: 'Feature', geometry: { type: 'Point', coordinates: [2.35, 48.85] }, properties: {} }
    ]
  }
});

map.addLayer({
  id: 'circle-layer',
  type: 'circle',
  source: 'points',
  paint: {
    'circle-radius': 20,           // pixels
    'circle-color': '#3b82f6',
    'circle-opacity': 0.5,
    'circle-stroke-width': 2,
    'circle-stroke-color': '#1d4ed8'
  }
});

Method 2: Polygon Circle (Geographic radius) ​

For a circle with a real-world radius (e.g., 5km), generate polygon coordinates:

javascript
function createGeoCircle(center, radiusKm, points = 64) {
  const coords = [];
  for (let i = 0; i < points; i++) {
    const angle = (i / points) * 2 * Math.PI;
    const dx = radiusKm / 111.32; // degrees longitude
    const dy = radiusKm / 110.574; // degrees latitude
    coords.push([
      center[0] + dx * Math.cos(angle),
      center[1] + dy * Math.sin(angle)
    ]);
  }
  coords.push(coords[0]); // close the ring
  return coords;
}

map.addSource('area', {
  type: 'geojson',
  data: {
    type: 'Feature',
    geometry: {
      type: 'Polygon',
      coordinates: [createGeoCircle([2.35, 48.85], 50)] // 50km radius
    }
  }
});

map.addLayer({
  id: 'area-fill',
  type: 'fill',
  source: 'area',
  paint: {
    'fill-color': '#3b82f6',
    'fill-opacity': 0.2
  }
});

map.addLayer({
  id: 'area-outline',
  type: 'line',
  source: 'area',
  paint: {
    'line-color': '#3b82f6',
    'line-width': 2
  }
});

Data-Driven Circle Size ​

javascript
map.addLayer({
  id: 'circles',
  type: 'circle',
  source: 'points',
  paint: {
    'circle-radius': ['get', 'radius'],       // from feature property
    'circle-color': ['get', 'color'],          // from feature property
    'circle-opacity': 0.6
  }
});

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: [2.349902, 48.852966],
        zoom: 5
      });

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

      map.on('load', () => {
        map.addSource('points', {
          type: 'geojson',
          data: {
            type: 'FeatureCollection',
            features: [
              { type: 'Feature', properties: {}, geometry: { type: 'Point', coordinates: [2.349902, 48.852966] } },
              { type: 'Feature', properties: {}, geometry: { type: 'Point', coordinates: [-0.1276, 51.5074] } },
              { type: 'Feature', properties: {}, geometry: { type: 'Point', coordinates: [13.405, 52.52] } },
            ]
          }
        });

        map.addLayer({
          id: 'circles',
          type: 'circle',
          source: 'points',
          paint: {
            'circle-radius': 20,
            'circle-color': '#3b82f6',
            'circle-opacity': 0.5,
            'circle-stroke-width': 2,
            'circle-stroke-color': '#1d4ed8'
          }
        });

        // Click to add circles
        map.on('click', (e) => {
          const source = map.getSource('points');
          const data = source._data;
          data.features.push({
            type: 'Feature', properties: {},
            geometry: { type: 'Point', coordinates: [e.lngLat.lng, e.lngLat.lat] }
          });
          source.setData(data);
        });
      });
    </script>
  </body>
</html>
jsx
import React, { useEffect, useRef } from 'react';
import mapmetricsgl from '@mapmetrics/mapmetrics-gl';
import '@mapmetrics/mapmetrics-gl/dist/mapmetrics-gl.css';

const DrawCircle = () => {
  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: [2.349902, 48.852966],
      zoom: 5
    });

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

    const data = {
      type: 'FeatureCollection',
      features: [
        { type: 'Feature', properties: {}, geometry: { type: 'Point', coordinates: [2.349902, 48.852966] } },
        { type: 'Feature', properties: {}, geometry: { type: 'Point', coordinates: [-0.1276, 51.5074] } },
      ]
    };

    map.current.on('load', () => {
      map.current.addSource('points', { type: 'geojson', data });

      map.current.addLayer({
        id: 'circles',
        type: 'circle',
        source: 'points',
        paint: {
          'circle-radius': 20,
          'circle-color': '#3b82f6',
          'circle-opacity': 0.5,
          'circle-stroke-width': 2,
          'circle-stroke-color': '#1d4ed8'
        }
      });

      map.current.on('click', (e) => {
        data.features.push({
          type: 'Feature', properties: {},
          geometry: { type: 'Point', coordinates: [e.lngLat.lng, e.lngLat.lat] }
        });
        map.current.getSource('points').setData({ ...data });
      });
    });

    return () => { map.current?.remove(); map.current = null; };
  }, []);

  return <div ref={mapContainer} style={{ height: '500px', width: '100%' }} />;
};

export default DrawCircle;

For more information, visit the MapMetrics GitHub repository.