234 行
		
	
	
	
		
			7 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
		
		
			
		
	
	
			234 行
		
	
	
	
		
			7 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
|  | /* | ||
|  |  * Utility functions to decode/encode numbers and array's of numbers | ||
|  |  * to/from strings (Google maps polyline encoding) | ||
|  |  * | ||
|  |  * Extends the L.Polyline and L.Polygon object with methods to convert | ||
|  |  * to and create from these strings. | ||
|  |  * | ||
|  |  * Jan Pieter Waagmeester <jieter@jieter.nl> | ||
|  |  * | ||
|  |  * Original code from: | ||
|  |  * http://facstaff.unca.edu/mcmcclur/GoogleMaps/EncodePolyline/
 | ||
|  |  * (which is down as of december 2014) | ||
|  |  */ | ||
|  | 
 | ||
|  | (function () { | ||
|  |     'use strict'; | ||
|  | 
 | ||
|  |     var defaultOptions = function (options) { | ||
|  |         if (typeof options === 'number') { | ||
|  |             // Legacy
 | ||
|  |             options = { | ||
|  |                 precision: options | ||
|  |             }; | ||
|  |         } else { | ||
|  |             options = options || {}; | ||
|  |         } | ||
|  | 
 | ||
|  |         options.precision = options.precision || 5; | ||
|  |         options.factor = options.factor || Math.pow(10, options.precision); | ||
|  |         options.dimension = options.dimension || 2; | ||
|  |         return options; | ||
|  |     }; | ||
|  | 
 | ||
|  |     var PolylineUtil = { | ||
|  |         encode: function (points, options) { | ||
|  |             options = defaultOptions(options); | ||
|  | 
 | ||
|  |             var flatPoints = []; | ||
|  |             for (var i = 0, len = points.length; i < len; ++i) { | ||
|  |                 var point = points[i]; | ||
|  | 
 | ||
|  |                 if (options.dimension === 2) { | ||
|  |                     flatPoints.push(point.lat || point[0]); | ||
|  |                     flatPoints.push(point.lng || point[1]); | ||
|  |                 } else { | ||
|  |                     for (var dim = 0; dim < options.dimension; ++dim) { | ||
|  |                         flatPoints.push(point[dim]); | ||
|  |                     } | ||
|  |                 } | ||
|  |             } | ||
|  | 
 | ||
|  |             return this.encodeDeltas(flatPoints, options); | ||
|  |         }, | ||
|  | 
 | ||
|  |         decode: function (encoded, options) { | ||
|  |             options = defaultOptions(options); | ||
|  | 
 | ||
|  |             var flatPoints = this.decodeDeltas(encoded, options); | ||
|  | 
 | ||
|  |             var points = []; | ||
|  |             for (var i = 0, len = flatPoints.length; i + (options.dimension - 1) < len;) { | ||
|  |                 var point = []; | ||
|  | 
 | ||
|  |                 for (var dim = 0; dim < options.dimension; ++dim) { | ||
|  |                     point.push(flatPoints[i++]); | ||
|  |                 } | ||
|  | 
 | ||
|  |                 points.push(point); | ||
|  |             } | ||
|  | 
 | ||
|  |             return points; | ||
|  |         }, | ||
|  | 
 | ||
|  |         encodeDeltas: function (numbers, options) { | ||
|  |             options = defaultOptions(options); | ||
|  | 
 | ||
|  |             var lastNumbers = []; | ||
|  | 
 | ||
|  |             for (var i = 0, len = numbers.length; i < len;) { | ||
|  |                 for (var d = 0; d < options.dimension; ++d, ++i) { | ||
|  |                     var num = numbers[i].toFixed(options.precision); | ||
|  |                     var delta = num - (lastNumbers[d] || 0); | ||
|  |                     lastNumbers[d] = num; | ||
|  | 
 | ||
|  |                     numbers[i] = delta; | ||
|  |                 } | ||
|  |             } | ||
|  | 
 | ||
|  |             return this.encodeFloats(numbers, options); | ||
|  |         }, | ||
|  | 
 | ||
|  |         decodeDeltas: function (encoded, options) { | ||
|  |             options = defaultOptions(options); | ||
|  | 
 | ||
|  |             var lastNumbers = []; | ||
|  | 
 | ||
|  |             var numbers = this.decodeFloats(encoded, options); | ||
|  |             for (var i = 0, len = numbers.length; i < len;) { | ||
|  |                 for (var d = 0; d < options.dimension; ++d, ++i) { | ||
|  |                     numbers[i] = Math.round((lastNumbers[d] = numbers[i] + (lastNumbers[d] || 0)) * options.factor) / options.factor; | ||
|  |                 } | ||
|  |             } | ||
|  | 
 | ||
|  |             return numbers; | ||
|  |         }, | ||
|  | 
 | ||
|  |         encodeFloats: function (numbers, options) { | ||
|  |             options = defaultOptions(options); | ||
|  | 
 | ||
|  |             for (var i = 0, len = numbers.length; i < len; ++i) { | ||
|  |                 numbers[i] = Math.round(numbers[i] * options.factor); | ||
|  |             } | ||
|  | 
 | ||
|  |             return this.encodeSignedIntegers(numbers); | ||
|  |         }, | ||
|  | 
 | ||
|  |         decodeFloats: function (encoded, options) { | ||
|  |             options = defaultOptions(options); | ||
|  | 
 | ||
|  |             var numbers = this.decodeSignedIntegers(encoded); | ||
|  |             for (var i = 0, len = numbers.length; i < len; ++i) { | ||
|  |                 numbers[i] /= options.factor; | ||
|  |             } | ||
|  | 
 | ||
|  |             return numbers; | ||
|  |         }, | ||
|  | 
 | ||
|  |         encodeSignedIntegers: function (numbers) { | ||
|  |             for (var i = 0, len = numbers.length; i < len; ++i) { | ||
|  |                 var num = numbers[i]; | ||
|  |                 numbers[i] = (num < 0) ? ~(num << 1) : (num << 1); | ||
|  |             } | ||
|  | 
 | ||
|  |             return this.encodeUnsignedIntegers(numbers); | ||
|  |         }, | ||
|  | 
 | ||
|  |         decodeSignedIntegers: function (encoded) { | ||
|  |             var numbers = this.decodeUnsignedIntegers(encoded); | ||
|  | 
 | ||
|  |             for (var i = 0, len = numbers.length; i < len; ++i) { | ||
|  |                 var num = numbers[i]; | ||
|  |                 numbers[i] = (num & 1) ? ~(num >> 1) : (num >> 1); | ||
|  |             } | ||
|  | 
 | ||
|  |             return numbers; | ||
|  |         }, | ||
|  | 
 | ||
|  |         encodeUnsignedIntegers: function (numbers) { | ||
|  |             var encoded = ''; | ||
|  |             for (var i = 0, len = numbers.length; i < len; ++i) { | ||
|  |                 encoded += this.encodeUnsignedInteger(numbers[i]); | ||
|  |             } | ||
|  |             return encoded; | ||
|  |         }, | ||
|  | 
 | ||
|  |         decodeUnsignedIntegers: function (encoded) { | ||
|  |             var numbers = []; | ||
|  | 
 | ||
|  |             var current = 0; | ||
|  |             var shift = 0; | ||
|  | 
 | ||
|  |             for (var i = 0, len = encoded.length; i < len; ++i) { | ||
|  |                 var b = encoded.charCodeAt(i) - 63; | ||
|  | 
 | ||
|  |                 current |= (b & 0x1f) << shift; | ||
|  | 
 | ||
|  |                 if (b < 0x20) { | ||
|  |                     numbers.push(current); | ||
|  |                     current = 0; | ||
|  |                     shift = 0; | ||
|  |                 } else { | ||
|  |                     shift += 5; | ||
|  |                 } | ||
|  |             } | ||
|  | 
 | ||
|  |             return numbers; | ||
|  |         }, | ||
|  | 
 | ||
|  |         encodeSignedInteger: function (num) { | ||
|  |             num = (num < 0) ? ~(num << 1) : (num << 1); | ||
|  |             return this.encodeUnsignedInteger(num); | ||
|  |         }, | ||
|  | 
 | ||
|  |         // This function is very similar to Google's, but I added
 | ||
|  |         // some stuff to deal with the double slash issue.
 | ||
|  |         encodeUnsignedInteger: function (num) { | ||
|  |             var value, encoded = ''; | ||
|  |             while (num >= 0x20) { | ||
|  |                 value = (0x20 | (num & 0x1f)) + 63; | ||
|  |                 encoded += (String.fromCharCode(value)); | ||
|  |                 num >>= 5; | ||
|  |             } | ||
|  |             value = num + 63; | ||
|  |             encoded += (String.fromCharCode(value)); | ||
|  | 
 | ||
|  |             return encoded; | ||
|  |         } | ||
|  |     }; | ||
|  | 
 | ||
|  |     // Export Node module
 | ||
|  |     if (typeof module === 'object' && typeof module.exports === 'object') { | ||
|  |         module.exports = PolylineUtil; | ||
|  |     } | ||
|  | 
 | ||
|  |     // Inject functionality into Leaflet
 | ||
|  |     if (typeof L === 'object') { | ||
|  |         if (!(L.Polyline.prototype.fromEncoded)) { | ||
|  |             L.Polyline.fromEncoded = function (encoded, options) { | ||
|  |                 return L.polyline(PolylineUtil.decode(encoded), options); | ||
|  |             }; | ||
|  |         } | ||
|  |         if (!(L.Polygon.prototype.fromEncoded)) { | ||
|  |             L.Polygon.fromEncoded = function (encoded, options) { | ||
|  |                 return L.polygon(PolylineUtil.decode(encoded), options); | ||
|  |             }; | ||
|  |         } | ||
|  | 
 | ||
|  |         var encodeMixin = { | ||
|  |             encodePath: function () { | ||
|  |                 return PolylineUtil.encode(this.getLatLngs()); | ||
|  |             } | ||
|  |         }; | ||
|  | 
 | ||
|  |         if (!L.Polyline.prototype.encodePath) { | ||
|  |             L.Polyline.include(encodeMixin); | ||
|  |         } | ||
|  |         if (!L.Polygon.prototype.encodePath) { | ||
|  |             L.Polygon.include(encodeMixin); | ||
|  |         } | ||
|  | 
 | ||
|  |         L.PolylineUtil = PolylineUtil; | ||
|  |     } | ||
|  | })(); |