AI-generated Key Takeaways
- 
          Google Maps JavaScript API allows customization of map types, including standard options like roadmap,satellite,hybrid, andterrain, and custom options.
- 
          Developers can create custom map types by implementing the MapTypeinterface, defining tile retrieval, coordinate translation, and visual behavior.
- 
          The ImageMapTypeclass simplifies the creation of image-based map types by providing a streamlined approach to define tile sources and zoom levels.
- 
          Google Maps supports various projections, including the default Mercator and custom projections defined using the Projectioninterface withfromLatLngToPointandfromPointToLatLngmethods.
- 
          Developers can integrate custom map types and projections to enhance the visual experience and display unique data within their Google Maps implementations. 
This document discusses the types of maps you can display using the
  Maps JavaScript API. The API uses a MapType
  object to hold information about these maps. A MapType
  is an interface that defines the display and usage of map tiles and
  the translation of coordinate systems from screen coordinates to world
  coordinates (on the map). Each MapType must contain a
  few methods to handle retrieval and release of tiles, and properties
  that define its visual behavior.
The inner workings of map types within the Maps JavaScript API is an advanced topic. Most developers can use the basic map types noted below. However, you can also modify the presentation of existing map types using Styled Maps or define your own map tiles using custom map types. When providing custom map types, you will need to understand how to modify the map's Map Type Registry.
Basic Map Types
There are four types of maps available within the Maps JavaScript API. In addition to the familiar "painted" road map tiles, the Maps JavaScript API also supports other maps types.
The following map types are available in the Maps JavaScript API:
- roadmapdisplays the default road map view with basemap labels.
- satellitedisplays a photorealistic map based on aerial imagery.
- hybriddisplays the satellite map view with basemap labels.
- terraindisplays a physical map based on terrain information.
You modify the map type in use by the Map by setting its
  mapTypeId property, either within the constructor by setting
  its Map options object, or by calling the map's
  setMapTypeId() method. The mapTypeID property
  defaults to roadmap.
Setting the mapTypeId upon construction:
var myLatlng = new google.maps.LatLng(-34.397, 150.644); var mapOptions = { zoom: 8, center: myLatlng, mapTypeId: 'satellite' }; var map = new google.maps.Map(document.getElementById('map'), mapOptions);
Modifying the mapTypeId dynamically:
map.setMapTypeId('terrain');
Note that you don't actually set the map's map type directly,
  but instead set its mapTypeId to reference a
  MapType using an identifier.
  The Maps JavaScript API uses a map type registry,
  explained below, to manage these references.
3D Maps
The Maps JavaScript API supports 3D imagery. Many of the actions and customization capabilities available for 2D maps are also available for 3D maps.
Learn more about 3D maps in the 3D maps overview.
The following example shows a 3D perspective view of San Francisco:
Learn more about 3D Maps in the 3D maps overview.
45° Imagery
The Maps JavaScript API supports special 45° imagery for certain locations. This high-resolution imagery provides perspective views towards each of the cardinal direction (North, South, East, West). These images are available at higher zoom levels for supported map types.
The following image shows a 45° perspective view of New York City:
The satellite and hybrid map types support 45°
  imagery at high zoom levels (12 and greater) where available. If the user
  zooms into a location for which such imagery exists, these map types
  automatically alter their views in the following manner:
- The satellite or hybrid imagery is replaced with imagery giving a 45°
    perspective, centered on the current location. By default, such views are
    oriented towards north. If the user zooms out, the default satellite or
    hybrid imagery appears again. The behavior varies depending on zoom level
    and the value of tilt:
- Between zoom levels 12 and 18 the top-down basemap (0°) displays by
    default unless tiltis set to 45.
- At zoom levels of 18 or greater the 45° basemap displays unless
    tiltis set to 0.
- The rotate control becomes visible. The rotate control provides options
    that enable the user to toggle tilt, and to rotate the view in 90°
    increments in either direction. To hide the rotate control, set
    rotateControltofalse.
Zooming out from a map type displaying 45° imagery reverts each of these changes, re-establishing the original map types.
Enable and Disable 45° Imagery
You can disable 45° imagery by calling setTilt(0) on the
  Map object. To enable 45° imagery for supported map types,
  call setTilt(45). The Map's getTilt()
  method will always reflect the current tilt being shown on the
  map; if you set a tilt on a map and then later remove that
  tilt (by zooming the map out, for example), the map's
  getTilt() method will return 0.
Important: 45° imagery is only supported on raster maps; this imagery cannot be used with vector maps.
The following example displays a 45° view of New York City:
TypeScript
function initMap(): void { const map = new google.maps.Map( document.getElementById("map") as HTMLElement, { center: { lat: 40.76, lng: -73.983 }, zoom: 15, mapTypeId: "satellite", } ); map.setTilt(45); } declare global { interface Window { initMap: () => void; } } window.initMap = initMap;
JavaScript
function initMap() { const map = new google.maps.Map(document.getElementById("map"), { center: { lat: 40.76, lng: -73.983 }, zoom: 15, mapTypeId: "satellite", }); map.setTilt(45); } window.initMap = initMap;
Try Sample
Rotate 45° Imagery
The 45° imagery actually consists of a collection of images
  for each cardinal direction (North, South, East, West). Once your map
  is displaying 45° imagery, you can orient the
  imagery towards one of its cardinal directions by calling
  setHeading() on the Map object, passing
  a number value expressed as degrees from North.
The following example shows an aerial map and auto-rotates the map every 3 seconds when the button is clicked:
TypeScript
let map: google.maps.Map; function initMap(): void { map = new google.maps.Map(document.getElementById("map") as HTMLElement, { center: { lat: 40.76, lng: -73.983 }, zoom: 15, mapTypeId: "satellite", heading: 90, tilt: 45, }); // add listener to button document.getElementById("rotate")!.addEventListener("click", autoRotate); } function rotate90(): void { const heading = map.getHeading() || 0; map.setHeading(heading + 90); } function autoRotate(): void { // Determine if we're showing aerial imagery. if (map.getTilt() !== 0) { window.setInterval(rotate90, 3000); } } declare global { interface Window { initMap: () => void; } } window.initMap = initMap;
JavaScript
let map; function initMap() { map = new google.maps.Map(document.getElementById("map"), { center: { lat: 40.76, lng: -73.983 }, zoom: 15, mapTypeId: "satellite", heading: 90, tilt: 45, }); // add listener to button document.getElementById("rotate").addEventListener("click", autoRotate); } function rotate90() { const heading = map.getHeading() || 0; map.setHeading(heading + 90); } function autoRotate() { // Determine if we're showing aerial imagery. if (map.getTilt() !== 0) { window.setInterval(rotate90, 3000); } } window.initMap = initMap;
Try Sample
Modify the Map Type Registry
A map's mapTypeId is a string identifier
  that is used to associate a MapType with a
  unique value. Each Map object maintains a
  MapTypeRegistry which contains the collection of
  available MapTypes for that map. This registry
  is used to select the types of maps which are available in
  the Map's MapType control, for example.
You don't read directly from the map type registry. Instead,
  you modify the registry by adding custom map types and associating
  them with a string identifier of your choosing. You cannot modify
  or alter the basic map types (though you can remove them from the
  map by altering the appearance of the map's associated
  mapTypeControlOptions).
The following code sets the map to show only
  two map types in the map's mapTypeControlOptions
  and modifies the registry to add the association with
  this identifier to the actual implementation of the
  MapType interface.
// Modify the control to only display two maptypes, the // default ROADMAP and the custom 'mymap'. // Note that because this is an association, we // don't need to modify the MapTypeRegistry beforehand. var MY_MAPTYPE_ID = 'mymaps'; var mapOptions = { zoom: 12, center: brooklyn, mapTypeControlOptions: { mapTypeIds: ['roadmap', MY_MAPTYPE_ID] }, mapTypeId: MY_MAPTYPE_ID }; // Create our map. This creation will implicitly create a // map type registry. map = new google.maps.Map(document.getElementById('map'), mapOptions); // Create your custom map type using your own code. // (See below.) var myMapType = new MyMapType(); // Set the registry to associate 'mymap' with the // custom map type we created, and set the map to // show that map type. map.mapTypes.set(MY_MAPTYPE_ID, myMapType);
Styled Maps
The StyledMapType lets you customize the presentation of
  the standard Google base maps, changing the visual display of such elements
  as roads, parks, and built-up areas to reflect a different style than that
  used in the default map type. The StyledMapType affects only the default roadmap map type.
For more information about the StyledMapType, see
  Using embedded JSON style
  declarations.
Custom Map Types
The Maps JavaScript API supports the display and management of custom map types, allowing you to implement your own map imagery or tile overlays.
Several possible map type implementations exist within the Maps JavaScript API:
- Standard tile sets consisting of images which
    collectively constitute full cartographic maps. These tile
    sets are also known as base map types. These map types
    act and behave like the existing default map types:
    roadmap,satellite,hybridandterrain. You can add your custom map type to a Map'smapTypesarray to allow the UI within the Maps JavaScript API to treat your custom map type as a standard map type (by including it in the MapType control, for example).
- Image tile overlays which display on top of existing base map types. Generally, these map types are used to augment an existing map type to display additional information and are often constrained to specific locations and/or zoom levels. Note that these tiles may be transparent, allowing you to add features to existing maps.
- Non-image map types, which allow you to manipulate the display of map information at its most fundamental level.
Each of these options relies on creating a class that
  implements the MapType
  interface. Additionally, the 
  ImageMapType class provides some built-in
  behavior to simplify the creation of imagery map types.
The MapType Interface
Before you create classes which implement MapType,
  it is important to understand how Google Maps determines
  coordinates and decides which parts of the map to show. You need to
  implement similar logic for any base or overlay map types.
  Read the guide to map
  and tile coordinates.
Custom map types must implement the MapType
  interface. This interface specifies certain properties and
  methods that allow the API to initiate requests to your map
  type(s) when the API determines that it needs to display map
  tiles within the current viewport and zoom level. You handle
  these requests to decide which tile to load.
Note: You may create your
  own class to implement this interface. Alternatively, if you have
  compatible imagery you can use the 
  ImageMapType class which already implements
  this interface.
Classes implementing the MapType interface
  require that you define and populate the following properties:
- tileSize(required) specifies the size of the tile (of type- google.maps.Size). Sizes must be rectangular though they need not be square.
- maxZoom(required) specifies the maximum zoom level at which to display tiles of this map type.
- minZoom(optional) specifies the minimum zoom level at which to display tile of this map type. By default, this value is- 0indicating that no minimum zoom level exists.
- name(optional) specifies the name for this map type. This property is only necessary if you want this map type to be selectable within a MapType control. (See Control Options.)
- alt(optional) specifies the alternate text for this map type, exhibited as hover text. This property is only necessary if you want this map type to be selectable within a MapType control. (See Control Options.)
Additionally, classes implementing the MapType interface
  need to implement the following methods:
- 
    getTile()(required) is called whenever the API determines that the map needs to display new tiles for the given viewport. ThegetTile()method must have the following signature:getTile(tileCoord:Point,zoom:number,ownerDocument:Document):NodeThe API determines whether it needs to call getTile()based on theMapType'stileSize,minZoom, andmaxZoomproperties and the map's current viewport and zoom level. The handler for this method should return an HTML element given a passed coordinate, zoom level, and DOM element on which to append the tile image.
- 
    releaseTile()(optional) is called whenever the API determines that the map needs to remove a tile as it falls out of view. This method must have the following signature:releaseTile(tile:Node)You typically should handle removal of any elements that were attached to the map tiles upon addition to the map. For example, if you attached event listeners to map tile overlays, you should remove them here. 
The getTile() method acts as the main controller for
  determining which tiles to load within a given viewport.
Base Map Types
Map types which you construct in this manner may either stand
  alone or be combined with other map types as overlays. Standalone
  map types are known as base map types. You may want to have the API
  treat such custom MapTypes as it would any other existing
  base map type (ROADMAP, TERRAIN, etc.). To do
  so, add your custom MapType to the Map's
  mapTypes property. This property is of type
  MapTypeRegistry.
The following code creates a base MapType to display
  a map's tile coordinates and draws an outline of the tiles:
TypeScript
/* * This demo demonstrates how to replace default map tiles with custom imagery. * In this case, the CoordMapType displays gray tiles annotated with the tile * coordinates. * * Try panning and zooming the map to see how the coordinates change. */ class CoordMapType { tileSize: google.maps.Size; maxZoom = 19; name = "Tile #s"; alt = "Tile Coordinate Map Type"; constructor(tileSize: google.maps.Size) { this.tileSize = tileSize; } getTile( coord: google.maps.Point, zoom: number, ownerDocument: Document ): HTMLElement { const div = ownerDocument.createElement("div"); div.innerHTML = String(coord); div.style.width = this.tileSize.width + "px"; div.style.height = this.tileSize.height + "px"; div.style.fontSize = "10"; div.style.borderStyle = "solid"; div.style.borderWidth = "1px"; div.style.borderColor = "#AAAAAA"; div.style.backgroundColor = "#E5E3DF"; return div; } releaseTile(tile: HTMLElement): void {} } function initMap(): void { const map = new google.maps.Map( document.getElementById("map") as HTMLElement, { zoom: 10, center: { lat: 41.85, lng: -87.65 }, streetViewControl: false, mapTypeId: "coordinate", mapTypeControlOptions: { mapTypeIds: ["coordinate", "roadmap"], style: google.maps.MapTypeControlStyle.DROPDOWN_MENU, }, } ); map.addListener("maptypeid_changed", () => { const showStreetViewControl = (map.getMapTypeId() as string) !== "coordinate"; map.setOptions({ streetViewControl: showStreetViewControl, }); }); // Now attach the coordinate map type to the map's registry. map.mapTypes.set( "coordinate", new CoordMapType(new google.maps.Size(256, 256)) ); } declare global { interface Window { initMap: () => void; } } window.initMap = initMap;
JavaScript
/* * This demo demonstrates how to replace default map tiles with custom imagery. * In this case, the CoordMapType displays gray tiles annotated with the tile * coordinates. * * Try panning and zooming the map to see how the coordinates change. */ class CoordMapType { tileSize; maxZoom = 19; name = "Tile #s"; alt = "Tile Coordinate Map Type"; constructor(tileSize) { this.tileSize = tileSize; } getTile(coord, zoom, ownerDocument) { const div = ownerDocument.createElement("div"); div.innerHTML = String(coord); div.style.width = this.tileSize.width + "px"; div.style.height = this.tileSize.height + "px"; div.style.fontSize = "10"; div.style.borderStyle = "solid"; div.style.borderWidth = "1px"; div.style.borderColor = "#AAAAAA"; div.style.backgroundColor = "#E5E3DF"; return div; } releaseTile(tile) {} } function initMap() { const map = new google.maps.Map(document.getElementById("map"), { zoom: 10, center: { lat: 41.85, lng: -87.65 }, streetViewControl: false, mapTypeId: "coordinate", mapTypeControlOptions: { mapTypeIds: ["coordinate", "roadmap"], style: google.maps.MapTypeControlStyle.DROPDOWN_MENU, }, }); map.addListener("maptypeid_changed", () => { const showStreetViewControl = map.getMapTypeId() !== "coordinate"; map.setOptions({ streetViewControl: showStreetViewControl, }); }); // Now attach the coordinate map type to the map's registry. map.mapTypes.set( "coordinate", new CoordMapType(new google.maps.Size(256, 256)), ); } window.initMap = initMap;
Try Sample
Overlay Map Types
Some map types are designed to work on top of existing map types. Such map types may have transparent layers indicating points of interest, or showing additional data to the user.
In these cases, you do not want the map type treated as a separate entity but as an overlay.
  You can do this by adding the map type to an existing MapType directly using
  the Map's overlayMapTypes property. This property contains
  an MVCArray of MapTypes. All map types
  (base and overlay) are rendered within the
  mapPane
  layer. Overlay map types will display on top of the base map they
  are attached to, in the order in which they appear in the
  Map.overlayMapTypes array (overlays with higher index
  values are displayed in front of overlays with lower index values).
The following example is identical to the previous one
  except that we've created a tile overlay MapType
  on top of the ROADMAP map type:
TypeScript
/* * This demo illustrates the coordinate system used to display map tiles in the * API. * * Tiles in Google Maps are numbered from the same origin as that for * pixels. For Google's implementation of the Mercator projection, the origin * tile is always at the northwest corner of the map, with x values increasing * from west to east and y values increasing from north to south. * * Try panning and zooming the map to see how the coordinates change. */ class CoordMapType implements google.maps.MapType { tileSize: google.maps.Size; alt: string|null = null; maxZoom: number = 17; minZoom: number = 0; name: string|null = null; projection: google.maps.Projection|null = null; radius: number = 6378137; constructor(tileSize: google.maps.Size) { this.tileSize = tileSize; } getTile( coord: google.maps.Point, zoom: number, ownerDocument: Document ): HTMLElement { const div = ownerDocument.createElement("div"); div.innerHTML = String(coord); div.style.width = this.tileSize.width + "px"; div.style.height = this.tileSize.height + "px"; div.style.fontSize = "10"; div.style.borderStyle = "solid"; div.style.borderWidth = "1px"; div.style.borderColor = "#AAAAAA"; return div; } releaseTile(tile: Element): void {} } function initMap(): void { const map = new google.maps.Map( document.getElementById("map") as HTMLElement, { zoom: 10, center: { lat: 41.85, lng: -87.65 }, } ); // Insert this overlay map type as the first overlay map type at // position 0. Note that all overlay map types appear on top of // their parent base map. const coordMapType = new CoordMapType(new google.maps.Size(256, 256)) map.overlayMapTypes.insertAt( 0, coordMapType ); } declare global { interface Window { initMap: () => void; } } window.initMap = initMap;
JavaScript
/* * This demo illustrates the coordinate system used to display map tiles in the * API. * * Tiles in Google Maps are numbered from the same origin as that for * pixels. For Google's implementation of the Mercator projection, the origin * tile is always at the northwest corner of the map, with x values increasing * from west to east and y values increasing from north to south. * * Try panning and zooming the map to see how the coordinates change. */ class CoordMapType { tileSize; alt = null; maxZoom = 17; minZoom = 0; name = null; projection = null; radius = 6378137; constructor(tileSize) { this.tileSize = tileSize; } getTile(coord, zoom, ownerDocument) { const div = ownerDocument.createElement("div"); div.innerHTML = String(coord); div.style.width = this.tileSize.width + "px"; div.style.height = this.tileSize.height + "px"; div.style.fontSize = "10"; div.style.borderStyle = "solid"; div.style.borderWidth = "1px"; div.style.borderColor = "#AAAAAA"; return div; } releaseTile(tile) {} } function initMap() { const map = new google.maps.Map(document.getElementById("map"), { zoom: 10, center: { lat: 41.85, lng: -87.65 }, }); // Insert this overlay map type as the first overlay map type at // position 0. Note that all overlay map types appear on top of // their parent base map. const coordMapType = new CoordMapType(new google.maps.Size(256, 256)); map.overlayMapTypes.insertAt(0, coordMapType); } window.initMap = initMap;
Try Sample
Image Map Types
Implementing a MapType to act as a base map
  type can be a time-consuming and laborious task. The API
  provides a special class that implements the MapType
  interface for the most common map types: map types that consist
  of tiles made up of single image files.
This class, the ImageMapType class,
  is constructed using an ImageMapTypeOptions
  object specification defining the following required
  properties:
- tileSize(required) specifies the size of the tile (of type- google.maps.Size). Sizes must be rectangular though they need not be square.
- getTileUrl(required) specifies the function, usually provided as an inline function literal, to handle selection of the proper image tile based on supplied world coordinates and zoom level.
The following code implements a basic ImageMapType
  using Google's moon tiles. The example makes use of a normalization
  function to ensure that tiles repeat along the x-axis, but not along the
  y-axis of your map.
TypeScript
function initMap(): void { const map = new google.maps.Map( document.getElementById("map") as HTMLElement, { center: { lat: 0, lng: 0 }, zoom: 1, streetViewControl: false, mapTypeControlOptions: { mapTypeIds: ["moon"], }, } ); const moonMapType = new google.maps.ImageMapType({ getTileUrl: function (coord, zoom): string { const normalizedCoord = getNormalizedCoord(coord, zoom); if (!normalizedCoord) { return ""; } const bound = Math.pow(2, zoom); return ( "https://mw1.google.com/mw-planetary/lunar/lunarmaps_v1/clem_bw" + "/" + zoom + "/" + normalizedCoord.x + "/" + (bound - normalizedCoord.y - 1) + ".jpg" ); }, tileSize: new google.maps.Size(256, 256), maxZoom: 9, minZoom: 0, // @ts-ignore TODO 'radius' does not exist in type 'ImageMapTypeOptions' radius: 1738000, name: "Moon", }); map.mapTypes.set("moon", moonMapType); map.setMapTypeId("moon"); } // Normalizes the coords that tiles repeat across the x axis (horizontally) // like the standard Google map tiles. function getNormalizedCoord(coord, zoom) { const y = coord.y; let x = coord.x; // tile range in one direction range is dependent on zoom level // 0 = 1 tile, 1 = 2 tiles, 2 = 4 tiles, 3 = 8 tiles, etc const tileRange = 1 << zoom; // don't repeat across y-axis (vertically) if (y < 0 || y >= tileRange) { return null; } // repeat across x-axis if (x < 0 || x >= tileRange) { x = ((x % tileRange) + tileRange) % tileRange; } return { x: x, y: y }; } declare global { interface Window { initMap: () => void; } } window.initMap = initMap;
JavaScript
function initMap() { const map = new google.maps.Map(document.getElementById("map"), { center: { lat: 0, lng: 0 }, zoom: 1, streetViewControl: false, mapTypeControlOptions: { mapTypeIds: ["moon"], }, }); const moonMapType = new google.maps.ImageMapType({ getTileUrl: function (coord, zoom) { const normalizedCoord = getNormalizedCoord(coord, zoom); if (!normalizedCoord) { return ""; } const bound = Math.pow(2, zoom); return ( "https://mw1.google.com/mw-planetary/lunar/lunarmaps_v1/clem_bw" + "/" + zoom + "/" + normalizedCoord.x + "/" + (bound - normalizedCoord.y - 1) + ".jpg" ); }, tileSize: new google.maps.Size(256, 256), maxZoom: 9, minZoom: 0, // @ts-ignore TODO 'radius' does not exist in type 'ImageMapTypeOptions' radius: 1738000, name: "Moon", }); map.mapTypes.set("moon", moonMapType); map.setMapTypeId("moon"); } // Normalizes the coords that tiles repeat across the x axis (horizontally) // like the standard Google map tiles. function getNormalizedCoord(coord, zoom) { const y = coord.y; let x = coord.x; // tile range in one direction range is dependent on zoom level // 0 = 1 tile, 1 = 2 tiles, 2 = 4 tiles, 3 = 8 tiles, etc const tileRange = 1 << zoom; // don't repeat across y-axis (vertically) if (y < 0 || y >= tileRange) { return null; } // repeat across x-axis if (x < 0 || x >= tileRange) { x = ((x % tileRange) + tileRange) % tileRange; } return { x: x, y: y }; } window.initMap = initMap;
Try Sample
Projections
The Earth is a three-dimensional sphere (approximately), while a map is a flat two-dimensional surface. The map that you see within the Maps JavaScript API, like any flat map of the Earth, is a projection of that sphere onto a flat surface. In its simplest terms, a projection can be defined as a mapping of latitude/longitude values into coordinates on the projection's map.
Projections in the Maps JavaScript API must implement the
  Projection interface. A Projection
  implementation must provide not only a mapping from one coordinate
  system to another, but a bi-directional mapping. That is, you must
  define how to translate from Earth coordinates (LatLng objects)
  to the Projection class's
  world
  coordinate system, and from the world coordinate system back to the Earth coordinates.
  Google Maps uses the Mercator projection to create its maps
  from geographic data and convert events on the map into
  geographic coordinates. You can obtain this projection by
  calling getProjection() on the Map
  (or any of the standard base MapType types.) For most uses,
  this standard Projection will suffice, but you may also
  define and use your own custom projections.
Implement a Projection
When implementing a custom projection, you will need to define a few things:
- The formulae for mapping latitude and longitude coordinates into
    a Cartesian plane and the corresponding formulae for mapping from a Cartesian plane to latitude
    and longitude coordinates. (The Projectioninterface only supports transformations into rectilinear coordinates.)
- The base tile size. All tiles must be rectangular.
- The "world size" of a map using the base tile set at zoom level 0. Note that for maps consisting of one tile at zoom 0, the world size and base tile size are identical.
Coordinate Transformations in Projections
Each projection provides two methods which translate between these two coordinate systems, allowing you to convert between geographic and world coordinates:
- The Projection.fromLatLngToPoint()method converts aLatLngvalue into a world coordinate. This method is used to position overlays on the map (and to position the map itself).
- The Projection.fromPointToLatLng()method converts a world coordinate into aLatLngvalue. This method is used to convert events such as clicks that happen on the map into geographic coordinates.
Google Maps assumes that projections are rectilinear.
Generally, you may use a projection for two cases: to create a map of the world, or to create a map of a local area. In the former case, you should ensure that your projection is also rectilinear and normal at all longitudes. Some projections (especially conic projections) may be "locally normal" (i.e. point north) but deviate from true north; for example, the further the map is positioned relative to some reference longitude. You may use such a projection locally, but be aware that the projection is necessarily imprecise and transformation errors will become increasingly apparently the further away from the reference longitude you deviate.
Map Tile Selection in Projections
Projections are not only useful for determining the positions of
  locations or overlays, but for positioning the map tiles themselves.
  The Maps JavaScript API renders base maps using a MapType
  interface, which must declare both a projection property for
  identifying the map's projection and a getTile()
  method for retrieving map tiles based on
  tile
  coordinate values. Tile coordinates are based on
  both your basic tile size (which must be rectangular) and the "world
  size" of your map, which is the pixel size of your map world
  at zoom level 0. (For maps consisting of one tile at zoom 0, the tile
  size and world size are identical.)
You define the base tile size within your MapType's
  tileSize property. You define the world size implicitly
  within your projection's fromLatLngToPoint()
  and fromPointToLatLng() methods.
Since image selection depends on these passed values, it is useful
  to name images that can be selected programmatically given those
  passed values, such as
  map_zoom_tileX_tileY.png.
The following example defines an ImageMapType
  using the
  
  Gall-Peters projection:
TypeScript
// This example defines an image map type using the Gall-Peters // projection. // https://en.wikipedia.org/wiki/Gall%E2%80%93Peters_projection const mapElement = document.querySelector("gmp-map") as google.maps.MapElement; let innerMap; async function initMap() { // Request the needed libraries. await google.maps.importLibrary("maps"); // Create a map. innerMap = mapElement.innerMap; innerMap.setOptions({ mapTypeControl: false, }); // Set the Gall-Peters map type. initGallPeters(); innerMap.mapTypes.set("gallPeters", gallPetersMapType); innerMap.setMapTypeId("gallPeters"); // Show the lat and lng under the mouse cursor. const coordsDiv = document.getElementById("coords") as HTMLElement; innerMap.addListener("mousemove", (event: google.maps.MapMouseEvent) => { coordsDiv.textContent = "lat: " + Math.round(event.latLng!.lat()) + ", " + "lng: " + Math.round(event.latLng!.lng()); }); // Add some markers to the map. innerMap.data.setStyle((feature) => { return { title: feature.getProperty("name") as string, optimized: false, }; }); innerMap.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 ( "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" }, }, ], }; initMap();
JavaScript
// This example defines an image map type using the Gall-Peters // projection. // https://en.wikipedia.org/wiki/Gall%E2%80%93Peters_projection const mapElement = document.querySelector("gmp-map"); let innerMap; async function initMap() { // Request the needed libraries. await google.maps.importLibrary("maps"); // Create a map. innerMap = mapElement.innerMap; innerMap.setOptions({ mapTypeControl: false, }); // Set the Gall-Peters map type. initGallPeters(); innerMap.mapTypes.set("gallPeters", gallPetersMapType); innerMap.setMapTypeId("gallPeters"); // Show the lat and lng under the mouse cursor. const coordsDiv = document.getElementById("coords"); innerMap.addListener("mousemove", (event) => { coordsDiv.textContent = "lat: " + Math.round(event.latLng.lat()) + ", " + "lng: " + Math.round(event.latLng.lng()); }); // Add some markers to the map. innerMap.data.setStyle((feature) => { return { title: feature.getProperty("name"), optimized: false, }; }); innerMap.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 ("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" }, }, ], }; initMap();