Google Maps API, Part 2

In my last post, I explained the basic implementation of the Google Maps API to allow a previously unindexed set of points to be mapped out. After completing the first version of the code, I immediately noticed a few small bugs that hindered its operation – specifically, the ability to save and load previously selected points.

To enable saving and loading, an AJAX call was needed to query a PHP script. In short, the script would either take a JSON string and store it in a text file when saving, or take the contents of the text file and return it as a JSON string when loading. Saving is a much shorter process, as the data only needs to be dumped into the text file. Loading, on the other hand, requires that the data be parsed from the JSON string back into the correct format, and then all of the markers and lines be placed back on the map. In this iteration of the code, the line created among points when the data is loaded does not resemble any usable information to the user – this was addressed in the current version of the code later on.

Below, you’ll find the two functions that call the PHP script, and the PHP script itself. You can check out a usable copy here. In the demo, you’ll also notice that there is an option to copy the longitude/latitude coordinates of the buildings for later use, and to calculate the distances between markers present on the map.

?View Code JAVASCRIPT
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
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
$('#saveA').click(function() {
  $.ajax({
    type: 'POST',
    url: 'nodes_save.php',
    data: {
      func : "save",
      fname : prompt("File Name:"),
      JSON : JSON.stringify(A)
    },
    dataType: 'json',
    success : function(data){
      $('#returnA').html("Data saved successfully");
      $('#containerA').show();
    }
  });
  $('#containerA').delay(2000).fadeOut('slow');
});
 
$('#loadA').click(function() {
  $.ajax({
    type: 'POST',
    url: 'nodes_save.php',
    data: {
      func : "load",
      fname : prompt("File Name:")
    },
    dataType: 'json',
    success : function(data){
      // Remove all Markers from Map
      for (var bar = 0; bar < markers.length; bar++) {
        var foo = markers[bar].getTitle();
        markers[bar].setMap(null);
        for (var baz = 0; baz < polyCoordinates.length; baz++) {
          if (polyCoordinates[baz] == foo) {
            polyCoordinates.splice(baz, 1);
            baz = 0;
          }
        }
      }
      // Update Polyline
      if (polyLine != undefined) polyLine.setMap(null);
      polyLine = new google.maps.Polyline({
        path: polyCoordinates,
        strokeColor: "#FF0000",
        strokeOpacity: 1.0,
        strokeWeight: 2
      });
      polyLine.setMap(map);
      // Delete values currently in A
      for (var qux in A) delete A[qux];
 
      // Load new values into A
      A = JSON.parse(data.d);
 
      // Reset cnt
      cnt = 0;
 
      // Load new values into markers
      for (var qux in A) {
        var coord = qux.toString().replace('(', '');
        coord = coord.replace(')', '');
        var c = coord.split(',');
        var pos = new google.maps.LatLng(c[0], c[1]);
        markers.push(new google.maps.Marker({
          position: pos, 
          map: map,
          draggable: false,
          title: qux
        }));
        google.maps.event.addListener(markers[cnt],'click', (function(cnt) { 
          return function() { 
            if (mode == 0) {
              var foo = markers[cnt].getTitle();
              // Remove Marker
              markers[cnt].setMap(null);
              // Delete array in A
              delete A[markers[cnt].getTitle()];
              // Delete entries in A and polyCoordinates, if any
              for (var baz = 0; baz < polyCoordinates.length; baz++) {
                if (polyCoordinates[baz] == foo) {
                  polyCoordinates.splice(baz, 1);
                  baz = 0;
                }
              }
              for (var qux in A) {
                for (var baz = 0; baz < A[qux].length; baz++) {
                  if (A[qux][baz] == foo) {
                    A[qux].splice(baz, 1);
                    baz = 0;
                  }
                }
              }
              // Update Polyline
              if (polyLine != undefined) polyLine.setMap(null);
              polyLine = new google.maps.Polyline({
                path: polyCoordinates,
                strokeColor: "#FF0000",
                strokeOpacity: 1.0,
                strokeWeight: 2
              });
              polyLine.setMap(map);
            } else if (mode == 1) {
              // If Marker already selected, remove selection
              if (markers[cnt].getIcon() == "http://itouchmap.com/i/blue-dot.png") {
                markers[cnt].setIcon(null);
                markers[cnt].setShadow(null);
                first ? endPt = -1 : startPt = -1;
                first = first ? false : true;
              } else {
                // Select Marker
                markers[cnt].setIcon("http://itouchmap.com/i/blue-dot.png");
                first ? startPt = cnt : endPt = cnt;
                first = first ? false : true;
              }
              // If 2 Markers selected, add to A and update Polyline
              if (startPt != -1 && endPt != -1) {
                // Check if relation has already been entered
                if ($.inArray(markers[endPt].getTitle(), A[markers[startPt].getTitle()]) == -1) {
                  // Add to A in appropriate locations
                  A[markers[startPt].getTitle()].push(markers[endPt].getTitle());
                  A[markers[endPt].getTitle()].push(markers[startPt].getTitle());
                  // Create Polyline
                  var foo = new google.maps.LatLng(markers[startPt].getPosition().lat(), markers[startPt].getPosition().lng());
                  if ($.inArray(markers[startPt].getTitle(), polyCoordinates) == -1)
                    polyCoordinates.push(foo);
                  var bar = new google.maps.LatLng(markers[endPt].getPosition().lat(), markers[endPt].getPosition().lng());
                  if ($.inArray(markers[endPt].getTitle(), polyCoordinates) == -1)
                    polyCoordinates.push(bar);
                  if (polyLine != undefined) polyLine.setMap(null);
                  polyLine = new google.maps.Polyline({
                    path: polyCoordinates,
                    strokeColor: "#FF0000",
                    strokeOpacity: 1.0,
                    strokeWeight: 2
                  });
                  polyLine.setMap(map);
                }
                // Reset Markers to Default
                markers[startPt].setIcon(null);
                markers[endPt].setIcon(null);
                // Reset Variables
                startPt = -1; endPt = -1;
              }
            } else if (mode == 2) {
              if ($.inArray(markers[cnt].getTitle(), buildings) == -1) {
                buildings.push(markers[cnt].getTitle())
              }
            }
          }; 
        })(cnt));
        cnt++;
      }
 
      // Recreate Polyline
      for (var qux in A) {
        for (var bar = 0; bar < A[qux].length; bar++) {
          var coord = qux.toString().replace('(', '');
          coord = coord.replace(')', '');
          var c = coord.split(',');
          var pos = new google.maps.LatLng(c[0], c[1]);
          polyCoordinates.push(pos);
 
          if (polyLine != undefined) polyLine.setMap(null);
          polyLine = new google.maps.Polyline({
            path: polyCoordinates,
            strokeColor: "#FF0000",
            strokeOpacity: 1.0,
            strokeWeight: 2
          });
          polyLine.setMap(map);
        }
      }
 
      $('#returnA').html("Data loaded successfully");
      $('#containerA').show();
    }
  });
  $('#containerA').delay(2000).fadeOut('slow');
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
  if (isset($_POST['func']) && $_POST['func'] == "save") {
    $data = str_replace('\"', '"', $_POST['JSON']);
    $file_name = $_POST['fname'];
    file_put_contents($file_name, $data, LOCK_EX);
    $return['error'] = false;
    $return['msg'] = "Data saved successfully";
 
    echo json_encode($return);
  } elseif (isset($_POST['func']) && $_POST['func'] == "load") {
    $return['error'] = false;
    $return['d'] = file_get_contents($_POST['fname']);
 
    echo json_encode($return);
  }

The final step to getting the site to work was to implement Dijkstra’s Algorithm for shortest path. I used the pseudocode on Wikipedia as a starting point, and implemented it in Javscript.

?View Code JAVASCRIPT
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
function dijkstraPath() {
  var dist = {};
  var previous = {};
 
  for (var key in ptGraph) {
    dist[key] = Infinity;
    previous[key] = undefined;
  }
  dist[startNode] = 0;
  createQ();
  while (Q.length != 0) {
    var u = sortDist(dist);
    if ((dist[u] == Infinity) || (u == endNode) || (u == "")) break;
    removeU(u);
    for (var foo = 0; foo < ptGraph[u].length; foo++) {
      var v = ptGraph[u][foo];
      var alt = dist[u] + distance[u][foo];
      if (alt < dist[v]) {
        dist[v] = alt;
        previous[v] = u;
      }
    }
  }
  var S = [];
  while (previous[u] != undefined) {
    S.push(u);
    u = previous[u];
  }
  S.push(startNode);
  createMarker(startNode); createMarker(endNode);
  polyCoordinates.length = 0;
  for (var bar = 0; bar < S.length; bar++) createLine(S[bar]);
      }
 
function sortDist(dist) {
  var foo = Infinity;
  var ret = "";
  for (var bar = 0; bar < Q.length; bar++) {
    if (dist[Q[bar]] < foo) {
      foo = dist[Q[bar]];
      ret = Q[bar];
    }
  }
  return ret;
}
 
function removeU(u) {
  for (var foo = 0; foo < Q.length; foo++) {
    if (Q[foo] == u) {
      Q.splice(foo, 1);
      break;
    }
  }
}

After getting all of this working, I decided on the name ‘binghamtonumaps.com‘, and set up the site. I quickly realized that in designing the backend code the way I did, this site did not have to be limited to Binghamton University. Rather, any school could be set up as long as it was indexed properly. While the code for setting up the underlying graph made sense to me, I knew that it would need to be more automated if other people were going to be setting up their own schools. At the same time, I realized that binghamtonumaps.com was no longer an appropriate name given the new scope, and moved over to youruniversitymaps.com. Any questions/comments, leave a message below – I’ll save the final version writeup for the next post.

This entry was written by Marc Budofsky , posted on Monday October 03 2011at 03:10 pm , filed under Binghamton University, Javascript, PHP, Programming, Tutorial, Web Design . Bookmark the permalink . Post a comment below or leave a trackback: Trackback URL.

One Response to “Google Maps API, Part 2”

Leave a Reply

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>