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.
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.
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.
[...] RSS Feed « Google Maps API, Part 2 [...]