googlemaps-v3-utility-library
Version:
Google Maps API V3 Utility Library
284 lines (248 loc) • 9.6 kB
JavaScript
/**
* @name ExtOverviewMapControl for V3
* @version 0.1
* @author: Randy Becker
* @fileoverview This library adds an overview map to a Google map.
*/
/*!
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//TODO: Add corner arrow toggler
//TODO: Make transparant rectangle draggable
//TODO: Programatically construct and style overview div
//TODO: Encapsulate into an object, rather than window.onload
//TODO: Add docstrings
//TODO: Fix bugs near equator, prime meridian, poles
//TODO: Clean up everything
/*global google*/
window.onload = function () {
// Initialize two maps: one full size and one in a small div in the corner
// of the large map.
var map = new google.maps.Map(document.getElementById('map_canvas'), {
"noClear": true
});
var overlayMap = new google.maps.Map(
document.getElementById('overlayMap'),
{
mapTypeId: google.maps.MapTypeId.ROADMAP, // Always show roadmap
disableDefaultUI: true, // Turn off the controls
scrollwheel: false, // Disable scrollwheel zooming
disableDoubleClickZoom: true
}
);
var translucentBox = new google.maps.Polygon({
strokeColor: "#4444BB",
strokeOpacity: 0.8,
strokeWeight: 2,
fillColor: "#4444BB",
fillOpacity: 0.25
});
translucentBox.setMap(overlayMap);
var transparentBox = new google.maps.Polygon({
strokeColor: "#4444BB",
strokeOpacity: 0.8,
strokeWeight: 2,
fillColor: "#4444BB",
fillOpacity: 0.01
});
transparentBox.setMap(overlayMap);
function pathFromBounds(bounds) {
var northEastCorner = bounds.getNorthEast();
var southWestCorner = bounds.getSouthWest();
var northEastLat = northEastCorner.lat();
var northEastLng = northEastCorner.lng();
var southWestLat = southWestCorner.lat();
var southWestLng = southWestCorner.lng();
var southEastCorner = new google.maps.LatLng(southWestLat, northEastLng);
var northWestCorner = new google.maps.LatLng(northEastLat, southWestLng);
return [
northEastCorner,
southEastCorner,
southWestCorner,
northWestCorner,
northEastCorner
];
}
function updateOverlayMapCenter() {
var newCenter = map.getCenter();
if (overlayMap.getCenter() !== newCenter) {
overlayMap.panTo(newCenter);
}
}
google.maps.event.addListener(map, 'bounds_changed', function () {
var newBounds = map.getBounds();
var path = [];
if (newBounds !== undefined) {
var mapWidth = null;
var mapHeight = null;
(function () {
var northEastCorner = newBounds.getNorthEast();
var southWestCorner = newBounds.getSouthWest();
var northEastLat = northEastCorner.lat();
var northEastLng = northEastCorner.lng();
var southWestLat = southWestCorner.lat();
var southWestLng = southWestCorner.lng();
mapHeight = Math.abs(180 + northEastLat - southWestLat) - 180;
mapWidth = Math.abs(360 + northEastLng - southWestLng) - 360;
})();
var overlayMapHeight = null;
var overlayMapWidth = null;
(function () {
var overlayBounds = overlayMap.getBounds();
var northEastCorner = overlayBounds.getNorthEast();
var southWestCorner = overlayBounds.getSouthWest();
var northEastLat = northEastCorner.lat();
var northEastLng = northEastCorner.lng();
var southWestLat = southWestCorner.lat();
var southWestLng = southWestCorner.lng();
overlayMapHeight = Math.abs(180 + northEastLat - southWestLat) - 180;
overlayMapHeight = overlayMapHeight / 2;
overlayMapWidth = Math.abs(360 + northEastLng - southWestLng) - 360;
})();
var heightOverage = (overlayMapHeight - mapHeight);
var widthOverage = (overlayMapWidth - mapWidth);
var margin = 0.2;
var divisor = (2 + 2 * margin);
var wayTooBig = false;
if (
// margin of one means zoom in when overage is big enough that
// zooming in would leave > half of width
// which would be when overage is > three quarters width
// margin of zero mean zoom in when overage is > half width
(widthOverage > (divisor - 1) * (overlayMapWidth / divisor)) &&
(heightOverage > (divisor - 1) * (overlayMapHeight / divisor))
) {
//FIXME: sometimes it isn't enough to change by only 1.
overlayMap.setZoom(overlayMap.getZoom() + 1);
} else if (
// margin of one means, zoom out when overage is < half width
// margin of half means zoom out when overage is < quarter width
// margin of zero means zoom out when overage is < 0
(widthOverage < margin * overlayMapWidth / 2) ||
(heightOverage < margin * overlayMapHeight / 2)
) {
var overlayZoom = overlayMap.getZoom();
if (overlayZoom > 0) {
//FIXME: sometimes it isn't enough to change by only 1.
overlayMap.setZoom(overlayZoom - 1);
} else {
wayTooBig = true;
}
}
if (wayTooBig === false) {
path = pathFromBounds(newBounds);
}
}
translucentBox.setPath(path);
});
function degToRad(degrees) {
return degrees * Math.PI / 180;
}
function latToY(latitude) {
var lat = degToRad(latitude);
return Math.log(Math.tan(lat) + 1 / Math.cos(lat));
}
function radToDeg(radians) {
return radians * 180 / Math.PI;
}
function yToLat(y) {
var angle = 2 * Math.atan(Math.pow(Math.E, y)) - Math.PI / 2;
return radToDeg(angle);
}
google.maps.event.addListener(overlayMap, 'bounds_changed', function () {
var mapBounds = map.getBounds();
if (mapBounds !== undefined) {
var northEastCorner = mapBounds.getNorthEast();
var southWestCorner = mapBounds.getSouthWest();
var northEastLat = northEastCorner.lat();
var northEastLng = northEastCorner.lng();
var southWestLat = southWestCorner.lat();
var southWestLng = southWestCorner.lng();
var mapCenter = map.getCenter();
var overlayCenter = overlayMap.getCenter();
var lngDelta = overlayCenter.lng() - mapCenter.lng();
northEastLng += lngDelta;
southWestLng += lngDelta;
var overlayMapBounds = overlayMap.getBounds();
var overlayTopLat = overlayMapBounds.getNorthEast().lat();
var overlayBottomLat = overlayMapBounds.getSouthWest().lat();
var overlayTop = latToY(overlayTopLat);
var overlayBottom = latToY(overlayBottomLat);
var overlayHeight = Math.abs(overlayTop - overlayBottom);
var mapHeight = Math.abs(latToY(northEastLat) - latToY(southWestLat));
var bottomLatDelta = overlayBottom + (overlayHeight - mapHeight) / 2;
var topLatDelta = overlayTop - (overlayHeight - mapHeight) / 2;
northEastLat = yToLat(topLatDelta);
southWestLat = yToLat(bottomLatDelta);
var sw = new google.maps.LatLng(southWestLat, southWestLng);
var se = new google.maps.LatLng(southWestLat, northEastLng);
var ne = new google.maps.LatLng(northEastLat, northEastLng);
var nw = new google.maps.LatLng(northEastLat, southWestLng);
transparentBox.setPath([sw, nw, ne, se, sw]);
}
});
google.maps.event.addListener(map, 'zoom_changed', function () {
var newZoom = Math.max(map.getZoom() - 4, 0);
if (overlayMap.getZoom() !== newZoom) {
overlayMap.setZoom(newZoom);
}
});
var mapDragInProgress = false;
var panHasBegun = false;
google.maps.event.addListener(map, 'center_changed', function () {
if ((mapDragInProgress === false) && (panHasBegun === false)) {
updateOverlayMapCenter();
}
});
google.maps.event.addListener(map, 'idle', function () {
if (panHasBegun === true) {
panHasBegun = false;
mapDragInProgress = false;
}
});
google.maps.event.addListener(map, 'dragstart', function () {
panHasBegun = false;
mapDragInProgress = true;
});
google.maps.event.addListener(map, 'dragend', function () {
updateOverlayMapCenter();
mapDragInProgress = false;
});
google.maps.event.addListener(overlayMap, 'dragstart', function () {
panHasBegun = false;
mapDragInProgress = true;
});
google.maps.event.addListener(overlayMap, 'dragend', function () {
panHasBegun = true;
var newCenter = overlayMap.getCenter();
if (map.getCenter() !== newCenter) {
map.panTo(newCenter);
}
});
google.maps.event.addListener(overlayMap, 'dblclick', function (mEvent) {
mapDragInProgress = true;
overlayMap.panTo(mEvent.latLng);
map.panTo(mEvent.latLng);
});
google.maps.event.addListener(map, 'maptypeid_changed', function () {
overlayMap.setOptions({mapTypeId: map.getMapTypeId()});
});
// Set map's properties now that all bindings and listeners are set up.
map.setMapTypeId(google.maps.MapTypeId.ROADMAP);
map.setZoom(8); // This will trigger a zoom_changed on the map
var defaultCenter = new google.maps.LatLng(41.889, -87.629);
map.setCenter(defaultCenter);
overlayMap.setZoom(4);
overlayMap.setCenter(defaultCenter);
};