Commit 15167bf3d4eb6b85d6e9f6dbe032ff1fd87e58a8
Merge branch 'master' of http://service.routetopa.eu:7480/WebCompDev/COMPONENTS
Showing
16 changed files
with
9923 additions
and
5 deletions
controllets/data-table-controllet/data-table-controllet.html
... | ... | @@ -335,13 +335,14 @@ |
335 | 335 | |
336 | 336 | this._resize(); |
337 | 337 | |
338 | - this.$.tooltip_wornings.show(); | |
338 | + this.async(function() { | |
339 | + this.$.tooltip_wornings.show(); | |
340 | + }, 100); | |
339 | 341 | }, |
340 | 342 | |
341 | 343 | reset : function(){ |
342 | 344 | this.setData([]); |
343 | 345 | $(this.$.tbody).animate({ scrollTop: 0}, 0); |
344 | -// this.filter = ""; | |
345 | 346 | }, |
346 | 347 | |
347 | 348 | _onPrevClick : function(){ |
... | ... | @@ -478,7 +479,7 @@ |
478 | 479 | var w = $(this.$.data_table_container).width(); |
479 | 480 | $(this.$.tbody).width(w).height(h); |
480 | 481 | $(this.$.tbody).perfectScrollbar('update'); |
481 | - }, 1); | |
482 | + }, 0); | |
482 | 483 | } |
483 | 484 | |
484 | 485 | }); | ... | ... |
controllets/select-visualization-controllet/select-datalet-inputs.html
... | ... | @@ -276,7 +276,11 @@ |
276 | 276 | |
277 | 277 | setInputs : function(inputs) { |
278 | 278 | var temp = this._copy(inputs); |
279 | - if (inputs.constructor != Array) {//table --> 1 input | |
279 | + if (inputs.constructor != Array && inputs.name == "GEOJSON") { | |
280 | + temp = []; | |
281 | + temp.push(inputs); | |
282 | + } | |
283 | + else if (inputs.constructor != Array) {//table --> 1 input | |
280 | 284 | var name = inputs.name; |
281 | 285 | var description = inputs.description; |
282 | 286 | var selection = inputs.selection; | ... | ... |
datalets/base-ajax-json-alasql-datalet/base-ajax-json-alasql-datalet.html
... | ... | @@ -34,7 +34,7 @@ |
34 | 34 | <script type="text/javascript" src="../../alasql-utility/alasql.min.js"></script> |
35 | 35 | <script type="text/javascript" src="../../alasql-utility/alasql-utility.js"></script> |
36 | 36 | |
37 | -<script type="text/javascript" src="../../bower_components/JSDataChecker/jsdatachecker.min.js"></script> | |
37 | +<script type="text/javascript" src="../../bower_components/jsdatachecker/jsdatachecker.min.js"></script> | |
38 | 38 | |
39 | 39 | <!-- |
40 | 40 | The `base-ajax-json-jsonpath-datalet` extend the base component and define the mechanism to access and select data. | ... | ... |
datalets/leafletjs-geojson-datalet/demo/index.html
0 โ 100755
1 | +<!DOCTYPE html> | |
2 | +<html lang="en"> | |
3 | +<head> | |
4 | + <meta charset="UTF-8"> | |
5 | + <title></title> | |
6 | + | |
7 | + <script> | |
8 | + </script> | |
9 | + | |
10 | +</head> | |
11 | +<body> | |
12 | + | |
13 | +<script src="https://code.jquery.com/jquery-2.1.4.min.js" type="text/javascript"></script> | |
14 | +<link rel="import" href="../leafletjs-datalet.html" /> | |
15 | + | |
16 | +<leafletjs-datalet data-url="http://ckan.routetopa.eu/api/action/datastore_search?resource_id=73e02092-85a1-434e-85fe-0c9a43aa9a52&limit=10000" | |
17 | + fields='["result,records,Lat","result,records,Lng", "result,records,Link"]'></leafletjs-datalet> | |
18 | + | |
19 | + | |
20 | +</body> | |
21 | +</html> | |
0 | 22 | \ No newline at end of file | ... | ... |
datalets/leafletjs-geojson-datalet/docs.html
0 โ 100755
1 | +<!DOCTYPE html> | |
2 | +<html lang="en"> | |
3 | +<head> | |
4 | + <link rel="import" href="../../bower_components/iron-component-page/iron-component-page.html"> | |
5 | + <meta charset="UTF-8"> | |
6 | +</head> | |
7 | +<body> | |
8 | + | |
9 | +<iron-component-page src="leafletjs-datalet.html"></iron-component-page> | |
10 | + | |
11 | +</body> | |
12 | +</html> | |
0 | 13 | \ No newline at end of file | ... | ... |
datalets/leafletjs-geojson-datalet/leafletjs-geojson-datalet.html
0 โ 100755
1 | +<!-- | |
2 | +@license | |
3 | + The MIT License (MIT) | |
4 | + | |
5 | + Copyright (c) 2015 Dipartimento di Informatica - Universitร di Salerno - Italy | |
6 | + | |
7 | + Permission is hereby granted, free of charge, to any person obtaining a copy | |
8 | + of this software and associated documentation files (the "Software"), to deal | |
9 | + in the Software without restriction, including without limitation the rights | |
10 | + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
11 | + copies of the Software, and to permit persons to whom the Software is | |
12 | + furnished to do so, subject to the following conditions: | |
13 | + | |
14 | + The above copyright notice and this permission notice shall be included in | |
15 | + all copies or substantial portions of the Software. | |
16 | + | |
17 | + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
18 | + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
19 | + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
20 | + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
21 | + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
22 | + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
23 | + THE SOFTWARE. | |
24 | +--> | |
25 | + | |
26 | +<!-- | |
27 | +* Developed by : | |
28 | +* ROUTE-TO-PA Project - grant No 645860. - www.routetopa.eu | |
29 | +* | |
30 | +--> | |
31 | + | |
32 | +<link rel="import" href="../base-ajax-json-alasql-datalet/base-ajax-json-alasql-datalet.html"> | |
33 | + | |
34 | +<!-- | |
35 | + | |
36 | +`leafletjs-datalet` is a map datalet based on open source project leafletjs <http://leafletjs.com/> | |
37 | + | |
38 | +Example: | |
39 | + | |
40 | + <leafletjs-datalet | |
41 | + data-url="http://ckan.routetopa.eu/api/action/datastore_search?resource_id=#" | |
42 | + fields='["field1","field2"]'> | |
43 | + </leafletjs-datalet> | |
44 | + | |
45 | +@element leafletjs-datalet | |
46 | +@status v0.1 | |
47 | +@demo demo/index.html | |
48 | +@group datalets | |
49 | +--> | |
50 | + | |
51 | +<dom-module name="leafletjs-geojson-datalet"> | |
52 | + <template> | |
53 | + <link rel="stylesheet" href="leafletsjs/leaflet.css" /> | |
54 | + <style> | |
55 | + #leafletjs {height: 600px;} | |
56 | + </style> | |
57 | + | |
58 | + <div id="leafletjs"></div> | |
59 | + <base-ajax-json-alasql-datalet data-url="{{dataUrl}}" fields="{{fields}}" data="{{data}}" title="{{title}}" description="{{description}}" export_menu="{{export_menu}}"></base-ajax-json-alasql-datalet> | |
60 | + | |
61 | + </template> | |
62 | + | |
63 | + <script src="leafletsjs/leaflet.js"></script> | |
64 | + | |
65 | + <script> | |
66 | + | |
67 | + var leafletjsBehavior = { | |
68 | + | |
69 | + /** | |
70 | + * Read markers coordinates from the data object and add the marker to the map. | |
71 | + * Call a method for the map redraw and set the viewport in order to fit all the markers in the viewport.. | |
72 | + * | |
73 | + * @method transformData | |
74 | + */ | |
75 | + presentData: function(){ | |
76 | + | |
77 | + var t = this; | |
78 | + try{ | |
79 | + this._component.map = L.map(this._component.$.leafletjs).setView([0, 0], 13, {reset:true}); | |
80 | + }catch(e){} | |
81 | + | |
82 | + | |
83 | + L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { | |
84 | + maxZoom: 18, | |
85 | + attribution: 'Map data ยฉ <a href="http://openstreetmap.org">OpenStreetMap</a> contributors' | |
86 | + }).addTo(this._component.map); | |
87 | + | |
88 | + | |
89 | + L.Icon.Default.imagePath = 'http://services.routetopa.eu/DEEalerProvider/COMPONENTS/datalets/leafletjs-datalet/leafletsjs/images'; | |
90 | + | |
91 | + var coordinates = []; | |
92 | + var coordinates_index = 0; | |
93 | + var isArray = t.data[0].data[0].constructor === Array; | |
94 | + | |
95 | + for(var i=0; i<t.data[0].data.length; i++) | |
96 | + { | |
97 | + if(isArray) | |
98 | + { | |
99 | + if(!isNaN(t.data[0].data[i][0]) && !isNaN(t.data[0].data[i][1])) | |
100 | + coordinates.push([parseFloat(t.data[0].data[i][0]), parseFloat(t.data[0].data[i][1])]); | |
101 | + else | |
102 | + continue; | |
103 | + } | |
104 | + else | |
105 | + { | |
106 | + if(!isNaN(t.data[0].data[i]) && !isNaN(t.data[1].data[i])) | |
107 | + coordinates.push([parseFloat(t.data[0].data[i]), parseFloat(t.data[1].data[i])]); | |
108 | + else | |
109 | + continue; | |
110 | + } | |
111 | + | |
112 | + var marker = L.marker([coordinates[coordinates_index][0], coordinates[coordinates_index][1]]).addTo(t._component.map); | |
113 | + coordinates_index++; | |
114 | + | |
115 | + if(t.data.length > 2) | |
116 | + { | |
117 | + var popupText = ""; | |
118 | + for(var j=2; j<t.data.length; j++) | |
119 | + { | |
120 | + if(typeof t.data[j] != 'undefined' && typeof t.data[j].data[i] != 'undefined') | |
121 | + { | |
122 | + if (t.data[j].data[i].toString().match(new RegExp("^(http[s]?:\\/\\/(www\\.)?|ftp:\\/\\/(www\\.)?|www\\.){1}([0-9A-Za-z-\\.@:%_\+~#=]+)+((\\.[a-zA-Z]{2,3})+)(/(.)*)?(\\?(.)*)?"))) | |
123 | + popupText += '<image height="100" width="100" src="' + t.data[j].data[i] + '" /><br/>'; | |
124 | + else | |
125 | + popupText += '<span>' + t.data[j].name + ' : ' + t.data[j].data[i] + '</span><br/>' | |
126 | + } | |
127 | + } | |
128 | + | |
129 | + var popup = L.popup().setContent(popupText); | |
130 | + marker.bindPopup(popup); | |
131 | + } | |
132 | + } | |
133 | + | |
134 | + t._component.map._onResize(); | |
135 | + t._component.map.invalidateSize(false); | |
136 | + t._component.map.fitBounds(coordinates); | |
137 | + | |
138 | + } | |
139 | + }; | |
140 | + | |
141 | + | |
142 | + Polymer({ | |
143 | + | |
144 | + is : 'leafletjs-geojson-datalet', | |
145 | + | |
146 | + properties : { | |
147 | + /** | |
148 | + * Store a reference to the leafletjs map object created in 'ready' callback | |
149 | + * @attribute map | |
150 | + * @type Object | |
151 | + */ | |
152 | + map : | |
153 | + { | |
154 | + type: Object, | |
155 | + value:null | |
156 | + }, | |
157 | + /** | |
158 | + * An Array with all the markers extracted from the dataset | |
159 | + * @attribute markers | |
160 | + * @type Array | |
161 | + */ | |
162 | + markers : | |
163 | + { | |
164 | + type : Array, | |
165 | + value : [] | |
166 | + }, | |
167 | + /** | |
168 | + * It's the component behavior | |
169 | + * | |
170 | + * @attribute behavior | |
171 | + * @type Object | |
172 | + * @default {} | |
173 | + */ | |
174 | + behavior : { | |
175 | + type : Object, | |
176 | + value : {} | |
177 | + }, | |
178 | + /** | |
179 | + * Control the export menu | |
180 | + * xxxx BITMASK. FROM RIGHT : HTML, PNG, RTF, MY SPACE (eg. 1111 show all, 0000 hide all) | |
181 | + * | |
182 | + * @attribute export_menu | |
183 | + * @type Number | |
184 | + * @default 15 | |
185 | + */ | |
186 | + export_menu : { | |
187 | + type : Number, | |
188 | + value : 9 // xxxx BITMASK. FROM RIGHT : HTML, PNG, RTF, MY SPACE (eg. 1111 show all, 0000 hide all) | |
189 | + } | |
190 | + }, | |
191 | + | |
192 | + /** | |
193 | + * 'ready' callback create the map object, set the tileLayer to openstreetmap and the default icon image path. | |
194 | + * Moreover extend the leafletjsComponentBehavior with BaseDataletBehavior, WorkcycleBehavior and leafletjsBehavior | |
195 | + * and run the Datalet workcycle. | |
196 | + * | |
197 | + * @method ready | |
198 | + */ | |
199 | + ready: function(){ | |
200 | + this.behavior = $.extend(true, {}, BaseDataletBehavior, WorkcycleBehavior, AjaxJsonAlasqlBehavior, leafletjsBehavior); | |
201 | + this.async(function(){this.behavior.init(this)},100); | |
202 | + } | |
203 | + }); | |
204 | + </script> | |
205 | +</dom-module> | |
206 | + | ... | ... |
datalets/leafletjs-geojson-datalet/leafletjs-geojson-datalet.png
0 โ 100644
5.32 KB
datalets/leafletjs-geojson-datalet/leafletsjs/images/layers-2x.png
0 โ 100755
2.83 KB
datalets/leafletjs-geojson-datalet/leafletsjs/images/layers.png
0 โ 100755
1.47 KB
datalets/leafletjs-geojson-datalet/leafletsjs/images/marker-icon-2x.png
0 โ 100755
3.94 KB
datalets/leafletjs-geojson-datalet/leafletsjs/images/marker-icon.png
0 โ 100755
1.71 KB
datalets/leafletjs-geojson-datalet/leafletsjs/images/marker-shadow.png
0 โ 100755
797 Bytes
datalets/leafletjs-geojson-datalet/leafletsjs/leaflet-src.js
0 โ 100755
Changes suppressed. Click to show
1 | +/* | |
2 | + Leaflet, a JavaScript library for mobile-friendly interactive maps. http://leafletjs.com | |
3 | + (c) 2010-2013, Vladimir Agafonkin | |
4 | + (c) 2010-2011, CloudMade | |
5 | +*/ | |
6 | +(function (window, document, undefined) { | |
7 | +var oldL = window.L, | |
8 | + L = {}; | |
9 | + | |
10 | +L.version = '0.7.3'; | |
11 | + | |
12 | +// define Leaflet for Node module pattern loaders, including Browserify | |
13 | +if (typeof module === 'object' && typeof module.exports === 'object') { | |
14 | + module.exports = L; | |
15 | + | |
16 | +// define Leaflet as an AMD module | |
17 | +} else if (typeof define === 'function' && define.amd) { | |
18 | + define(L); | |
19 | +} | |
20 | + | |
21 | +// define Leaflet as a global L variable, saving the original L to restore later if needed | |
22 | + | |
23 | +L.noConflict = function () { | |
24 | + window.L = oldL; | |
25 | + return this; | |
26 | +}; | |
27 | + | |
28 | +window.L = L; | |
29 | + | |
30 | + | |
31 | +/* | |
32 | + * L.Util contains various utility functions used throughout Leaflet code. | |
33 | + */ | |
34 | + | |
35 | +L.Util = { | |
36 | + extend: function (dest) { // (Object[, Object, ...]) -> | |
37 | + var sources = Array.prototype.slice.call(arguments, 1), | |
38 | + i, j, len, src; | |
39 | + | |
40 | + for (j = 0, len = sources.length; j < len; j++) { | |
41 | + src = sources[j] || {}; | |
42 | + for (i in src) { | |
43 | + if (src.hasOwnProperty(i)) { | |
44 | + dest[i] = src[i]; | |
45 | + } | |
46 | + } | |
47 | + } | |
48 | + return dest; | |
49 | + }, | |
50 | + | |
51 | + bind: function (fn, obj) { // (Function, Object) -> Function | |
52 | + var args = arguments.length > 2 ? Array.prototype.slice.call(arguments, 2) : null; | |
53 | + return function () { | |
54 | + return fn.apply(obj, args || arguments); | |
55 | + }; | |
56 | + }, | |
57 | + | |
58 | + stamp: (function () { | |
59 | + var lastId = 0, | |
60 | + key = '_leaflet_id'; | |
61 | + return function (obj) { | |
62 | + obj[key] = obj[key] || ++lastId; | |
63 | + return obj[key]; | |
64 | + }; | |
65 | + }()), | |
66 | + | |
67 | + invokeEach: function (obj, method, context) { | |
68 | + var i, args; | |
69 | + | |
70 | + if (typeof obj === 'object') { | |
71 | + args = Array.prototype.slice.call(arguments, 3); | |
72 | + | |
73 | + for (i in obj) { | |
74 | + method.apply(context, [i, obj[i]].concat(args)); | |
75 | + } | |
76 | + return true; | |
77 | + } | |
78 | + | |
79 | + return false; | |
80 | + }, | |
81 | + | |
82 | + limitExecByInterval: function (fn, time, context) { | |
83 | + var lock, execOnUnlock; | |
84 | + | |
85 | + return function wrapperFn() { | |
86 | + var args = arguments; | |
87 | + | |
88 | + if (lock) { | |
89 | + execOnUnlock = true; | |
90 | + return; | |
91 | + } | |
92 | + | |
93 | + lock = true; | |
94 | + | |
95 | + setTimeout(function () { | |
96 | + lock = false; | |
97 | + | |
98 | + if (execOnUnlock) { | |
99 | + wrapperFn.apply(context, args); | |
100 | + execOnUnlock = false; | |
101 | + } | |
102 | + }, time); | |
103 | + | |
104 | + fn.apply(context, args); | |
105 | + }; | |
106 | + }, | |
107 | + | |
108 | + falseFn: function () { | |
109 | + return false; | |
110 | + }, | |
111 | + | |
112 | + formatNum: function (num, digits) { | |
113 | + var pow = Math.pow(10, digits || 5); | |
114 | + return Math.round(num * pow) / pow; | |
115 | + }, | |
116 | + | |
117 | + trim: function (str) { | |
118 | + return str.trim ? str.trim() : str.replace(/^\s+|\s+$/g, ''); | |
119 | + }, | |
120 | + | |
121 | + splitWords: function (str) { | |
122 | + return L.Util.trim(str).split(/\s+/); | |
123 | + }, | |
124 | + | |
125 | + setOptions: function (obj, options) { | |
126 | + obj.options = L.extend({}, obj.options, options); | |
127 | + return obj.options; | |
128 | + }, | |
129 | + | |
130 | + getParamString: function (obj, existingUrl, uppercase) { | |
131 | + var params = []; | |
132 | + for (var i in obj) { | |
133 | + params.push(encodeURIComponent(uppercase ? i.toUpperCase() : i) + '=' + encodeURIComponent(obj[i])); | |
134 | + } | |
135 | + return ((!existingUrl || existingUrl.indexOf('?') === -1) ? '?' : '&') + params.join('&'); | |
136 | + }, | |
137 | + template: function (str, data) { | |
138 | + return str.replace(/\{ *([\w_]+) *\}/g, function (str, key) { | |
139 | + var value = data[key]; | |
140 | + if (value === undefined) { | |
141 | + throw new Error('No value provided for variable ' + str); | |
142 | + } else if (typeof value === 'function') { | |
143 | + value = value(data); | |
144 | + } | |
145 | + return value; | |
146 | + }); | |
147 | + }, | |
148 | + | |
149 | + isArray: Array.isArray || function (obj) { | |
150 | + return (Object.prototype.toString.call(obj) === '[object Array]'); | |
151 | + }, | |
152 | + | |
153 | + emptyImageUrl: 'data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=' | |
154 | +}; | |
155 | + | |
156 | +(function () { | |
157 | + | |
158 | + // inspired by http://paulirish.com/2011/requestanimationframe-for-smart-animating/ | |
159 | + | |
160 | + function getPrefixed(name) { | |
161 | + var i, fn, | |
162 | + prefixes = ['webkit', 'moz', 'o', 'ms']; | |
163 | + | |
164 | + for (i = 0; i < prefixes.length && !fn; i++) { | |
165 | + fn = window[prefixes[i] + name]; | |
166 | + } | |
167 | + | |
168 | + return fn; | |
169 | + } | |
170 | + | |
171 | + var lastTime = 0; | |
172 | + | |
173 | + function timeoutDefer(fn) { | |
174 | + var time = +new Date(), | |
175 | + timeToCall = Math.max(0, 16 - (time - lastTime)); | |
176 | + | |
177 | + lastTime = time + timeToCall; | |
178 | + return window.setTimeout(fn, timeToCall); | |
179 | + } | |
180 | + | |
181 | + var requestFn = window.requestAnimationFrame || | |
182 | + getPrefixed('RequestAnimationFrame') || timeoutDefer; | |
183 | + | |
184 | + var cancelFn = window.cancelAnimationFrame || | |
185 | + getPrefixed('CancelAnimationFrame') || | |
186 | + getPrefixed('CancelRequestAnimationFrame') || | |
187 | + function (id) { window.clearTimeout(id); }; | |
188 | + | |
189 | + | |
190 | + L.Util.requestAnimFrame = function (fn, context, immediate, element) { | |
191 | + fn = L.bind(fn, context); | |
192 | + | |
193 | + if (immediate && requestFn === timeoutDefer) { | |
194 | + fn(); | |
195 | + } else { | |
196 | + return requestFn.call(window, fn, element); | |
197 | + } | |
198 | + }; | |
199 | + | |
200 | + L.Util.cancelAnimFrame = function (id) { | |
201 | + if (id) { | |
202 | + cancelFn.call(window, id); | |
203 | + } | |
204 | + }; | |
205 | + | |
206 | +}()); | |
207 | + | |
208 | +// shortcuts for most used utility functions | |
209 | +L.extend = L.Util.extend; | |
210 | +L.bind = L.Util.bind; | |
211 | +L.stamp = L.Util.stamp; | |
212 | +L.setOptions = L.Util.setOptions; | |
213 | + | |
214 | + | |
215 | +/* | |
216 | + * L.Class powers the OOP facilities of the library. | |
217 | + * Thanks to John Resig and Dean Edwards for inspiration! | |
218 | + */ | |
219 | + | |
220 | +L.Class = function () {}; | |
221 | + | |
222 | +L.Class.extend = function (props) { | |
223 | + | |
224 | + // extended class with the new prototype | |
225 | + var NewClass = function () { | |
226 | + | |
227 | + // call the constructor | |
228 | + if (this.initialize) { | |
229 | + this.initialize.apply(this, arguments); | |
230 | + } | |
231 | + | |
232 | + // call all constructor hooks | |
233 | + if (this._initHooks) { | |
234 | + this.callInitHooks(); | |
235 | + } | |
236 | + }; | |
237 | + | |
238 | + // instantiate class without calling constructor | |
239 | + var F = function () {}; | |
240 | + F.prototype = this.prototype; | |
241 | + | |
242 | + var proto = new F(); | |
243 | + proto.constructor = NewClass; | |
244 | + | |
245 | + NewClass.prototype = proto; | |
246 | + | |
247 | + //inherit parent's statics | |
248 | + for (var i in this) { | |
249 | + if (this.hasOwnProperty(i) && i !== 'prototype') { | |
250 | + NewClass[i] = this[i]; | |
251 | + } | |
252 | + } | |
253 | + | |
254 | + // mix static properties into the class | |
255 | + if (props.statics) { | |
256 | + L.extend(NewClass, props.statics); | |
257 | + delete props.statics; | |
258 | + } | |
259 | + | |
260 | + // mix includes into the prototype | |
261 | + if (props.includes) { | |
262 | + L.Util.extend.apply(null, [proto].concat(props.includes)); | |
263 | + delete props.includes; | |
264 | + } | |
265 | + | |
266 | + // merge options | |
267 | + if (props.options && proto.options) { | |
268 | + props.options = L.extend({}, proto.options, props.options); | |
269 | + } | |
270 | + | |
271 | + // mix given properties into the prototype | |
272 | + L.extend(proto, props); | |
273 | + | |
274 | + proto._initHooks = []; | |
275 | + | |
276 | + var parent = this; | |
277 | + // jshint camelcase: false | |
278 | + NewClass.__super__ = parent.prototype; | |
279 | + | |
280 | + // add method for calling all hooks | |
281 | + proto.callInitHooks = function () { | |
282 | + | |
283 | + if (this._initHooksCalled) { return; } | |
284 | + | |
285 | + if (parent.prototype.callInitHooks) { | |
286 | + parent.prototype.callInitHooks.call(this); | |
287 | + } | |
288 | + | |
289 | + this._initHooksCalled = true; | |
290 | + | |
291 | + for (var i = 0, len = proto._initHooks.length; i < len; i++) { | |
292 | + proto._initHooks[i].call(this); | |
293 | + } | |
294 | + }; | |
295 | + | |
296 | + return NewClass; | |
297 | +}; | |
298 | + | |
299 | + | |
300 | +// method for adding properties to prototype | |
301 | +L.Class.include = function (props) { | |
302 | + L.extend(this.prototype, props); | |
303 | +}; | |
304 | + | |
305 | +// merge new default options to the Class | |
306 | +L.Class.mergeOptions = function (options) { | |
307 | + L.extend(this.prototype.options, options); | |
308 | +}; | |
309 | + | |
310 | +// add a constructor hook | |
311 | +L.Class.addInitHook = function (fn) { // (Function) || (String, args...) | |
312 | + var args = Array.prototype.slice.call(arguments, 1); | |
313 | + | |
314 | + var init = typeof fn === 'function' ? fn : function () { | |
315 | + this[fn].apply(this, args); | |
316 | + }; | |
317 | + | |
318 | + this.prototype._initHooks = this.prototype._initHooks || []; | |
319 | + this.prototype._initHooks.push(init); | |
320 | +}; | |
321 | + | |
322 | + | |
323 | +/* | |
324 | + * L.Mixin.Events is used to add custom events functionality to Leaflet classes. | |
325 | + */ | |
326 | + | |
327 | +var eventsKey = '_leaflet_events'; | |
328 | + | |
329 | +L.Mixin = {}; | |
330 | + | |
331 | +L.Mixin.Events = { | |
332 | + | |
333 | + addEventListener: function (types, fn, context) { // (String, Function[, Object]) or (Object[, Object]) | |
334 | + | |
335 | + // types can be a map of types/handlers | |
336 | + if (L.Util.invokeEach(types, this.addEventListener, this, fn, context)) { return this; } | |
337 | + | |
338 | + var events = this[eventsKey] = this[eventsKey] || {}, | |
339 | + contextId = context && context !== this && L.stamp(context), | |
340 | + i, len, event, type, indexKey, indexLenKey, typeIndex; | |
341 | + | |
342 | + // types can be a string of space-separated words | |
343 | + types = L.Util.splitWords(types); | |
344 | + | |
345 | + for (i = 0, len = types.length; i < len; i++) { | |
346 | + event = { | |
347 | + action: fn, | |
348 | + context: context || this | |
349 | + }; | |
350 | + type = types[i]; | |
351 | + | |
352 | + if (contextId) { | |
353 | + // store listeners of a particular context in a separate hash (if it has an id) | |
354 | + // gives a major performance boost when removing thousands of map layers | |
355 | + | |
356 | + indexKey = type + '_idx'; | |
357 | + indexLenKey = indexKey + '_len'; | |
358 | + | |
359 | + typeIndex = events[indexKey] = events[indexKey] || {}; | |
360 | + | |
361 | + if (!typeIndex[contextId]) { | |
362 | + typeIndex[contextId] = []; | |
363 | + | |
364 | + // keep track of the number of keys in the index to quickly check if it's empty | |
365 | + events[indexLenKey] = (events[indexLenKey] || 0) + 1; | |
366 | + } | |
367 | + | |
368 | + typeIndex[contextId].push(event); | |
369 | + | |
370 | + | |
371 | + } else { | |
372 | + events[type] = events[type] || []; | |
373 | + events[type].push(event); | |
374 | + } | |
375 | + } | |
376 | + | |
377 | + return this; | |
378 | + }, | |
379 | + | |
380 | + hasEventListeners: function (type) { // (String) -> Boolean | |
381 | + var events = this[eventsKey]; | |
382 | + return !!events && ((type in events && events[type].length > 0) || | |
383 | + (type + '_idx' in events && events[type + '_idx_len'] > 0)); | |
384 | + }, | |
385 | + | |
386 | + removeEventListener: function (types, fn, context) { // ([String, Function, Object]) or (Object[, Object]) | |
387 | + | |
388 | + if (!this[eventsKey]) { | |
389 | + return this; | |
390 | + } | |
391 | + | |
392 | + if (!types) { | |
393 | + return this.clearAllEventListeners(); | |
394 | + } | |
395 | + | |
396 | + if (L.Util.invokeEach(types, this.removeEventListener, this, fn, context)) { return this; } | |
397 | + | |
398 | + var events = this[eventsKey], | |
399 | + contextId = context && context !== this && L.stamp(context), | |
400 | + i, len, type, listeners, j, indexKey, indexLenKey, typeIndex, removed; | |
401 | + | |
402 | + types = L.Util.splitWords(types); | |
403 | + | |
404 | + for (i = 0, len = types.length; i < len; i++) { | |
405 | + type = types[i]; | |
406 | + indexKey = type + '_idx'; | |
407 | + indexLenKey = indexKey + '_len'; | |
408 | + | |
409 | + typeIndex = events[indexKey]; | |
410 | + | |
411 | + if (!fn) { | |
412 | + // clear all listeners for a type if function isn't specified | |
413 | + delete events[type]; | |
414 | + delete events[indexKey]; | |
415 | + delete events[indexLenKey]; | |
416 | + | |
417 | + } else { | |
418 | + listeners = contextId && typeIndex ? typeIndex[contextId] : events[type]; | |
419 | + | |
420 | + if (listeners) { | |
421 | + for (j = listeners.length - 1; j >= 0; j--) { | |
422 | + if ((listeners[j].action === fn) && (!context || (listeners[j].context === context))) { | |
423 | + removed = listeners.splice(j, 1); | |
424 | + // set the old action to a no-op, because it is possible | |
425 | + // that the listener is being iterated over as part of a dispatch | |
426 | + removed[0].action = L.Util.falseFn; | |
427 | + } | |
428 | + } | |
429 | + | |
430 | + if (context && typeIndex && (listeners.length === 0)) { | |
431 | + delete typeIndex[contextId]; | |
432 | + events[indexLenKey]--; | |
433 | + } | |
434 | + } | |
435 | + } | |
436 | + } | |
437 | + | |
438 | + return this; | |
439 | + }, | |
440 | + | |
441 | + clearAllEventListeners: function () { | |
442 | + delete this[eventsKey]; | |
443 | + return this; | |
444 | + }, | |
445 | + | |
446 | + fireEvent: function (type, data) { // (String[, Object]) | |
447 | + if (!this.hasEventListeners(type)) { | |
448 | + return this; | |
449 | + } | |
450 | + | |
451 | + var event = L.Util.extend({}, data, { type: type, target: this }); | |
452 | + | |
453 | + var events = this[eventsKey], | |
454 | + listeners, i, len, typeIndex, contextId; | |
455 | + | |
456 | + if (events[type]) { | |
457 | + // make sure adding/removing listeners inside other listeners won't cause infinite loop | |
458 | + listeners = events[type].slice(); | |
459 | + | |
460 | + for (i = 0, len = listeners.length; i < len; i++) { | |
461 | + listeners[i].action.call(listeners[i].context, event); | |
462 | + } | |
463 | + } | |
464 | + | |
465 | + // fire event for the context-indexed listeners as well | |
466 | + typeIndex = events[type + '_idx']; | |
467 | + | |
468 | + for (contextId in typeIndex) { | |
469 | + listeners = typeIndex[contextId].slice(); | |
470 | + | |
471 | + if (listeners) { | |
472 | + for (i = 0, len = listeners.length; i < len; i++) { | |
473 | + listeners[i].action.call(listeners[i].context, event); | |
474 | + } | |
475 | + } | |
476 | + } | |
477 | + | |
478 | + return this; | |
479 | + }, | |
480 | + | |
481 | + addOneTimeEventListener: function (types, fn, context) { | |
482 | + | |
483 | + if (L.Util.invokeEach(types, this.addOneTimeEventListener, this, fn, context)) { return this; } | |
484 | + | |
485 | + var handler = L.bind(function () { | |
486 | + this | |
487 | + .removeEventListener(types, fn, context) | |
488 | + .removeEventListener(types, handler, context); | |
489 | + }, this); | |
490 | + | |
491 | + return this | |
492 | + .addEventListener(types, fn, context) | |
493 | + .addEventListener(types, handler, context); | |
494 | + } | |
495 | +}; | |
496 | + | |
497 | +L.Mixin.Events.on = L.Mixin.Events.addEventListener; | |
498 | +L.Mixin.Events.off = L.Mixin.Events.removeEventListener; | |
499 | +L.Mixin.Events.once = L.Mixin.Events.addOneTimeEventListener; | |
500 | +L.Mixin.Events.fire = L.Mixin.Events.fireEvent; | |
501 | + | |
502 | + | |
503 | +/* | |
504 | + * L.Browser handles different browser and feature detections for internal Leaflet use. | |
505 | + */ | |
506 | + | |
507 | +(function () { | |
508 | + | |
509 | + var ie = 'ActiveXObject' in window, | |
510 | + ielt9 = ie && !document.addEventListener, | |
511 | + | |
512 | + // terrible browser detection to work around Safari / iOS / Android browser bugs | |
513 | + ua = navigator.userAgent.toLowerCase(), | |
514 | + webkit = ua.indexOf('webkit') !== -1, | |
515 | + chrome = ua.indexOf('chrome') !== -1, | |
516 | + phantomjs = ua.indexOf('phantom') !== -1, | |
517 | + android = ua.indexOf('android') !== -1, | |
518 | + android23 = ua.search('android [23]') !== -1, | |
519 | + gecko = ua.indexOf('gecko') !== -1, | |
520 | + | |
521 | + mobile = typeof orientation !== undefined + '', | |
522 | + msPointer = window.navigator && window.navigator.msPointerEnabled && | |
523 | + window.navigator.msMaxTouchPoints && !window.PointerEvent, | |
524 | + pointer = (window.PointerEvent && window.navigator.pointerEnabled && window.navigator.maxTouchPoints) || | |
525 | + msPointer, | |
526 | + retina = ('devicePixelRatio' in window && window.devicePixelRatio > 1) || | |
527 | + ('matchMedia' in window && window.matchMedia('(min-resolution:144dpi)') && | |
528 | + window.matchMedia('(min-resolution:144dpi)').matches), | |
529 | + | |
530 | + doc = document.documentElement, | |
531 | + ie3d = ie && ('transition' in doc.style), | |
532 | + webkit3d = ('WebKitCSSMatrix' in window) && ('m11' in new window.WebKitCSSMatrix()) && !android23, | |
533 | + gecko3d = 'MozPerspective' in doc.style, | |
534 | + opera3d = 'OTransition' in doc.style, | |
535 | + any3d = !window.L_DISABLE_3D && (ie3d || webkit3d || gecko3d || opera3d) && !phantomjs; | |
536 | + | |
537 | + | |
538 | + // PhantomJS has 'ontouchstart' in document.documentElement, but doesn't actually support touch. | |
539 | + // https://github.com/Leaflet/Leaflet/pull/1434#issuecomment-13843151 | |
540 | + | |
541 | + var touch = !window.L_NO_TOUCH && !phantomjs && (function () { | |
542 | + | |
543 | + var startName = 'ontouchstart'; | |
544 | + | |
545 | + // IE10+ (We simulate these into touch* events in L.DomEvent and L.DomEvent.Pointer) or WebKit, etc. | |
546 | + if (pointer || (startName in doc)) { | |
547 | + return true; | |
548 | + } | |
549 | + | |
550 | + // Firefox/Gecko | |
551 | + var div = document.createElement('div'), | |
552 | + supported = false; | |
553 | + | |
554 | + if (!div.setAttribute) { | |
555 | + return false; | |
556 | + } | |
557 | + div.setAttribute(startName, 'return;'); | |
558 | + | |
559 | + if (typeof div[startName] === 'function') { | |
560 | + supported = true; | |
561 | + } | |
562 | + | |
563 | + div.removeAttribute(startName); | |
564 | + div = null; | |
565 | + | |
566 | + return supported; | |
567 | + }()); | |
568 | + | |
569 | + | |
570 | + L.Browser = { | |
571 | + ie: ie, | |
572 | + ielt9: ielt9, | |
573 | + webkit: webkit, | |
574 | + gecko: gecko && !webkit && !window.opera && !ie, | |
575 | + | |
576 | + android: android, | |
577 | + android23: android23, | |
578 | + | |
579 | + chrome: chrome, | |
580 | + | |
581 | + ie3d: ie3d, | |
582 | + webkit3d: webkit3d, | |
583 | + gecko3d: gecko3d, | |
584 | + opera3d: opera3d, | |
585 | + any3d: any3d, | |
586 | + | |
587 | + mobile: mobile, | |
588 | + mobileWebkit: mobile && webkit, | |
589 | + mobileWebkit3d: mobile && webkit3d, | |
590 | + mobileOpera: mobile && window.opera, | |
591 | + | |
592 | + touch: touch, | |
593 | + msPointer: msPointer, | |
594 | + pointer: pointer, | |
595 | + | |
596 | + retina: retina | |
597 | + }; | |
598 | + | |
599 | +}()); | |
600 | + | |
601 | + | |
602 | +/* | |
603 | + * L.Point represents a point with x and y coordinates. | |
604 | + */ | |
605 | + | |
606 | +L.Point = function (/*Number*/ x, /*Number*/ y, /*Boolean*/ round) { | |
607 | + this.x = (round ? Math.round(x) : x); | |
608 | + this.y = (round ? Math.round(y) : y); | |
609 | +}; | |
610 | + | |
611 | +L.Point.prototype = { | |
612 | + | |
613 | + clone: function () { | |
614 | + return new L.Point(this.x, this.y); | |
615 | + }, | |
616 | + | |
617 | + // non-destructive, returns a new point | |
618 | + add: function (point) { | |
619 | + return this.clone()._add(L.point(point)); | |
620 | + }, | |
621 | + | |
622 | + // destructive, used directly for performance in situations where it's safe to modify existing point | |
623 | + _add: function (point) { | |
624 | + this.x += point.x; | |
625 | + this.y += point.y; | |
626 | + return this; | |
627 | + }, | |
628 | + | |
629 | + subtract: function (point) { | |
630 | + return this.clone()._subtract(L.point(point)); | |
631 | + }, | |
632 | + | |
633 | + _subtract: function (point) { | |
634 | + this.x -= point.x; | |
635 | + this.y -= point.y; | |
636 | + return this; | |
637 | + }, | |
638 | + | |
639 | + divideBy: function (num) { | |
640 | + return this.clone()._divideBy(num); | |
641 | + }, | |
642 | + | |
643 | + _divideBy: function (num) { | |
644 | + this.x /= num; | |
645 | + this.y /= num; | |
646 | + return this; | |
647 | + }, | |
648 | + | |
649 | + multiplyBy: function (num) { | |
650 | + return this.clone()._multiplyBy(num); | |
651 | + }, | |
652 | + | |
653 | + _multiplyBy: function (num) { | |
654 | + this.x *= num; | |
655 | + this.y *= num; | |
656 | + return this; | |
657 | + }, | |
658 | + | |
659 | + round: function () { | |
660 | + return this.clone()._round(); | |
661 | + }, | |
662 | + | |
663 | + _round: function () { | |
664 | + this.x = Math.round(this.x); | |
665 | + this.y = Math.round(this.y); | |
666 | + return this; | |
667 | + }, | |
668 | + | |
669 | + floor: function () { | |
670 | + return this.clone()._floor(); | |
671 | + }, | |
672 | + | |
673 | + _floor: function () { | |
674 | + this.x = Math.floor(this.x); | |
675 | + this.y = Math.floor(this.y); | |
676 | + return this; | |
677 | + }, | |
678 | + | |
679 | + distanceTo: function (point) { | |
680 | + point = L.point(point); | |
681 | + | |
682 | + var x = point.x - this.x, | |
683 | + y = point.y - this.y; | |
684 | + | |
685 | + return Math.sqrt(x * x + y * y); | |
686 | + }, | |
687 | + | |
688 | + equals: function (point) { | |
689 | + point = L.point(point); | |
690 | + | |
691 | + return point.x === this.x && | |
692 | + point.y === this.y; | |
693 | + }, | |
694 | + | |
695 | + contains: function (point) { | |
696 | + point = L.point(point); | |
697 | + | |
698 | + return Math.abs(point.x) <= Math.abs(this.x) && | |
699 | + Math.abs(point.y) <= Math.abs(this.y); | |
700 | + }, | |
701 | + | |
702 | + toString: function () { | |
703 | + return 'Point(' + | |
704 | + L.Util.formatNum(this.x) + ', ' + | |
705 | + L.Util.formatNum(this.y) + ')'; | |
706 | + } | |
707 | +}; | |
708 | + | |
709 | +L.point = function (x, y, round) { | |
710 | + if (x instanceof L.Point) { | |
711 | + return x; | |
712 | + } | |
713 | + if (L.Util.isArray(x)) { | |
714 | + return new L.Point(x[0], x[1]); | |
715 | + } | |
716 | + if (x === undefined || x === null) { | |
717 | + return x; | |
718 | + } | |
719 | + return new L.Point(x, y, round); | |
720 | +}; | |
721 | + | |
722 | + | |
723 | +/* | |
724 | + * L.Bounds represents a rectangular area on the screen in pixel coordinates. | |
725 | + */ | |
726 | + | |
727 | +L.Bounds = function (a, b) { //(Point, Point) or Point[] | |
728 | + if (!a) { return; } | |
729 | + | |
730 | + var points = b ? [a, b] : a; | |
731 | + | |
732 | + for (var i = 0, len = points.length; i < len; i++) { | |
733 | + this.extend(points[i]); | |
734 | + } | |
735 | +}; | |
736 | + | |
737 | +L.Bounds.prototype = { | |
738 | + // extend the bounds to contain the given point | |
739 | + extend: function (point) { // (Point) | |
740 | + point = L.point(point); | |
741 | + | |
742 | + if (!this.min && !this.max) { | |
743 | + this.min = point.clone(); | |
744 | + this.max = point.clone(); | |
745 | + } else { | |
746 | + this.min.x = Math.min(point.x, this.min.x); | |
747 | + this.max.x = Math.max(point.x, this.max.x); | |
748 | + this.min.y = Math.min(point.y, this.min.y); | |
749 | + this.max.y = Math.max(point.y, this.max.y); | |
750 | + } | |
751 | + return this; | |
752 | + }, | |
753 | + | |
754 | + getCenter: function (round) { // (Boolean) -> Point | |
755 | + return new L.Point( | |
756 | + (this.min.x + this.max.x) / 2, | |
757 | + (this.min.y + this.max.y) / 2, round); | |
758 | + }, | |
759 | + | |
760 | + getBottomLeft: function () { // -> Point | |
761 | + return new L.Point(this.min.x, this.max.y); | |
762 | + }, | |
763 | + | |
764 | + getTopRight: function () { // -> Point | |
765 | + return new L.Point(this.max.x, this.min.y); | |
766 | + }, | |
767 | + | |
768 | + getSize: function () { | |
769 | + return this.max.subtract(this.min); | |
770 | + }, | |
771 | + | |
772 | + contains: function (obj) { // (Bounds) or (Point) -> Boolean | |
773 | + var min, max; | |
774 | + | |
775 | + if (typeof obj[0] === 'number' || obj instanceof L.Point) { | |
776 | + obj = L.point(obj); | |
777 | + } else { | |
778 | + obj = L.bounds(obj); | |
779 | + } | |
780 | + | |
781 | + if (obj instanceof L.Bounds) { | |
782 | + min = obj.min; | |
783 | + max = obj.max; | |
784 | + } else { | |
785 | + min = max = obj; | |
786 | + } | |
787 | + | |
788 | + return (min.x >= this.min.x) && | |
789 | + (max.x <= this.max.x) && | |
790 | + (min.y >= this.min.y) && | |
791 | + (max.y <= this.max.y); | |
792 | + }, | |
793 | + | |
794 | + intersects: function (bounds) { // (Bounds) -> Boolean | |
795 | + bounds = L.bounds(bounds); | |
796 | + | |
797 | + var min = this.min, | |
798 | + max = this.max, | |
799 | + min2 = bounds.min, | |
800 | + max2 = bounds.max, | |
801 | + xIntersects = (max2.x >= min.x) && (min2.x <= max.x), | |
802 | + yIntersects = (max2.y >= min.y) && (min2.y <= max.y); | |
803 | + | |
804 | + return xIntersects && yIntersects; | |
805 | + }, | |
806 | + | |
807 | + isValid: function () { | |
808 | + return !!(this.min && this.max); | |
809 | + } | |
810 | +}; | |
811 | + | |
812 | +L.bounds = function (a, b) { // (Bounds) or (Point, Point) or (Point[]) | |
813 | + if (!a || a instanceof L.Bounds) { | |
814 | + return a; | |
815 | + } | |
816 | + return new L.Bounds(a, b); | |
817 | +}; | |
818 | + | |
819 | + | |
820 | +/* | |
821 | + * L.Transformation is an utility class to perform simple point transformations through a 2d-matrix. | |
822 | + */ | |
823 | + | |
824 | +L.Transformation = function (a, b, c, d) { | |
825 | + this._a = a; | |
826 | + this._b = b; | |
827 | + this._c = c; | |
828 | + this._d = d; | |
829 | +}; | |
830 | + | |
831 | +L.Transformation.prototype = { | |
832 | + transform: function (point, scale) { // (Point, Number) -> Point | |
833 | + return this._transform(point.clone(), scale); | |
834 | + }, | |
835 | + | |
836 | + // destructive transform (faster) | |
837 | + _transform: function (point, scale) { | |
838 | + scale = scale || 1; | |
839 | + point.x = scale * (this._a * point.x + this._b); | |
840 | + point.y = scale * (this._c * point.y + this._d); | |
841 | + return point; | |
842 | + }, | |
843 | + | |
844 | + untransform: function (point, scale) { | |
845 | + scale = scale || 1; | |
846 | + return new L.Point( | |
847 | + (point.x / scale - this._b) / this._a, | |
848 | + (point.y / scale - this._d) / this._c); | |
849 | + } | |
850 | +}; | |
851 | + | |
852 | + | |
853 | +/* | |
854 | + * L.DomUtil contains various utility functions for working with DOM. | |
855 | + */ | |
856 | + | |
857 | +L.DomUtil = { | |
858 | + get: function (id) { | |
859 | + return (typeof id === 'string' ? document.getElementById(id) : id); | |
860 | + }, | |
861 | + | |
862 | + getStyle: function (el, style) { | |
863 | + | |
864 | + var value = el.style[style]; | |
865 | + | |
866 | + if (!value && el.currentStyle) { | |
867 | + value = el.currentStyle[style]; | |
868 | + } | |
869 | + | |
870 | + if ((!value || value === 'auto') && document.defaultView) { | |
871 | + var css = document.defaultView.getComputedStyle(el, null); | |
872 | + value = css ? css[style] : null; | |
873 | + } | |
874 | + | |
875 | + return value === 'auto' ? null : value; | |
876 | + }, | |
877 | + | |
878 | + getViewportOffset: function (element) { | |
879 | + | |
880 | + var top = 0, | |
881 | + left = 0, | |
882 | + el = element, | |
883 | + docBody = document.body, | |
884 | + docEl = document.documentElement, | |
885 | + pos; | |
886 | + | |
887 | + do { | |
888 | + top += el.offsetTop || 0; | |
889 | + left += el.offsetLeft || 0; | |
890 | + | |
891 | + //add borders | |
892 | + top += parseInt(L.DomUtil.getStyle(el, 'borderTopWidth'), 10) || 0; | |
893 | + left += parseInt(L.DomUtil.getStyle(el, 'borderLeftWidth'), 10) || 0; | |
894 | + | |
895 | + pos = L.DomUtil.getStyle(el, 'position'); | |
896 | + | |
897 | + if (el.offsetParent === docBody && pos === 'absolute') { break; } | |
898 | + | |
899 | + if (pos === 'fixed') { | |
900 | + top += docBody.scrollTop || docEl.scrollTop || 0; | |
901 | + left += docBody.scrollLeft || docEl.scrollLeft || 0; | |
902 | + break; | |
903 | + } | |
904 | + | |
905 | + if (pos === 'relative' && !el.offsetLeft) { | |
906 | + var width = L.DomUtil.getStyle(el, 'width'), | |
907 | + maxWidth = L.DomUtil.getStyle(el, 'max-width'), | |
908 | + r = el.getBoundingClientRect(); | |
909 | + | |
910 | + if (width !== 'none' || maxWidth !== 'none') { | |
911 | + left += r.left + el.clientLeft; | |
912 | + } | |
913 | + | |
914 | + //calculate full y offset since we're breaking out of the loop | |
915 | + top += r.top + (docBody.scrollTop || docEl.scrollTop || 0); | |
916 | + | |
917 | + break; | |
918 | + } | |
919 | + | |
920 | + el = el.offsetParent; | |
921 | + | |
922 | + } while (el); | |
923 | + | |
924 | + el = element; | |
925 | + | |
926 | + do { | |
927 | + if (el === docBody) { break; } | |
928 | + | |
929 | + top -= el.scrollTop || 0; | |
930 | + left -= el.scrollLeft || 0; | |
931 | + | |
932 | + el = el.parentNode; | |
933 | + } while (el); | |
934 | + | |
935 | + return new L.Point(left, top); | |
936 | + }, | |
937 | + | |
938 | + documentIsLtr: function () { | |
939 | + if (!L.DomUtil._docIsLtrCached) { | |
940 | + L.DomUtil._docIsLtrCached = true; | |
941 | + L.DomUtil._docIsLtr = L.DomUtil.getStyle(document.body, 'direction') === 'ltr'; | |
942 | + } | |
943 | + return L.DomUtil._docIsLtr; | |
944 | + }, | |
945 | + | |
946 | + create: function (tagName, className, container) { | |
947 | + | |
948 | + var el = document.createElement(tagName); | |
949 | + el.className = className; | |
950 | + | |
951 | + if (container) { | |
952 | + container.appendChild(el); | |
953 | + } | |
954 | + | |
955 | + return el; | |
956 | + }, | |
957 | + | |
958 | + hasClass: function (el, name) { | |
959 | + if (el.classList !== undefined) { | |
960 | + return el.classList.contains(name); | |
961 | + } | |
962 | + var className = L.DomUtil._getClass(el); | |
963 | + return className.length > 0 && new RegExp('(^|\\s)' + name + '(\\s|$)').test(className); | |
964 | + }, | |
965 | + | |
966 | + addClass: function (el, name) { | |
967 | + if (el.classList !== undefined) { | |
968 | + var classes = L.Util.splitWords(name); | |
969 | + for (var i = 0, len = classes.length; i < len; i++) { | |
970 | + el.classList.add(classes[i]); | |
971 | + } | |
972 | + } else if (!L.DomUtil.hasClass(el, name)) { | |
973 | + var className = L.DomUtil._getClass(el); | |
974 | + L.DomUtil._setClass(el, (className ? className + ' ' : '') + name); | |
975 | + } | |
976 | + }, | |
977 | + | |
978 | + removeClass: function (el, name) { | |
979 | + if (el.classList !== undefined) { | |
980 | + el.classList.remove(name); | |
981 | + } else { | |
982 | + L.DomUtil._setClass(el, L.Util.trim((' ' + L.DomUtil._getClass(el) + ' ').replace(' ' + name + ' ', ' '))); | |
983 | + } | |
984 | + }, | |
985 | + | |
986 | + _setClass: function (el, name) { | |
987 | + if (el.className.baseVal === undefined) { | |
988 | + el.className = name; | |
989 | + } else { | |
990 | + // in case of SVG element | |
991 | + el.className.baseVal = name; | |
992 | + } | |
993 | + }, | |
994 | + | |
995 | + _getClass: function (el) { | |
996 | + return el.className.baseVal === undefined ? el.className : el.className.baseVal; | |
997 | + }, | |
998 | + | |
999 | + setOpacity: function (el, value) { | |
1000 | + | |
1001 | + if ('opacity' in el.style) { | |
1002 | + el.style.opacity = value; | |
1003 | + | |
1004 | + } else if ('filter' in el.style) { | |
1005 | + | |
1006 | + var filter = false, | |
1007 | + filterName = 'DXImageTransform.Microsoft.Alpha'; | |
1008 | + | |
1009 | + // filters collection throws an error if we try to retrieve a filter that doesn't exist | |
1010 | + try { | |
1011 | + filter = el.filters.item(filterName); | |
1012 | + } catch (e) { | |
1013 | + // don't set opacity to 1 if we haven't already set an opacity, | |
1014 | + // it isn't needed and breaks transparent pngs. | |
1015 | + if (value === 1) { return; } | |
1016 | + } | |
1017 | + | |
1018 | + value = Math.round(value * 100); | |
1019 | + | |
1020 | + if (filter) { | |
1021 | + filter.Enabled = (value !== 100); | |
1022 | + filter.Opacity = value; | |
1023 | + } else { | |
1024 | + el.style.filter += ' progid:' + filterName + '(opacity=' + value + ')'; | |
1025 | + } | |
1026 | + } | |
1027 | + }, | |
1028 | + | |
1029 | + testProp: function (props) { | |
1030 | + | |
1031 | + var style = document.documentElement.style; | |
1032 | + | |
1033 | + for (var i = 0; i < props.length; i++) { | |
1034 | + if (props[i] in style) { | |
1035 | + return props[i]; | |
1036 | + } | |
1037 | + } | |
1038 | + return false; | |
1039 | + }, | |
1040 | + | |
1041 | + getTranslateString: function (point) { | |
1042 | + // on WebKit browsers (Chrome/Safari/iOS Safari/Android) using translate3d instead of translate | |
1043 | + // makes animation smoother as it ensures HW accel is used. Firefox 13 doesn't care | |
1044 | + // (same speed either way), Opera 12 doesn't support translate3d | |
1045 | + | |
1046 | + var is3d = L.Browser.webkit3d, | |
1047 | + open = 'translate' + (is3d ? '3d' : '') + '(', | |
1048 | + close = (is3d ? ',0' : '') + ')'; | |
1049 | + | |
1050 | + return open + point.x + 'px,' + point.y + 'px' + close; | |
1051 | + }, | |
1052 | + | |
1053 | + getScaleString: function (scale, origin) { | |
1054 | + | |
1055 | + var preTranslateStr = L.DomUtil.getTranslateString(origin.add(origin.multiplyBy(-1 * scale))), | |
1056 | + scaleStr = ' scale(' + scale + ') '; | |
1057 | + | |
1058 | + return preTranslateStr + scaleStr; | |
1059 | + }, | |
1060 | + | |
1061 | + setPosition: function (el, point, disable3D) { // (HTMLElement, Point[, Boolean]) | |
1062 | + | |
1063 | + // jshint camelcase: false | |
1064 | + el._leaflet_pos = point; | |
1065 | + | |
1066 | + if (!disable3D && L.Browser.any3d) { | |
1067 | + el.style[L.DomUtil.TRANSFORM] = L.DomUtil.getTranslateString(point); | |
1068 | + } else { | |
1069 | + el.style.left = point.x + 'px'; | |
1070 | + el.style.top = point.y + 'px'; | |
1071 | + } | |
1072 | + }, | |
1073 | + | |
1074 | + getPosition: function (el) { | |
1075 | + // this method is only used for elements previously positioned using setPosition, | |
1076 | + // so it's safe to cache the position for performance | |
1077 | + | |
1078 | + // jshint camelcase: false | |
1079 | + return el._leaflet_pos; | |
1080 | + } | |
1081 | +}; | |
1082 | + | |
1083 | + | |
1084 | +// prefix style property names | |
1085 | + | |
1086 | +L.DomUtil.TRANSFORM = L.DomUtil.testProp( | |
1087 | + ['transform', 'WebkitTransform', 'OTransform', 'MozTransform', 'msTransform']); | |
1088 | + | |
1089 | +// webkitTransition comes first because some browser versions that drop vendor prefix don't do | |
1090 | +// the same for the transitionend event, in particular the Android 4.1 stock browser | |
1091 | + | |
1092 | +L.DomUtil.TRANSITION = L.DomUtil.testProp( | |
1093 | + ['webkitTransition', 'transition', 'OTransition', 'MozTransition', 'msTransition']); | |
1094 | + | |
1095 | +L.DomUtil.TRANSITION_END = | |
1096 | + L.DomUtil.TRANSITION === 'webkitTransition' || L.DomUtil.TRANSITION === 'OTransition' ? | |
1097 | + L.DomUtil.TRANSITION + 'End' : 'transitionend'; | |
1098 | + | |
1099 | +(function () { | |
1100 | + if ('onselectstart' in document) { | |
1101 | + L.extend(L.DomUtil, { | |
1102 | + disableTextSelection: function () { | |
1103 | + L.DomEvent.on(window, 'selectstart', L.DomEvent.preventDefault); | |
1104 | + }, | |
1105 | + | |
1106 | + enableTextSelection: function () { | |
1107 | + L.DomEvent.off(window, 'selectstart', L.DomEvent.preventDefault); | |
1108 | + } | |
1109 | + }); | |
1110 | + } else { | |
1111 | + var userSelectProperty = L.DomUtil.testProp( | |
1112 | + ['userSelect', 'WebkitUserSelect', 'OUserSelect', 'MozUserSelect', 'msUserSelect']); | |
1113 | + | |
1114 | + L.extend(L.DomUtil, { | |
1115 | + disableTextSelection: function () { | |
1116 | + if (userSelectProperty) { | |
1117 | + var style = document.documentElement.style; | |
1118 | + this._userSelect = style[userSelectProperty]; | |
1119 | + style[userSelectProperty] = 'none'; | |
1120 | + } | |
1121 | + }, | |
1122 | + | |
1123 | + enableTextSelection: function () { | |
1124 | + if (userSelectProperty) { | |
1125 | + document.documentElement.style[userSelectProperty] = this._userSelect; | |
1126 | + delete this._userSelect; | |
1127 | + } | |
1128 | + } | |
1129 | + }); | |
1130 | + } | |
1131 | + | |
1132 | + L.extend(L.DomUtil, { | |
1133 | + disableImageDrag: function () { | |
1134 | + L.DomEvent.on(window, 'dragstart', L.DomEvent.preventDefault); | |
1135 | + }, | |
1136 | + | |
1137 | + enableImageDrag: function () { | |
1138 | + L.DomEvent.off(window, 'dragstart', L.DomEvent.preventDefault); | |
1139 | + } | |
1140 | + }); | |
1141 | +})(); | |
1142 | + | |
1143 | + | |
1144 | +/* | |
1145 | + * L.LatLng represents a geographical point with latitude and longitude coordinates. | |
1146 | + */ | |
1147 | + | |
1148 | +L.LatLng = function (lat, lng, alt) { // (Number, Number, Number) | |
1149 | + lat = parseFloat(lat); | |
1150 | + lng = parseFloat(lng); | |
1151 | + | |
1152 | + if (isNaN(lat) || isNaN(lng)) { | |
1153 | + throw new Error('Invalid LatLng object: (' + lat + ', ' + lng + ')'); | |
1154 | + } | |
1155 | + | |
1156 | + this.lat = lat; | |
1157 | + this.lng = lng; | |
1158 | + | |
1159 | + if (alt !== undefined) { | |
1160 | + this.alt = parseFloat(alt); | |
1161 | + } | |
1162 | +}; | |
1163 | + | |
1164 | +L.extend(L.LatLng, { | |
1165 | + DEG_TO_RAD: Math.PI / 180, | |
1166 | + RAD_TO_DEG: 180 / Math.PI, | |
1167 | + MAX_MARGIN: 1.0E-9 // max margin of error for the "equals" check | |
1168 | +}); | |
1169 | + | |
1170 | +L.LatLng.prototype = { | |
1171 | + equals: function (obj) { // (LatLng) -> Boolean | |
1172 | + if (!obj) { return false; } | |
1173 | + | |
1174 | + obj = L.latLng(obj); | |
1175 | + | |
1176 | + var margin = Math.max( | |
1177 | + Math.abs(this.lat - obj.lat), | |
1178 | + Math.abs(this.lng - obj.lng)); | |
1179 | + | |
1180 | + return margin <= L.LatLng.MAX_MARGIN; | |
1181 | + }, | |
1182 | + | |
1183 | + toString: function (precision) { // (Number) -> String | |
1184 | + return 'LatLng(' + | |
1185 | + L.Util.formatNum(this.lat, precision) + ', ' + | |
1186 | + L.Util.formatNum(this.lng, precision) + ')'; | |
1187 | + }, | |
1188 | + | |
1189 | + // Haversine distance formula, see http://en.wikipedia.org/wiki/Haversine_formula | |
1190 | + // TODO move to projection code, LatLng shouldn't know about Earth | |
1191 | + distanceTo: function (other) { // (LatLng) -> Number | |
1192 | + other = L.latLng(other); | |
1193 | + | |
1194 | + var R = 6378137, // earth radius in meters | |
1195 | + d2r = L.LatLng.DEG_TO_RAD, | |
1196 | + dLat = (other.lat - this.lat) * d2r, | |
1197 | + dLon = (other.lng - this.lng) * d2r, | |
1198 | + lat1 = this.lat * d2r, | |
1199 | + lat2 = other.lat * d2r, | |
1200 | + sin1 = Math.sin(dLat / 2), | |
1201 | + sin2 = Math.sin(dLon / 2); | |
1202 | + | |
1203 | + var a = sin1 * sin1 + sin2 * sin2 * Math.cos(lat1) * Math.cos(lat2); | |
1204 | + | |
1205 | + return R * 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); | |
1206 | + }, | |
1207 | + | |
1208 | + wrap: function (a, b) { // (Number, Number) -> LatLng | |
1209 | + var lng = this.lng; | |
1210 | + | |
1211 | + a = a || -180; | |
1212 | + b = b || 180; | |
1213 | + | |
1214 | + lng = (lng + b) % (b - a) + (lng < a || lng === b ? b : a); | |
1215 | + | |
1216 | + return new L.LatLng(this.lat, lng); | |
1217 | + } | |
1218 | +}; | |
1219 | + | |
1220 | +L.latLng = function (a, b) { // (LatLng) or ([Number, Number]) or (Number, Number) | |
1221 | + if (a instanceof L.LatLng) { | |
1222 | + return a; | |
1223 | + } | |
1224 | + if (L.Util.isArray(a)) { | |
1225 | + if (typeof a[0] === 'number' || typeof a[0] === 'string') { | |
1226 | + return new L.LatLng(a[0], a[1], a[2]); | |
1227 | + } else { | |
1228 | + return null; | |
1229 | + } | |
1230 | + } | |
1231 | + if (a === undefined || a === null) { | |
1232 | + return a; | |
1233 | + } | |
1234 | + if (typeof a === 'object' && 'lat' in a) { | |
1235 | + return new L.LatLng(a.lat, 'lng' in a ? a.lng : a.lon); | |
1236 | + } | |
1237 | + if (b === undefined) { | |
1238 | + return null; | |
1239 | + } | |
1240 | + return new L.LatLng(a, b); | |
1241 | +}; | |
1242 | + | |
1243 | + | |
1244 | + | |
1245 | +/* | |
1246 | + * L.LatLngBounds represents a rectangular area on the map in geographical coordinates. | |
1247 | + */ | |
1248 | + | |
1249 | +L.LatLngBounds = function (southWest, northEast) { // (LatLng, LatLng) or (LatLng[]) | |
1250 | + if (!southWest) { return; } | |
1251 | + | |
1252 | + var latlngs = northEast ? [southWest, northEast] : southWest; | |
1253 | + | |
1254 | + for (var i = 0, len = latlngs.length; i < len; i++) { | |
1255 | + this.extend(latlngs[i]); | |
1256 | + } | |
1257 | +}; | |
1258 | + | |
1259 | +L.LatLngBounds.prototype = { | |
1260 | + // extend the bounds to contain the given point or bounds | |
1261 | + extend: function (obj) { // (LatLng) or (LatLngBounds) | |
1262 | + if (!obj) { return this; } | |
1263 | + | |
1264 | + var latLng = L.latLng(obj); | |
1265 | + if (latLng !== null) { | |
1266 | + obj = latLng; | |
1267 | + } else { | |
1268 | + obj = L.latLngBounds(obj); | |
1269 | + } | |
1270 | + | |
1271 | + if (obj instanceof L.LatLng) { | |
1272 | + if (!this._southWest && !this._northEast) { | |
1273 | + this._southWest = new L.LatLng(obj.lat, obj.lng); | |
1274 | + this._northEast = new L.LatLng(obj.lat, obj.lng); | |
1275 | + } else { | |
1276 | + this._southWest.lat = Math.min(obj.lat, this._southWest.lat); | |
1277 | + this._southWest.lng = Math.min(obj.lng, this._southWest.lng); | |
1278 | + | |
1279 | + this._northEast.lat = Math.max(obj.lat, this._northEast.lat); | |
1280 | + this._northEast.lng = Math.max(obj.lng, this._northEast.lng); | |
1281 | + } | |
1282 | + } else if (obj instanceof L.LatLngBounds) { | |
1283 | + this.extend(obj._southWest); | |
1284 | + this.extend(obj._northEast); | |
1285 | + } | |
1286 | + return this; | |
1287 | + }, | |
1288 | + | |
1289 | + // extend the bounds by a percentage | |
1290 | + pad: function (bufferRatio) { // (Number) -> LatLngBounds | |
1291 | + var sw = this._southWest, | |
1292 | + ne = this._northEast, | |
1293 | + heightBuffer = Math.abs(sw.lat - ne.lat) * bufferRatio, | |
1294 | + widthBuffer = Math.abs(sw.lng - ne.lng) * bufferRatio; | |
1295 | + | |
1296 | + return new L.LatLngBounds( | |
1297 | + new L.LatLng(sw.lat - heightBuffer, sw.lng - widthBuffer), | |
1298 | + new L.LatLng(ne.lat + heightBuffer, ne.lng + widthBuffer)); | |
1299 | + }, | |
1300 | + | |
1301 | + getCenter: function () { // -> LatLng | |
1302 | + return new L.LatLng( | |
1303 | + (this._southWest.lat + this._northEast.lat) / 2, | |
1304 | + (this._southWest.lng + this._northEast.lng) / 2); | |
1305 | + }, | |
1306 | + | |
1307 | + getSouthWest: function () { | |
1308 | + return this._southWest; | |
1309 | + }, | |
1310 | + | |
1311 | + getNorthEast: function () { | |
1312 | + return this._northEast; | |
1313 | + }, | |
1314 | + | |
1315 | + getNorthWest: function () { | |
1316 | + return new L.LatLng(this.getNorth(), this.getWest()); | |
1317 | + }, | |
1318 | + | |
1319 | + getSouthEast: function () { | |
1320 | + return new L.LatLng(this.getSouth(), this.getEast()); | |
1321 | + }, | |
1322 | + | |
1323 | + getWest: function () { | |
1324 | + return this._southWest.lng; | |
1325 | + }, | |
1326 | + | |
1327 | + getSouth: function () { | |
1328 | + return this._southWest.lat; | |
1329 | + }, | |
1330 | + | |
1331 | + getEast: function () { | |
1332 | + return this._northEast.lng; | |
1333 | + }, | |
1334 | + | |
1335 | + getNorth: function () { | |
1336 | + return this._northEast.lat; | |
1337 | + }, | |
1338 | + | |
1339 | + contains: function (obj) { // (LatLngBounds) or (LatLng) -> Boolean | |
1340 | + if (typeof obj[0] === 'number' || obj instanceof L.LatLng) { | |
1341 | + obj = L.latLng(obj); | |
1342 | + } else { | |
1343 | + obj = L.latLngBounds(obj); | |
1344 | + } | |
1345 | + | |
1346 | + var sw = this._southWest, | |
1347 | + ne = this._northEast, | |
1348 | + sw2, ne2; | |
1349 | + | |
1350 | + if (obj instanceof L.LatLngBounds) { | |
1351 | + sw2 = obj.getSouthWest(); | |
1352 | + ne2 = obj.getNorthEast(); | |
1353 | + } else { | |
1354 | + sw2 = ne2 = obj; | |
1355 | + } | |
1356 | + | |
1357 | + return (sw2.lat >= sw.lat) && (ne2.lat <= ne.lat) && | |
1358 | + (sw2.lng >= sw.lng) && (ne2.lng <= ne.lng); | |
1359 | + }, | |
1360 | + | |
1361 | + intersects: function (bounds) { // (LatLngBounds) | |
1362 | + bounds = L.latLngBounds(bounds); | |
1363 | + | |
1364 | + var sw = this._southWest, | |
1365 | + ne = this._northEast, | |
1366 | + sw2 = bounds.getSouthWest(), | |
1367 | + ne2 = bounds.getNorthEast(), | |
1368 | + | |
1369 | + latIntersects = (ne2.lat >= sw.lat) && (sw2.lat <= ne.lat), | |
1370 | + lngIntersects = (ne2.lng >= sw.lng) && (sw2.lng <= ne.lng); | |
1371 | + | |
1372 | + return latIntersects && lngIntersects; | |
1373 | + }, | |
1374 | + | |
1375 | + toBBoxString: function () { | |
1376 | + return [this.getWest(), this.getSouth(), this.getEast(), this.getNorth()].join(','); | |
1377 | + }, | |
1378 | + | |
1379 | + equals: function (bounds) { // (LatLngBounds) | |
1380 | + if (!bounds) { return false; } | |
1381 | + | |
1382 | + bounds = L.latLngBounds(bounds); | |
1383 | + | |
1384 | + return this._southWest.equals(bounds.getSouthWest()) && | |
1385 | + this._northEast.equals(bounds.getNorthEast()); | |
1386 | + }, | |
1387 | + | |
1388 | + isValid: function () { | |
1389 | + return !!(this._southWest && this._northEast); | |
1390 | + } | |
1391 | +}; | |
1392 | + | |
1393 | +//TODO International date line? | |
1394 | + | |
1395 | +L.latLngBounds = function (a, b) { // (LatLngBounds) or (LatLng, LatLng) | |
1396 | + if (!a || a instanceof L.LatLngBounds) { | |
1397 | + return a; | |
1398 | + } | |
1399 | + return new L.LatLngBounds(a, b); | |
1400 | +}; | |
1401 | + | |
1402 | + | |
1403 | +/* | |
1404 | + * L.Projection contains various geographical projections used by CRS classes. | |
1405 | + */ | |
1406 | + | |
1407 | +L.Projection = {}; | |
1408 | + | |
1409 | + | |
1410 | +/* | |
1411 | + * Spherical Mercator is the most popular map projection, used by EPSG:3857 CRS used by default. | |
1412 |