It's the 15th anniversary of Google Maps Platform - Check out the latest news and announcements

Custom Map Projections

This example creates a map using the Gall-Peters projection, rather than the default Mercator projection.

Read the documentation.

TypeScript

// This example defines an image map type using the Gall-Peters
// projection.
// https://en.wikipedia.org/wiki/Gall%E2%80%93Peters_projection

function initMap(): void {
  // Create a map. Use the Gall-Peters map type.
  const map = new google.maps.Map(
    document.getElementById("map") as HTMLElement,
    {
      zoom: 0,
      center: { lat: 0, lng: 0 },
      mapTypeControl: false,
    }
  );

  initGallPeters();
  map.mapTypes.set("gallPeters", gallPetersMapType);
  map.setMapTypeId("gallPeters");

  // Show the lat and lng under the mouse cursor.
  const coordsDiv = document.getElementById("coords") as HTMLElement;
  map.controls[google.maps.ControlPosition.TOP_CENTER].push(coordsDiv);
  map.addListener("mousemove", (event: google.maps.MouseEvent) => {
    coordsDiv.textContent =
      "lat: " +
      Math.round(event.latLng.lat()) +
      ", " +
      "lng: " +
      Math.round(event.latLng.lng());
  });

  // Add some markers to the map.
  map.data.setStyle((feature) => {
    return {
      title: feature.getProperty("name"),
      optimized: false,
    };
  });
  map.data.addGeoJson(cities);
}

let gallPetersMapType;

function initGallPeters() {
  const GALL_PETERS_RANGE_X = 800;
  const GALL_PETERS_RANGE_Y = 512;

  // Fetch Gall-Peters tiles stored locally on our server.
  gallPetersMapType = new google.maps.ImageMapType({
    getTileUrl: function (coord, zoom) {
      const scale = 1 << zoom;

      // Wrap tiles horizontally.
      const x = ((coord.x % scale) + scale) % scale;

      // Don't wrap tiles vertically.
      const y = coord.y;

      if (y < 0 || y >= scale) return "";

      return (
        "https://developers.google.com/maps/documentation/" +
        "javascript/examples/full/images/gall-peters_" +
        zoom +
        "_" +
        x +
        "_" +
        y +
        ".png"
      );
    },
    tileSize: new google.maps.Size(GALL_PETERS_RANGE_X, GALL_PETERS_RANGE_Y),
    minZoom: 0,
    maxZoom: 1,
    name: "Gall-Peters",
  });

  // Describe the Gall-Peters projection used by these tiles.
  gallPetersMapType.projection = {
    fromLatLngToPoint: function (latLng) {
      const latRadians = (latLng.lat() * Math.PI) / 180;
      return new google.maps.Point(
        GALL_PETERS_RANGE_X * (0.5 + latLng.lng() / 360),
        GALL_PETERS_RANGE_Y * (0.5 - 0.5 * Math.sin(latRadians))
      );
    },
    fromPointToLatLng: function (point, noWrap) {
      const x = point.x / GALL_PETERS_RANGE_X;
      const y = Math.max(0, Math.min(1, point.y / GALL_PETERS_RANGE_Y));

      return new google.maps.LatLng(
        (Math.asin(1 - 2 * y) * 180) / Math.PI,
        -180 + 360 * x,
        noWrap
      );
    },
  };
}

// GeoJSON, describing the locations and names of some cities.
const cities = {
  type: "FeatureCollection",
  features: [
    {
      type: "Feature",
      geometry: { type: "Point", coordinates: [-87.65, 41.85] },
      properties: { name: "Chicago" },
    },
    {
      type: "Feature",
      geometry: { type: "Point", coordinates: [-149.9, 61.218] },
      properties: { name: "Anchorage" },
    },
    {
      type: "Feature",
      geometry: { type: "Point", coordinates: [-99.127, 19.427] },
      properties: { name: "Mexico City" },
    },
    {
      type: "Feature",
      geometry: { type: "Point", coordinates: [-0.126, 51.5] },
      properties: { name: "London" },
    },
    {
      type: "Feature",
      geometry: { type: "Point", coordinates: [28.045, -26.201] },
      properties: { name: "Johannesburg" },
    },
    {
      type: "Feature",
      geometry: { type: "Point", coordinates: [15.322, -4.325] },
      properties: { name: "Kinshasa" },
    },
    {
      type: "Feature",
      geometry: { type: "Point", coordinates: [151.207, -33.867] },
      properties: { name: "Sydney" },
    },
    {
      type: "Feature",
      geometry: { type: "Point", coordinates: [0, 0] },
      properties: { name: "0°N 0°E" },
    },
  ],
};

JavaScript

// This example defines an image map type using the Gall-Peters
// projection.
// https://en.wikipedia.org/wiki/Gall%E2%80%93Peters_projection
function initMap() {
  // Create a map. Use the Gall-Peters map type.
  const map = new google.maps.Map(document.getElementById("map"), {
    zoom: 0,
    center: { lat: 0, lng: 0 },
    mapTypeControl: false,
  });
  initGallPeters();
  map.mapTypes.set("gallPeters", gallPetersMapType);
  map.setMapTypeId("gallPeters");
  // Show the lat and lng under the mouse cursor.
  const coordsDiv = document.getElementById("coords");
  map.controls[google.maps.ControlPosition.TOP_CENTER].push(coordsDiv);
  map.addListener("mousemove", (event) => {
    coordsDiv.textContent =
      "lat: " +
      Math.round(event.latLng.lat()) +
      ", " +
      "lng: " +
      Math.round(event.latLng.lng());
  });
  // Add some markers to the map.
  map.data.setStyle((feature) => {
    return {
      title: feature.getProperty("name"),
      optimized: false,
    };
  });
  map.data.addGeoJson(cities);
}
let gallPetersMapType;

function initGallPeters() {
  const GALL_PETERS_RANGE_X = 800;
  const GALL_PETERS_RANGE_Y = 512;
  // Fetch Gall-Peters tiles stored locally on our server.
  gallPetersMapType = new google.maps.ImageMapType({
    getTileUrl: function (coord, zoom) {
      const scale = 1 << zoom;
      // Wrap tiles horizontally.
      const x = ((coord.x % scale) + scale) % scale;
      // Don't wrap tiles vertically.
      const y = coord.y;

      if (y < 0 || y >= scale) return "";
      return (
        "https://developers.google.com/maps/documentation/" +
        "javascript/examples/full/images/gall-peters_" +
        zoom +
        "_" +
        x +
        "_" +
        y +
        ".png"
      );
    },
    tileSize: new google.maps.Size(GALL_PETERS_RANGE_X, GALL_PETERS_RANGE_Y),
    minZoom: 0,
    maxZoom: 1,
    name: "Gall-Peters",
  });
  // Describe the Gall-Peters projection used by these tiles.
  gallPetersMapType.projection = {
    fromLatLngToPoint: function (latLng) {
      const latRadians = (latLng.lat() * Math.PI) / 180;
      return new google.maps.Point(
        GALL_PETERS_RANGE_X * (0.5 + latLng.lng() / 360),
        GALL_PETERS_RANGE_Y * (0.5 - 0.5 * Math.sin(latRadians))
      );
    },
    fromPointToLatLng: function (point, noWrap) {
      const x = point.x / GALL_PETERS_RANGE_X;
      const y = Math.max(0, Math.min(1, point.y / GALL_PETERS_RANGE_Y));
      return new google.maps.LatLng(
        (Math.asin(1 - 2 * y) * 180) / Math.PI,
        -180 + 360 * x,
        noWrap
      );
    },
  };
}
// GeoJSON, describing the locations and names of some cities.
const cities = {
  type: "FeatureCollection",
  features: [
    {
      type: "Feature",
      geometry: { type: "Point", coordinates: [-87.65, 41.85] },
      properties: { name: "Chicago" },
    },
    {
      type: "Feature",
      geometry: { type: "Point", coordinates: [-149.9, 61.218] },
      properties: { name: "Anchorage" },
    },
    {
      type: "Feature",
      geometry: { type: "Point", coordinates: [-99.127, 19.427] },
      properties: { name: "Mexico City" },
    },
    {
      type: "Feature",
      geometry: { type: "Point", coordinates: [-0.126, 51.5] },
      properties: { name: "London" },
    },
    {
      type: "Feature",
      geometry: { type: "Point", coordinates: [28.045, -26.201] },
      properties: { name: "Johannesburg" },
    },
    {
      type: "Feature",
      geometry: { type: "Point", coordinates: [15.322, -4.325] },
      properties: { name: "Kinshasa" },
    },
    {
      type: "Feature",
      geometry: { type: "Point", coordinates: [151.207, -33.867] },
      properties: { name: "Sydney" },
    },
    {
      type: "Feature",
      geometry: { type: "Point", coordinates: [0, 0] },
      properties: { name: "0°N 0°E" },
    },
  ],
};

CSS

/* Always set the map height explicitly to define the size of the div
       * element that contains the map. */
#map {
  height: 100%;
}

/* Optional: Makes the sample page fill the window. */
html,
body {
  height: 100%;
  margin: 0;
  padding: 0;
}

#coords {
  background-color: black;
  color: white;
  padding: 5px;
}

HTML

<!DOCTYPE html>
<html>
  <head>
    <title>Custom Map Projections</title>
    <script src="https://polyfill.io/v3/polyfill.min.js?features=default"></script>
    <script
      src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&callback=initMap&libraries=&v=weekly"
      defer
    ></script>
    <link rel="stylesheet" type="text/css" href="./style.css" />
    <script src="./app.js"></script>
  </head>
  <body>
    <div id="map"></div>
    <div id="coords"></div>
  </body>
</html>

All

<!DOCTYPE html>
<html>
  <head>
    <title>Custom Map Projections</title>
    <script src="https://polyfill.io/v3/polyfill.min.js?features=default"></script>
    <script
      src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&callback=initMap&libraries=&v=weekly"
      defer
    ></script>
    <style type="text/css">
      /* Always set the map height explicitly to define the size of the div
       * element that contains the map. */
      #map {
        height: 100%;
      }

      /* Optional: Makes the sample page fill the window. */
      html,
      body {
        height: 100%;
        margin: 0;
        padding: 0;
      }

      #coords {
        background-color: black;
        color: white;
        padding: 5px;
      }
    </style>
    <script>
      "use strict";

      // This example defines an image map type using the Gall-Peters
      // projection.
      // https://en.wikipedia.org/wiki/Gall%E2%80%93Peters_projection
      function initMap() {
        // Create a map. Use the Gall-Peters map type.
        const map = new google.maps.Map(document.getElementById("map"), {
          zoom: 0,
          center: {
            lat: 0,
            lng: 0,
          },
          mapTypeControl: false,
        });
        initGallPeters();
        map.mapTypes.set("gallPeters", gallPetersMapType);
        map.setMapTypeId("gallPeters"); // Show the lat and lng under the mouse cursor.

        const coordsDiv = document.getElementById("coords");
        map.controls[google.maps.ControlPosition.TOP_CENTER].push(coordsDiv);
        map.addListener("mousemove", (event) => {
          coordsDiv.textContent =
            "lat: " +
            Math.round(event.latLng.lat()) +
            ", " +
            "lng: " +
            Math.round(event.latLng.lng());
        }); // Add some markers to the map.

        map.data.setStyle((feature) => {
          return {
            title: feature.getProperty("name"),
            optimized: false,
          };
        });
        map.data.addGeoJson(cities);
      }

      let gallPetersMapType;

      function initGallPeters() {
        const GALL_PETERS_RANGE_X = 800;
        const GALL_PETERS_RANGE_Y = 512; // Fetch Gall-Peters tiles stored locally on our server.

        gallPetersMapType = new google.maps.ImageMapType({
          getTileUrl: function (coord, zoom) {
            const scale = 1 << zoom; // Wrap tiles horizontally.

            const x = ((coord.x % scale) + scale) % scale; // Don't wrap tiles vertically.

            const y = coord.y;
            if (y < 0 || y >= scale) return "";
            return (
              "https://developers.google.com/maps/documentation/" +
              "javascript/examples/full/images/gall-peters_" +
              zoom +
              "_" +
              x +
              "_" +
              y +
              ".png"
            );
          },
          tileSize: new google.maps.Size(
            GALL_PETERS_RANGE_X,
            GALL_PETERS_RANGE_Y
          ),
          minZoom: 0,
          maxZoom: 1,
          name: "Gall-Peters",
        }); // Describe the Gall-Peters projection used by these tiles.

        gallPetersMapType.projection = {
          fromLatLngToPoint: function (latLng) {
            const latRadians = (latLng.lat() * Math.PI) / 180;
            return new google.maps.Point(
              GALL_PETERS_RANGE_X * (0.5 + latLng.lng() / 360),
              GALL_PETERS_RANGE_Y * (0.5 - 0.5 * Math.sin(latRadians))
            );
          },
          fromPointToLatLng: function (point, noWrap) {
            const x = point.x / GALL_PETERS_RANGE_X;
            const y = Math.max(0, Math.min(1, point.y / GALL_PETERS_RANGE_Y));
            return new google.maps.LatLng(
              (Math.asin(1 - 2 * y) * 180) / Math.PI,
              -180 + 360 * x,
              noWrap
            );
          },
        };
      } // GeoJSON, describing the locations and names of some cities.

      const cities = {
        type: "FeatureCollection",
        features: [
          {
            type: "Feature",
            geometry: {
              type: "Point",
              coordinates: [-87.65, 41.85],
            },
            properties: {
              name: "Chicago",
            },
          },
          {
            type: "Feature",
            geometry: {
              type: "Point",
              coordinates: [-149.9, 61.218],
            },
            properties: {
              name: "Anchorage",
            },
          },
          {
            type: "Feature",
            geometry: {
              type: "Point",
              coordinates: [-99.127, 19.427],
            },
            properties: {
              name: "Mexico City",
            },
          },
          {
            type: "Feature",
            geometry: {
              type: "Point",
              coordinates: [-0.126, 51.5],
            },
            properties: {
              name: "London",
            },
          },
          {
            type: "Feature",
            geometry: {
              type: "Point",
              coordinates: [28.045, -26.201],
            },
            properties: {
              name: "Johannesburg",
            },
          },
          {
            type: "Feature",
            geometry: {
              type: "Point",
              coordinates: [15.322, -4.325],
            },
            properties: {
              name: "Kinshasa",
            },
          },
          {
            type: "Feature",
            geometry: {
              type: "Point",
              coordinates: [151.207, -33.867],
            },
            properties: {
              name: "Sydney",
            },
          },
          {
            type: "Feature",
            geometry: {
              type: "Point",
              coordinates: [0, 0],
            },
            properties: {
              name: "0°N 0°E",
            },
          },
        ],
      };
    </script>
  </head>
  <body>
    <div id="map"></div>
    <div id="coords"></div>
  </body>
</html>
"use strict"; // This example defines an image map type using the Gall-Peters // projection. // https://en.wikipedia.org/wiki/Gall%E2%80%93Peters_projection function initMap() { // Create a map. Use the Gall-Peters map type. const map = new google.maps.Map(document.getElementById("map"), { zoom: 0, center: { lat: 0, lng: 0, }, mapTypeControl: false, }); initGallPeters(); map.mapTypes.set("gallPeters", gallPetersMapType); map.setMapTypeId("gallPeters"); // Show the lat and lng under the mouse cursor. const coordsDiv = document.getElementById("coords"); map.controls[google.maps.ControlPosition.TOP_CENTER].push(coordsDiv); map.addListener("mousemove", (event) => { coordsDiv.textContent = "lat: " + Math.round(event.latLng.lat()) + ", " + "lng: " + Math.round(event.latLng.lng()); }); // Add some markers to the map. map.data.setStyle((feature) => { return { title: feature.getProperty("name"), optimized: false, }; }); map.data.addGeoJson(cities); } let gallPetersMapType; function initGallPeters() { const GALL_PETERS_RANGE_X = 800; const GALL_PETERS_RANGE_Y = 512; // Fetch Gall-Peters tiles stored locally on our server. gallPetersMapType = new google.maps.ImageMapType({ getTileUrl: function (coord, zoom) { const scale = 1 << zoom; // Wrap tiles horizontally. const x = ((coord.x % scale) + scale) % scale; // Don't wrap tiles vertically. const y = coord.y; if (y < 0 || y >= scale) return ""; return ( "https://developers.google.com/maps/documentation/" + "javascript/examples/full/images/gall-peters_" + zoom + "_" + x + "_" + y + ".png" ); }, tileSize: new google.maps.Size(GALL_PETERS_RANGE_X, GALL_PETERS_RANGE_Y), minZoom: 0, maxZoom: 1, name: "Gall-Peters", }); // Describe the Gall-Peters projection used by these tiles. gallPetersMapType.projection = { fromLatLngToPoint: function (latLng) { const latRadians = (latLng.lat() * Math.PI) / 180; return new google.maps.Point( GALL_PETERS_RANGE_X * (0.5 + latLng.lng() / 360), GALL_PETERS_RANGE_Y * (0.5 - 0.5 * Math.sin(latRadians)) ); }, fromPointToLatLng: function (point, noWrap) { const x = point.x / GALL_PETERS_RANGE_X; const y = Math.max(0, Math.min(1, point.y / GALL_PETERS_RANGE_Y)); return new google.maps.LatLng( (Math.asin(1 - 2 * y) * 180) / Math.PI, -180 + 360 * x, noWrap ); }, }; } // GeoJSON, describing the locations and names of some cities. const cities = { type: "FeatureCollection", features: [ { type: "Feature", geometry: { type: "Point", coordinates: [-87.65, 41.85], }, properties: { name: "Chicago", }, }, { type: "Feature", geometry: { type: "Point", coordinates: [-149.9, 61.218], }, properties: { name: "Anchorage", }, }, { type: "Feature", geometry: { type: "Point", coordinates: [-99.127, 19.427], }, properties: { name: "Mexico City", }, }, { type: "Feature", geometry: { type: "Point", coordinates: [-0.126, 51.5], }, properties: { name: "London", }, }, { type: "Feature", geometry: { type: "Point", coordinates: [28.045, -26.201], }, properties: { name: "Johannesburg", }, }, { type: "Feature", geometry: { type: "Point", coordinates: [15.322, -4.325], }, properties: { name: "Kinshasa", }, }, { type: "Feature", geometry: { type: "Point", coordinates: [151.207, -33.867], }, properties: { name: "Sydney", }, }, { type: "Feature", geometry: { type: "Point", coordinates: [0, 0], }, properties: { name: "0°N 0°E", }, }, ], };
/* Always set the map height explicitly to define the size of the div * element that contains the map. */ #map { height: 100%; } /* Optional: Makes the sample page fill the window. */ html, body { height: 100%; margin: 0; padding: 0; } #coords { background-color: black; color: white; padding: 5px; }
<!DOCTYPE html> <html> <head> <title>Custom Map Projections</title> <script src="https://polyfill.io/v3/polyfill.min.js?features=default"></script> <script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyBIwzALxUPNbatRBj3Xi1Uhp0fFzwWNBkE&callback=initMap&libraries=&v=weekly" defer ></script> <!-- jsFiddle will insert css and js --> </head> <body> <div id="map"></div> <div id="coords"></div> </body> </html>

Create a starter application from sample

A skeleton starter application using TypeScript, Webpack, and Babel can be generated from this sample using one of the methods below.

Run Locally

Node.js is required to run this sample locally. Follow these instructions to install Node.js and NPM.

npm i -g '@googlemaps/js-samples'
googlemaps-js-samples init map-projection-simple DESTINATION_FOLDER

Run in Google Cloud Shell

Google Cloud Shell is an interactive shell environment for Google Cloud Platform that makes it easy for you to learn and experiment with GCP and manage your projects and resources from your web browser.

Run in Cloud Shell