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;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								})();
							 |