Click here to see your recently viewed pages and most viewed pages.
Google Maps JavaScript API

Map Types

  1. Map Types
  2. Basic Map Types
  3. 45° Imagery
    1. Enabling and Disabling 45° Imagery
    2. Rotating 45° Imagery
  4. Modifying the Map Type Registry
  5. Styled Maps
  6. Custom Map Types
    1. Map Coordinates
      1. World Coordinates
      2. Pixel Coordinates
      3. Tile Coordinates
    2. The MapType Interface
      1. Base Map Types
      2. Overlay Map Types
      3. Image Map Types
  7. Custom Projections
    1. Implementing the Projection Interface
    2. Coordinate Transformation in Projections
    3. Tile Selection in Projections

Map Types

This document discusses the types of maps you can display using the Google 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 API is an advanced topic. Most developers can simply use the basic map types noted below. However, you can also define your own map tiles using custom map types or modify the presentation of existing map types using Styled Maps. 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 Google Maps API. In addition to the familiar "painted" road map tiles, the Google Maps API also supports other maps types.

The following map types are available in the Google Maps API:

  • MapTypeId.ROADMAP displays the default road map view. This is the default map type.
  • MapTypeId.SATELLITE displays Google Earth satellite images
  • MapTypeId.HYBRID displays a mixture of normal and satellite views
  • MapTypeId.TERRAIN displays 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 via setting its Map options object, or by calling the map's setMapTypeId() method. The mapTypeID property defaults to MapTypeId.ROADMAP.

Setting the mapTypeId upon construction:

var myLatlng = new google.maps.LatLng(-34.397, 150.644);
var mapOptions = {
  zoom: 8,
  center: myLatlng,
  mapTypeId: google.maps.MapTypeId.SATELLITE
var map = new google.maps.Map(document.getElementById("map-canvas"),

Modifying the mapTypeId dynamically:


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 V3 uses a map type registry, explained below, to manage these references.

45° Imagery

The Google Maps 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 the boardwalk in Santa Cruz, CA:

The existing google.maps.MapTypeId.SATELLITE and google.maps.MapTypeId.HYBRID map types support 45° perspective imagery at high zoom levels (where available). If you zoom into a location for which such imagery exists, these map types will automatically alter their views in the following manner:

  • Any existing Pan control on a map will alter to add a compass wheel around the existing navigation controls. This compass allows you to change the heading of any 45° imagery by dragging the wheel, snapping the direction to the nearest supported direction which contains imagery.
  • An interstitial Rotate control will appear between the existing Pan and Zoom controls, allowing you to rotate through supported directions. The Rotate control only allows clockwise rotation.
  • The satellite or hybrid imagery will be replaced with 45° perspective imagery centered on the current location. By default, such views will orient towards north. If you zoom out, you will return to viewing the default satellite or hybrid imagery.
  • The MapType control will enable a submenu toggle control for displaying 45° imagery.

Zooming out from a map type displaying 45° imagery will revert each of these changes, re-establishing the original map types.

Google adds 45° Imagery for new cities on an ongoing basis. Check out the list of 45° imagery on Google Maps for the latest information.

Enabling and Disabling 45° Imagery

You can disable 45° imagery by calling setTilt(0) on the Map object. To enable 45° perspective 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.

The following example displays a 45° view of downtown Portland, OR:

var map;

function initialize() {
  var mapOptions = {
    center: new google.maps.LatLng(36.964645, -122.01523),
    zoom: 18,
    mapTypeId: google.maps.MapTypeId.SATELLITE
  map = new google.maps.Map(document.getElementById('map-canvas'), mapOptions);

google.maps.event.addDomListener(window, 'load', initialize);

View example (aerial-simple.html).

Rotating 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:

var map;
function initialize() {
  var mapOptions = {
    center: new google.maps.LatLng(45.518970, -122.672899),
    zoom: 18,
    mapTypeId: google.maps.MapTypeId.SATELLITE,
    heading: 90,
    tilt: 45
  map = new google.maps.Map(document.getElementById('map-canvas'), mapOptions);

function rotate90() {
  var 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);

google.maps.event.addDomListener(window, 'load', initialize);

View example (aerial-rotation.html).

Modifying 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 do not 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. Note: we purposefully did not document the creation of the custom map type itself in the previous code. See Styled Maps or Custom Map Types below for information on constructing a map type.

// Modify the control to only display two maptypes, the
// default ROADMAP and the custom 'mymap'.
// Note that because this is simply an association, we
// don't need to modify the MapTypeRegistry beforehand.

var MY_MAPTYPE_ID = 'mymaps';

var mapOptions = {
  zoom: 12,
  center: brooklyn,
  mapTypeControlOptions: {
     mapTypeIds: [google.maps.MapTypeId.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-canvas"),

// 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 allows you to 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.

Information about the StyledMapType is included in the Styled Maps section of this Developer's Guide.

Custom Map Types

The Google Maps JavaScript API V3 now 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 V3 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, HYBRID and TERRAIN. You can add your custom map type to a Map's mapTypes array to allow the UI within the Maps 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 MapTypes.

Before we explain classes which implement MapType, it is important to understand how Google Maps determines coordinates and decides which parts of the map to show. You will need to implement similar logic for any base or overlay MapTypes.

Map Coordinates

There are several coordinate systems that the Google Maps API uses:

  • Latitude and Longitude values which reference a point on the world uniquely. (Google uses the World Geodetic System WGS84 standard.)
  • World coordinates which reference a point on the map uniquely
  • Tile coordinates which reference a specific tile on the map at the specific zoom level

World Coordinates

Whenever the Maps API needs to translate a location in the world to a location on a map (the screen), it needs to first translate latitude and longitude values into a "world" coordinate. This translation is accomplished using a map projection. Google Maps uses the Mercator projection for this purpose. You may also define your own projection implementing the google.maps.Projection interface. (Note that interfaces in V3 are not classes you "subclass" but instead are simply specifications for classes you define yourself.)

For convenience in the calculation of pixel coordinates (see below) we assume a map at zoom level 0 is a single tile of the base tile size. We then define world coordinates relative to pixel coordinates at zoom level 0, using the projection to convert latitudes & longitudes to pixel positions on this base tile. This world coordinate is a floating point value measured from the origin of the map's projection to the specific location. Note that since this value is a floating point value, it may be much more precise than the current resolution of the map image being shown. A world coordinate is independent of the current zoom level, in other words.

World coordinates in Google Maps are measured from the Mercator projection's origin (the northwest corner of the map at 180 degrees longitude and approximately 85 degrees latitude) and increase in the x direction towards the east (right) and increase in the y direction towards the south (down). Because the basic Mercator Google Maps tile is 256 x 256 pixels, the usable world coordinate space is {0-256}, {0-256} (See below.)

Note that a Mercator projection has a finite width longitudinally but an infinite height latitudinally. We "cut off" base map imagery utilizing the Mercator projection at approximately +/- 85 degrees to make the resulting map shape square, which allows easier logic for tile selection. Note that a projection may produce world coordinates outside the base map's usable coordinate space if you plot very near the poles, for example.

Pixel Coordinates

World coordinates reflect absolute locations on a given projection, but we need to translate these into pixel coordinates to determine the "pixel" offset at a given zoom level. These pixel coordinates are calculated using the following formula:

pixelCoordinate = worldCoordinate * 2zoomLevel

From the above equation, note that each increasing zoom level is twice as large in both the x and y directions. Therefore, each higher zoom level contains four times as much resolution as the preceding level. For example, at zoom level 1, the map consists of 4 256x256 pixels tiles, resulting in a pixel space from 512x512. At zoom level 19, each x and y pixel on the map can be referenced using a value between 0 and 256 * 219

Because we based world coordinates on the map's tile size, a pixel coordinates' integer part has the effect of identifying the exact pixel at that location in the current zoom level. Note that for zoom level 0, the pixel coordinates are equal to the world coordinates.

We now have a way to accurately denote each location on the map, at each zoom level. The Maps API constructs a viewport given the zoom level center of the map (as a LatLng), and the size of the containing DOM element and translates this bounding box into pixel coordinates. The API then determines logically all map tiles which lie within the given pixel bounds. Each of these map tiles are referenced using Tile Coordinates which greatly simplify the displaying of map imagery.

Tile Coordinates

The Google Maps API could not possibly load all map imagery at the higher zoom levels that are most useful; instead, the Maps API breaks up imagery at each zoom level into a set of map tiles, which are logically arranged in an order which the application understands. When a map scrolls to a new location, or to a new zoom level, the Maps API determines which tiles are needed using pixel coordinates, and translates those values into a set of tiles to retrieve. These tile coordinates are assigned using a scheme which makes it logically easy to determine which tile contains the imagery for any given point.

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. Tiles are indexed using x,y coordinates from that origin. For example, at zoom level 2, when the earth is divided up into 16 tiles, each tile can be referenced by a unique x,y pair:

Note that by dividing the pixel coordinates by the tile size and taking the integer parts of the result, you produce as a by-product the tile coordinate at the current zoom level.

The following example displays coordinates — LatLng values, world coordinates, pixel coordinates, and tile coordinates — for Chicago, IL at different zoom levels:

View example (map-coordinates.html)

The MapType Interface

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, or —if you have compatible imagery — 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 0 indicating 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 Adding MapType Controls below.)
  • 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 Adding MapType Controls below.)

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. The getTile() method must have the following signature:


    The API determines whether it needs to call getTile() based on the MapType's tileSize, minZoom, and maxZoom properties 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:


    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 wish 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:

 * 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.

 * @constructor
 * @implements {google.maps.MapType}
function CoordMapType() {

CoordMapType.prototype.tileSize = new google.maps.Size(256,256);
CoordMapType.prototype.maxZoom = 19;

CoordMapType.prototype.getTile = function(coord, zoom, ownerDocument) {
  var div = ownerDocument.createElement('div');
  div.innerHTML = coord; = this.tileSize.width + 'px'; = this.tileSize.height + 'px'; = '10'; = 'solid'; = '1px'; = '#AAAAAA'; = '#E5E3DF';
  return div;
}; = 'Tile #s';
CoordMapType.prototype.alt = 'Tile Coordinate Map Type';

var map;
var chicago = new google.maps.LatLng(41.850033,-87.6500523);
var coordinateMapType = new CoordMapType();

function initialize() {
  var mapOptions = {
    zoom: 10,
    center: chicago,
    streetViewControl: false,
    mapTypeId: 'coordinate',
    mapTypeControlOptions: {
      mapTypeIds: ['coordinate', google.maps.MapTypeId.ROADMAP],
      style: google.maps.MapTypeControlStyle.DROPDOWN_MENU
  map = new google.maps.Map(document.getElementById('map-canvas'),

  google.maps.event.addListener(map, 'maptypeid_changed', function() {
    var showStreetViewControl = map.getMapTypeId() != 'coordinate';
    map.setOptions({'streetViewControl': showStreetViewControl});

  // Now attach the coordinate map type to the map's registry
  map.mapTypes.set('coordinate', coordinateMapType);

google.maps.event.addDomListener(window, 'load', initialize);

View example (maptype-base.html).

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. (Google's traffic layer is an example of such a map type.)

In these cases, you do not wish to have the map type treated as a separate entity. Instead, you can add 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 any base map they are attached to, in the order in which they appear in the Map.overlayMapTypes array.

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:

 * 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.

/** @constructor */
function CoordMapType(tileSize) {
  this.tileSize = tileSize;

CoordMapType.prototype.getTile = function(coord, zoom, ownerDocument) {
  var div = ownerDocument.createElement('div');
  div.innerHTML = coord; = this.tileSize.width + 'px'; = this.tileSize.height + 'px'; = '10'; = 'solid'; = '1px'; = '#AAAAAA';
  return div;

var map;
var chicago = new google.maps.LatLng(41.850033,-87.6500523);

function initialize() {
  var mapOptions = {
    zoom: 10,
    center: chicago
  map = new google.maps.Map(document.getElementById('map-canvas'),

  // 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.
      0, new CoordMapType(new google.maps.Size(256, 256)));

google.maps.event.addDomListener(window, 'load', initialize);

View example (maptype-overlay.html).

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.

var moonTypeOptions = {
  getTileUrl: function(coord, zoom) {
      var normalizedCoord = getNormalizedCoord(coord, zoom);
      if (!normalizedCoord) {
        return null;
      var bound = Math.pow(2, zoom);
      return '' +
          '/' + zoom + '/' + normalizedCoord.x + '/' +
          (bound - normalizedCoord.y - 1) + '.jpg';
  tileSize: new google.maps.Size(256, 256),
  maxZoom: 9,
  minZoom: 0,
  radius: 1738000,
  name: 'Moon'

var moonMapType = new google.maps.ImageMapType(moonTypeOptions);

function initialize() {
  var myLatlng = new google.maps.LatLng(0, 0);
  var mapOptions = {
    center: myLatlng,
    zoom: 1,
    streetViewControl: false,
    mapTypeControlOptions: {
      mapTypeIds: ['moon']

  var map = new google.maps.Map(document.getElementById('map-canvas'),
  map.mapTypes.set('moon', moonMapType);

// Normalizes the coords that tiles repeat across the x axis (horizontally)
// like the standard Google map tiles.
function getNormalizedCoord(coord, zoom) {
  var y = coord.y;
  var 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
  var 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

google.maps.event.addDomListener(window, 'load', initialize);

View example (maptype-image.html).


The Earth is a three-dimensional sphere (approximately), while a map is a flat two-dimensional surface. The map that you see within the Google Maps 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 Google Maps 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 (LatLngs) to the Projection's world coordinate system, and vice versa. 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 MapTypes.) For most uses, this standard Projection will suffice, but you may also define and use your own custom projections.

Implementing 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 vice versa. (The Projection interface 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 a LatLng value 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 a LatLng value. 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 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:

var chicago = new google.maps.LatLng(41.850033, -87.6500523);
var anchorage = new google.maps.LatLng(61.2180556, -149.9002778);
var mexico = new google.maps.LatLng(19.4270499, -99.1275711);
var equator = new google.maps.LatLng(0,0);
var london = new google.maps.LatLng(51.5001524, -0.1262362);
var johannesburg = new google.maps.LatLng(-26.201452, 28.045488);
var kinshasa = new google.maps.LatLng(-4.325, 15.322222);
var sydney = new google.maps.LatLng( -33.867139, 151.207114);

var locationArray = [chicago,anchorage,mexico,equator,london,johannesburg,kinshasa,sydney];
var locationNameArray = ['Chicago','Anchorage','Mexico City','The Equator','London','Johannesburg','Kinshasa','Sydney'];

// Note: this value is exact as the map projects a full 360 degrees of longitude

// Note: this value is inexact as the map is cut off at ~ +/- 83 degrees.
// However, the polar regions produce very little increase in Y range, so
// we will use the tile size.

function degreesToRadians(deg) {
  return deg * (Math.PI / 180);

function radiansToDegrees(rad) {
  return rad / (Math.PI / 180);

 * @constructor
 * @implements {google.maps.Projection}
function GallPetersProjection() {

  // Using the base map tile, denote the lat/lon of the equatorial origin.
  this.worldOrigin_ = new google.maps.Point(GALL_PETERS_RANGE_X * 400 / 800,

  // This projection has equidistant meridians, so each longitude degree is a linear
  // mapping.
  this.worldCoordinatePerLonDegree_ = GALL_PETERS_RANGE_X / 360;

  // This constant merely reflects that latitudes vary from +90 to -90 degrees.
  this.worldCoordinateLatRange = GALL_PETERS_RANGE_Y / 2;

GallPetersProjection.prototype.fromLatLngToPoint = function(latLng) {

  var origin = this.worldOrigin_;
  var x = origin.x + this.worldCoordinatePerLonDegree_ * latLng.lng();

  // Note that latitude is measured from the world coordinate origin
  // at the top left of the map.
  var latRadians = degreesToRadians(;
  var y = origin.y - this.worldCoordinateLatRange * Math.sin(latRadians);

  return new google.maps.Point(x, y);

GallPetersProjection.prototype.fromPointToLatLng = function(point, noWrap) {

  var y = point.y;
  var x = point.x;

  if (y < 0) {
    y = 0;
  if (y >= GALL_PETERS_RANGE_Y) {

  var origin = this.worldOrigin_;
  var lng = (x - origin.x) / this.worldCoordinatePerLonDegree_;
  var latRadians = Math.asin((origin.y - y) / this.worldCoordinateLatRange);
  var lat = radiansToDegrees(latRadians);
  return new google.maps.LatLng(lat, lng, noWrap);

function initialize() {

  var gallPetersMap;

  var gallPetersMapType = new google.maps.ImageMapType({
    getTileUrl: function(coord, zoom) {
      var numTiles = 1 << zoom;

      // Don't wrap tiles vertically.
      if (coord.y < 0 || coord.y >= numTiles) {
        return null;

      // Wrap tiles horizontally.
      var x = ((coord.x % numTiles) + numTiles) % numTiles;

      // For simplicity, we use a tileset consisting of 1 tile at zoom level 0
      // and 4 tiles at zoom level 1. Note that we set the base URL to a
      // relative directory.
      var baseURL = 'images/';
      baseURL += 'gall-peters_' + zoom + '_' + x + '_' + coord.y + '.png';
      return baseURL;
    tileSize: new google.maps.Size(800, 512),
    isPng: true,
    minZoom: 0,
    maxZoom: 1,
    name: 'Gall-Peters'

  gallPetersMapType.projection = new GallPetersProjection();

  var mapOptions = {
    zoom: 0,
    center: new google.maps.LatLng(0,0),
    mapTypeControlOptions: {
      mapTypeIds: [google.maps.MapTypeId.ROADMAP, 'gallPetersMap']
  gallPetersMap = new google.maps.Map(document.getElementById('map-canvas'),

  gallPetersMap.mapTypes.set('gallPetersMap', gallPetersMapType);

  var coord;
  for (coord in locationArray) {
    new google.maps.Marker({
      position: locationArray[coord],
      map: gallPetersMap,
      title: locationNameArray[coord]

  google.maps.event.addListener(gallPetersMap, 'click', function(event) {
    alert('Point.X.Y: ' + event.latLng);

google.maps.event.addDomListener(window, 'load', initialize);

View example (map-projection-simple.html).