Google Maps Example

 Optimize  Avoid highway  Avoid toll
Loading Google Maps...
Return to my portfolio

What the Hell is This?

Google Maps

Google Maps

Google Maps absolutely rocks. Their free API is accessible to anyone and you can implement the entire thing with javascript (or Flash, if you prefer). I had created a few mashups before in v2, but there were some features in v3 that I implemented for a project at work, so I thought I would share them here. Specifically, I wanted the map to have these features/functionality:

  • Directions from literally any clickable point on the map
  • A local search to search for restaurants, hotels, etc in the area
  • GPS geolocation to determine where the user actually was
  • Street View integration via javascript
  • Custom controls for zoom and map style
  • The ability to toggle the map into fullscreen

I found most of these features in the Google Maps examples online, so I decided to combine them in one big, fat script for easy integration into sites. Try it out.

Directions Results

Turn by Turn Directions

Click a few points on the map and then click the 'Directions' button.

Search Results.

Local Results. Around You.

Try searching for coffee or something.

Get the Javascript

The Full JS for the Map Functions

Copy and paste the javascript below into your js file and reference it in the document head.

			
//the Google Maps example - combines a bunch of stuff, including local search, directions, geolocation and more!  

  var directionDisplay;
  var directionsService = new google.maps.DirectionsService();
  var origin = null;
  var destination = null;
  var waypoints = [];
  var markers = [];
  var directionsVisible = false;

    // Our global state
    var gLocalSearch;
    var gMap;
    var Southside;
    var Southsidemarker;
    var gInfoWindow;
    var gSelectedResults = [];
    var gCurrentResults = [];
    var gSearchForm;

   // Create our "tiny" marker icon
    var gYellowIcon = new google.maps.MarkerImage(
      "../images/pushpin1.png",
      new google.maps.Size(16, 23),
      new google.maps.Point(0, 0),
      new google.maps.Point(16, 23));
    var gRedIcon = new google.maps.MarkerImage(
      "../images/pushpin2.png",
      new google.maps.Size(16, 23),
      new google.maps.Point(0, 0),
      new google.maps.Point(16, 23));
    var gSmallShadow = new google.maps.MarkerImage(
      "../images/pushpin_shadow.png",
      new google.maps.Size(22, 20),
      new google.maps.Point(0, 0),
      new google.maps.Point(8, 21));

//making the exit fullscreen button
function FSControl(controlDiv, map) {

  // Set CSS styles for the DIV containing the control
  // Setting padding to 5 px will offset the control
  // from the edge of the map
  controlDiv.style.padding = '5px';

  // Set CSS for the control border
  var controlUI = document.createElement('DIV');
  controlUI.style.backgroundColor = '#f8f8f8';
  controlUI.style.borderStyle = 'solid';
  controlUI.style.borderWidth = '1px';
  controlUI.style.borderColor = '#a9bbdf';;
  controlUI.style.boxShadow = '0 1px 3px rgba(0,0,0,0.5)';
  controlUI.style.cursor = 'pointer';
  controlUI.style.textAlign = 'center';
  controlUI.title = 'Toggle the fullscreen mode';
  controlDiv.appendChild(controlUI);

  // Set CSS for the control interior
  var controlText = document.createElement('DIV');
  controlText.style.fontSize = '12px';
  controlText.style.fontWeight = 'bold';
  controlText.style.color = '#000000';
  controlText.style.paddingLeft = '4px';
  controlText.style.paddingRight = '4px';
  controlText.style.paddingTop = '3px';
  controlText.style.paddingBottom = '2px';
  controlUI.appendChild(controlText);

  //toggle the text of the button
   if($("#map_canvas").hasClass("full_screen_map")){
      controlText.innerHTML = 'Exit Fullscreen';
    } else {
      controlText.innerHTML = 'Fullscreen';
    }

  // Setup the click event listeners: toggle the full screen
  google.maps.event.addDomListener(controlUI, 'click', function() {
   if($("#map_canvas").hasClass("full_screen_map")){
    exitFullScreen();
    } else {
    fullScreen();
    }
  });
}


 
  function initialize() {
    directionsDisplay = new google.maps.DirectionsRenderer();
    Southside = new google.maps.LatLng(38.796845, -77.048721);
    var myOptions = {
      zoom:13,
      mapTypeControl: true,
      mapTypeControlOptions: {style: google.maps.MapTypeControlStyle.DROPDOWN_MENU},
      navigationControl: true,
      navigationControlOptions: {style: google.maps.NavigationControlStyle.SMALL},
      mapTypeId: google.maps.MapTypeId.ROADMAP,
      streetViewControl: true,
      center: Southside
    }

//////////////////////////////////////////////////////
    gMap = new google.maps.Map(document.getElementById("map_canvas"), myOptions);

  //adding the fullscreen control to exit fullscreen
  var fsControlDiv = document.createElement('DIV');
  var fsControl = new FSControl(fsControlDiv, gMap);
  fsControlDiv.index = 1;
  gMap.controls[google.maps.ControlPosition.TOP_RIGHT].push(fsControlDiv);


    //adding the Southside marker
    Southsidemarker = new google.maps.Marker({     
		map: gMap, 
		draggable: false, 
		animation: google.maps.Animation.DROP, 
		position: Southside
	});
	//removing the bounce for now - causing too much jitters in non-IE browsers
	//google.maps.event.addListener(Southsidemarker, 'mouseover', toggleBounce);
	//google.maps.event.addListener(Southsidemarker, 'mouseout', function(){Southsidemarker.setAnimation(null);});
	google.maps.event.addListener(Southsidemarker, 'click', SouthsideWindow);

    directionsDisplay.setMap(gMap);
    directionsDisplay.setPanel(document.getElementById("directionsPanel"));

 
      // Initialize the local searcher
      gLocalSearch = new GlocalSearch();
      gLocalSearch.setSearchCompleteCallback(null, OnLocalSearch);

      // Create one InfoWindow to open when a marker is clicked.
      gInfoWindow = new google.maps.InfoWindow;
      google.maps.event.addListener(gInfoWindow, 'closeclick', function() {
        unselectMarkers();
      });

 /////////////////////////////////////////////////////////////the directions stuff

    google.maps.event.addListener(gMap, 'click', function(event) {
      if (origin == null) {
        origin = event.latLng;
        addMarker(origin);
      } else if (destination == null) {
        destination = event.latLng;
        addMarker(destination);
      } else {
        if (waypoints.length < 9) {
          waypoints.push({ location: destination, stopover: true });
          destination = event.latLng;
          addMarker(destination);
        } else {
          alert("Maximum number of waypoints reached");
        }
      }
    });

//end of initialize
  }
 

  function toggleBounce() {
	if (Southsidemarker.getAnimation() != null) {
		Southsidemarker.setAnimation(null);
	} else {
		Southsidemarker.setAnimation(google.maps.Animation.BOUNCE);
		}
	}

  function toHere() {
	//directions to Southside
	$("#Southsideaddr").hide();
	$("#saddr").fadeIn('slow');
	$("#daddr").hide();
	$("#calcBttn").fadeIn('slow').css("display","block");
	$("#saddr").val("Enter your start address");
	$("#daddr").val("1510 H Street NW, Washington, DC 20005");
	}

  function fromHere() {
	//directions from Southside
	$("#Southsideaddr").hide();
	$("#daddr").fadeIn('slow');
	$("#saddr").hide();
	$("#calcBttn").fadeIn('slow').css("display","block");
	$("#saddr").val("1510 H Street NW, Washington, DC 20005");
	$("#daddr").val("Enter your destination");
	}

  function clearText(thefield) {
	thefield.value = "";
	}

  function SouthsideWindow() {
	Southsidemarker.setAnimation(null);

	var contentString = '<div id="InfoHolder">' + 
			    '<h4>Southside 815</h4>' + 
			    '<p id="Southsideaddr">815 S. Washington St.<br />' +
			    'Alexandria, VA 22314</p>' +
			    '<div id="getDir">Directions: <a href="javascript:toHere();">to here</a> - <a href="javascript:fromHere();">from here</a></div>' +
			    '<input type="text" id="saddr" class="formfieldmap hide" value="Enter your start address" style="width: 95%;" onfocus="clearText(this);" />' + 
			    '<input type="text" id="daddr" class="formfieldmap hide" value="Enter your destination" style="width: 95%;" onfocus="clearText(this);" />' + 
			    '<input type="button" class="awesome small" style="display: none; margin-top: 5px;" id="calcBttn" onclick="calcRoute(\'Southside\');" value="Get Directions »" />' + 
			    '</div>';

	var infowindow = new google.maps.InfoWindow({ 
		content: contentString,  
		size: new google.maps.Size(500, 500)
		});

	infowindow.open(gMap,Southsidemarker); 

	}

  function addMarker(latlng) {
    markers.push(new google.maps.Marker({
      position: latlng, 
      map: gMap,
      draggable: false, 
      icon: "//maps.google.com/mapfiles/marker" + String.fromCharCode(markers.length + 65) + ".png"
    }));    
  }
 
  function calcRoute(rtype) {

   //blank the directions panel html
	$("#directionsPanel").html("");

  //determine if the directions are from SouthsideMarker or the waypoint markers
   if(rtype == "Southside") {
	origin = document.getElementById("saddr").value;
	destination = document.getElementById("daddr").value;
	}


    if (origin == null) {
      $("#directionsPanel").html("<p>No dice - check the alert for instructions.</p>");
      alert("Click the marker to get directions to/from Southside (the best bar ever), or click anywhere on the map to set a different starting point");
      return;
    }
    
    if (destination == null) {
      $("#directionsPanel").html("<p>No dice - check the alert for instructions.</p>");
      alert("Click on the map to add an end point");
      return;
    }
    
    var mode;
    switch (document.getElementById("mode").value) {
      case "bicycling":
        mode = google.maps.DirectionsTravelMode.BICYCLING;
        break;
      case "driving":
        mode = google.maps.DirectionsTravelMode.DRIVING;
        break;
      case "walking":
        mode = google.maps.DirectionsTravelMode.WALKING;
        break;
    }
    
    var request = {
        origin: origin,
        destination: destination,
        waypoints: waypoints,
        travelMode: mode,
        optimizeWaypoints: document.getElementById('optimize').checked,
        avoidHighways: document.getElementById('highways').checked,
        avoidTolls: document.getElementById('tolls').checked
    };
    
    directionsService.route(request, function(response, status) {
      if (status == google.maps.DirectionsStatus.OK) {
	if(rtype == "Southside") {
	Southsidemarker.setMap(null);
	}
	if($("#directionsPanel").html().indexOf("<h4>Directions Results:</h4>")<0) {
	$("#directionsPanel").prepend("<h4>Directions Results:</h4>");	
	}
        directionsDisplay.setDirections(response);
      } else {
	if(status == "NOT_FOUND") {
	$("#directionsPanel").html('<h4>Your address was not found. Please try again.</h4>');
	} else {
	$("#directionsPanel").html('<h4>There was an error processing the directions. Please try again.</h4>');
	 }
	}
    });
    
    clearMarkers();
    directionsVisible = true;

    //this opens the directions panel on this page - calls the jquery junks
    $('.acc_trigger').removeClass('active').next().slideUp(); //Remove all "active" state and slide up the immediate next container
    $('.acc_trigger::nth(1)').addClass('active').next().show();

  }
  
  function updateMode() {
    if (directionsVisible) {
      calcRoute();
    }
  }
  
  function clearMarkers() {
    for (var i = 0; i < markers.length; i++) {
      markers[i].setMap(null);
    }
  }
  
  function clearWaypoints() {
    markers = [];
    origin = null;
    destination = null;
    waypoints = [];
    directionsVisible = false;
  }
  
  //reset the whole mother fucker
  function resetMap() {
    clearMarkers();
    clearWaypoints();
    directionsDisplay.setMap(null);
    directionsDisplay.setPanel(null);
    directionsDisplay = new google.maps.DirectionsRenderer();
    directionsDisplay.setMap(gMap);
    directionsDisplay.setPanel(document.getElementById("directionsPanel"));
    $("#directionsPanel").html("");
    $("#directionsPanel").hide();  
    $("#searchwell").html("");
    $("#searchwell").hide(""); 
      for (var i = 0; i < gCurrentResults.length; i++) {
        gCurrentResults[i].marker().setMap(null);
      }
    $("#queryInput").val("");
    $("#location").html("");
     initialize();
  }


////////////////////////////////////////////////////////////////////the search stuff
    function doSearch() {
      var query = document.getElementById("queryInput").value;
      gLocalSearch.setCenterPoint(gMap.getCenter());
      gLocalSearch.execute(query);
    }
 
    // Called when Local Search results are returned, we clear the old
    // results and load the new ones.
    function OnLocalSearch() {
      if (!gLocalSearch.results) return;
      var searchWell = document.getElementById("searchwell");

    //this opens the directions panel on this page - calls the jquery junks
    $('.acc_trigger').removeClass('active').next().slideUp(); //Remove all "active" state and slide up the immediate next container
    $('.acc_trigger::nth(2)').addClass('active').next().show();

 
      // Clear the map and the old search well
      searchWell.innerHTML = "";
      for (var i = 0; i < gCurrentResults.length; i++) {
        gCurrentResults[i].marker().setMap(null);
      }
      // Close the infowindow
      gInfoWindow.close();
 
      gCurrentResults = [];
      for (var i = 0; i < gLocalSearch.results.length; i++) {
        gCurrentResults.push(new LocalResult(gLocalSearch.results[i]));
      }
 
      var attribution = gLocalSearch.getAttribution();
      if (attribution) {
        document.getElementById("searchwell").appendChild(attribution);
      }
 
      // Move the map to the first result and unhide the panel
      $("#searchwell").fadeIn('slow');
      var first = gLocalSearch.results[0];
      if(first != undefined){
      gMap.setCenter(new google.maps.LatLng(parseFloat(first.lat),
                                            parseFloat(first.lng)));
	$("#searchwell").prepend("<h4>Local search results for '" + $("#queryInput").val() + "':</h4>");
	}else{
	//no results for search
	$("#searchwell").prepend("<h4>There were no search results for '" + $("#queryInput").val() + "'.</h4>")
	}
 
    }
 
    // Cancel the form submission, executing an AJAX Search API search.
    function CaptureForm(searchForm) {
      gLocalSearch.execute(searchForm.input.value);
      return false;
    }
 
 
 
    // A class representing a single Local Search result returned by the
    // Google AJAX Search API.
    function LocalResult(result) {
      var me = this;
      me.result_ = result;
      me.resultNode_ = me.node();
      me.marker_ = me.marker();
      google.maps.event.addDomListener(me.resultNode_, 'mouseover', function() {
        // Highlight the marker and result icon when the result is
        // mouseovered.  Do not remove any other highlighting at this time.
        me.highlight(true);
      });
      google.maps.event.addDomListener(me.resultNode_, 'mouseout', function() {
        // Remove highlighting unless this marker is selected (the info
        // window is open).
        if (!me.selected_) me.highlight(false);
      });
      google.maps.event.addDomListener(me.resultNode_, 'click', function() {
        me.select();
      });
      document.getElementById("searchwell").appendChild(me.resultNode_);
    }
 
    LocalResult.prototype.node = function() {
      if (this.resultNode_) return this.resultNode_;
      return this.html();
    };
 
    // Returns the GMap marker for this result, creating it with the given
    // icon if it has not already been created.
    LocalResult.prototype.marker = function() {
      var me = this;
      if (me.marker_) return me.marker_;
      var marker = me.marker_ = new google.maps.Marker({
        position: new google.maps.LatLng(parseFloat(me.result_.lat),
                                         parseFloat(me.result_.lng)),
        icon: gYellowIcon, shadow: gSmallShadow, map: gMap});
      google.maps.event.addListener(marker, "click", function() {
        me.select();
      });
      return marker;
    };
 
    // Unselect any selected markers and then highlight this result and
    // display the info window on it.
    LocalResult.prototype.select = function() {
      unselectMarkers();
      this.selected_ = true;
      this.highlight(true);
      gInfoWindow.setContent(this.html(true));
      gInfoWindow.open(gMap, this.marker());
    };
 
    LocalResult.prototype.isSelected = function() {
      return this.selected_;
    };
 
    // Remove any highlighting on this result.
    LocalResult.prototype.unselect = function() {
      this.selected_ = false;
      this.highlight(false);
    };
 
    // Returns the HTML we display for a result before it has been "saved"
    LocalResult.prototype.html = function() {
      var me = this;
      var container = document.createElement("div");
      container.className = "unselected";
      container.appendChild(me.result_.html.cloneNode(true));
      return container;
    }
 
    LocalResult.prototype.highlight = function(highlight) {
      this.marker().setOptions({icon: highlight ? gRedIcon : gYellowIcon});
      this.node().className = "unselected" + (highlight ? " red" : "");
    }

//this unselects the marker when a new one is clicked
    function unselectMarkers() {
      for (var i = 0; i < gCurrentResults.length; i++) {
        gCurrentResults[i].unselect();
          }
	}
 
    GSearch.setOnLoadCallback(initialize);

////////////////////////////////////////////////////////////////////////
//this is the geolocation junkx
//access firefox junks and any browser with google gears
function findLocation() {
	var mygeo = null;
	if (navigator.geolocation){
        	mygeo = navigator.geolocation;
      		} else {
		     if (google.gears) {
			mygeo = google.gears.factory.create('beta.geolocation');
			}
		}
	if(mygeo !==null){
		mygeo.getCurrentPosition(successCallback,errorCallback,{maximumAge:3000000});
		}else{
			document.getElementById("location").innerHTML = "<strong>Your browser doesn't support geolocation. <a href='http://gears.google.com/?action=install&message=To use the geolocation services, you can install Google Gears.&return=http://www.halnesbitt.com/pages/maps.php'>Install Google Gears</a></strong>";
		}
}


function successCallback(position) {
        
	var latitude = position.coords.latitude;
	var longitude = position.coords.longitude;
	document.getElementById("location").innerHTML="<strong>Your location: latitude: " + latitude + ", longitude:" + longitude + "</strong>";
  
	
	// grab the coordinates and set the zoom
	var latlng = new google.maps.LatLng(latitude,longitude);
	var zoom = 15;

	//center this joint
        gMap.setCenter(latlng, zoom); 

   //reverse geocode to get the address
    var geocoder;
    geocoder = new google.maps.Geocoder();
    var blueIcon = '../images/blue_dot_circle.png';
    var infowindow = new google.maps.InfoWindow();
    var marker;

    if (geocoder) {
      geocoder.geocode({'latLng': latlng}, function(results, status) {
        if (status == google.maps.GeocoderStatus.OK) {
          if (results[1]) {
            gMap.setZoom(15);
            marker = new google.maps.Marker({
                position: latlng, 
		icon: blueIcon, 
                map: gMap
            }); 
            infowindow.setContent('<div id="locationHolder"><h4>Your Current Location</h4><br /><br />' + results[0].formatted_address + '</div>');
            infowindow.open(gMap, marker);
          } else {
            alert("Sorry, I could not determine your location");
          }
        } else {
          alert("Geocoder failed due to: " + status);
        }
      });
    }

}

function errorCallback() {
	document.getElementById("location").innerHTML = "<strong>Sorry, we couldn't find your location.</strong>";
}

function fullScreen(){
$("#map_canvas").addClass('full_screen_map');
$("#directionOptions").addClass('full_screen_directionOptions');
$("#directionsPanel").addClass('full_screen_directionsPanel');
$("#directionsPanel").toggleClass('addPadding');
$("#searchControls").addClass('full_screen_searchControls');
$("#searchwell").addClass('full_screen_searchwell');
$("#searchwell").toggleClass('addPadding');
$('html, body').animate({scrollTop:0}, 'slow');
if($("#directionsPanel").html() == "") {
	//hiding the directions panel - will show later
	$("#directionsPanel").hide();
	}

if($("#searchwell").html() == "") {
	//hiding the search panel - will show later
	$("#searchwell").hide();
	}
initialize();
}

function exitFullScreen() {
$("#map_canvas").removeClass('full_screen_map');
$("#directionOptions").removeClass('full_screen_directionOptions');
$("#directionsPanel").removeClass('full_screen_directionsPanel');
$("#directionsPanel").toggleClass('addPadding');
$("#searchControls").removeClass('full_screen_searchControls');
$("#searchwell").removeClass('full_screen_searchwell');
$("#searchwell").toggleClass('addPadding');
initialize();
}



			
			

Get the HTML

The HTML to Display the Map Stuff

This is the basic HTML to display the map and the information holders.

			
<html>
<head>
<!--starting the Google Maps AND Local Search Service -->
<!--these should be placed in your document head before your custom maps js file-->
<script src="http://maps.google.com/maps/api/js?sensor=false" type="text/javascript"></script>
<script src="http://www.google.com/uds/api?file=uds.js&v=1.0&key=YOUR_GOOGLE_MAPS_API_KEY" type="text/javascript"></script>
<script type="text/javascript" src="http://www.google.com/jsapi?key=YOUR_GOOGLE_MAPS_API_KEY"></script>
<script type="text/javascript" src="yourgooglemapsscriptfile.js"></script>
</head>

<!--the maps script is called onload -->
<body onload="initialize()">

<!--this calls the GPS location script -->
<a href="#" onClick="findLocation(); return false;">Get Current Location</a>

<!--this displays the GPS location info -->
<div id="location"></div>

<!--these are the directions controls for the map -->
<div id="directionOptions">
<input type="checkbox" id="optimize" checked />Optimize
<input type="checkbox" id="highways" checked />Avoid highways
<input type="checkbox" id="tolls" checked />Avoid tolls

<select id="mode" onchange="updateMode()" class="formfieldxshort">
<option value="bicycling">Bike</option>
<option value="driving">Drive</option>
<option value="walking">Walk</option>
</select>
<input type="button" class="formbuttontight" value="Get Directions" onclick="calcRoute()" />
</div>

<!--this displays the map -->
<div id="map_canvas"></div>

<!--these are the search controls for the map -->
<div id="searchControls">
<input type="text" id="queryInput" class="formfieldmid" />
<input type="button" class="formbuttontight" value="Search" onclick="doSearch()"/>
</div>

<!--this displays the directions results -->
<div id="directionsPanel"></div>

<!--this displays the search results -->
<div id="searchwell"></div>

</body>
</html>