Introduction
Overlays are objects on the map that are tied to latitude/longitude coordinates, so they move when you drag or zoom the map. For information on predefined overlay types, see Drawing on the map.
The Google Maps JavaScript API provides an
OverlayView class for creating your own custom overlays. The
OverlayView is a base class that provides several methods you
must implement when creating your overlays. The class also provides a few
methods that make it possible to translate between screen coordinates and
locations on the map.
Add a custom overlay
Here is a summary of the steps required to create a custom overlay:
- Set your custom overlay object's
prototypeto a new instance ofgoogle.maps.OverlayView(). In effect, this will subclass the overlay class. - Create a constructor for your custom overlay, and set any initialization parameters.
- Implement an
onAdd()method within your prototype, and attach the overlay to the map.OverlayView.onAdd()will be called when the map is ready for the overlay to be attached. - Implement a
draw()method within your prototype, and handle the visual display of your object.OverlayView.draw()will be called when the object is first displayed. - You should also implement an
onRemove()method to clean up any elements you added within the overlay.
Below are more details on each step. You can also see the full, working example: View example (overlay-simple.html).
Subclass the overlay
The example below uses OverlayView to create a simple image
overlay.
// This example creates a custom overlay called USGSOverlay, containing
// a U.S. Geological Survey (USGS) image of the relevant area on the map.
// Set the custom overlay object's prototype to a new instance
// of OverlayView. In effect, this will subclass the overlay class therefore
// it's simpler to load the API synchronously, using
// google.maps.event.addDomListener().
// Note that we set the prototype to an instance, rather than the
// parent class itself, because we do not wish to modify the parent class.
var overlay;
USGSOverlay.prototype = new google.maps.OverlayView();
// Initialize the map and the custom overlay.
function initMap() {
var map = new google.maps.Map(document.getElementById('map'), {
zoom: 11,
center: {lat: 62.323907, lng: -150.109291},
mapTypeId: google.maps.MapTypeId.SATELLITE
});
var bounds = new google.maps.LatLngBounds(
new google.maps.LatLng(62.281819, -150.287132),
new google.maps.LatLng(62.400471, -150.005608));
// The photograph is courtesy of the U.S. Geological Survey.
var srcImage = 'https://developers.google.com/maps/documentation/' +
'javascript/examples/full/images/talkeetna.png';
// The custom USGSOverlay object contains the USGS image,
// the bounds of the image, and a reference to the map.
overlay = new USGSOverlay(bounds, srcImage, map);
}
Now we create a constructor for the USGSOverlay class, and
initialize the passed parameters as properties of the new object.
/** @constructor */
function USGSOverlay(bounds, image, map) {
// Initialize all properties.
this.bounds_ = bounds;
this.image_ = image;
this.map_ = map;
// Define a property to hold the image's div. We'll
// actually create this div upon receipt of the onAdd()
// method so we'll leave it null for now.
this.div_ = null;
// Explicitly call setMap on this overlay.
this.setMap(map);
}
We can't yet attach this overlay to the map in the overlay's constructor. First, we need to ensure that all of the map's panes are available, because they specify the order in which objects are displayed on a map. The API provides a helper method indicating this has occurred. We'll handle that method in the next section.
Initialize the overlay
When the overlay is first instantiated and ready to display, we need to
attach it to the map via the browser's DOM. The API indicates that the overlay
has been added to the map by invoking the overlay's onAdd()
method. To handle this method we create a <div>
to hold our image, add an <img> element, attach it to the
<div>, and then attach the overlay to one of the
map's panes. A pane is a node within the DOM tree.
The panes, of type
MapPanes, specify the stacking
order for different layers on the map. The following panes are available,
and are enumerated in the order in which they are stacked from bottom to top:
mapPaneis the lowest pane and is above the tiles. It may not receive DOM events. (Pane 0).overlayLayercontains polylines, polygons, ground overlays and tile layer overlays. It may not receive DOM events. (Pane 1).overlayShadowcontains the marker shadows. It may not receive DOM events. (Pane 2).overlayImagecontains the marker foreground images. (Pane 3).floatShadowcontains the info window shadow. It is above theoverlayImage, so that markers can be in the shadow of the info window. (Pane 4).overlayMouseTargetcontains elements that receive DOM mouse events, such as the transparent targets for markers. It is above thefloatShadow, so that markers in the shadow of the info window can be clickable. (Pane 5).floatPanecontains the info window. It is above all map overlays. (Pane 6).
Because our image is a "ground overlay," we'll use the overlayLayer
pane. When we have that pane, we'll attach our object to it as a
child.
/**
* onAdd is called when the map's panes are ready and the overlay has been
* added to the map.
*/
USGSOverlay.prototype.onAdd = function() {
var div = document.createElement('div');
div.style.borderStyle = 'none';
div.style.borderWidth = '0px';
div.style.position = 'absolute';
// Create the img element and attach it to the div.
var img = document.createElement('img');
img.src = this.image_;
img.style.width = '100%';
img.style.height = '100%';
img.style.position = 'absolute';
div.appendChild(img);
this.div_ = div;
// Add the element to the "overlayLayer" pane.
var panes = this.getPanes();
panes.overlayLayer.appendChild(div);
};
Draw the overlay
Note that we haven't invoked any special visual display in the code
above. The API invokes a separate draw() method on
the overlay whenever it needs to draw the overlay on the map,
including when first added.
We'll therefore implement this draw() method, retrieve
the overlay's MapCanvasProjection
using getProjection() and calculate the exact coordinates at
which to anchor the object's top right and bottom left points. Then we can
resize the <div>. In turn this will resize the
image to match the bounds we specified in the overlay's constructor.
USGSOverlay.prototype.draw = function() {
// We use the south-west and north-east
// coordinates of the overlay to peg it to the correct position and size.
// To do this, we need to retrieve the projection from the overlay.
var overlayProjection = this.getProjection();
// Retrieve the south-west and north-east coordinates of this overlay
// in LatLngs and convert them to pixel coordinates.
// We'll use these coordinates to resize the div.
var sw = overlayProjection.fromLatLngToDivPixel(this.bounds_.getSouthWest());
var ne = overlayProjection.fromLatLngToDivPixel(this.bounds_.getNorthEast());
// Resize the image's div to fit the indicated dimensions.
var div = this.div_;
div.style.left = sw.x + 'px';
div.style.top = ne.y + 'px';
div.style.width = (ne.x - sw.x) + 'px';
div.style.height = (sw.y - ne.y) + 'px';
};
Remove a custom overlay
We also add an onRemove() method to cleanly remove the
overlay from the map.
// The onRemove() method will be called automatically from the API if
// we ever set the overlay's map property to 'null'.
USGSOverlay.prototype.onRemove = function() {
this.div_.parentNode.removeChild(this.div_);
this.div_ = null;
};
Hide and show a custom overlay
If you wish to hide or show an overlay rather than simply create or remove
it, you can implement your own hide() and
show() methods to adjust the overlay's visibility. Alternatively,
you can detach the overlay from the map's DOM, though this operation is
slightly more expensive. Note that if you then reattach the overlay to the
map's DOM, it will re-invoke the overlay's onAdd() method.
The following example adds hide() and show()
methods to the overlay's prototype which toggle the visibility of the
container <div>. Additionally, we add a
toggleDOM() method, which attaches or detaches the overlay
to/from the map.
// Set the visibility to 'hidden' or 'visible'.
USGSOverlay.prototype.hide = function() {
if (this.div_) {
// The visibility property must be a string enclosed in quotes.
this.div_.style.visibility = 'hidden';
}
};
USGSOverlay.prototype.show = function() {
if (this.div_) {
this.div_.style.visibility = 'visible';
}
};
USGSOverlay.prototype.toggle = function() {
if (this.div_) {
if (this.div_.style.visibility === 'hidden') {
this.show();
} else {
this.hide();
}
}
};
// Detach the map from the DOM via toggleDOM().
// Note that if we later reattach the map, it will be visible again,
// because the containing <div> is recreated in the overlay's onAdd() method.
USGSOverlay.prototype.toggleDOM = function() {
if (this.getMap()) {
// Note: setMap(null) calls OverlayView.onRemove()
this.setMap(null);
} else {
this.setMap(this.map_);
}
};
Take care of the user interface:
<!-- Add an input button to initiate the toggle method on the overlay. -->
<div id="floating-panel">
<input type="button" value="Toggle visibility" onclick="overlay.toggle();"></input>
<input type="button" value="Toggle DOM attachment" onclick="overlay.toggleDOM();"></input>
</div>
