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