The “livemap” tag for WhatTheBus completes the work that I seeded in the last commit.
In the last update, we had finished a page that used jQuery AJAX updates to get the latest bus location from the cache. Using the simulator to provide updates, the AJAX updates shows that we could get location updates as latitude and longitudes. By watching the dev web server, I also saw that these requests were super light (0ms DB, 0ms view).
In this update, I took the same basic code and added Google maps (v3) interaction. Using Google and jQuery together maps is refreshingly easy.
The first step was to render the map when the page loads. This required adding the Google javascript library and pointing the page’s onload event to initMap. The initMap function creates a new map object centered on the bus’ location, creates a bus marker at the center, and then replaces the page’s live_map div with the map.
<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=true&key=<%= MAP_KEY || "not_set_in_#{RAILS_ENV}_config" %>"> </script> <script type="text/javascript"> var map; var busMarker; var xref = '<%= @bus.xref %>'; var name = '<%= @bus.name %>'; var tstamp = new Date(); function initMap() { var centerCoord = new google.maps.LatLng(<%= @pos %>); var mapOptions = { zoom: 16, center: centerCoord, mapTypeId: google.maps.MapTypeId.ROADMAP }; map = new google.maps.Map(document.getElementById("live_map"), mapOptions); busMarker = new google.maps.Marker({ position: centerCoord, map: map, title: name, icon: "/images/bus.png" }); window.setInterval('updateMap();', <%= MAP_UPDATE_SECS %>000); }
The second step was to add the AJAX call on a timer. After adding the update function timer registration, the updates simply extended the existing AJAX request. This existing request already had the bus’ position so the work centered on interacting with the map.
To keep things friendly, we turn the last marker into a bullet point and change the bus name to the last time. Then we create a new marker based on that latest position and center the map on that position too. To prevent reduce server load for non-reporting buses, we move off the map page if there is no position data.
function updateMap() { busMarker.setIcon("/images/track.png"); busMarker.setTitle(tstamp.getHours() + ":" + tstamp.getMinutes() + ":" + tstamp.getSeconds()); tstamp = new Date(); // get the data for the map jQuery.getJSON("/bus/index/"+ xref +".json?cache", {}, function(data){ if (data.length==0) window.location.href("/bus/index/<%= @bus.xref %>"); var newCoord = new google.maps.LatLng(parseFloat(data.buses[xref].lat), parseFloat(data.buses[xref].lng)); busMarker = new google.maps.Marker({ position: newCoord, map: map, title: name, icon: "/images/bus.png" }); map.setCenter(newCoord); }); }
After a few tweaks to add navigation between the existing pages, the first use-case of WhatTheBus is in the bag!
The next step is to setup the code online and get a district to send updates!