首先,引入PolylineEncoder.js
// PolylineEncoder.js copyright Mark McClure April/May 2007
//
// This software is placed explicitly in the public
// domain and may be freely distributed or modified.
// No warranty express or implied is provided.
//
// History:
// V 2.1 July 2007
// Minor modification in distance function to enhance
// speed. Suggested by Joel Rosenberg.
// V 2.0 May 2007.
// Major revisions include:
// Incorporation of Douglas-Peucker algorithm
// Encapsulation into the PolylineEncoder package.
// V 1.0 September 2006
// Original version based on simple vertex reduction
//
// This module defines a PolylineEncoder class to encode
// polylines for use with Google Maps together with a few
// auxiliary functions. Documentation at
// http://facstaff.unca.edu/mcmcclur/GoogleMaps/EncodePolyline/PolylineEncoder.html
//
// Google map reference including encoded polylines:
// http://www.google.com/apis/maps/documentation/
//
// Details on the algorithm used here:
// http://facstaff.unca.edu/mcmcclur/GoogleMaps/EncodePolyline/
//
// Constructor:
// polylineEncoder = new PolylineEncoder(numLevels,
// zoomFactor, verySmall, forceEndpoints?);
// where numLevels and zoomFactor indicate how many
// different levels of magnification the polyline has
// and the change in magnification between those levels,
// verySmall indicates the length of a barely visible
// object at the highest zoom level, forceEndpoints
// indicates whether or not the endpoints should be
// visible at all zoom levels. forceEndpoints is
// optional with a default value of true. Probably
// should stay true regardless.
//
// Main methods:
// * PolylineEncoder.dpEncodeToPolyline(points,
// color?, weight?, opacity?)
// Accepts an array of latLng objects (see below) and
// optional style specifications. Returns an encoded
// polyline that may be directly overlayed on a Google
// Map. Requires that the Google Maps API be loaded.
//
// * PolylineEncoder.dpEncodeToPolygon(pointsArray,
// boundaryColor?, boundaryWeight?, boundaryOpacity?,
// fillColor?, fillOpacity?, fill?, outline?)
// Accepts an array of arrays latLng objects and
// optional style specifications. Returns an encoded
// polylgon that may be directly overlayed on a Google
// Map. Requires that the Google Maps API be loaded.
//
//
// Convenience classes and methods:
// * PolylineEncoder.latLng
// Constructor:
// myLatLng = new PolylineEncoder.latLng(y,x);
// The dpEncode* functions expect points in the
// form of an object with lat and lng methods. A
// GLatLng as defined by the Google Maps API does
// quite nicely. If you're developing a javascript
// without loading the API, however, you can use
// a PolylineEncoder.latLng for this purpose.
// //
// PolylineEncoder.pointsToLatLngs
// Sometimes your points are defined in terms of an
// array of arrays, rather than an array of latLngs.
// PolylineEncoder.pointsToLatLngs converts to an array
// of arrays to an array of latLngs for use by the
// dpEncode functions.
// //
// PolylineEncoder.pointsToGLatLngs
// PolylineEncoder.pointsToGLatLngs is analagous to the
// previous function, but it returns GLatLngs rather
// than PolylineEncoder.latLngs. The first function may
// be used independently of Google Maps. Use the second,
// if you need to use the result in a Goole Map function.
//
//
// Lower level methods
// PolylineEncoder.dpEncodeToJSON(points,
// color?, weight?, opacity?)
// Returns a legal argument to GPolyline.fromEncoded.
// //
// PolylineEncoder.dpEncode(points);
// This is where the real work is done. The return value
// is a JSON object with properties named encodedLevels,
// encdodedPoints and encodedPointsLiteral. These are
// strings which are acceptable input to the points and
// levels properties of the GPolyline.fromEncoded
// function. The encodedPoints string should be used for
// maps generated dynamically, while the
// encodedPointsLiteral string should be copied into a
// static document.
//
// The standard disclaimers, such as "use at your own risk,
// since I really don't have any idea what I'm doing," apply.
// The constructor
PolylineEncoder = function(numLevels, zoomFactor, verySmall, forceEndpoints) {
var i;
if(!numLevels) {
numLevels = 18;
}
if(!zoomFactor) {
zoomFactor = 2;
}
if(!verySmall) {
verySmall = 0.00001;
}
if(!forceEndpoints) {
forceEndpoints = true;
}
this.numLevels = numLevels;
this.zoomFactor = zoomFactor;
this.verySmall = verySmall;
this.forceEndpoints = forceEndpoints;
this.zoomLevelBreaks = new Array(numLevels);
for(i = 0; i < numLevels; i++) {
this.zoomLevelBreaks[i] = verySmall*Math.pow(zoomFactor, numLevels-i-1);
}
}
// The main function. Essentially the Douglas-Peucker
// algorithm, adapted for encoding. Rather than simply
// eliminating points, we record their from the
// segment which occurs at that recursive step. These
// distances are then easily converted to zoom levels.
PolylineEncoder.prototype.dpEncode = function(points) {
var absMaxDist = 0;
var stack = [];
var dists = new Array(points.length);
var maxDist, maxLoc, temp, first, last, current;
var i, encodedPoints, encodedLevels;
var segmentLength;
if(points.length > 2) {
stack.push([0, points.length-1]);
while(stack.length > 0) {
current = stack.pop();
maxDist = 0;
segmentLength = Math.pow(points[current[1]].lat()-points[current[0]].lat(),2) +
Math.pow(points[current[1]].lng()-points[current[0]].lng(),2);
for(i = current[0]+1; i < current[1]; i++) {
temp = this.distance(points[i],
points[current[0]], points[current[1]],
segmentLength);
if(temp > maxDist) {
maxDist = temp;
maxLoc = i;
if(maxDist > absMaxDist) {
absMaxDist = maxDist;
}
}
}
if(maxDist > this.verySmall) {
dists[maxLoc] = maxDist;
stack.push([current[0], maxLoc]);
stack.push([maxLoc, current[1]]);
}
}
}
encodedPoints = this.createEncodings(points, dists);
encodedLevels = this.encodeLevels(points, dists, absMaxDist);
return {
encodedPoints: encodedPoints,
encodedLevels: encodedLevels,
encodedPointsLiteral: encodedPoints.replace(g,"")
}
}
PolylineEncoder.prototype.dpEncodeToJSON = function(points,
color, weight, opacity) {
var result;
if(!opacity) {
opacity = 0.9;
}
if(!weight) {
weight = 3;
}
if(!color) {
color = "#0000ff";
}
result = this.dpEncode(points);
return {
color: color,
weight: weight,
opacity: opacity,
points: result.encodedPoints,
levels: result.encodedLevels,
numLevels: this.numLevels,
zoomFactor: this.zoomFactor
}
}
PolylineEncoder.prototype.dpEncodeToGPolyline = function(points,
color, weight, opacity) {
if(!opacity) {
opacity = 0.9;
}
if(!weight) {
weight = 3;
}
if(!color) {
color = "#0000ff";
}
return new GPolyline.fromEncoded(
this.dpEncodeToJSON(points, color, weight, opacity));
}
PolylineEncoder.prototype.dpEncodeToGPolygon = function(pointsArray,
boundaryColor, boundaryWeight, boundaryOpacity,
fillColor, fillOpacity, fill, outline) {
var i, boundaries;
if(!boundaryColor) {
boundaryColor = "#0000ff";
}
if(!boundaryWeight) {
boundaryWeight = 3;
}
if(!boundaryOpacity) {
boundaryOpacity = 0.9;
}
if(!fillColor) {
fillColor = boundaryColor;
}
if(!fillOpacity) {
fillOpacity = boundaryOpacity/3;
}
if(fill==undefined) {
fill = true;
}
if(outline==undefined) {
outline = true;
}
boundaries = new Array(0);
for(i=0; i<pointsArray.length; i++) {
boundaries.push(this.dpEncodeToJSON(pointsArray[i],
boundaryColor, boundaryWeight, boundaryOpacity));
}
return new GPolygon.fromEncoded({
polylines: boundaries,
color: fillColor,
opacity: fillOpacity,
fill: fill,
outline: outline
});
}
// distance(p0, p1, p2) computes the distance between the point p0
// and the segment [p1,p2]. This could probably be replaced with
// something that is a bit more numerically stable.
PolylineEncoder.prototype.distance = function(p0, p1, p2, segLength) {
var u, out;
if(p1.lat() === p2.lat() && p1.lng() === p2.lng()) {
out = Math.sqrt(Math.pow(p2.lat()-p0.lat(),2) + Math.pow(p2.lng()-p0.lng(),2));
}
else {
u = ((p0.lat()-p1.lat())*(p2.lat()-p1.lat())+(p0.lng()-p1.lng())*(p2.lng()-p1.lng()))/
segLength;
if(u <= 0) {
out = Math.sqrt(Math.pow(p0.lat() - p1.lat(),2) + Math.pow(p0.lng() - p1.lng(),2));
}
if(u >= 1) {
out = Math.sqrt(Math.pow(p0.lat() - p2.lat(),2) + Math.pow(p0.lng() - p2.lng(),2));
}
if(0 < u && u < 1) {
out = Math.sqrt(Math.pow(p0.lat()-p1.lat()-u*(p2.lat()-p1.lat()),2) +
Math.pow(p0.lng()-p1.lng()-u*(p2.lng()-p1.lng()),2));
}
}
return out;
}
// The createEncodings function is very similar to Google's
// http://www.google.com/apis/maps/documentation/polyline.js
// The key difference is that not all points are encoded,
// since some were eliminated by Douglas-Peucker.
PolylineEncoder.prototype.createEncodings = function(points, dists) {
var i, dlat, dlng;
var plat = 0;
var plng = 0;
var encoded_points = "";
for(i = 0; i < points.length; i++) {
if(dists[i] != undefined || i == 0 || i == points.length-1) {
var point = points[i];
var lat = point.lat();
var lng = point.lng();
var late5 = Math.floor(lat * 1e5);
var lnge5 = Math.floor(lng * 1e5);
dlat = late5 - plat;
dlng = lnge5 - plng;
plat = late5;
plng = lnge5;
encoded_points += this.encodeSignedNumber(dlat) +
this.encodeSignedNumber(dlng);
}
}
return encoded_points;
}
// This computes the appropriate zoom level of a point in terms of it's
// distance from the relevant segment in the DP algorithm. Could be done
// in terms of a logarithm, but this approach makes it a bit easier to
// ensure that the level is not too large.
PolylineEncoder.prototype.computeLevel = function(dd) {
var lev;
if(dd > this.verySmall) {
lev=0;
while(dd < this.zoomLevelBreaks[lev]) {
lev++;
}
return lev;
}
}
// Now we can use the previous function to march down the list
// of points and encode the levels. Like createEncodings, we
// ignore points whose distance (in dists) is undefined.
PolylineEncoder.prototype.encodeLevels = function(points, dists, absMaxDist) {
var i;
var encoded_levels = "";
if(this.forceEndpoints) {
encoded_levels += this.encodeNumber(this.numLevels-1)
} else {
encoded_levels += this.encodeNumber(
this.numLevels-this.computeLevel(absMaxDist)-1)
}
for(i=1; i < points.length-1; i++) {
if(dists[i] != undefined) {
encoded_levels += this.encodeNumber(
this.numLevels-this.computeLevel(dists[i])-1);
}
}
if(this.forceEndpoints) {
encoded_levels += this.encodeNumber(this.numLevels-1)
} else {
encoded_levels += this.encodeNumber(
this.numLevels-this.computeLevel(absMaxDist)-1)
}
return encoded_levels;
}
// This function is very similar to Google's, but I added
// some stuff to deal with the double slash issue.
PolylineEncoder.prototype.encodeNumber = function(num) {
var encodeString = "";
var nextValue, finalValue;
while (num >= 0x20) {
nextValue = (0x20 | (num & 0x1f)) + 63;
// if (nextValue == 92) {
// encodeString += (String.fromCharCode(nextValue));
// }
encodeString += (String.fromCharCode(nextValue));
num >>= 5;
}
finalValue = num + 63;
// if (finalValue == 92) {
// encodeString += (String.fromCharCode(finalValue));
// }
encodeString += (String.fromCharCode(finalValue));
return encodeString;
}
// This one is Google's verbatim.
PolylineEncoder.prototype.encodeSignedNumber = function(num) {
var sgn_num = num << 1;
if (num < 0) {
sgn_num = ~(sgn_num);
}
return(this.encodeNumber(sgn_num));
}
// The remaining code defines a few convenience utilities.
// PolylineEncoder.latLng
PolylineEncoder.latLng = function(y, x) {
this.y = y;
this.x = x;
}
PolylineEncoder.latLng.prototype.lat = function() {
return this.y;
}
PolylineEncoder.latLng.prototype.lng = function() {
return this.x;
}
// PolylineEncoder.pointsToLatLngs
PolylineEncoder.pointsToLatLngs = function(points) {
var i, latLngs;
latLngs = new Array(0);
for(i=0; i<points.length; i++) {
latLngs.push(new PolylineEncoder.latLng(points[i][0], points[i][1]));
}
return latLngs;
}
// PolylineEncoder.pointsToGLatLngs
PolylineEncoder.pointsToGLatLngs = function(points) {
var i, gLatLngs;
gLatLngs = new Array(0);
for(i=0; i<points.length; i++) {
gLatLngs.push(new GLatLng(points[i][0], points[i][1]));
}
return gLatLngs;
}
然後根據你所求出的所有點的坐标
var count = trackList.length; //坐标點的個數
var points = new Array(0);
var polylineEncoder = new PolylineEncoder(); //定義編碼對象
for ( var j = 0; j < count; j++) {
var track = trackList[j];
points[j] = new GLatLng(parseFloat(trackList[j].lat),parseFloat(trackList[j].lng)); //得到坐标點數組
}
polyline = polylineEncoder.dpEncodeToGPolyline(points,'#ff0000',2,0.5); //根據 PolylineEncoder.js自動json編碼
map.addOverlay(polyline); //地圖上添加折線 一次性畫出所有折線