Thursday, January 30, 2014

Google Maps - Marking multiple locations on google map from human-readable text addresses

At last, I displayed the Google map using JavaScript API V3 in a web browser like Firefox. Thanks for some articles posted in Code Project, that I referred mainly.

My requirement was to display place-markers on multiple places on Google map and the human readable text addresses are only supplied as CSV. It’s created a local HTML page which can be used to display maps (note the HTML page is not hosted anywhere). It’s used Google API v3 geocoding service for getting the latitude and longitude from the addresses supplied.

The code parts are explained below:
----------------------------------------------------
First part of the file contains the HTML header and Google API 'declarations'
<!DOCTYPE html>
<html>
    <head>
        <meta charset='utf-8'>
        <meta http-equiv='X-UA-Compatible' content='IE=edge,chrome=1'>
        <title>Bethanie Inc. data : geographically linked</title>
        <script src='http://ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min.js'></script>
        <script src='https://maps.googleapis.com/maps/api/js?v=3.11&sensor=false' type='text/javascript'></script>
        <script type='text/javascript'>
Second, supply all the addresses as CSV’s string array. The first field serves as the name, the rest is the address itself. Also note that the whole Java scripting is started when the document loading is ready ():The variable total locations is introduced to calculate the progress.
----------------------------------------------------
<script type="text/javascript">
    $(document).ready(function() {
        // execute
        (function() {
            // Points of interest
            var locations = new Array();
            var i = 0;
            locations[i++] = "Rijksmuseum, Museumstraat 1, Amsterdam"
            locations[i++] = "Van Gogh Museum, Paulus Potterstraat 7, Amsterdam";
            locations[i++] = "Kroller-Muller Museum, Houtkampweg 6, Otterlo";
            locations[i++] = "Beeckestijn, Rijksweg 136, Velsen";
            var total_locations = i;
            i = 0;

Third, creating the map and the parameters are:
zoom: sets the default zoom level of the map;
center: specifies the center of the map, using GPS coordinates (latitude, longitude); You can change it if your area of consideration is different
mapTypeId: for this example we use terrain; see other types (https://developers.google.com/maps/documentation/javascript/maptypes?hl=pl#MapTypes)
mapTypeControl: set to 'true' so that controls are added to the map (zoom, navigate).
Then a new instance of the map is created with the options specified. The 'map_canvas' identifier comes from the HTML part. It is the identifier of a <div> element to hold the map image.
----------------------------------------------------
console.log('About to look up ' + total_locations + ' locations'); / To view Chrome console press: ctrl+shift+J
// map options
var options = {
    zoom: 8,
    center: new google.maps.LatLng(52.2313, 4.83565), // Amstelhoek, center of the world
    mapTypeId: google.maps.MapTypeId.TERRAIN,
    mapTypeControl: true
};
// init map
console.log('Initialise map...');
var map = new google.maps.Map(document.getElementById('map_canvas'), options);

Fourth, fetch the latitude and longitude of the text address supplied from Google Map API. When not using a Google API key, the number of requests per second is limited, so a time delay in mille-seconds is added
----------------------------------------------------
// use the Google API to translate addresses to GPS coordinates
var geocoder = new google.maps.Geocoder();
if (geocoder) {
    console.log('Got a new instance of Google Geocoder object');
    // Call function 'createNextMarker' every second
    var myVar = window.setInterval(function(){createNextMarker()}, 1000);

function createNextMarker() {
    if (i < locations.length) {
        var customer = locations[i];
        var parts = customer.split(",");
        var name = parts.splice(0,1);
        var address = parts.join(",");
        console.log('Looking up ' + name + ' at address ' + address);
        geocoder.geocode({ 'address': address }, makeCallback(name));
        i++;
        updateProgressBar(i / total_locations);
    } else {
        console.log('Ready looking up ' + i + ' addresses');
        window.clearInterval(myVar);
    }
}


Fifth, try to catch errors from API, if any
----------------------------------------------------
function makeCallback(name) {
        var geocodeCallBack = function (results, status) {
            if (status == google.maps.GeocoderStatus.OK) {
                var longitude = results[0].geometry.location.lng();
                var latitude = results[0].geometry.location.lat();
                console.log('Received result: lat:' + latitude + ' long:' + longitude);
                var marker = new google.maps.Marker({
                    position: new google.maps.LatLng(latitude, longitude),
                    map: map,
                    title: name + ' : ' + results[0].formatted_address});
            } else {
                console.log('No results found: ' + status);
            }
        }
        return geocodeCallBack;
    }
} // endif geocoder

Sixth, run the Progress bar
-----------------------------------------------
function updateProgressBar(percentage_factor) {
            var map_canvas = document.getElementById('map_canvas');
            var node = document.getElementById('progress_bar');
            var w = map_canvas.style.width.match(/\d+/);
            w = w * percentage_factor;
            node.style.width = parseInt(w) + 'px';
            if (percentage_factor == 1) {
                // jscript style properties are different to the CSS style properties
                node.style.backgroundColor = 'green';
            }
        }
    // Closing bits of jscript...
    })();
});
</script>

Seventh, HTML closures
</head>
    <body>
    <div style="border: 1px solid black; width:1024px; height:3px;">
        <div id="progress_bar" style="height:3px; width:0px; background-color:red;"/>
    </div>
    <!-- if you change this id, then also update code of progress bar above -->
        <div id="map_canvas" style="width: 1024px; height:600px;"></div>
    </body>

</html>


ALL CODES TOGETHER WITH LITTLE CHANGES; AS I ADDED AN USER TYPE AND USERCODE IN FRONT OF ADDRESSES. THE USER TYPE USED TO DIFFERENTIATE USERS AND GIVE SEPARATE MARKERS FOR THEM..

<!DOCTYPE html>
<html>
    <head>
        <meta charset='utf-8'>
        <meta http-equiv='X-UA-Compatible' content='IE=edge,chrome=1'>
        <title>Bethanie Inc. data : geographically linked</title>
        <script src='http://ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min.js'></script>
        <script src='https://maps.googleapis.com/maps/api/js?v=3.11&sensor=false' type='text/javascript'></script>
        <script type='text/javascript'>
        // check DOM Ready
        $(document).ready(function() {
            // execute
            (function() {
                /////////////// Addresses ///////////////////
                var locations = new Array();
                var i = 0;
                locations[i++] = 'C,C001: Carig Evans,3 Gibney St Cottesloe WA 6011'
                locations[i++] = 'C,C002: Mathew Phil,25 Marchwood Boulevard Butler WA 6036'
                locations[i++] = 'E,C003: Sachin Tendulkar,4 Dover Court Mosman Park WA 6012'
                locations[i++] = 'E,C004: Kapil Yadav,6 Bussell Road Wembley Downs WA 6019'
                locations[i++] = 'S,C005: George mathew,7 Mildura Place Rockingham WA 6168'
                locations[i++] = 'S,C006: Bunny Collins,22 Plantation Street Mt Lawley WA 6050'
                /////// Addresses/////////
                var total_locations = i;
                i = 0;
                console.log('About to look up ' + total_locations + ' locations');
                // map options
                var options = {
                    zoom: 10,
                    center: new google.maps.LatLng(-31.9522, 115.8589),//Perth, WA 
                    mapTypeId: google.maps.MapTypeId.ROADMAP,//TERRAIN
                    mapTypeControl: true
                };
                // init map
                console.log('Initialise map...');
                var map = new google.maps.Map(document.getElementById('map_canvas'), options);
               // use the Google API to translate addresses to GPS coordinates
               //(See Limits: https://developers.google.com/maps/documentation/geocoding/#Limits)
                var geocoder = new google.maps.Geocoder();
                if (geocoder) {
                    console.log('Got a new instance of Google Geocoder object');
                    // Call function 'createNextMarker' every second
                    var myVar = window.setInterval(function(){createNextMarker()}, 700);
                    function createNextMarker() {
                        if (i < locations.length)
                       {
                            var customer = locations[i];
                            var parts = customer.split(','); // split line into parts (fields)
                            var type= parts.splice(0,1);    // type from location line (remove)
                            var name = parts.splice(0,1);    // name from location line(remove)
                            var address =parts.join(',');   // combine remaining parts
                            console.log('Looking up ' + name + ' at address ' + address);
                            geocoder.geocode({ 'address': address }, makeCallback(name, type));
                            i++; // next location in list
                            updateProgressBar(i / total_locations);
                        } else
                       {
                            console.log('Ready looking up ' + i + ' addresses');
                            window.clearInterval(myVar);
                        }
                    }
                    function makeCallback(name,type)
                   {
                        var geocodeCallBack = function (results, status) {
                            if (status == google.maps.GeocoderStatus.OK) {
                                var longitude = results[0].geometry.location.lng();
                                var latitude = results[0].geometry.location.lat();
                                console.log('Received result: lat:' + latitude + ' long:' + longitude);
                                var marker = new google.maps.Marker({
                                    position: new google.maps.LatLng(latitude, longitude),
                                    map: map,
                                    title: name + ' : ' + '\r\n' + results[0].formatted_address});// this is display in tool tip/ icon color
                                   if (type=='E')  {marker.setIcon('http://maps.google.com/mapfiles/ms/icons/green-dot.png')};
                                   if (type=='S')  {marker.setIcon('http://maps.google.com/mapfiles/kml/pal4/icon53.png')};
                                   if (type=='C')  {marker.setIcon('http://maps.google.com/mapfiles/ms/icons/blue-dot.png')};
                            }
                           else {
                                console.log('No results found: ' + status);
                            }
                        }
                        return geocodeCallBack;
                    }
                } else
               {
                    console.log('Failed to instantiate Google Geocoder object');
                }
                function updateProgressBar(percentage_factor) {
                    var map_canvas = document.getElementById('map_canvas');
                    var node = document.getElementById('progress_bar');
                    var w = map_canvas.style.width.match(/\d+/);
                    w = w * percentage_factor;
                    node.style.width = parseInt(w) + 'px';
                    if (percentage_factor == 1) {
                        // jscript style properties are different to the CSS style properties...
                        node.style.backgroundColor = 'green';
                    }
                }
            })();
        });
        </script>
    </head>
    <body>
    <div style='border: 1px solid black; width:1366px; height:3px;'>
        <div id='progress_bar' style='height:3px; width:0px; background-color:red;'/>
    </div>
    <!-- if you change this id, then also update code of progress bar above -->
        <div id='map_canvas' style='width:1900px; height:1000px;'></div>
    </body>

</html>