Skip to content

Add a Pattern to a Polygon ​

Fill a polygon with a repeating image texture using fill-pattern and map.loadImage().

How It Works ​

  1. Load or create an image to use as the tile pattern
  2. Register it with map.addImage('name', imageData)
  3. Apply it using fill-pattern: 'name' in the layer paint

Using a Remote Image ​

javascript
map.on('load', () => {
  map.loadImage('https://example.com/pattern.png', (error, image) => {
    if (error) throw error;
    map.addImage('my-pattern', image);

    map.addLayer({
      id: 'polygon-fill',
      type: 'fill',
      source: 'polygon',
      paint: {
        'fill-pattern': 'my-pattern'
      }
    });
  });
});

Using a Canvas-Generated Pattern ​

javascript
// Create pattern programmatically with Canvas API
const size = 16;
const canvas = document.createElement('canvas');
canvas.width = size;
canvas.height = size;
const ctx = canvas.getContext('2d');

// Draw diagonal lines
ctx.strokeStyle = '#3b82f6';
ctx.lineWidth = 2;
ctx.beginPath();
ctx.moveTo(0, size);
ctx.lineTo(size, 0);
ctx.stroke();

// Register as a map image
const imageData = ctx.getImageData(0, 0, size, size);
map.addImage('hatch', imageData);

map.addLayer({
  id: 'fill',
  type: 'fill',
  source: 'polygon',
  paint: { 'fill-pattern': 'hatch' }
});

Pattern Layer Properties ​

javascript
map.addLayer({
  id: 'polygon-fill',
  type: 'fill',
  source: 'polygon',
  paint: {
    'fill-pattern': 'my-pattern',  // image name from addImage()
    'fill-opacity': 0.9,           // overall opacity
    // Note: fill-color is ignored when fill-pattern is set
  }
});

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

      map.on('load', () => {
        // Create hatch pattern
        const size = 16;
        const canvas = document.createElement('canvas');
        canvas.width = size; canvas.height = size;
        const ctx = canvas.getContext('2d');
        ctx.strokeStyle = '#3b82f6';
        ctx.lineWidth = 2;
        ctx.beginPath(); ctx.moveTo(0, size); ctx.lineTo(size, 0); ctx.stroke();
        ctx.beginPath(); ctx.moveTo(-size, size); ctx.lineTo(size, -size); ctx.stroke();
        ctx.beginPath(); ctx.moveTo(0, 2 * size); ctx.lineTo(2 * size, 0); ctx.stroke();
        map.addImage('hatch', ctx.getImageData(0, 0, size, size));

        map.addSource('polygon', {
          type: 'geojson',
          data: {
            type: 'Feature',
            geometry: {
              type: 'Polygon',
              coordinates: [[[0, 44], [12, 44], [12, 54], [0, 54], [0, 44]]]
            }
          }
        });

        map.addLayer({
          id: 'polygon-fill',
          type: 'fill',
          source: 'polygon',
          paint: { 'fill-pattern': 'hatch', 'fill-opacity': 0.8 }
        });

        map.addLayer({
          id: 'polygon-outline',
          type: 'line',
          source: 'polygon',
          paint: { 'line-color': '#1d4ed8', 'line-width': 2 }
        });
      });
    </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 polygonData = {
  type: 'Feature',
  geometry: {
    type: 'Polygon',
    coordinates: [[[0, 44], [12, 44], [12, 54], [0, 54], [0, 44]]]
  }
};

const AddPatternToPolygon = () => {
  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: [5, 48],
      zoom: 4
    });

    map.current.on('load', () => {
      // Create hatch pattern
      const size = 16;
      const canvas = document.createElement('canvas');
      canvas.width = size; canvas.height = size;
      const ctx = canvas.getContext('2d');
      ctx.strokeStyle = '#3b82f6';
      ctx.lineWidth = 2;
      ctx.beginPath(); ctx.moveTo(0, size); ctx.lineTo(size, 0); ctx.stroke();
      ctx.beginPath(); ctx.moveTo(-size, size); ctx.lineTo(size, -size); ctx.stroke();
      ctx.beginPath(); ctx.moveTo(0, 2 * size); ctx.lineTo(2 * size, 0); ctx.stroke();
      map.current.addImage('hatch', ctx.getImageData(0, 0, size, size));

      map.current.addSource('polygon', { type: 'geojson', data: polygonData });

      map.current.addLayer({
        id: 'polygon-fill',
        type: 'fill',
        source: 'polygon',
        paint: { 'fill-pattern': 'hatch', 'fill-opacity': 0.8 }
      });

      map.current.addLayer({
        id: 'polygon-outline',
        type: 'line',
        source: 'polygon',
        paint: { 'line-color': '#1d4ed8', 'line-width': 2 }
      });
    });

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

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

export default AddPatternToPolygon;

For more information, visit the MapMetrics GitHub repository.