]> git.openstreetmap.org Git - rails.git/blob - vendor/assets/leaflet/leaflet.polyline.js
Merge remote-tracking branch 'upstream/pull/2839'
[rails.git] / vendor / assets / leaflet / leaflet.polyline.js
1 /*
2  * Utility functions to decode/encode numbers and array's of numbers
3  * to/from strings (Google maps polyline encoding)
4  *
5  * Extends the L.Polyline and L.Polygon object with methods to convert
6  * to and create from these strings.
7  *
8  * Jan Pieter Waagmeester <jieter@jieter.nl>
9  *
10  * Original code from:
11  * http://facstaff.unca.edu/mcmcclur/GoogleMaps/EncodePolyline/
12  * (which is down as of december 2014)
13  */
14
15 (function () {
16     'use strict';
17
18     var defaultOptions = function (options) {
19         if (typeof options === 'number') {
20             // Legacy
21             options = {
22                 precision: options
23             };
24         } else {
25             options = options || {};
26         }
27
28         options.precision = options.precision || 5;
29         options.factor = options.factor || Math.pow(10, options.precision);
30         options.dimension = options.dimension || 2;
31         return options;
32     };
33
34     var PolylineUtil = {
35         encode: function (points, options) {
36             options = defaultOptions(options);
37
38             var flatPoints = [];
39             for (var i = 0, len = points.length; i < len; ++i) {
40                 var point = points[i];
41
42                 if (options.dimension === 2) {
43                     flatPoints.push(point.lat || point[0]);
44                     flatPoints.push(point.lng || point[1]);
45                 } else {
46                     for (var dim = 0; dim < options.dimension; ++dim) {
47                         flatPoints.push(point[dim]);
48                     }
49                 }
50             }
51
52             return this.encodeDeltas(flatPoints, options);
53         },
54
55         decode: function (encoded, options) {
56             options = defaultOptions(options);
57
58             var flatPoints = this.decodeDeltas(encoded, options);
59
60             var points = [];
61             for (var i = 0, len = flatPoints.length; i + (options.dimension - 1) < len;) {
62                 var point = [];
63
64                 for (var dim = 0; dim < options.dimension; ++dim) {
65                     point.push(flatPoints[i++]);
66                 }
67
68                 points.push(point);
69             }
70
71             return points;
72         },
73
74         encodeDeltas: function (numbers, options) {
75             options = defaultOptions(options);
76
77             var lastNumbers = [];
78
79             for (var i = 0, len = numbers.length; i < len;) {
80                 for (var d = 0; d < options.dimension; ++d, ++i) {
81                     var num = numbers[i].toFixed(options.precision);
82                     var delta = num - (lastNumbers[d] || 0);
83                     lastNumbers[d] = num;
84
85                     numbers[i] = delta;
86                 }
87             }
88
89             return this.encodeFloats(numbers, options);
90         },
91
92         decodeDeltas: function (encoded, options) {
93             options = defaultOptions(options);
94
95             var lastNumbers = [];
96
97             var numbers = this.decodeFloats(encoded, options);
98             for (var i = 0, len = numbers.length; i < len;) {
99                 for (var d = 0; d < options.dimension; ++d, ++i) {
100                     numbers[i] = Math.round((lastNumbers[d] = numbers[i] + (lastNumbers[d] || 0)) * options.factor) / options.factor;
101                 }
102             }
103
104             return numbers;
105         },
106
107         encodeFloats: function (numbers, options) {
108             options = defaultOptions(options);
109
110             for (var i = 0, len = numbers.length; i < len; ++i) {
111                 numbers[i] = Math.round(numbers[i] * options.factor);
112             }
113
114             return this.encodeSignedIntegers(numbers);
115         },
116
117         decodeFloats: function (encoded, options) {
118             options = defaultOptions(options);
119
120             var numbers = this.decodeSignedIntegers(encoded);
121             for (var i = 0, len = numbers.length; i < len; ++i) {
122                 numbers[i] /= options.factor;
123             }
124
125             return numbers;
126         },
127
128         encodeSignedIntegers: function (numbers) {
129             for (var i = 0, len = numbers.length; i < len; ++i) {
130                 var num = numbers[i];
131                 numbers[i] = (num < 0) ? ~(num << 1) : (num << 1);
132             }
133
134             return this.encodeUnsignedIntegers(numbers);
135         },
136
137         decodeSignedIntegers: function (encoded) {
138             var numbers = this.decodeUnsignedIntegers(encoded);
139
140             for (var i = 0, len = numbers.length; i < len; ++i) {
141                 var num = numbers[i];
142                 numbers[i] = (num & 1) ? ~(num >> 1) : (num >> 1);
143             }
144
145             return numbers;
146         },
147
148         encodeUnsignedIntegers: function (numbers) {
149             var encoded = '';
150             for (var i = 0, len = numbers.length; i < len; ++i) {
151                 encoded += this.encodeUnsignedInteger(numbers[i]);
152             }
153             return encoded;
154         },
155
156         decodeUnsignedIntegers: function (encoded) {
157             var numbers = [];
158
159             var current = 0;
160             var shift = 0;
161
162             for (var i = 0, len = encoded.length; i < len; ++i) {
163                 var b = encoded.charCodeAt(i) - 63;
164
165                 current |= (b & 0x1f) << shift;
166
167                 if (b < 0x20) {
168                     numbers.push(current);
169                     current = 0;
170                     shift = 0;
171                 } else {
172                     shift += 5;
173                 }
174             }
175
176             return numbers;
177         },
178
179         encodeSignedInteger: function (num) {
180             num = (num < 0) ? ~(num << 1) : (num << 1);
181             return this.encodeUnsignedInteger(num);
182         },
183
184         // This function is very similar to Google's, but I added
185         // some stuff to deal with the double slash issue.
186         encodeUnsignedInteger: function (num) {
187             var value, encoded = '';
188             while (num >= 0x20) {
189                 value = (0x20 | (num & 0x1f)) + 63;
190                 encoded += (String.fromCharCode(value));
191                 num >>= 5;
192             }
193             value = num + 63;
194             encoded += (String.fromCharCode(value));
195
196             return encoded;
197         }
198     };
199
200     // Export Node module
201     if (typeof module === 'object' && typeof module.exports === 'object') {
202         module.exports = PolylineUtil;
203     }
204
205     // Inject functionality into Leaflet
206     if (typeof L === 'object') {
207         if (!(L.Polyline.prototype.fromEncoded)) {
208             L.Polyline.fromEncoded = function (encoded, options) {
209                 return L.polyline(PolylineUtil.decode(encoded), options);
210             };
211         }
212         if (!(L.Polygon.prototype.fromEncoded)) {
213             L.Polygon.fromEncoded = function (encoded, options) {
214                 return L.polygon(PolylineUtil.decode(encoded), options);
215             };
216         }
217
218         var encodeMixin = {
219             encodePath: function () {
220                 return PolylineUtil.encode(this.getLatLngs());
221             }
222         };
223
224         if (!L.Polyline.prototype.encodePath) {
225             L.Polyline.include(encodeMixin);
226         }
227         if (!L.Polygon.prototype.encodePath) {
228             L.Polygon.include(encodeMixin);
229         }
230
231         L.PolylineUtil = PolylineUtil;
232     }
233 })();