]> git.openstreetmap.org Git - rails.git/blob - vendor/assets/leaflet/leaflet.polyline.js
Merge branch 'master' into routing
[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 = { precision: options };
22                 } else {
23                         options = options || {};
24                 }
25
26                 options.precision = options.precision || 5;
27                 options.factor = options.factor || Math.pow(10, options.precision);
28                 options.dimension = options.dimension || 2;
29                 return options;
30         };
31
32         var PolylineUtil = {
33                 encode: function (points, options) {
34                         options = defaultOptions(options);
35
36                         var flatPoints = [];
37                         for (var i = 0, len = points.length; i < len; ++i) {
38                                 var point = points[i];
39
40                                 if (options.dimension === 2) {
41                                         flatPoints.push(point.lat || point[0]);
42                                         flatPoints.push(point.lng || point[1]);
43                                 } else {
44                                         for (var dim = 0; dim < options.dimension; ++dim) {
45                                                 flatPoints.push(point[dim]);
46                                         }
47                                 }
48                         }
49
50                         return this.encodeDeltas(flatPoints, options);
51                 },
52
53                 decode: function (encoded, options) {
54                         options = defaultOptions(options);
55
56                         var flatPoints = this.decodeDeltas(encoded, options);
57
58                         var points = [];
59                         for (var i = 0, len = flatPoints.length; i + (options.dimension - 1) < len;) {
60                                 var point = [];
61
62                                 for (var dim = 0; dim < options.dimension; ++dim) {
63                                         point.push(flatPoints[i++]);
64                                 }
65
66                                 points.push(point);
67                         }
68
69                         return points;
70                 },
71
72                 encodeDeltas: function(numbers, options) {
73                         options = defaultOptions(options);
74
75                         var lastNumbers = [];
76
77                         for (var i = 0, len = numbers.length; i < len;) {
78                                 for (var d = 0; d < options.dimension; ++d, ++i) {
79                                         var num = numbers[i];
80                                         var delta = num - (lastNumbers[d] || 0);
81                                         lastNumbers[d] = num;
82
83                                         numbers[i] = delta;
84                                 }
85                         }
86
87                         return this.encodeFloats(numbers, options);
88                 },
89
90                 decodeDeltas: function(encoded, options) {
91                         options = defaultOptions(options);
92
93                         var lastNumbers = [];
94
95                         var numbers = this.decodeFloats(encoded, options);
96                         for (var i = 0, len = numbers.length; i < len;) {
97                                 for (var d = 0; d < options.dimension; ++d, ++i) {
98                                         numbers[i] = lastNumbers[d] = numbers[i] + (lastNumbers[d] || 0);
99                                 }
100                         }
101
102                         return numbers;
103                 },
104
105                 encodeFloats: function(numbers, options) {
106                         options = defaultOptions(options);
107
108                         for (var i = 0, len = numbers.length; i < len; ++i) {
109                                 numbers[i] = Math.round(numbers[i] * options.factor);
110                         }
111
112                         return this.encodeSignedIntegers(numbers);
113                 },
114
115                 decodeFloats: function(encoded, options) {
116                         options = defaultOptions(options);
117
118                         var numbers = this.decodeSignedIntegers(encoded);
119                         for (var i = 0, len = numbers.length; i < len; ++i) {
120                                 numbers[i] /= options.factor;
121                         }
122
123                         return numbers;
124                 },
125
126                 /* jshint bitwise:false */
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                 /* jshint bitwise:true */
200         };
201
202         // Export Node module
203         if (typeof module === 'object' && typeof module.exports === 'object') {
204                 module.exports = PolylineUtil;
205         }
206
207         // Inject functionality into Leaflet
208         if (typeof L === 'object') {
209                 if (!(L.Polyline.prototype.fromEncoded)) {
210                         L.Polyline.fromEncoded = function (encoded, options) {
211                                 return new L.Polyline(PolylineUtil.decode(encoded), options);
212                         };
213                 }
214                 if (!(L.Polygon.prototype.fromEncoded)) {
215                         L.Polygon.fromEncoded = function (encoded, options) {
216                                 return new L.Polygon(PolylineUtil.decode(encoded), options);
217                         };
218                 }
219
220                 var encodeMixin = {
221                         encodePath: function () {
222                                 return PolylineUtil.encode(this.getLatLngs());
223                         }
224                 };
225
226                 if (!L.Polyline.prototype.encodePath) {
227                         L.Polyline.include(encodeMixin);
228                 }
229                 if (!L.Polygon.prototype.encodePath) {
230                         L.Polygon.include(encodeMixin);
231                 }
232
233                 L.PolylineUtil = PolylineUtil;
234         }
235 })();