var Codec = { // The algorithm for route encoding can be found here: // http://www.thrall.net/~mking/maps/points.py // I translated it into Javascript. encodePoints : function (locations) { var points = []; var x0 = 0; var y0 = 0; locations = this.map(function (x) { return Math.round(x / 1.0E-5); }, locations); for (var i = 0; i < locations.length / 2; i++) { var y = locations[i << 1]; var dy = y - y0; y0 = y; var f = (Math.abs(dy) << 1) - (dy < 0); while (1) { var e = f & 31; f >>= 5; if (f) e |= 32; points.push(String.fromCharCode(e + 63)); if (f == 0) break; } var x = locations[(i << 1) + 1] var dx = x - x0; x0 = x; f = (Math.abs(dx) << 1) - (dx < 0); while (1) { var e = f & 31; f >>= 5; if (f) e |= 32; points.push(String.fromCharCode(e + 63)); if (f == 0) break; } } return points.join(""); }, decodePoints : function (points) { if (!points) return []; var locations = []; var pb = 0; var Ka = 0; var Pa = 0; while (pb < points.length) { var oc = 0; var Fa = 0; while (1) { var ub = points.charCodeAt(pb) - 63; pb += 1; Fa |= (ub & 31) << oc; oc += 5; if (ub < 32) break; } var i; if (Fa & 1) i = ~(Fa >> 1); else i = Fa >> 1; Ka += i; locations.push(Ka * 1.0E-5); oc = 0; Fa = 0; while (1) { var ub = points.charCodeAt(pb) - 63; pb += 1; Fa |= (ub & 31) << oc; oc += 5; if (ub < 32) break; } if (Fa & 1) i = ~(Fa >> 1); else i = Fa >> 1; Pa += i; locations.push(Pa * 1.0E-5); } return locations; }, map : function (f, a) { var results = []; for(var i = 0; i < a.length; i++) { results[i] = f(a[i]); } return results; } } var map; var routePoints = new Array(0); var total_distance = 0.0; var MILES = { label : "miles", f : function (distance) { return distance / 1609.344; } } var KMS = { label: "km", f : function (distance) { return distance / 1000; } } var unit_handler = KMS; var geocoder = null; function showAddress(address) { if (geocoder) { geocoder.getLatLng(address, function(point) { if (!point) { alert(address + " ei löydy Pompassista."); } else { map.setCenter(point, 13); var marker = new GMarker(point); map.addOverlay(marker); } }); } } function onLoad() { map = new GMap2(document.getElementById("map")); geocoder = new GClientGeocoder(); var url = window.location.href.split("?"); if (url[1]) { initialiseMapFromURL(window.location.href); } else { // Use the default map.setCenter(new GLatLng(60.394183327580706, 25.663204193115234), 15); } map.addControl(new GLargeMapControl()); map.addControl(new GMapTypeControl()); GEvent.addListener(map, "click", function(overlay, point) { if (point) { map.clearOverlays(); routePoints.push(point); map.addOverlay(new GPolyline(routePoints)); // Add a marker at the beginning and the end map.addOverlay(new GMarker(routePoints[0])); if ( routePoints.length > 1 ) { map.addOverlay(new GMarker(routePoints[routePoints.length - 1])); // Re-calculate the distance so far var lastLeg = point.distanceFrom( routePoints[ routePoints.length - 2 ] ); total_distance += lastLeg; updateDisplay(); } } }); } function initialiseMapFromURL(url) { var url = url.split("?"); if (!url[1]) { return null; } var params = new Object(); var queryStr = url[1].split("&"); var pattern = /(\w+)=(.+)/; var result; for (var i = 0; i < queryStr.length; i++) { if ((result = pattern.exec(queryStr[i])) != null) { var param = result[1]; params[param] = decodeURI(result[2]); } } var zoomLevel = parseInt(params.zl); // Determine if this permalink was generated using version 1.0 // of the Google Maps API. if (params.v == null) { zoomLevel = 17 - zoomLevel; } // This MUST be the first call after the map has been initialised map.setCenter(new GLatLng(params.y, params.x), zoomLevel); // Determine the current map type, e.g. map, satellite, hybrid var obj; if (params.type) { switch (params.type) { case "1": map.setMapType(G_NORMAL_MAP); break; case "2": map.setMapType(G_SATELLITE_MAP); break; case "3": map.setMapType(G_HYBRID_MAP); break; default: map.setMapType(G_NORMAL_MAP); } } if (params.path) { // Returns an array of lat/lon pairs [lat1,lon1,lat2,lon2 ...] var path = Codec.decodePoints(params.path); var point; total_distance = 0; for (var i = 0; i < path.length / 2; i++) { point = new GLatLng( path[2*i], path[2*i +1] ); if (i > 0) { // Calculate the length of the route var prev = routePoints[i-1]; total_distance += point.distanceFrom( prev ); } routePoints.push( point ); } map.addOverlay(new GPolyline(routePoints)); // Add the start/end markers map.addOverlay(new GMarker(routePoints[0])); map.addOverlay(new GMarker(routePoints[routePoints.length - 1])); } updateDisplay(); } function updateDisplay () { var dist = unit_handler.f(total_distance); document.getElementById("distance").value = dist.toFixed(2); // Set the label var span = document.getElementById("units"); span.firstChild.nodeValue = unit_handler.label; } function toggleUnits (arg) { if (arg == "MILES") unit_handler = MILES; else if (arg == "KMS") unit_handler = KMS; else // Revert to the default unit_handler = KMS; // Refresh updateDisplay(); } // Generates a unique URL for this route function generatePermalink ( ) { var params = []; // grab whatever the existing URL is var url = window.location.href.split("?")[0]; var zl = map.getZoom(); params.push("zl=" + zl); var center = map.getCenter(); // Ideally we would call these parameters "lat" and "lng" but we have to maintain // backwards compatibility with previously generated permalinks. params.push("x=" + center.lng()); params.push("y=" + center.lat()); var location = []; var pt; for (var i = 0; i < routePoints.length; i++) { pt = routePoints[i]; location.push(pt.y); location.push(pt.x); } params.push("path=" + Codec.encodePoints(location)); var type = map.getCurrentMapType(); // Determine the current map type, e.g. map, satellite, hybrid switch (type) { case G_NORMAL_MAP: t = 1; break; case G_SATELLITE_MAP: t = 2; break; case G_HYBRID_MAP: t = 3; break; default: t = 1; } params.push("type=" + t); params.push("v=2"); url += "?"; url += params.join("&"); return url; } // Clear the last leg function clearLastLeg ( ) { if (routePoints.length < 2) return; var point = routePoints.pop(); map.clearOverlays(); // Re-draw map.addOverlay(new GPolyline(routePoints)); // Add the start/end markers map.addOverlay(new GMarker(routePoints[0])); map.addOverlay(new GMarker(routePoints[routePoints.length - 1])); // Re-calculate the total distance total_distance = total_distance - point.distanceFrom(routePoints[routePoints.length - 1]); updateDisplay(); } // Clears the existing route function clearRoute ( ) { routePoints = []; map.clearOverlays(); total_distance = 0.00; // Refresh the distance field updateDisplay(); } function generateURL ( ) { var url = generatePermalink(); // Reload the document window.location = url; } function generateTinyURL ( ) { document.getElementById("TinyURL").value = generatePermalink(); document.tinyURLform.submit(); }