233 行
		
	
	
	
		
			7 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			233 行
		
	
	
	
		
			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;
 | |
|     }
 | |
| })();
 |