8.2 Mapping a Google Form Part 2

Getting started

Now you are ready to map your Google Form.  The following tutorial will accomplish the following:

  1. take in a Google Doc,
  2. finds the correct field for the “address” column,
  3. geocode each row,
  4. and display it on a map

(view starter site)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
<br />
<!DOCTYPE html><br />
<html><br />
<head><br />
    <meta name="viewport" content="initial-scale=1.0, user-scalable=no" /> </p>
<style type="text/css">
        html { height: 100% }
        body { height: 100%; margin: 0px; padding: 0px }
        #map_canvas { height: 100% }
    </style>
<p>    <script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false"></script><br />
    <script type="text/javascript" src="http://yohman.bol.ucla.edu/jquery-1.5.2.min.js"></script> </p>
<p>    <script type="text/javascript">    
        //declare namespace
        var up206b = {};</p>
<p>         var geocoder;</p>
<p>        var bounds;</p>
<p>        //declare map
        var map;
        var marker = [];</p>
<p>     function trace(message)
        {
            if (typeof console != 'undefined')
            {
                console.log(message);
            }
        }</p>
<p>     //Function to create marker
        up206b.createMarker = function(latitude,longitude,address,i,info)
        {</p>
<p>         $('#addresslist').append(i+': '+address+'<br />');</p>
<p>         var markerLatLng = new google.maps.LatLng(latitude,longitude);
             marker[i] = new google.maps.Marker({
                position: markerLatLng,
                map: map,
                title: address,
                icon:' http://www.yohman.com/students/yoh/home.png'
            });</p>
<p>         bounds.extend(markerLatLng);
            map.fitBounds(bounds);</p>
<p>         google.maps.event.addListener(marker[i], 'click', function() {
                up206b.showStreetView(latitude,longitude,info);
            });</p>
<p>     }</p>
<p>     // Generate street view
        up206b.showStreetView = function(lat,lng,info)
        {
            var streetviewlocation = new google.maps.LatLng(lat,lng);
            // Note: constructed panorama objects have visible: true
            // set by default.
            trace(streetviewlocation);
            var panoramaOptions = {
              position: streetviewlocation,
              pov: {
                heading: 34,
                pitch: 10,
                zoom: 1
              }
            };
            var panorama = new google.maps.StreetViewPanorama(
            document.getElementById("streetview"), panoramaOptions);
            map.setStreetView(panorama);
            $('#info').html(info);
        }</p>
<p>     //Parse the geocoded results and map it
        up206b.jsonParser = function(json,i,info)
        {
            //Make sure geocode returned results
            if (typeof json.results[0] == 'undefined') {
                $('#addresslist').append(i+': '+json.status+'<br />');
            }
            else
            {</p>
<p>             lat = json.results[0].geometry.location.lat;
                lng = json.results[0].geometry.location.lng;
                address = json.results[0].formatted_address;</p>
<p>             up206b.createMarker(lat,lng,address,i,info);
            }
        }</p>
<p>     //Geocode function: uses google geocoding API (not maps API)
        up206b.geocode = function (address, i,info) {</p>
<p>         //encode address for URL
            address = encodeURI(address);</p>
<p>         url = 'http://maps.googleapis.com/maps/api/geocode/json?address='+address+'&#038;sensor=false';
            encodedurl = encodeURIComponent(url);</p>
<p>         $.ajax({
                type: "GET",
                url: "http://www.yohman.com/proxy/proxy_json.php?url=" + (encodedurl),
                dataType: "json",
                success: function(data){ up206b.jsonParser(data,i,info) }
            })
        }</p>
<p>     //Parse the google doc
        up206b.parseGoogleDoc = function(json)
        {
            //create a counter
            var counter = 0;</p>
<p>         //Geocode this one at a time at a set interval... Google does not allow too many simultaneous geocodes 
            var handle = setInterval(function () {
                if (typeof json.feed.entry[counter] == 'undefined') {
                    clearInterval(handle);
                    return;
                }
                else
                {
                    //Use the trace to find what fields are in your google doc
                    trace(counter);
                    trace(json.feed.entry[counter]);</p>
<p>                 //adjust these lines to match the information from your spreadsheet
                    var info = '
<h3>'
+json.feed.entry[counter].gsx$address.$t+'</h3>
<p>'
;
                    /* sample fields
                    info += json.feed.entry[counter].gsx$description.$t+'</br>';
                    info += json.feed.entry[counter].gsx$howmanybedroomsandbathrooms.$t+'<br />';
                    info += json.feed.entry[counter].gsx$howmuchisrent.$t+'</br>';
                    */
</p>
<p>                 up206b.geocode(json.feed.entry[counter].gsx$address.$t,counter,info);
                    counter++;
                }
            }, 200);
        }</p>
<p>     //Get the google doc
        up206b.getGoogleDoc = function()
        {
            //The google doc url: REPLACE WITH YOURS
            var url = 'https://{your google doc url}/public/values';</p>
<p>         // Add a callback to parseGoogleDoc function
            var script = document.createElement('script');     
            script.setAttribute('src', url + '?alt=json-in-script&#038;callback=up206b.parseGoogleDoc');
            script.setAttribute('id', 'jsonScript');
            script.setAttribute('type', 'text/javascript');
            document.documentElement.firstChild.appendChild(script);
        }</p>
<p>     //Function that gets run when the document loads
        up206b.initialize = function()
        {
            geocoder = new google.maps.Geocoder();
            bounds = new google.maps.LatLngBounds ();
            var latlng = new google.maps.LatLng(34.070264, -118.4440562);
            var myOptions = {
                zoom: 13,
                center: latlng,
                mapTypeId: google.maps.MapTypeId.ROADMAP
            };
            map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);</p>
<p>         up206b.getGoogleDoc();</p>
<p>     }
</script><br />
</head><br />
<body onload="up206b.initialize()"> </p>
<p>    <!-- side panel div container --> </p>
<div style="position:absolute; width:380px; height: 100%; overflow:auto; float:left; padding-left:10px; padding-right:10px;">
<h1>8.2 For Rent! Tutorial</h1>
<p>        Found a rental property?  <a href="https://spreadsheets.google.com/viewform?hl=en&#038;pli=1&#038;formkey=dG1TVFlyTFpDaFJ1aFc4bC0wSmZTVEE6MQ#gid=0" target="_blank">Add it to the map now!</a></p>
<div id="info" style="border:1px solid gainsboro; background:#e5e5e5; padding:10px;"></div>
<div id="streetview" style="width:100%; height:250px;"></div>
</p></div>
<p>    <!-- map div container --> </p>
<div id="map_canvas" style="height:100%; margin-left:400px;"></div>
<p></body><br />
</html><br />

Now let’s break it down to see how this program works.

Connecting to Google Docs

First, add the link to your Google Doc URL you extracted from the previous tutorial. You will need to make a small change. Make sure the last part of the URL string that begins with “basic” is changed to “values“:

1
2
<br />
https://spreadsheets.google.com/feeds/list/{your key}/od6/public/basic<br />

Needs to be changed to:

1
2
<br />
https://spreadsheets.google.com/feeds/list/{your key}/od6/public/values<br />

After you have made the change in the Google Doc URL, the following function allows you to connect to it:

1
2
3
4
5
6
7
8
9
10
11
12
13
<br />
//Get the google doc<br />
up206b.getGoogleDoc = function()<br />
{<br />
    //The google doc url: REPLACE WITH YOURS<br />
    var url = 'https://spreadsheets.google.com/feeds/list/{your google doc info}/public/values';</p>
<p> // Add a callback to parseGoogleDoc function<br />
    var script = document.createElement('script');<br />
    script.setAttribute('src', url + '?alt=json-in-script&#038;callback=up206b.parseGoogleDoc');<br />
    script.setAttribute('id', 'jsonScript');<br />
    script.setAttribute('type', 'text/javascript');<br />
    document.documentElement.firstChild.appendChild(script);<br />
}<br />

This function calls the Google Doc, and has a callback function for “yoh.parseGoogleDoc”. This function will parse the contents of the document retrieved.

parseGoogleDoc

The callback function (meaning that it gets run after it retrieves data from your Google Doc) is called “parseGoogleDoc”.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<br />
//Parse the google doc<br />
up206b.parseGoogleDoc = function(json)<br />
{<br />
    //create a counter<br />
    var counter = 0;</p>
<p> //Geocode this one at a time at a set interval... Google does not allow too many simultaneous geocodes<br />
    var handle = setInterval(function () {<br />
        if (typeof json.feed.entry[counter] == 'undefined') {<br />
            clearInterval(handle);<br />
            return;<br />
        }<br />
        else<br />
        {<br />
            //Use the trace to find what fields are in your google doc<br />
            trace(counter);<br />
            trace(json.feed.entry[counter]);</p>
<p>         //adjust these lines to match the information from your spreadsheet<br />
            var info = '<br />
<h3>'
+json.feed.entry[counter].gsx$address.$t+'</h3>
<p>'
;<br />
            /* sample fields<br />
            info += json.feed.entry[counter].gsx$description.$t+'</br>';<br />
            info += json.feed.entry[counter].gsx$howmanybedroomsandbathrooms.$t+'<br />';<br />
            info += json.feed.entry[counter].gsx$howmuchisrent.$t+'</br>';<br />
            */
</p>
<p>         up206b.geocode(json.feed.entry[counter].gsx$address.$t,counter,info);<br />
            counter++;<br />
        }<br />
    }, 200);<br />
}<br />

Important! Notice that the function above creates an “info” variable based on the fields generated by MY google form. These will need to be adjusted based on the field names created by your google doc.

After tracing the data returned, we know that json.feed.entry[] is the array that holds each row in the Google Doc. What we want to do is loop through every value in the array, geocode it, and then map it. However… Google Maps has a limit to the number of simultaneous geocodes it allows. It also has a limit on how many total geocodes you can have in a 24 hour period. Because of this, we cannot effectively geocode more than 10 addresses at a time. One way around this is to time the rate at which we request the addresses to be geocoded. This can be done using the setInterval javascript function, that allows you to run tasks at set intervals. In this case, we are requesting the Google Geocoder API to geocode one address every 200 milliseconds. Note that we are also setting a counter variable to increment each time the interval runs, so that it will geocode the next record in the array.

Geocoding

The geocoding process if fairly straight forward. Note that we are opting to use the Google Geocoder API, which is a different service than the geocoder built in the Maps API. The reason for this is that the Geocoder API allows for more simultaneous calls than does the Maps API.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<br />
//Geocode function: uses google geocoding API (not maps API)<br />
up206b.geocode = function (address, i,info) {</p>
<p> //encode address for URL<br />
    address = encodeURI(address);</p>
<p> url = 'http://maps.googleapis.com/maps/api/geocode/json?address='+address+'&#038;sensor=false';<br />
    encodedurl = encodeURIComponent(url);</p>
<p> $.ajax({<br />
        type: "GET",<br />
        url: "http://www.yohman.com/proxy/proxy_json.php?url=" + (encodedurl),<br />
        dataType: "json",<br />
        success: function(data){ up206b.jsonParser(data,i,info) }<br />
    })<br />
}<br />

Note that the Geocoding API requires the usage of a proxy. On success, the yoh.jsonParser function is called.

Parsing and mapping the results from the Geocoder

Once the Geocoder API returns data, it calls the jsonParser function.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<br />
//Parse the geocoded results and map it<br />
up206b.jsonParser = function(json,i,info)<br />
{<br />
    //Make sure geocode returned results<br />
    if (typeof json.results[0] == 'undefined') {<br />
        $('#addresslist').append(i+': '+json.status+'<br />');<br />
    }<br />
    else<br />
    {</p>
<p>     lat = json.results[0].geometry.location.lat;<br />
        lng = json.results[0].geometry.location.lng;<br />
        address = json.results[0].formatted_address;</p>
<p>     up206b.createMarker(lat,lng,address,i,info);<br />
    }<br />
}<br />

If an address is returned, it will create a marker on the map by calling the createMarker function.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<br />
//Function to create marker<br />
up206b.createMarker = function(latitude,longitude,address,i,info)<br />
{</p>
<p> $('#addresslist').append(i+': '+address+'<br />');</p>
<p> var markerLatLng = new google.maps.LatLng(latitude,longitude);<br />
     marker[i] = new google.maps.Marker({<br />
        position: markerLatLng,<br />
        map: map,<br />
        title: address,<br />
        icon:' http://www.yohman.com/students/yoh/home.png'<br />
    });</p>
<p> bounds.extend(markerLatLng);<br />
    map.fitBounds(bounds);</p>
<p> google.maps.event.addListener(marker[i], 'click', function() {<br />
        up206b.showStreetView(latitude,longitude,info);<br />
    });</p>
<p>}<br />

Street View

Notice that this function above has an onclick event on the marker. Every time a user clicks on a marker, it calls the showStreetView() function that generates an interactive street view image of the site location.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<br />
// Generate street view<br />
up206b.showStreetView = function(lat,lng,info)<br />
{<br />
    var streetviewlocation = new google.maps.LatLng(lat,lng);<br />
    // Note: constructed panorama objects have visible: true<br />
    // set by default.<br />
    trace(streetviewlocation);<br />
    var panoramaOptions = {<br />
      position: streetviewlocation,<br />
      pov: {<br />
        heading: 34,<br />
        pitch: 10,<br />
        zoom: 1<br />
      }<br />
    };<br />
    var panorama = new google.maps.StreetViewPanorama(<br />
    document.getElementById("streetview"), panoramaOptions);<br />
    map.setStreetView(panorama);<br />
    $('#info').html(info);<br />
}<br />

Leave a Reply