PageSourceSearch

https://vilanova.cat/SIG/js/Leaflet/leaflet-layerjson.src.js

js vilanova.cat collected 2026-10-02 06:03:14 UTC 10,940 bytes, 391 lines download raw bytes

1/* 
2 * Leaflet JSON Layer v0.2.8 - 2017-08-11 
3 * 
4 * Copyright 2017 Stefano Cudini 
5 * [email protected] 
6 * http://labs.easyblog.it/ 
7 * 
8 * Licensed under the MIT license. 
9 * 
10 * Demo: 
11 * http://labs.easyblog.it/maps/leaflet-layerjson/ 
12 * 
13 * Source: 
14 * [email protected]:stefanocudini/leaflet-layerjson.git 
15 * 
16 */
17
18if (typeof L != 'undefined') {
19	 
20	(function() {
21
22	L.LayerJSON = L.FeatureGroup.extend({
23
24		includes: L.version[0]==='1' ? L.Evented.prototype : L.Mixin.Events,
25		//
26		//Managed Events:
27		//	Event			Data passed		 Description
28		//  dataloading		{req: url|bbox}	 fired before ajax/jsonp request, req is bbox if url option is null
29		//	dataloaded		{data: json}	 fired on ajax/jsonp request success
30		//
31		options: {
32			url: '',					//url map: "search.php?lat1={lat1}&lat2={lat2}&lon1={lon1}&lon2={lon2}"
33			jsonpParam: null,			//parameter name for jsonp requests
34			callData: null,				//custom function for data source, params: (req: url|bbox, callback: func), return {abort: func} or jQuery jqXHR Object
35			filterData: null,			//function that filter marker by its data, run before onEachMarker
36			//
37			locAsGeoJSON: false, 		//interpret location data as [lon, lat] value pair instead of [lat, lon]		
38			propertyItems: '', 			//json property used contains data items
39			propertyTitle: 'title', 	//json property used as title(popup, marker, icon)
40			propertyLoc: 'loc', 		//json property used as Latlng of marker use array for select double fields(ex. ['lat','lon'] )
41			propertyId: 'id',			//json property used to uniquely identify data items
42			//							// support dotted format: 'prop.subprop.title'
43			layerTarget: null,			//pre-existing layer to add markers, is a LayerGroup or L.MarkerClusterGroup http://goo.gl/tvmu0
44			dataToMarker: null,			//function that will be used for creating markers from json points, similar to pointToLayer of L.GeoJSON
45			onEachMarker: null,			//function called on each marker created, similar to option onEachFeature of L.GeoJSON
46			buildPopup: null,			//function popup builder
47			buildIcon: null,			//function icon builder
48			optsPopup: null,			//popup options		
49			//
50			minZoom: 10,				//min zoom for call data
51			caching: true,				//enable requests caching
52			cacheId: null,				//function to generate id used to uniquely identify data items in cache
53			minShift: 1000,				//min shift before update data(in meters)
54			precision: 6,				//number of digit send to server for lat,lng precision
55			attribution: ''				//attribution text
56			//TODO option: enabled, if false
57			//TODO methods: enable()/disable()
58			//TODO send map bounds decremented of certain margin
59		},
60
61		initialize: function(options) {
62			L.FeatureGroup.prototype.initialize.call(this, []);
63			L.Util.setOptions(this, options);
64			this._dataToMarker = this.options.dataToMarker || this._defaultDataToMarker;
65			this._buildIcon = this.options.buildIcon || this._defaultBuildIcon;
66			this._filterData = this.options.filterData || null;
67			this._hashUrl = this.options.url;
68
69			if(this._hashUrl)
70			{
71				this._callData = this.getAjax;
72				if(this.options.jsonpParam)
73				{
74					this._hashUrl += '&'+this.options.jsonpParam+'=';
75					this._callData = this.getJsonp;
76				}
77			}
78			else
79				this._callData = this.options.callData;
80
81			this._curReq = null;
82			this._center = null;
83			this._cacheBounds = null;
84			this._markersCache = {};	//used for caching _dataToMarker builds
85		},
86
87		onAdd: function(map) {
88
89			L.FeatureGroup.prototype.onAdd.call(this, map);		//set this._map
90			this._center = map.getCenter();
91			this._cacheBounds = map.getBounds();
92
93			map.on('moveend zoomend', this._onMove, this);
94
95			this.update();
96		},
97
98		onRemove: function(map) {
99
100			map.off('moveend zoomend', this._onMove, this);
101
102			L.FeatureGroup.prototype.onRemove.call(this, map);
103
104			for (var i in this._layers) {
105				if (this._layers.hasOwnProperty(i)) {
106					L.FeatureGroup.prototype.removeLayer.call(this, this._layers[i]);
107				}
108			}
109		},
110
111		getAttribution: function() {
112			return this.options.attribution;
113		},
114
115		addLayer: function (layer) {
116			if(this.options.layerTarget)
117			{
118				this.options.layerTarget.addLayer.call(this.options.layerTarget, layer);
119				return this.fire('layeradd', {layer: layer});
120			}
121			else
122				L.FeatureGroup.prototype.addLayer.call(this, layer);
123			return this;
124		},
125
126		removeLayer: function (layer) {
127			if(this.options.layerTarget)
128			{
129				this.options.layerTarget.removeLayer.call(this.options.layerTarget, layer);
130				return this.fire('layerremove', {layer: layer});
131			}
132			else
133				L.FeatureGroup.prototype.removeLayer.call(this, layer);
134			return this;
135		},
136
137		clearLayers: function () {
138
139			this._markersCache = {};	//cached gen markers
140
141			if(this.options.layerTarget)
142				this.options.layerTarget.clearLayers.call(this.options.layerTarget);
143			else
144				L.FeatureGroup.prototype.clearLayers.call(this);
145			return this;
146		},
147		
148		_debouncer: function(func, timeout) {
149			var timeoutID;
150			timeout = timeout || 300;
151			return function () {
152				var scope = this , args = arguments;
153				clearTimeout( timeoutID );
154				timeoutID = setTimeout( function () {
155					func.apply( scope , Array.prototype.slice.call( args ) );
156				}, timeout);
157			};
158		},
159
160		_getPath: function(obj, prop) {
161			var parts = prop.split('.'),
162				last = parts.pop(),
163				len = parts.length,
164				cur = parts[0],
165				i = 1;
166
167			if(len > 0)
168				while((obj = obj[cur]) && i < len)
169					cur = parts[i++];
170
171			if(obj)
172				return obj[last];
173		},
174
175		_defaultBuildIcon: function(data, title) {
176			return new L.Icon.Default();
177		},
178
179		_defaultDataToMarker: function(data, latlng) {	//make marker from data
180
181			var title = this._getPath(data, this.options.propertyTitle),
182				markerOpts = L.Util.extend({icon: this._buildIcon(data,title), title: title }, data),
183				marker = new L.Marker(latlng, markerOpts ),
184				htmlPopup = null;
185
186			if(this.options.buildPopup && (htmlPopup = this.options.buildPopup(data, marker)))
187				marker.bindPopup(htmlPopup, this.options.optsPopup );
188
189			return marker;
190		},
191
192		addMarker: function(data) {
193
194			var loc, hash, propLoc = this.options.propertyLoc;
195
196			if( L.Util.isArray(propLoc) ) {
197				loc = L.latLng( parseFloat( this._getPath(data, propLoc[0]) ),
198								   parseFloat( this._getPath(data, propLoc[1]) )  );
199			}
200			else {
201				if (this.options.locAsGeoJSON) {
202					var lnglat = this._getPath(data, propLoc);
203					loc = L.latLng( lnglat[1], lnglat[0] );
204				} else {
205					loc = L.latLng( this._getPath(data, propLoc) );
206				}
207			}
208
209			if(this.options.cacheId) {
210				hash = this.options.cacheId.call(this, data, loc);
211			}
212			else {
213				if(this.options.propertyId)
214					hash = this._getPath(data, this.options.propertyId);
215				else
216					hash = loc.lat+''+loc.lng+''+this._getPath(data, this.options.propertyTitle);
217			}
218
219			if(typeof this._markersCache[hash] === 'undefined')
220				this._markersCache[hash] = this._dataToMarker(data, loc);
221
222			if(this.options.onEachMarker)//maybe useless
223				this.options.onEachMarker(data, this._markersCache[hash]);
224
225			if(this._markersCache[hash])
226				this.addLayer( this._markersCache[hash] );
227		},
228
229		_contains: function(bounds, el) {
230			var loc;
231			
232			if(el.getLatLng)
233				loc = el.getLatLng();
234			else if(el.getBounds)
235				loc = el.getBounds();
236
237			return bounds.contains(loc);
238		},
239
240		_loadCacheToBounds: function(bounds) {	//show/hide cached markers
241			for(var i in this._markersCache)
242			{
243				if(this._markersCache[i])
244				{
245					if(this._contains(bounds, this._markersCache[i]) )
246						this.addLayer(this._markersCache[i]);
247					else
248						this.removeLayer(this._markersCache[i]);
249				}
250			}
251		},
252
253		_onMove: function(e) {
254			var newZoom = this._map.getZoom(),
255				newCenter = this._map.getCenter(),
256				newBounds = this._map.getBounds();
257
258			if(newZoom < this.options.minZoom)
259				return false;
260				
261			if( this.options.minShift && this._center.distanceTo(newCenter) < this.options.minShift )
262				return false;
263			else
264				this._center = newCenter;
265
266			if(this.options.caching) {
267
268				if( this._cacheBounds.contains(newBounds) )
269				{
270					this._loadCacheToBounds(newBounds);
271					return false;
272				}
273				else
274					this._cacheBounds.extend(newBounds);
275			}
276			else
277				this.clearLayers();
278
279			this.update();
280		},
281
282		update: function() {	//populate target layer
283
284			var self = this;
285
286			var prec = self.options.precision,
287				bb = self._map.getBounds(),
288				sw = bb.getSouthWest(),
289				ne = bb.getNorthEast(),
290				bbox = [
291					[ parseFloat(sw.lat.toFixed(prec)), parseFloat(sw.lng.toFixed(prec)) ],
292					[ parseFloat(ne.lat.toFixed(prec)), parseFloat(ne.lng.toFixed(prec)) ]
293				];
294				
295			if(self._hashUrl)							//conver bbox to url string
296				bbox = L.Util.template(self._hashUrl, {
297						lat1: bbox[0][0], lon1: bbox[0][1],
298						lat2: bbox[1][0], lon2: bbox[1][1]
299					});
300
301			if(self._curReq && self._curReq.abort)
302				self._curReq.abort();		//prevent parallel requests
303
304			
305			self.fire('dataloading', {req: bbox });
306			self._curReq = self._callData(bbox, function(json) {
307
308				self._curReq = null;
309
310				if(self._filterData)
311					json = self._filterData(json);
312
313				if(self.options.propertyItems)
314					json = self._getPath(json, self.options.propertyItems);
315
316				self.fire('dataloaded', {data: json});
317
318				for (var k in json) {
319					if (!isNaN(parseFloat(k)) && isFinite(k))
320						self.addMarker.call(self, json[k]);
321				}
322			});
323		},
324
325
326	/////////////////ajax jsonp methods
327
328		getAjax: function(url, cb) {	//default ajax request
329
330			if (window.XMLHttpRequest === undefined) {
331				window.XMLHttpRequest = function() {
332					try {
333						return new ActiveXObject("Microsoft.XMLHTTP.6.0");
334					}
335					catch  (e1) {
336						try {
337							return new ActiveXObject("Microsoft.XMLHTTP.3.0");
338						}
339						catch (e2) {
340							throw new Error("XMLHttpRequest is not supported");
341						}
342					}
343				};
344			}
345			var request = new XMLHttpRequest();
346			request.open('GET', url);
347			request.onreadystatechange = function() {
348				var response = {};
349				if (request.readyState === 4 && request.status === 200) {
350					try {
351						if(window.JSON)
352							response = JSON.parse(request.responseText);
353						else
354							response = eval("("+ request.responseText + ")");
355					} catch(err) {
356						response = {};		    		
357						throw new Error('Ajax response is not JSON');
358					}
359					cb(response);
360				}
361			};
362			request.send();
363			return request;
364		},
365
366		getJsonp: function(url, cb) {  //extract searched records from remote jsonp service
367			var body = document.getElementsByTagName('body')[0],
368				script = L.DomUtil.create('script','leaflet-layerjson-jsonp', body );
369
370			//JSONP callback
371			L.LayerJSON.callJsonp = function(data) {
372				cb(data);
373				body.removeChild(script);
374			}
375			script.type = 'text/javascript';
376			script.src = url+'L.LayerJSON.callJsonp';
377			return {
378				abort: function() {
379					script.parentNode.removeChild(script);
380				}
381			};
382		}
383	});
384
385	L.layerJSON = function (options) {
386		return new L.LayerJSON(options);
387	};
388
389	}).call(this);
390
391}

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.