//
// Modified version of Google's polyline utility:
// http://code.google.com/apis/maps/documentation/polylineutility.html
//
// adapted to add a text-box to make it easier to encode lots of data in 1 go.
// and slightly improved error messages. assumes firefox with console.log.
//
var points = [];
var marker = null;
var highlighted_marker = null;
var point_markers = [];
// Add a point to the points list.
function addPoint() {
var lat = document.getElementById('txtLatitude').value;
var lng = document.getElementById('txtLongitude').value;
var level = document.getElementById('txtLevel').value;
addThisPoint(lat, lng, level);
}
function addThisPoint(lat, lng, level, recenter) {
if (recenter == null) recenter = false;
var pLat = parseFloat(lat);
if (pLat.toString() != lat) {
console.log( "Warning: '" + pLat.toString() + "' != '" + lat + "'" );
}
if (pLat < -90 || pLat > 90) {
alert('Invalid latitude entered. Must be in range of -90 to 90');
return;
}
var pLong = parseFloat(lng);
if (pLong.toString() != lng) {
console.log( "Warning: '" + pLong.toString() + "' != '" + lng + "'" );
}
if (pLong < -180 || pLong > 180) {
alert('Invalid longitude entered. Must be in range of -180 to 180');
return;
}
var pLevel = parseInt(level);
if (pLevel.toString() != level) {
console.log( "Warning: '" + pLevel.toString() + "' != '" + level + "'" );
//alert('Invalid minimum level entered. Must be in range of 0 to 3');
return;
}
if (pLevel < 0 || pLevel > 17) {
alert('Invalid minimum level entered. Must be in range of 0 to 17');
return;
}
createPoint(lat, lng, pLevel);
createEncodings( recenter );
}
function addPointsList() {
var pointsList = document.getElementById('txtPointsList').value;
var points = pointsList.split( "\n" );
for (i in points) {
var point = points[i].split( "," );
if (point.length >= 2) {
var level = point[2];
if (level == null) level = 3;
var recenter = false;
if (i == 0) recenter = true;
addThisPoint( point[0], point[1], level, recenter );
} else {
console.log( "invalid point: '" + points[i] + "'" );
}
}
return false;
}
// Returns the index of the marker in the polyline.
function findMarkerIndex(point_marker) {
var index = -1;
for (var i = 0; i < point_markers.length; ++i) {
if (point_markers[i] == point_marker) {
index = i;
break;
}
}
return index;
}
// Creates a point and adds it to both the polyline and the list.
function createPoint(lat, lng, pLevel) {
addPointItem(lat, lng, pLevel);
var newPoint = {
Latitude: lat,
Longitude: lng,
Level: pLevel
};
points.push(newPoint);
if (marker) {
document.map.removeOverlay(marker);
marker = null;
}
var point_marker = createPointMarker(new GLatLng(lat, lng), false);
document.map.addOverlay(point_marker);
point_markers.push(point_marker);
}
// Creates a marker representing a point in the polyline.
function createPointMarker(point, highlighted) {
var clr = highlighted ? "yellow" : "blue";
var point_marker = createMarker(point, clr);
point_marker.enableDragging();
GEvent.addListener(point_marker, "drag", function() {
var index = findMarkerIndex(point_marker);
if (index >= 0) {
var nLat = point_marker.getPoint().lat();
var nLng = point_marker.getPoint().lng();
var pLevel = points[index].Level;
var modifiedPoint = {
Latitude: nLat,
Longitude: nLng,
Level: pLevel
};
points[index] = modifiedPoint;
createEncodings(false);
document.getElementById('pointList').options[index]
= new Option('(' + nLat + ',' + nLng + ') Level: ' + pLevel, index);
}
});
GEvent.addListener(point_marker, "click", function() {
highlight(findMarkerIndex(point_marker));
});
return point_marker;
}
// Add an option to the points list with the specified information.
function addPointItem(lat, lng, pLevel) {
var displayPoint = new Option('(' + lat + ',' + lng + ') Level: ' + pLevel,
points.length);
document.getElementById('pointList').options.add(displayPoint);
}
// Highlights the point specified by index in both the map and the point list.
function highlight(index) {
var pointList = document.getElementById('pointList');
if (index < pointList.length) {
pointList.selectedIndex = index;
}
if (point_markers[index] != null
&& point_markers[index] != highlighted_marker) {
document.map.removeOverlay(point_markers[index]);
}
if (highlighted_marker != null) {
var oldIndex = findMarkerIndex(highlighted_marker);
document.map.removeOverlay(highlighted_marker);
if (oldIndex != index) {
point_markers[oldIndex]
= createPointMarker(highlighted_marker.getPoint(), false);
document.map.addOverlay(point_markers[oldIndex]);
}
}
highlighted_marker = createPointMarker(point_markers[index].getPoint(),
true);
point_markers[index] = highlighted_marker;
document.map.addOverlay(highlighted_marker);
}
// Encode a signed number in the encode format.
function encodeSignedNumber(num) {
var sgn_num = num << 1;
if (num < 0) {
sgn_num = ~(sgn_num);
}
return(encodeNumber(sgn_num));
}
// Encode an unsigned number in the encode format.
function encodeNumber(num) {
var encodeString = "";
while (num >= 0x20) {
encodeString += (String.fromCharCode((0x20 | (num & 0x1f)) + 63));
num >>= 5;
}
encodeString += (String.fromCharCode(num + 63));
return encodeString;
}
// Delete *all* the points from the polyline, with confirmation dialog before
// deletion.
function deleteAllPoints() {
var deleteConfirm = confirm("Are you sure you want to remove all the points"
+ " from this polyline?");
if (deleteConfirm) {
document.getElementById('pointList').options.length = 0;
points = [];
deleteAllMarkers();
createEncodings();
}
}
// Deletes all the markers for the points in the polyline
function deleteAllMarkers() {
for(var i = 0; i < point_markers.length; ++i) {
document.map.removeOverlay(point_markers[i]);
}
point_markers = [];
highlighted_marker = null;
}
// Delete a point from the polyline.
function deletePoint() {
if (points.length > 0) {
var point_index = document.getElementById('pointList').selectedIndex;
if (point_index >= 0 && point_index < points.length) {
points.splice(point_index, 1);
if (highlighted_marker == point_markers[point_index]) {
highlighted_marker = null;
}
document.map.removeOverlay(point_markers[point_index]);
point_markers.splice(point_index, 1);
document.getElementById('pointList').options[point_index] = null;
createEncodings();
}
if (points.length > 0) {
if (point_index == 0) {
point_index++;
}
highlight(point_index - 1);
}
}
}
// Try to encode an unsigned number. Used by the documentation.
function tryEncode() {
var txtValue = document.getElementById('txtNumber').value;
if (parseInt(txtValue).toString() == txtValue) {
document.getElementById('cdeValue').innerHTML
= encodeNumber(parseInt(txtValue));
}else{
document.getElementById('cdeValue').innerHTML = '(None)';
}
}
// Try to encode a signed number. Used by the documentation.
function trySignEncode() {
var txtValue = document.getElementById('txtSignNumber').value;
if (parseInt(txtValue).toString() == txtValue) {
document.getElementById('cdeSignValue').innerHTML
= encodeSignedNumber(parseInt(txtValue));
}else{
document.getElementById('cdeSignValue').innerHTML = '(None)';
}
}
// Create the encoded polyline and level strings. If moveMap is true
// move the map to the location of the first point in the polyline.
function createEncodings(moveMap) {
var i = 0;
var plat = 0;
var plng = 0;
var encoded_points = "";
var encoded_levels = "";
for(i = 0; i < points.length; ++i) {
var point = points[i];
var lat = point.Latitude;
var lng = point.Longitude;
var level = point.Level;
var late5 = Math.round(lat * 1e5);
var lnge5 = Math.round(lng * 1e5);
dlat = late5 - plat;
dlng = lnge5 - plng;
plat = late5;
plng = lnge5;
encoded_points += encodeSignedNumber(dlat) + encodeSignedNumber(dlng);
encoded_levels += encodeNumber(level);
}
// move if moveMap is true.
if (moveMap) {
document.map.setCenter(
new GLatLng(points[0].Latitude, points[0].Longitude),
document.map.getZoom());
}
document.getElementById('encodedLevels').value = encoded_levels;
document.getElementById('encodedPolyline').value = encoded_points;
if (document.overlay) {
document.map.removeOverlay(document.overlay);
}
if (points.length > 1) {
document.overlay = GPolyline.fromEncoded({color: "#0000FF",
weight: 10,
points: encoded_points,
zoomFactor: 32,
levels: encoded_levels,
numLevels: 4
});
document.map.addOverlay(document.overlay);
}
}
function centerMap() {
var address = document.getElementById('txtAddress').value;
if (address.length > 0) {
var geocoder = new GClientGeocoder();
geocoder.getLatLng(address,
function(point) {
if (!point) {
alert('Address "' + address + '" not found');
} else {
document.map.setCenter(point, 13);
}
});
}
}
// Decode an encoded polyline into a list of lat/lng tuples.
function decodeLine (encoded) {
var len = encoded.length;
var index = 0;
var array = [];
var lat = 0;
var lng = 0;
while (index < len) {
var b;
var shift = 0;
var result = 0;
do {
b = encoded.charCodeAt(index++) - 63;
result |= (b & 0x1f) << shift;
shift += 5;
} while (b >= 0x20);
var dlat = ((result & 1) ? ~(result >> 1) : (result >> 1));
lat += dlat;
shift = 0;
result = 0;
do {
b = encoded.charCodeAt(index++) - 63;
result |= (b & 0x1f) << shift;
shift += 5;
} while (b >= 0x20);
var dlng = ((result & 1) ? ~(result >> 1) : (result >> 1));
lng += dlng;
array.push([lat * 1e-5, lng * 1e-5]);
}
return array;
}
// Decode an encoded levels string into a list of levels.
function decodeLevels(encoded) {
var levels = [];
for (var pointIndex = 0; pointIndex < encoded.length; ++pointIndex) {
var pointLevel = encoded.charCodeAt(pointIndex) - 63;
levels.push(pointLevel);
}
return levels;
}
// Decode the supplied encoded polyline and levels.
function decode() {
var encoded_points = document.getElementById('encodedPolyline').value;
var encoded_levels = document.getElementById('encodedLevels').value;
if (encoded_points.length==0 || encoded_levels.length==0) {
return;
}
var enc_points = decodeLine(encoded_points);
var enc_levels = decodeLevels(encoded_levels);
if (enc_points.length==0 || enc_levels.length==0) {
return;
}
if (enc_points.length != enc_levels.length) {
alert('Point count and level count do not match');
return;
}
deleteAllMarkers();
document.getElementById('pointList').options.length = 0;
document.getElementById('txtPointsList').value = "";
points = [];
pointsStr = "";
for (var i = 0; i < enc_points.length; ++i) {
createPoint(enc_points[i][0], enc_points[i][1], enc_levels[i]);
pointsStr += enc_points[i][0] + "," + enc_points[i][1] + "," + enc_levels[i] + "\n";
}
document.getElementById('txtPointsList').value = pointsStr;
createEncodings(true);
}
function createMarker(point, color) {
var f = new GIcon();
f.image = "http://labs.google.com/ridefinder/images/mm_20_" + color
+ ".png";
f.shadow = "http://labs.google.com/ridefinder/images/mm_20_shadow.png";
f.iconSize = new GSize(12,20);
f.shadowSize = new GSize(22,20);
f.iconAnchor = new GPoint(6,20);
f.infoWindowAnchor = new GPoint(6,1);
f.infoShadowAnchor = new GPoint(13,13);
newMarker = new GMarker(point,
{icon: f,
draggable: true});
return newMarker;
}
// Create the Google Map to be used.
function createMap() {
if (!GBrowserIsCompatible()) {
alert('Your browser is not compatible with the Google Maps API');
return;
}
document.map = new GMap2(document.getElementById("map_canvas"));
document.map.setCenter(new GLatLng(37.4419, -122.1419), 13);
document.map.addControl(new GSmallMapControl());
document.map.addControl(new GMapTypeControl());
GEvent.addListener(document.map, "click", function(overlay, point) {
document.getElementById('txtLatitude').value = point.y;
document.getElementById('txtLongitude').value = point.x;
if (marker == null) {
marker = createMarker(point, "green");
marker.enableDragging();
GEvent.addListener(marker, "drag", function() {
document.getElementById('txtLatitude').value = marker.getPoint().y;
document.getElementById('txtLongitude').value = marker.getPoint().x;
});
document.map.addOverlay(marker);
} else {
marker.setPoint(point);
}
});
}
// Move the map to the selected point in the point list.
function jumpToPoint() {
var pointList = document.getElementById('pointList');
if (pointList.selectedIndex >= 0) {
var point = points[pointList.selectedIndex];
document.map.setCenter(new GLatLng(point.Latitude, point.Longitude),
document.map.getZoom());
}
}