]> git.openstreetmap.org Git - rails.git/blob - vendor/assets/leaflet/leaflet.polyline.js
Merge remote-tracking branch 'openstreetmap/pull/903'
[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];
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                 /* jshint bitwise:false */
129
130                 encodeSignedIntegers: function(numbers) {
131                         for (var i = 0, len = numbers.length; i < len; ++i) {
132                                 var num = numbers[i];
133                                 numbers[i] = (num < 0) ? ~(num << 1) : (num << 1);
134                         }
135
136                         return this.encodeUnsignedIntegers(numbers);
137                 },
138
139                 decodeSignedIntegers: function(encoded) {
140                         var numbers = this.decodeUnsignedIntegers(encoded);
141
142                         for (var i = 0, len = numbers.length; i < len; ++i) {
143                                 var num = numbers[i];
144                                 numbers[i] = (num & 1) ? ~(num >> 1) : (num >> 1);
145                         }
146
147                         return numbers;
148                 },
149
150                 encodeUnsignedIntegers: function(numbers) {
151                         var encoded = '';
152                         for (var i = 0, len = numbers.length; i < len; ++i) {
153                                 encoded += this.encodeUnsignedInteger(numbers[i]);
154                         }
155                         return encoded;
156                 },
157
158                 decodeUnsignedIntegers: function(encoded) {
159                         var numbers = [];
160
161                         var current = 0;
162                         var shift = 0;
163
164                         for (var i = 0, len = encoded.length; i < len; ++i) {
165                                 var b = encoded.charCodeAt(i) - 63;
166
167                                 current |= (b & 0x1f) << shift;
168
169                                 if (b < 0x20) {
170                                         numbers.push(current);
171                                         current = 0;
172                                         shift = 0;
173                                 } else {
174                                         shift += 5;
175                                 }
176                         }
177
178                         return numbers;
179                 },
180
181                 encodeSignedInteger: function (num) {
182                         num = (num < 0) ? ~(num << 1) : (num << 1);
183                         return this.encodeUnsignedInteger(num);
184                 },
185
186                 // This function is very similar to Google's, but I added
187                 // some stuff to deal with the double slash issue.
188                 encodeUnsignedInteger: function (num) {
189                         var value, encoded = '';
190                         while (num >= 0x20) {
191                                 value = (0x20 | (num & 0x1f)) + 63;
192                                 encoded += (String.fromCharCode(value));
193                                 num >>= 5;
194                         }
195                         value = num + 63;
196                         encoded += (String.fromCharCode(value));
197
198                         return encoded;
199                 }
200
201                 /* jshint bitwise:true */
202         };
203
204         // Export Node module
205         if (typeof module === 'object' && typeof module.exports === 'object') {
206                 module.exports = PolylineUtil;
207         }
208
209         // Inject functionality into Leaflet
210         if (typeof L === 'object') {
211                 if (!(L.Polyline.prototype.fromEncoded)) {
212                         L.Polyline.fromEncoded = function (encoded, options) {
213                                 return new L.Polyline(PolylineUtil.decode(encoded), options);
214                         };
215                 }
216                 if (!(L.Polygon.prototype.fromEncoded)) {
217                         L.Polygon.fromEncoded = function (encoded, options) {
218                                 return new L.Polygon(PolylineUtil.decode(encoded), options);
219                         };
220                 }
221
222                 var encodeMixin = {
223                         encodePath: function () {
224                                 return PolylineUtil.encode(this.getLatLngs());
225                         }
226                 };
227
228                 if (!L.Polyline.prototype.encodePath) {
229                         L.Polyline.include(encodeMixin);
230                 }
231                 if (!L.Polygon.prototype.encodePath) {
232                         L.Polygon.include(encodeMixin);
233                 }
234
235                 L.PolylineUtil = PolylineUtil;
236         }
237 })();