<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<!--
Copyright 2008 Google Inc.
Licensed under the Apache License, Version 2.0:
http://www.apache.org/licenses/LICENSE-2.0
-->
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml">
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8"/>
<title>Google Maps Street View API Driving Directions Example</title>
<script src="http://maps.google.com/maps?file=api&v=2&key=ABQIAAAAjU0EJWnWPMv7oQ-jjS7dYxSPW5CJgpdgO_s4yyMovOaVh_KvvhSfpvagV18eOyDWu7VytS6Bi1CWxw" type="text/javascript"></script>
<script type="text/javascript">
/**
* Copyright (c) 2008 Google Inc.
*
* 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.
*
*
* Author: Thor Mitchell
*
* Street View API Example: Following driving directions in Street View,
*
* We extract the polyline generated for the route and then attempt to
* follow links that match the direction of the line segment as we move
* along it. Sometimes we find a gap in coverage, or that a link does
* not exist in the direction we need. When this happens we jump to the
* start of the next step given in the text directions.
*/
/**
* GMap2 of the route map.
*/
var map;
/**
* GStreetviewPanorama of the Flash viewer.
*/
var pano;
/**
* GStreetviewClient used to retrieve meta data for panoramas we reach
* by following links.
*/
var svClient;
/**
* GDirections object used to submit driving direction requests.
*/
var directions;
/**
* The GRoute we are following extracted from the directions response.
*/
var route;
/**
* It turns out that the polyline generated for a driving directions
* route normally has a lot of repeated vertices. This causes problems
* when trying to determine how close we are to the next vertex, so it's
* better to collapse these duplicated vertices out.
*
* The array of route vertices with duplicates removed.
*/
var vertices;
/**
* Array that maps the polyline vertex indices to the
* index of the same point in the vertices array.
*
* For example, if the polyline vertices are
* [a, a, b, c, d, d, e], the vertices array will be
* [ a, b, c, d, e ] and the vertexMap array will be
* [ 1, 1, 2, 3, 4, 4, 5 ].
*/
var vertexMap;
/**
* Array that contains the index in the vertices array of
* the point at the start of the n'th step in the route
*/
var stepToVertex;
/**
* An array that gives the route step number that each
* point in the vertices array is part of.
*/
var stepMap;
/**
* The current position of the panorama and vehicle marker.
*/
var currentLatLng;
/**
* Metadata for the current panorama including the list of
* available links, loaded using GStreetviewClient.
*/
var panoMetaData;
/**
* boolean flag set when we are so close to the next vertex that we should
* check links in the panoramas we load for the next turning we need.
*/
var close = false;
/**
* The direction in degrees from our current location to the next
* vertex on the route. Used to select the most suitable link to follow.
*/
var bearing;
/**
* The direction from the next vertex on the route to the vertex
* after that. Used when we are close to a vertex and are looking
* for links that represent the next turn we need to make.
*/
var nextBearing;
/**
* The index of the vertex we are heading towards on the route in the
* vertices array.
*/
var nextVertexId;
/**
* GLatLng of the vertex we are heading towards on the route.
*/
var nextVertex;
/**
* An array that at any time contains the GLatLng of each vertex
* from the start of the current route step to the next vertex
* ahead of our current position. This is used to work out how
* far we are along the current step.
*/
var progressArray;
/**
* The distance in meters covered by traversing the points in the
* progressArray. By subtracting the distance from our current location
* to the next vertex from this value we find how far along the step
* we are, and use this to update the progress bar.
*/
var progressDistance;
/**
* Index of the route step we are currently on.
*/
var currentStep;
/**
* The marker on our map that shows the current location. For IE6 this
* is a standard red maps pushpin. For all other browsers it is a
* directional arrow.
*/
var carMarker;
/**
* A copy of the current step index used to unhighlight the previously
* highlighted step in the textual driving directions when the
* current step changes.
*/
var selectedStep = null;
/**
* boolean flag indicating whether we are currently driving (automatically
* following) links, or are stationary.
*/
var driving = false;
/**
* Id of the timer that adds a delay between following each link to give the
* panorama time to load. We need this to cancel the timer if the user clicks
* Stop while we are waiting to follow the next link.
*/
var advanceTimer = null;
/**
* Delay in seconds between following each link.
*/
var advanceDelay = 1;
/**
* Set up the initial view and register the various event listeners.
*/
function load() {
if (GBrowserIsCompatible()) {
var start = new GLatLng(37.090240,-95.712891);
map = new GMap2(document.getElementById("map"));
map.setCenter(start, 3);
map.addControl(new GSmallMapControl());
carMarker = getCarMarker(start);
map.addOverlay(carMarker);
carMarker.hide();
svClient = new GStreetviewClient();
pano = new GStreetviewPanorama(document.getElementById("streetview"));
GEvent.addListener(pano, "initialized", function(loc) {
panoMetaData = loc;
moveCar();
});
GEvent.addListener(pano, "error", function(errorCode) {
showStatus("The requested panorama could not be displayed");
});
directions = new GDirections(map);
GEvent.addListener(directions, "load", function() {
jumpInMyCar();
});
GEvent.addListener(directions, "error", function() {
showStatus("Could not generate a route for the current start and end addresses");
});
}
}
/**
* Create a vehicle marker suited to the user's browser
* Avoids a wierd IE6 bug that causes black backgrounds
* if we use the driving direction arrows as marker icons
* @param {GLatLng} start Initial location of the vehicle marker
* @return {GMarker}
*/
function getCarMarker(start) {
/*@cc_on @*/
/*@if (@_jscript_version < 5.7)
return new GMarker(start);
/*@end @*/
return new GMarker(start, getArrowIcon(0.0));
}
/**
* Set the vehicle marker icon based on the user's browser
* Avoids a wierd IE6 bug that causes black backgrounds
* if we use the driving direction arrows as marker icons
* @param {number} bearing The heading in degrees of the arrow we need
*/
function setCarMarkerImage(bearing) {
/*@cc_on @*/
/*@if (@_jscript_version < 5.7)
return;
/*@end @*/
carMarker.setImage(getArrowUrl(bearing));
}
/**
* Submit the driving directions request
* The load event handler calls jumpInMyCar() when this returns
*/
function generateRoute() {
var from = document.getElementById("from").value;
var to = document.getElementById("to").value;
directions.load("from: " + from + " to: " + to, { preserveViewport: true, getSteps: true });
}
/**
* It's too far to walk on your own
*/
function jumpInMyCar() {
/* Extract the one and only route from this response */
route = directions.getRoute(0);
/* Simplify the list of polyline vertices by removing duplicates */
collapseVertices(directions.getPolyline());
/* Center the map on the start of the route at street level */
map.setCenter(vertices[0], 16);
/* Display the textual driving directions */
renderTextDirections();
/* Begin checking the Street View coverage along this route */
checkCoverage(0);
}
/**
* Check that a Street View panorama exists at the start
* of this route step. This is a recursive function that
* checks every step along the route until it reaches the
* end of the route or no panorama is found for a step.
* @param {number} step The route step to check
*/
function checkCoverage(step) {
if (step > route.getNumSteps()) {
/* Coverage check across whole route passed */
hideStatus();
stopDriving();
jumpToVertex(0);
} else {
if (step == route.getNumSteps()) {
ll = route.getEndLatLng();
} else {
ll = route.getStep(step).getLatLng();
}
svClient.getNearestPanorama(ll, function(svData) {
if (svData.code == 500) {
/* Server error, retry once per second */
setTimeout("checkCoverage(" + step + ")", 1000);
} else if (svData.code == 600) {
/* Coverage check failed */
showStatus("Street View coverage is not available for this route");
} else {
/* Confirmed coverage for this step.
* Now check coverage for next step.
*/
checkCoverage(step + 1);
}
});
}
}
/**
* Jump to a particular point on the route. This is used to
* queue up the start of the route, when a user selects a step
* in the driving directions, and when there is a gap in coverage
* that we need to jump over.
* @param {number} idx The vertex number in the vertices array
*/
function jumpToVertex(idx) {
currentLatLng = vertices[idx];
nextVertex = vertices[idx + 1];
nextVertexId = idx + 1;
bearing = getBearingFromVertex(idx);
nextBearing = getBearingFromVertex(idx + 1);
setCarMarkerImage(bearing);
carMarker.setLatLng(currentLatLng);
carMarker.show();
currentStep = stepMap[idx];
constructProgressArray(idx);
setProgressDistance();
updateProgressBar(0);
map.panTo(currentLatLng, 16);
highlightStep(currentStep);
checkDistanceFromNextVertex();
pano.setLocationAndPOV(currentLatLng, { yaw:bearing, pitch:0 });
svClient.getNearestPanorama(currentLatLng, function(loc) {
if (loc.code == 500) {
setTimeout("jumpToVertex(" + idx + ")", 1000);
} else if (loc.code == 600) {
jumpToVertex(nextVertexId);
} else {
panoMetaData = loc.location;
panoMetaData.pov.yaw = bearing;
moveCar();
}
});
}
/**
* Called by the panorama's initialized event handler in
* response to a link being followed. Updates the location
* of the vehicle marker and the center of the map to match
* the location of the panorama loaded by following the link.
*/
function moveCar() {
currentLatLng = panoMetaData.latlng;
carMarker.setLatLng(currentLatLng);
map.panTo(currentLatLng);
/* Now retrieve the links for this panorama so we can
* work out where to go next.
*/
svClient.getNearestPanorama(panoMetaData.latlng, function(svData) {
if (svData.code == 500) {
/* Server error. Retry once a second */
setTimeout("moveCar()", 1000);
} else if (svData.code == 600) {
/* No panorama. Should never happen as we have
* already loaded this panorama in the Flash viewer.
*/
jumpToVertex(nextVertexId);
} else {
panoMetaData.links = svData.links;
checkDistanceFromNextVertex();
if (driving) {
advanceTimer = setTimeout("advance()", advanceDelay * 1000);
}
}
});
}
/**
* Check if we have already passed the next vertex, or if we are
* close enough to the next vertex to look out for the next turn.
*/
function checkDistanceFromNextVertex() {
close = false;
var d = currentLatLng.distanceFrom(nextVertex);
var b = getBearing(currentLatLng, nextVertex);
/* If the bearing of the next vertex is more than 90 degrees away from
* the bearing we have been travelling in, we must have passed it already.
*/
if (getYawDelta(bearing, b) > 90) {
incrementVertex();
/* If the vertices are closely spaced we may
* already be close to the next vertex
*/
if (driving) {
checkDistanceFromNextVertex();
}
} else {
/* Recalculate how far we have travelled within the current step
* and update the progress bar accordingly.
*/
updateProgressBar(progressDistance - d);
if (driving) {
updateViewerDirections(progressDistance - d);
}
/* If we are less than 10m from a vertex we consider ourself to be
* close enough to preferentially follow links that take us in the
* direction we should be going when the vertex has been passed.
*/
if (d < 10) {
close = true;
}
}
}
/**
* Move forward one link
*/
function advance() {
/* chose the best link for our current heading */
var selected = selectLink(bearing);
/* If we're very close to a vertex, also check for a
* link in the direction we should be turning next.
* If there is a link in that direction (to a
* tolerance of 15 degrees), chose that turning
*/
if (close && nextBearing) {
var selectedTurn = selectLink(nextBearing);
if (selectedTurn.delta < 15) {
selected = selectedTurn;
incrementVertex();
}
}
if (selected.delta > 40) {
/* If the chosen link is in a direction more than 40
* degrees different from the heading we want it
* will not take us in the right direction. As no
* better link has been found this implies that the
* route has no coverage in the direction we need so
* jump to the start of the next step.
*/
jumpToVertex(nextVertexId);
} else {
/* Pan the viewer round to face the direction of the
* link we want to follow and then follow the link. We
* need to give the pan time to complete before we follow
* the link for it to look smooth. The amount of time
* depends on the extent of the pan.
*/
var panAngle = getYawDelta(panoMetaData.pov.yaw, panoMetaData.links[selected.idx].yaw);
pano.panTo({ yaw:panoMetaData.links[selected.idx].yaw, pitch:0 });
setTimeout(function() {
pano.followLink(panoMetaData.links[selected.idx].yaw);
}, panAngle * 10);
}
}
/**
* Select which link in the current panorama most closely
* matches the directions we should be going in.
* @param {number} yaw The direction we are looking to move in
* @return {Object} The number of the closest link and the
* difference between it's yaw and the desired direction
*/
function selectLink(yaw) {
var Selected = new Object();
for (var i = 0; i < panoMetaData.links.length; i++) {
var d = getYawDelta(yaw, panoMetaData.links[i].yaw);
if (Selected.delta == null || d < Selected.delta) {
Selected.idx = i;
Selected.delta = d;
}
}
return Selected;
}
/**
* Called when we have reached a vertex
* and now need to head towards the next
*/
function incrementVertex() {
if (! vertices[nextVertexId + 1]) {
/* we are at the end of the route */
endReached();
} else {
nextVertexId++;
nextVertex = vertices[nextVertexId];
/* Rotate the vehicle marler to face the new bearing */
bearing = getBearingFromVertex(nextVertexId - 1);
nextBearing = getBearingFromVertex(nextVertexId);
setCarMarkerImage(bearing);
/* Check if we have reached the next step */
if (stepMap[nextVertexId - 1] == currentStep) {
/* Still on the same step so just extend the
* progressArray with the next vertex we are
* heading towards.
*/
progressArray.push(nextVertex);
} else {
/* We've moved on to the next step so start a new
* progressArray and update the text highlight and
* progress bar.
*/
currentStep = stepMap[nextVertexId - 1];
highlightStep(currentStep);
progressArray = [ currentLatLng, nextVertex ];
updateProgressBar(0);
}
setProgressDistance();
}
}
/**
* Called when the last vertex on the route is reached.
*/
function endReached() {
stopDriving();
updateProgressBar(0);
showInstruction("You have reached your destination");
document.getElementById("step" + selectedStep).style.backgroundColor = "white";
selectedStep = null;
}
/**
* Get the direction to head in from a particular vertex
* @param {number} n Index of the vertex in the vertices array
* @return {number} bearing in degrees
*/
function getBearingFromVertex(n) {
var origin = vertices[n];
var destination = vertices[n+1];
if (destination != undefined) {
return getBearing(origin, destination);
} else {
return null;
}
}
/**
* Update the in Flash viewer next step driving directions
* @param {number} distanceFromStartOfStep Distance in meters from the start
* of the current route step
*/
function updateViewerDirections(distanceFromStartOfStep) {
var lengthOfStep = route.getStep(currentStep).getDistance().meters;
var distanceFromEndOfStep = (lengthOfStep - distanceFromStartOfStep);
/* Convert from meters to feet */
distanceFromEndOfStep *= 3.2808399;
var uiDistance, unit;
/* Convert to human friendly representation */
if (distanceFromEndOfStep > 7920) {
distanceFromEndOfStep /= 5280;
uiDistance = distanceFromEndOfStep.toFixed(0);
unit = 'miles';
} else if (distanceFromEndOfStep > 4620) {
uiDistance = '1';
unit = 'mile';
} else if (distanceFromEndOfStep > 3300) {
/* Display "3/4 mile" between 5/8 and 7/8 of a mile */
uiDistance = '¾';
unit = 'mile';
} else if (distanceFromEndOfStep > 1980) {
/* Display "1/2 mile" between 3/8 and 5/8 of a mile */
uiDistance = '½';
unit = 'mile';
} else if (distanceFromEndOfStep > 660) {
/* Display "1/4 mile" between 1/8 and 3/8 of a mile */
uiDistance = '¼';
unit = 'mile';
} else {
uiDistance = (Math.round(distanceFromEndOfStep / 10)) * 10;
unit = "ft";
}
if (route.getStep(currentStep + 1) != undefined) {
showInstruction('In ' + uiDistance + ' ' + unit + ': ' + route.getStep(currentStep + 1).getDescriptionHtml());
} else {
showInstruction('In ' + uiDistance + ' ' + unit + ': You will reach your destination');
}
}
/**
* Rebuild the progressArray after jumping to a particular vertex
* @param {number} vertexId The vertex number in the vertices array
*/
function constructProgressArray(vertexId) {
progressArray = new Array();
var stepStart = stepToVertex[currentStep];
for (var i = stepToVertex[currentStep]; i <= vertexId + 1; i++) {
progressArray.push(vertices[i]);
}
}
/**
* Calculate the distance in meters from the start of this
* step to the next vertex by building a polyline from the
* intermediate points.
*/
function setProgressDistance() {
var polyline = new GPolyline(progressArray);
progressDistance = polyline.getLength();
}
/**
* Update the progress bar to reflect our position within this step
* @param {number} progress Distance in meters travelled
* since the start of this step
*/
function updateProgressBar(progress) {
progress = (progress < 0 ? 0 : progress);
var stepLength = route.getStep(currentStep).getDistance().meters;
setProgressBarLength(1 - (progress / stepLength));
}
/**
* Size the progress bar
* @param {number} progress Progress expressed as a fraction (0 to 1)
*/
function setProgressBarLength(progress) {
var width = (636 * progress);
if (width < 0) {
width = 0;
}
document.getElementById("progressBar").style.width = width + "px";
}
/**
* Calculate the difference in degrees between two bearings.
* @param {number} a bearing in degrees
* @param {number} b bearing in degrees
* @return {number} The angle between a and b
*/
function getYawDelta(a, b) {
var d = Math.abs(sanitiseYaw(a) - sanitiseYaw(b));
if (d > 180) {
d = 360 - d;
}
return d;
}
/**
* Sometimes after following a link the yaw is > 360
* @param {number} yaw bearing in degrees
* @return {number} yaw as a value between -360 and +360
*/
function sanitiseYaw(yaw) {
if (yaw > 360 || yaw < 360) {
yaw = yaw % 360;
}
return yaw;
}
/**
* Generate a GMarker icon of an direction arrow
* @param {number} bearing Direction arrow should point
* @return {GIcon}
*/
function getArrowIcon(bearing) {
var icon = new GIcon();
icon.image = getArrowUrl(bearing);
icon.iconSize = new GSize(24, 24);
icon.iconAnchor = new GPoint(12, 12);
return icon;
}
/**
* Determine URL of correct direction arrow image to use
* @param {number} bearing Direction arrow should point
* @return {String}
*/
function getArrowUrl(bearing) {
var id = (3 * Math.round(bearing / 3)) % 120;
return "http://maps.google.com/mapfiles/dir_" + id + ".png";
}
/**
* Build the vertices, vertexMap, stepToVertex, and stepMap
* arrays from the vertices of the route polyline.
* @param {GPolyline} path The route polyline to process
*/
function collapseVertices(path) {
vertices = new Array();
vertexMap = new Array(path.getVertexCount());
vertices.push(path.getVertex(0));
vertexMap[0] = 0;
/* Copy vertices from the polyline to the vertices array
* skipping any duplicates. Build the vertexMap as we go along */
for (var i = 1; i < path.getVertexCount(); i++) {
if (! path.getVertex(i).equals(vertices[vertices.length - 1])) {
vertices.push(path.getVertex(i));
}
vertexMap[i] = vertices.length - 1;
}
stepToVertex = new Array(route.getNumSteps());
stepMap = new Array(vertices.length);
for (var i = 0; i < route.getNumSteps(); i++) {
stepToVertex[i] = vertexMap[route.getStep(i).getPolylineIndex()];
}
var step = 0;
for (var i = 0; i < vertices.length; i++) {
if (stepToVertex[step + 1] == i) {
step++;
}
stepMap[i] = step;
}
}
/**
* Because we want to be highlight text directions steps and make them clickable
* we must render them ourselves rather than let GDirections do so as normal.
*/
function renderTextDirections() {
/* Get the addresses to display at the start and end of the directions */
var startAddress = route.getStartGeocode().address;
var endAddress = route.getEndGeocode().address;
/* Write the start address title, marker, and summary */
var html = getDirectionsWaypointHtml(startAddress, "A");
html += getDivHtml("summary", "", route.getSummaryHtml());
/* Build up the textual directions step by step */
for (var n = 0; n < route.getNumSteps(); n++) {
html += '<a onclick="selectStep(' + n + ')">';
html += getDivHtml("step" + n, "dstep", route.getStep(n).getDescriptionHtml());
html += '</a>';
}
/* Write the end address title and marker */
html += getDirectionsWaypointHtml(endAddress, "B");
/* Fill in the div on the page with the generated HTML */
document.getElementById("directions").innerHTML = html;
/* Set the icons used in the address blocks using the appropriate
* technique for the browser to preserve PNG transparency */
setWaypointIcon('A');
setWaypointIcon('B');
}
/**
* Generate the HTML of the header and footer of each set of textual directions
* @param {String} address The address of this endpoint
* @param {String} letter The letter to display in the marker
* (A at the start, B at the end)
* @return {String} the generated HTML
*/
function getDirectionsWaypointHtml(address, letter) {
var content = getDivHtml('letter' + letter, 'letterIcon', "");
content += '<span class="waypointAddress">' + address + '</span>';
return getDivHtml("wayPoint" + letter, "waypoint", content);
}
/**
* Set the icons used in the textual directions address blocks
* using the appropriate technique for the browser to preserve
* PNG transparency
*/
function setWaypointIcon(letter) {
var png = 'http://maps.google.com/intl/en_us/mapfiles/icon_green' + letter + '.png';
/*@cc_on @*/
/*@if (@_jscript_version < 5.7)
document.getElementById('letter' + letter).style.filter = 'progid:DXImageTransform.Microsoft.AlphaImageLoader(src="' + png + '", sizingMethod="scale");';
return;
/*@end @*/
document.getElementById('letter' + letter).style.backgroundImage = 'url(' + png + ')';
}
/**
* Utility function to wrap content in a div tags
* @param {String} id The id attribute value for this div element
* @param {String} cssClass The class attribute value for this div element
* @param {String} content The HTML content to wrap in this div element
* @return {String} the HTML of the generated div element
*/
function getDivHtml(id, cssClass, content) {
var div = "<div";
if (id != "") {
div += ' id="' + id + '"';
}
if (cssClass != "") {
div += ' class="' + cssClass + '"';
}
div += '>' + content + '</div>';
return div;
}
/**
* Handle a click on one of the text directions steps.
* @param {number} i The index of the step that was clicked on
*/
function selectStep(i) {
var vertex = vertexMap[route.getStep(i).getPolylineIndex()];
stopDriving();
jumpToVertex(vertex);
}
/**
* Highlight with a blue background one of the text directions steps.
* @param {number} i The index of the step to highlight
*/
function highlightStep(i) {
/* Remove highlighting from the currently highlighted step */
if (selectedStep != null) {
document.getElementById("step" + selectedStep).style.backgroundColor = "white";
}
/* Highlight the indicated step as requested */
document.getElementById("step" + i).style.backgroundColor = "#eeeeff";
selectedStep = i;
}
/**
* Update the UI for driving and start following links
*/
function startDriving() {
hideInstruction();
document.getElementById("route").disabled = true;
document.getElementById("stopgo").value = "Stop";
document.getElementById("stopgo").setAttribute('onclick', 'stopDriving()');
document.getElementById("stopgo").onclick = function() { stopDriving(); }
driving = true;
advance();
}
/**
* Stop following links and update the UI
*/
function stopDriving() {
driving = false;
if (advanceTimer != null) {
clearTimeout(advanceTimer);
advanceTimer = null;
}
document.getElementById("route").disabled = false;
document.getElementById("stopgo").disabled = false;
document.getElementById("stopgo").value = "Drive";
document.getElementById("stopgo").setAttribute('onclick', 'startDriving()');
document.getElementById("stopgo").onclick = function() { startDriving(); }
showInstruction('Press <b>Drive</b> to follow your route');
}
/**
* Change the speed at which driving progresses by adjusting the delay
* between following links from one panorama to the next
*/
function setSpeed() {
advanceDelay = document.getElementById('speed').selectedIndex;
}
/**
* Display a status message that fills the Flash viewer
* @param {String} message The message to display
*/
function showStatus(message) {
hideInstruction();
document.getElementById("status").innerHTML = message;
document.getElementById("status").style.display = "block";
document.getElementById("streetview").style.display = "none";
}
/**
* Hide the currently displayed status message
*/
function hideStatus() {
document.getElementById("status").style.display = "none";
document.getElementById("streetview").style.display = "block";
}
/**
* Display an instructional message at the bottom of the Flash viewer
* @param {String} message The message to display
*/
function showInstruction(message) {
document.getElementById("instruction").innerHTML = message;
document.getElementById("instruction").style.display = "block";
}
/**
* Hide the currently displayed instructional message
*/
function hideInstruction() {
document.getElementById("instruction").style.display = "none";
}
/* Following functions based on those provided at:
* http://www.movable-type.co.uk/scripts/latlong.html
* Copyright 2002-2008 Chris Veness
*/
/**
* Calculate the bearing in degrees between two points
* @param {number} origin GLatLng of current location
* @param {number} destination GLatLng of destination
* @return {number}
*/
function getBearing(origin, destination) {
if (origin.equals(destination)) {
return null;
}
var lat1 = origin.lat().toRad();
var lat2 = destination.lat().toRad();
var dLon = (destination.lng()-origin.lng()).toRad();
var y = Math.sin(dLon) * Math.cos(lat2);
var x = Math.cos(lat1)*Math.sin(lat2) -
Math.sin(lat1)*Math.cos(lat2)*Math.cos(dLon);
return Math.atan2(y, x).toBrng();
}
/**
* Convert an angle in degrees to radians
*/
Number.prototype.toRad = function() {
return this * Math.PI / 180;
}
/**
* Convert an angle in radians to degrees (signed)
*/
Number.prototype.toDeg = function() {
return this * 180 / Math.PI;
}
/**
* Convert radians to degrees (as bearing: 0...360)
*/
Number.prototype.toBrng = function() {
return (this.toDeg()+360) % 360;
}
</script>
<style>
body {
position: relative;
}
#content {
width: 640px;
padding: 8px;
background-color: #eeeeff;
border: 1px solid #000066;
}
#svPanel {
width: 638px;
height: 319px;
position: relative;
}
#status {
position: absolute;
top: 120px;
left: 0px;
width: 638px;
text-align: center;
font: 32pt sans-serif;
color: #666666;
background-color: white;
}
#instruction {
position: absolute;
top: 295px;
left: 0px;
width: 638px;
text-align: center;
font: 16pt sans-serif;
color: #eeeeee;
display: none;
}
#svPanel, #directions, #map {
border: 1px solid black;
background-color: white;
}
#streetview {
position: absolute;
top: 0px;
left: 0px;
width: 638px;
height: 319px;
}
#progressBorder {
position: relative;
width: 638px;
height: 10px;
margin: 2px 0px 2px 0px;
border: 1px solid #000066;
background-color: white;
overflow: hidden;
}
#progressBar {
position: absolute;
background-color: #000066;
width: 636px;
height: 8px;
top: 1px;
right:1px;
}
#map {
width: 317px;
height: 317px;
margin-right: 1px;
overflow: hidden;
}
#directions {
width: 317px;
height: 400px;
margin-left: 1px;
position: relative;
overflow: auto;
}
.waypoint {
position: relative;
background-color: #eeeeee;
border: 1px solid #666666;
padding: 6px;
margin: 4px;
font: 10pt sans-serif;
}
.letterIcon {
width: 24px;
height: 38px;
background-image: none;
}
.waypointAddress {
position: absolute;
top: 17px;
left: 32px;
}
#summary {
padding: 4px;
font: 10pt sans-serif;
}
.dstep {
border-top: 1px solid #666666;
padding: 4px;
padding-left: 8px;
font: 10pt sans-serif;
margin-left: 4px;
margin-right: 4px;
cursor: pointer;
background-color: white;
}
.label {
width: 52px;
text-align: right;
font: 12pt sans-serif;
float: left;
position: relative;
top: 4px;
margin-right: 5px;
}
.input {
float: left;
width: 252px;
text-align: left;
}
.controls {
clear: both;
padding: 4px;
}
#speed {
float: left;
}
#buttons {
float: right;
}
table {
border-collapse: collapse;
}
td {
vertical-align: top;
}
</style>
</head>
<body onload="load();" onunload="GUnload();">
<div id="content">
<table cellpadding="0" cellspacing="0">
<tr>
<td colspan="2">
<div id="svPanel">
<div id="streetview" style="width: 638px; height: 319px;"></div>
<div id="status">Enter your start and end addresses and click <b>Route</b></div>
<div id="instruction"></div>
</div>
<div id="progressBorder">
<div id="progressBar"></div>
</div>
</td>
</tr>
<tr>
<td>
<div id="map"></div>
<div class="controls">
<div class="label">From</div>
<div class="input"><input id="from" size="30" value="stanyan st, san francisco"/></div>
</div>
<div class="controls">
<div class="label">To</div>
<div class="input"><input id="to" size="30" value="twin peaks blvd, san francisco"/></div>
</div>
<div class="controls">
<div class="label">Speed</div>
<div id="actions">
<select id="speed" onchange="setSpeed()">
<option value="0">Fast</option>
<option value="1" SELECTED>Medium</option>
<option value="2">Slow</option>
</select>
<div id="buttons">
<input type="button" value="Route" id="route" onclick="generateRoute()" />
<input type="button" value="Drive" id="stopgo" onclick="startDriving()" disabled />
</div>
</div>
</div>
</div>
</td>
<td>
<div id="directions"></div>
</td>
</tr>
</table>
</div>
</body>
</html>
Saturday, December 18, 2010
Friday, December 17, 2010
Google Map Direction
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml">
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8"/>
<title>Google Maps JavaScript API Example: Advanced Directions</title>
<script src=" http://maps.google.com/?file=api&v=2.x&key=ABQIAAAAzr2EBOXUKnm_jVnk0OJI7xSosDVG8KKPE1-m51RBrvYughuyMxQ-i1QfUnH94QxWIa6N4U6MouMmBA"
type="text/javascript"></script>
<style type="text/css">
body {
font-family: Verdana, Arial, sans serif;
font-size: 11px;
margin: 2px;
}
table.directions th {
background-color:#EEEEEE;
}
img {
color: #000000;
}
</style>
<script type="text/javascript">
var map;
var gdir;
var geocoder = null;
var addressMarker;
function initialize() {
if (GBrowserIsCompatible()) {
map = new GMap2(document.getElementById("map_canvas"));
gdir = new GDirections(map, document.getElementById("directions"));
GEvent.addListener(gdir, "load", onGDirectionsLoad);
GEvent.addListener(gdir, "error", handleErrors);
setDirections("San Francisco", "Mountain View", "en_US");
}
}
function setDirections(fromAddress, toAddress, locale) {
gdir.load("from: " + fromAddress + " to: " + toAddress,
{ "locale": locale });
}
function handleErrors(){
if (gdir.getStatus().code == G_GEO_UNKNOWN_ADDRESS)
alert("No corresponding geographic location could be found for one of the specified addresses. This may be due to the fact that the address is relatively new, or it may be incorrect.\nError code: " + gdir.getStatus().code);
else if (gdir.getStatus().code == G_GEO_SERVER_ERROR)
alert("A geocoding or directions request could not be successfully processed, yet the exact reason for the failure is not known.\n Error code: " + gdir.getStatus().code);
else if (gdir.getStatus().code == G_GEO_MISSING_QUERY)
alert("The HTTP q parameter was either missing or had no value. For geocoder requests, this means that an empty address was specified as input. For directions requests, this means that no query was specified in the input.\n Error code: " + gdir.getStatus().code);
// else if (gdir.getStatus().code == G_UNAVAILABLE_ADDRESS) <--- Doc bug... this is either not defined, or Doc is wrong
// alert("The geocode for the given address or the route for the given directions query cannot be returned due to legal or contractual reasons.\n Error code: " + gdir.getStatus().code);
else if (gdir.getStatus().code == G_GEO_BAD_KEY)
alert("The given key is either invalid or does not match the domain for which it was given. \n Error code: " + gdir.getStatus().code);
else if (gdir.getStatus().code == G_GEO_BAD_REQUEST)
alert("A directions request could not be successfully parsed.\n Error code: " + gdir.getStatus().code);
else alert("An unknown error occurred.");
}
function onGDirectionsLoad(){
// Use this function to access information about the latest load()
// results.
// e.g.
// document.getElementById("getStatus").innerHTML = gdir.getStatus().code;
// and yada yada yada...
}
</script>
</head>
<body onload="initialize()" onunload="GUnload()">
<h2>Maps API Directions Illustrated</h2>
<form action="#" onsubmit="setDirections(this.from.value, this.to.value, this.locale.value); return false">
<table>
<tr><th align="right">From: </th>
<td><input type="text" size="25" id="fromAddress" name="from"
value="San Francisco"/></td>
<th align="right"> To: </th>
<td align="right"><input type="text" size="25" id="toAddress" name="to"
value="Mountain View" /></td></tr>
<tr><th>Language: </th>
<td colspan="3"><select id="locale" name="locale">
<option value="en" selected>English</option>
<option value="fr">French</option>
<option value="de">German</option>
<option value="ja">Japanese</option>
<option value="es">Spanish</option>
</select>
<input name="submit" type="submit" value="Get Directions!" />
</td></tr>
</table>
</form>
<br/>
<table class="directions">
<tr><th>Formatted Directions</th><th>Map</th></tr>
<tr>
<td valign="top"><div id="directions" style="width: 275px"></div></td>
<td valign="top"><div id="map_canvas" style="width: 350px; height: 400px"></div></td>
</tr>
</table>
</body>
</html>
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml">
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8"/>
<title>Google Maps JavaScript API Example: Advanced Directions</title>
<script src=" http://maps.google.com/?file=api&v=2.x&key=ABQIAAAAzr2EBOXUKnm_jVnk0OJI7xSosDVG8KKPE1-m51RBrvYughuyMxQ-i1QfUnH94QxWIa6N4U6MouMmBA"
type="text/javascript"></script>
<style type="text/css">
body {
font-family: Verdana, Arial, sans serif;
font-size: 11px;
margin: 2px;
}
table.directions th {
background-color:#EEEEEE;
}
img {
color: #000000;
}
</style>
<script type="text/javascript">
var map;
var gdir;
var geocoder = null;
var addressMarker;
function initialize() {
if (GBrowserIsCompatible()) {
map = new GMap2(document.getElementById("map_canvas"));
gdir = new GDirections(map, document.getElementById("directions"));
GEvent.addListener(gdir, "load", onGDirectionsLoad);
GEvent.addListener(gdir, "error", handleErrors);
setDirections("San Francisco", "Mountain View", "en_US");
}
}
function setDirections(fromAddress, toAddress, locale) {
gdir.load("from: " + fromAddress + " to: " + toAddress,
{ "locale": locale });
}
function handleErrors(){
if (gdir.getStatus().code == G_GEO_UNKNOWN_ADDRESS)
alert("No corresponding geographic location could be found for one of the specified addresses. This may be due to the fact that the address is relatively new, or it may be incorrect.\nError code: " + gdir.getStatus().code);
else if (gdir.getStatus().code == G_GEO_SERVER_ERROR)
alert("A geocoding or directions request could not be successfully processed, yet the exact reason for the failure is not known.\n Error code: " + gdir.getStatus().code);
else if (gdir.getStatus().code == G_GEO_MISSING_QUERY)
alert("The HTTP q parameter was either missing or had no value. For geocoder requests, this means that an empty address was specified as input. For directions requests, this means that no query was specified in the input.\n Error code: " + gdir.getStatus().code);
// else if (gdir.getStatus().code == G_UNAVAILABLE_ADDRESS) <--- Doc bug... this is either not defined, or Doc is wrong
// alert("The geocode for the given address or the route for the given directions query cannot be returned due to legal or contractual reasons.\n Error code: " + gdir.getStatus().code);
else if (gdir.getStatus().code == G_GEO_BAD_KEY)
alert("The given key is either invalid or does not match the domain for which it was given. \n Error code: " + gdir.getStatus().code);
else if (gdir.getStatus().code == G_GEO_BAD_REQUEST)
alert("A directions request could not be successfully parsed.\n Error code: " + gdir.getStatus().code);
else alert("An unknown error occurred.");
}
function onGDirectionsLoad(){
// Use this function to access information about the latest load()
// results.
// e.g.
// document.getElementById("getStatus").innerHTML = gdir.getStatus().code;
// and yada yada yada...
}
</script>
</head>
<body onload="initialize()" onunload="GUnload()">
<h2>Maps API Directions Illustrated</h2>
<form action="#" onsubmit="setDirections(this.from.value, this.to.value, this.locale.value); return false">
<table>
<tr><th align="right">From: </th>
<td><input type="text" size="25" id="fromAddress" name="from"
value="San Francisco"/></td>
<th align="right"> To: </th>
<td align="right"><input type="text" size="25" id="toAddress" name="to"
value="Mountain View" /></td></tr>
<tr><th>Language: </th>
<td colspan="3"><select id="locale" name="locale">
<option value="en" selected>English</option>
<option value="fr">French</option>
<option value="de">German</option>
<option value="ja">Japanese</option>
<option value="es">Spanish</option>
</select>
<input name="submit" type="submit" value="Get Directions!" />
</td></tr>
</table>
</form>
<br/>
<table class="directions">
<tr><th>Formatted Directions</th><th>Map</th></tr>
<tr>
<td valign="top"><div id="directions" style="width: 275px"></div></td>
<td valign="top"><div id="map_canvas" style="width: 350px; height: 400px"></div></td>
</tr>
</table>
</body>
</html>
Subscribe to:
Posts (Atom)