Skip to content

Both copy text to your clipboard — Build with AI copies a setup prompt to paste into Claude Code, Cursor, Codex or Copilot; Copy page as Markdown copies this page to paste into a chat. How it works

Customize the Map Transform Constrain

Control how and where the map camera can move by setting bounds, zoom limits, and using transformCameraUpdate to enforce custom constraints.

Set Max Bounds

Restrict panning so the camera cannot move outside a bounding box:

javascript
// At initialization
const map = new mapmetricsgl.Map({
  container: 'map',
  style: '<StyleFile_URL_with_Token>',
  maxBounds: [[-25, 34], [45, 72]], // [SW, NE]
});

// At runtime
map.setMaxBounds([[-25, 34], [45, 72]]);

// Remove constraint
map.setMaxBounds(null);

Limit Zoom Levels

javascript
// At initialization
const map = new mapmetricsgl.Map({
  minZoom: 3,
  maxZoom: 18,
  // ...
});

// At runtime
map.setMinZoom(3);
map.setMaxZoom(12);

// Remove limits
map.setMinZoom(null);
map.setMaxZoom(null);

Limit Pitch and Bearing

javascript
const map = new mapmetricsgl.Map({
  minPitch: 0,
  maxPitch: 60,  // default 60
  // ...
});

transformCameraUpdate — Custom Constraints

Use transformCameraUpdate to intercept and modify every camera update before it is applied:

javascript
const map = new mapmetricsgl.Map({
  // ...
  transformCameraUpdate: ({ center, zoom, pitch, bearing, elevation, padding }) => {
    // Example: keep latitude above the equator
    return {
      center: {
        lng: center.lng,
        lat: Math.max(0, center.lat), // clamp lat to >= 0
      },
      zoom,
      pitch,
      bearing,
    };
  }
});

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>
    <button id="lock">Lock to Europe</button>
    <button id="unlock">Unlock</button>
    <script>
      const europeBounds = [[-25, 34], [45, 72]];

      const map = new mapmetricsgl.Map({
        container: 'map',
        style: '<StyleFile_URL_with_Token>',
        center: [10, 50],
        zoom: 4,
        minZoom: 2,
        maxZoom: 18,
      });

      document.getElementById('lock').addEventListener('click', () => {
        map.setMaxBounds(europeBounds);
        map.fitBounds(europeBounds, { padding: 20 });
      });

      document.getElementById('unlock').addEventListener('click', () => {
        map.setMaxBounds(null);
      });
    </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 europeBounds = [[-25, 34], [45, 72]];

const CustomizeMapTransformConstrain = () => {
  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, 50],
      zoom: 4,
      minZoom: 2,
    });
    return () => { map.current?.remove(); map.current = null; };
  }, []);

  const lock = () => {
    map.current?.setMaxBounds(europeBounds);
    map.current?.fitBounds(europeBounds, { padding: 20 });
  };
  const unlock = () => map.current?.setMaxBounds(null);

  return (
    <div>
      <div ref={mapContainer} style={{ height: '500px', width: '100%' }} />
      <div style={{ marginTop: 10, display: 'flex', gap: 8 }}>
        <button onClick={lock}>Lock to Europe</button>
        <button onClick={unlock}>Unlock</button>
      </div>
    </div>
  );
};

export default CustomizeMapTransformConstrain;

For more information, visit the MapMetrics GitHub repository.