PageSourceSearch

https://vilanovaturisme.cat/SIG/js/mapa.v23.js?ver=1.5

js vilanovaturisme.cat collected 2026-10-02 11:58:44 UTC 65,063 bytes, 1,574 lines download raw bytes

1var Visors = new Object();
2var mapa_actual;
3var visor_actual;
4var error_nav = false;
5var error_desc = "";
6
7var map;
8var PosMarker;
9var situa = false;
10
11/*
12    Paràmetres que es poden passar:
13
14    map = grups de capes que es visualitzaran. Valors: 
15        - ciutat
16        - comercial
17        - turisme
18        - educacio
19        - mobilitat
20        - esp_public
21        - coneixer
22        - catalunya
23        - tributs
24        - mobguals
25        - agenda
26        - acustic
27        - urbanisme
28		- fira_nov
29    x = X (ETRS89, UTM Zone 31) del punt central del mapa
30    y = Y (ETRS89, UTM Zone 31) del punt central del mapa
31    lat = latitud del punt central del mapa
32    lon = longitud del punt central del mapa
33    zoom = nivell de zoom a aplicar inicialment
34    data_mapa = data per als mapes que es poden personalitzar a una data determinada
35    layers= codi de les capes que estaran actives inicialment
36    sel_mapa = si es vol que aparegui un botó de guardar i que passi els paràmetres del mapa a la pàgina mare
37*/
38
39var Lat;
40var Lon;
41var X;
42var Y;
43var zoom;
44var data_mapa;
45var sel_mapa = false;
46var actived_layers;
47var actived_map;
48var conf_button_accordion = true;
49var conf_button_cerca = true;
50var conf_button_mesura = true;
51var conf_button_options = true;
52
53var serv_Base = location.protocol + "//" + location.host + "/SIG/";
54var serv_AJAX_Base = location.protocol + "//" + location.host + "/SIG/";
55var URL_imatges_markers = serv_Base + "images/Leaflet/markers/";
56var URL_mapa = serv_Base + "mapa.aspx";
57
58const scriptTag = document.currentScript || document.querySelector("script[src*='mapa.v23.js']");
59const serv_base_path_sig = scriptTag?.dataset?.basepath || "https://www.vilanova.cat";
60const path_sig = scriptTag?.dataset?.sig || "/prog/SIG/Map";
61
62if (typeof default_serv_Base == "undefined") {
63    serv_Base = serv_Base + "";
64} else {
65    serv_Base = default_serv_Base;
66}
67
68var min_Zoom = 2;
69var max_Zoom = 20;
70var options_maps = "";
71var Titol_mapa = "Mapa general";
72//----//
73
74function CercaAdr(lon, lat, num_mapa){
75
76		if (!isNaN(lat) && !isNaN(lon)) {
77			var pointlatlng = new L.LatLng(lat, lon);
78			var x=pointlatlng.utm().toString({decimals: 0, format: '{x}'});
79			var y=pointlatlng.utm().toString({ decimals: 0, format: '{y}' });
80		
81			$.ajax({
82				dataType: 'json',
83                url: `${serv_base_path_sig + path_sig}/DirData/cerca-adreces-properes`,
84				data: "x=" + x + "&y=" + y,
85				xhrFields: {
86					'withCredentials': true
87				},
88				success: function (resposta) {
89                    const mesPropera = resposta[0];
90                    $("#observ_adr_" + num_mapa).val("");
91                    if (mesPropera?.metres <= 400) {
92                        if (mesPropera.metres > 20) {
93                            $("#observ_adr_" + num_mapa).val(mesPropera.observ);
94						}
95                        $("#carrer_" + num_mapa).val(mesPropera.adrmesprop);
96					} else {
97						$("#carrer_" + num_mapa).val("terme municipal");
98					}
99                    actualitza_adr(num_mapa);
100                    if (typeof (mesPropera?.idnucli) != "undefined") {
101                        $("#hdnIdNucli_" + num_mapa).val(mesPropera.idnucli);
102                    }
103				},
104				error: function (xhr, ajaxOptions, thrownError) {
105					alert("Error: " + xhr.status);
106				}
107			});
108		} 
109}
110function actualitza_adr(num_mapa){
111	var comentari = $("#observ_adr_" + num_mapa).first().val();
112    if ((comentari || "").trim()) {
113			comentari = " (" + comentari + ")";
114		} else {
115			comentari="";
116		};
117	var valor = $( "#carrer_" + num_mapa).first().val() + comentari;
118	$( "#adr_" + num_mapa ).val(valor);		
119}
120function actualitza_cruilla(num_mapa) {
121	var cruilla = $( "#cruilla_" + num_mapa +" option:selected" ).text() ;
122	$("#observ_adr_" + num_mapa).val( "cruïlla amb " + cruilla);
123	actualitza_adr(num_mapa);
124}	
125
126function onLocationFound(e) {
127    var radius = Math. round(e.accuracy);
128	CercaAdr(e.latlng.lng, e.latlng.lat, mapa_actual);
129	posiciona_marker(e.latlng.lat, e.latlng.lng, mapa_actual);
130//	alert("onLocationFound -->
130 Lat="+ e.latlng.lat + "/Lon=" + e.latlng.lng);
131	PosMarker.bindPopup("Estàs en un radi de " + radius + "m. d'aquest punt").openPopup();
132}
133function onLocationError(e) {
134    alert("Error en la localització: " + e.message);
135}
136
137function localitza(mapa) {
138	mapa_actual=mapa;
139	visor_actual.map.on('locationfound', onLocationFound);
140	visor_actual.map.on('locationerror', onLocationError);
141	visor_actual.map.locate({setView: true, maxZoom: 16});
142}
143
144function decode(string) {
145    return unescape(string.replace(/\+/g, " "));
146}
147
148function msieversion() {
149
150    var ua = window.navigator.userAgent;
151    var msie = ua.indexOf("MSIE ");
152
153    if (msie > 0 || !!navigator.userAgent.match(/Trident.*rv\:11\./))  // If Internet Explorer, return version number
154    {
155        return parseInt(ua.substring(msie + 5, ua.indexOf(".", msie)));
156    }
157    else  // If another browser, return 0
158    {
159        return 99;
160    }
161
162}
163
164if (msieversion() <= 8) {
165    error_nav = true;
166    error_desc = "Navegador no compatible";
167    // alert(error_desc);
168};
169
170function data_avui() {
171    var today = new Date();
172    var dd = today.getDate();
173    var mm = today.getMonth() + 1; //January is 0!
174
175    var yyyy = today.getFullYear();
176    if (dd < 10) {
177        dd = '0' + dd;
178    }
179    if (mm < 10) {
180        mm = '0' + mm;
181    }
182    return dd + '-' + mm + '-' + yyyy;
183}
184
185
186/* Fi funcions generals */
187
188function Inicialitza_Mapa() {
189    if (window.mapa_en_proces)
190        return;
191    window.mapa_en_proces = true;
192
193    for (var key in Visors) {
194        var visor = Visors[key];
195        if (typeof (visor.map) != "undefined") {
196            visor.map.off();
197            visor.map.remove();
198        }
199    };
200    Visors = new Object();
201
202    (async () => {
203        await getMapesLeaflet();
204
205        agafa_parametres_url();
206        $(".map").html("");
207
208        var elementsMapa = $(".map").get();
209
210        for (let index = 0; index < elementsMapa.length; index++) {
211            let element = elementsMapa[index];
212
213            situa = false;
214            mapa_actual = index;
215            element.id = "Mapa_" + index;
216
217            await Inicialitza_Mapa_Individual(mapa_actual, element.id, element);
218
219            limit_propagation(".leaflet-control");
220            //	limit_propagation(".accordion-layer");
221            //	limit_propagation(".acc_s_title");
222            //	limit_propagation(".checkboxes");
223        }
224
225        window.mapa_en_proces = false;
226    })();      
227}
228
229async function Inicialitza_Mapa_Individual(num_mapa, id_mapa, elem) {
230	if (typeof defconf_button_accordion != "undefined") {
231		conf_button_accordion = defconf_button_accordion;
232	}
233	if (typeof defconf_button_cerca != "undefined") {
234		conf_button_cerca = defconf_button_cerca;
235	}
236	if (typeof defconf_button_mesura != "undefined") {
237		conf_button_mesura = defconf_button_mesura;
238	}
239	if (typeof defconf_button_options != "undefined") {
240		conf_button_options = defconf_button_options;
241	}
242
243    var prop = $(elem.parentNode).find(".propietats_mapa");
244    if (prop.length > 0) {
245        if (typeof default_lat == "undefined") {
246            var default_lat = 41.2217309461729;
247        }
248        if (typeof default_lon == "undefined") {
249            var default_lon = 1.72596493594186;
250        }
251        if (typeof default_zoom == "undefined") {
252            var default_zoom = 14;
253        }
254        if (typeof default_data_mapa == "undefined") {
255            var default_data_mapa = data_avui();
256        }        
257        try {
258            Lat = Number(prop.find(".lat").text());
259            if (Lat == 0) Lat = default_lat;
260        }
261        catch (err) {
262            Lat = default_lat;
263        }
264        try {
265            X = Number(prop.find(".x").text());
266        }
267        catch (err) {
268            X = 0;
269        }
270        try {
271            Y = Number(prop.find(".y").text());
272        }
273        catch (err) {
274            Y = 0;
275        }
276        try {
277            if (prop.find(".situa").text() == "S" || prop.find(".situa").text() == "s") {
278                situa = true;
279            }
280        }
281        catch (err) {
282        }
283        try {
284            Lon = Number(prop.find(".lon").text());
285            if (Lon == 0) Lon = default_lon;
286        }
287        catch (err) {
288            Lon = default_lon;
289        }
290        var act_layers;
291        try {
292            act_layers = prop.find(".layers").text();
293        }
294        catch (err) {
295            if (typeof default_layers == "undefined") {
296                act_layers = "";
297            } else {
298                act_layers = default_layers;
299            }
300        }
301        actived_layers = act_layers.split(",");
302        if (typeof default_map == "undefined") {
303            actived_map = "";
304        } else {
305            actived_map = default_map;
306        }
307        try {
308            if (prop.find(".mapa").text()!="")
309            actived_map = prop.find(".mapa").text();
310        }
311        catch (err) {
312         }
313        try {
314            zoom = Number(prop.find(".zoom").text());
315            if (zoom == 0) zoom = default_zoom;
316        }
317        catch (err) {
318            zoom = default_zoom;
319        }
320        try {
321            var d = prop.find(".data_mapa").text();
322            if (d.length == 10) {
323                data_mapa = d;
324            } else {
325                data_mapa = default_data_mapa;
326            }
327        }
328        catch (err) {
329            data_mapa = default_data_mapa;
330        }
331    }
332
333    // FI Agafar dades de l'URL
334    visor_actual = new Object();
335    visor_actual.id_mapa = id_mapa;
336    visor_actual.num_mapa = num_mapa;
337    visor_actual.NomCapa = new Array();
338    visor_actual.CodiCapa = new Array();
339    visor_actual.Id = new Array();
340    visor_actual.Servidor = new Array();
341    visor_actual.minZoom = new Array();
342    visor_actual.maxZoom = new Array();
343    visor_actual.NomGrup = new Array();
344    visor_actual.ColorGrup = new Array();
345    visor_actual.ColorText = new Array();
346    visor_actual.Tipus = new Array();
347    visor_actual.Capa = new Array();
348    visor_actual.Llegenda = new Array();
349    visor_actual.Activa = new Array();
350    visor_actual.Attribution = new Array();
351    visor_actual.AccordionLegend = new Object();
352	visor_actual.conf_boto_accordion = conf_button_accordion;
353	visor_actual.conf_boto_cerca = conf_button_cerca;
354	visor_actual.conf_button_mesura = conf_button_mesura;
355	visor_actual.conf_button_options = conf_button_options;
356
357    visor_actual.NumCapes = 0;
358    visor_actual.Grups_i_capes = [];
359	if (!isNaN(X) && !isNaN(Y)) {
360		if ((X !=0) && (Y !=0)) {
361			var pointXY = L.utm({ x: X, y: Y, zone: 31, band: 'N' });
362			var pointlatlng = pointXY.latLng();
363			Lat = pointlatlng.lat;
364			Lon = pointlatlng.lng;
365		}		
366    }
367
368    if (Lat != 0) {
369
370        latlng = new L.LatLng(Lat, Lon);
371        var southWest = L.latLng(Lat - 0.2, Lon - 0.2),
372            northEast = L.latLng(Lat + 0.2, Lon + 0.2),
373            bounds = L.latLngBounds(southWest, northEast);
374        visor_actual.map = new L.Map(visor_actual.id_mapa, {
375            zoomControl: false,
376            maxBounds: bounds,
377            center: latlng,
378            zoom: zoom,
379            minZoom: min_Zoom,
380            maxZoom: max_Zoom,
381            attributionControl: false,
382            fullscreenControl: false
383        });
384        //visor_actual.map.scrollWheelZoom.disable();
385        // Fer servir "pane" per fer respectar l'ordre de les capes i que no amaguin unes a les altres						
386        //			map.createPane('fons'); tilePane
387        //			map.createPane('intermig'); // entre tilePane i overlayPane
388        visor_actual.map.createPane('intermig_s'); // entre overlayPane i shadowPane
389        //			map.createPane('superior'); markerPane
390        //			map.getPane('fons').style.zIndex = 210;
391        //			map.getPane('intermig').style.zIndex = 300;
392        visor_actual.map.getPane('intermig_s').style.zIndex = 450;
393        //			map.getPane('superior').style.zIndex = 412;
394        //			map.getPane('fons').style.pointerEvents = 'none';
395        //			map.getPane('intermig').style.pointerEvents = 'none';
396        visor_actual.map.getPane('intermig_s').style.pointerEvents = 'none';
397
398        L.control.zoom({
399            position: 'topleft',
400            zoomInTitle: 'Apropar',
401            zoomOutTitle: 'Allunyar'
402        }).addTo(visor_actual.map);
403
404
405
406        await Omple_dades(num_mapa);
407
408        visor_actual.AccordionLegend = new L.Control.AccordionLegend({
409            position: 'topright',
410            title: Titol_mapa + ": selecció de capes visibles",
411            content: visor_actual.Grups_i_capes,
412            num_mapa: visor_actual.num_mapa,
413            id_mapa: visor_actual.id_mapa
414        });
415        visor_actual.AccordionLegend.addTo(visor_actual.map);
416
417        visor_actual.AccordionLegend.go();
418		
419		if (!visor_actual.conf_boto_accordion) $('.leaflet-control-accordionlegend').hide();
420		
421        Visors[num_mapa] = visor_actual;
422        if (situa) situa_marker(Lat, Lon, num_mapa);
423
424
425        // Control amb panel
426
427        function on_Add(map) {
428
429            var classe = this.options.classe;
430            var classe_comb = this.options.classe;
431            if (typeof this.options.classe2 != "undefined") {
432                classe = this.options.classe2;
433                classe_comb = this.options.classe2 + " " + classe_comb;
434            }
435            this._div = L.DomUtil.create('div', classe_comb + ' leaflet-bar'); // create a div with a class "..."
436            this._button = L.DomUtil.create('div', "lflt-panel-button active-block", this._div);
437            this._button.innerHTML = '<a onclick="javascript:ObrePopUp(\'' + classe + '\');return false;" class="' + classe_comb + '_img" title="' + this.options.title + '"></a>';
438            this._panel = L.DomUtil.create('div', "lflt-control-panel", this._div);
439            this._panel_header = L.DomUtil.create('div', "header", this._panel);
440            this._panel_header.innerHTML = '<label class="header_label">' + this.options.title + '</label><a onclick="javascript:TancaPopUp(\'' + classe + '\');return false;" class="btn-top-t" title="Tanca"></a>';
441            this._panel_body = L.DomUtil.create('div', "body", this._panel);
442            this._panel_body.innerHTML = this.options.inner_HTML;
443            return this._div;
444        };
445
446
447        var button_ciutat = L.control({
448            position: 'topright',
449            classe: 'button_ciutat',
450            inner_HTML: '',
451            title: 'Mapa de fons: ciutat'
452        });
453
454        button_ciutat.onAdd = function (map) {
455            this._div = L.DomUtil.create('div', this.options.classe + ' leaflet-bar'); // create a div with a class "..."
456            this._button = L.DomUtil.create('div', "lflt-panel-button active-block", this._div);
457            this._button.innerHTML = '<a onclick="javascript:Canvia_Mapa_Fons(true, \'' + visor_actual.num_mapa + '\');return false;" class="' + this.options.classe + '_img" title="' + this.options.title + '"></a>';
458            return this._div;
459        };
460
461        button_ciutat.addTo(visor_actual.map);
462        var button_orto = L.control({
463            position: 'topright',
464            classe: 'button_orto',
465            inner_HTML: '',
466            title: 'Mapa de fons: Vista aèria'
467        });
468        button_orto.onAdd = function (map) {
469            this._div = L.DomUtil.create('div', this.options.classe + ' leaflet-bar'); // create a div with a class "..."
470            this._button = L.DomUtil.create('div', "lflt-panel-button active-block", this._div);
471            this._button.innerHTML = '<a onclick="javascript:Canvia_Mapa_Fons(false, \'' + visor_actual.num_mapa + '\');return false;" class="' + this.options.classe + '_img" title="' + this.options.title + '"></a>';
472            return this._div;
473        };
474
475        button_orto.addTo(visor_actual.map);
476		var boto_localitzar="";
477		if (typeof intranet == 'undefined') boto_localitzar= '<button onclick="javascript:localitza(0); return false;" type="button">Localitza\'m per GPS</button>'+'<br />';
478        if (visor_actual.conf_boto_cerca) {        
479			visor_actual.menu_button_cerca = L.control({
480				position: 'topright',
481				classe: 'menu_button_cerca',
482				classe2: 'menu_button_cerca' + visor_actual.num_mapa,
483				inner_HTML: '<label>Carrer i número:</label><br />' +
484					'<input title="Introdueix la totalitat o part del nom del carrer i a continuació, sense comes, el número del portal" type="" id="carrer_' + visor_actual.num_mapa + '" style="width:260px" />' +
485					'<div class="cruilla" style="display:none;"><label>Cruïlla amb:</label><br /><select id="cruilla_' + visor_actual.num_mapa + '"  class="combo" onchange="carrerer_show(' + visor_actual.num_mapa + '); actualitza_cruilla(' + visor_actual.num_mapa + '); return false;" style="width:260px" ><option value="0">Cerca un carrer prèviament</option></select></div>' +
486					'<div class="observ_adr" style="display:none;"><label>Observacions:</label><br /><input id="observ_adr_' + visor_actual.num_mapa + '" onchange="actualitza_adr(' + visor_actual.num_mapa + '); return false;"  ></div>' +
487					'<div class="adr_compl" style="display:none;"><input title="Adreça escollida" id="adr_' + visor_actual.num_mapa + '" disabled></div>' +
488					'<div style="border: 1px solid #9292a0; border-radius: 5px; padding: 2px 2px 2px 2px; margin-top: 15px;">' +
489						'<label>Coordenades GPS:</label><br />' +
490						'<div class="coordenades" style="width:250px">' +
491							'<div style="display:flex; justify-content:space-between">' +
492							'<label style="margin-left:10px">Longitud</label><input title="Introdueix la longitud del punt" type="" id="lon_' + visor_actual.num_mapa + '" />' +
493							'</div><div style="display:flex; justify-content:space-between">' +
494							'<label style="margin-left:10px">Latitud</label><input title="Introdueix la latitud del punt" type="" id="lat_' + visor_actual.num_mapa + '" />' +
495							'</div>' +
496						'</div>' +
497						'<br />' +
498						'<label>Coordenades XY:</label><br />' +
499						'<div class="coordenades_xy" style="width:250px">' +
500							'<div style="display:flex; justify-content:space-between">' +
501							'<label style="margin-left:10px">X</label><input title="Introdueix la coordenada X del punt" type="" id="x_' + visor_actual.num_mapa + '" />' +
502							'</div><div style="display:flex; justify-content:space-between">' +
503							'<label style="margin-left:10px">Y</label><input title="Introdueix la coordenada Y del punt" type="" id="y_' + visor_actual.num_mapa + '" />' +
504							'</div>' +
505						'</div>' +
506						'<div style="display:flex; justify-content:flex-end; padding-top:5px"><button id="cerca_punt_' + visor_actual.num_mapa + '" type="button">Cercar punt</button></div>' +
507					'</div>' +
508					'<br />' +
509					'<button id="esborra_icona_' + visor_actual.num_mapa + '" onclick="javascript:esborra_marker(' + visor_actual.num_mapa + '); return false;" type="button">Esborrar icona</button> '+ boto_localitzar,
510				title: 'Cercar'
511			});
512
513			visor_actual.menu_button_cerca.onAdd = on_Add;
514
515			visor_actual.menu_button_cerca.addTo(visor_actual.map);
516        }
517
518        if ($.fn.autocomplete) {
519            // S'ha carregat jQuery UI
520            var options = {
521                minLength: 1,
522                source: function (request, response) {
523                    $.ajax({
524                        url: `${serv_base_path_sig + path_sig}/DirData/cerca-adreca`,
525                        data: { adr: request.term },
526                        dataType: "json",
527                        success: function (data) {
528                            var elements = typeof data === "string" ? JSON.parse(data) : data;
529
530                            response($.map(elements, function (item) {
531                                return {
532                                    label: item.label,
533                                    value: item.label,
534                                    lat: item.lat,
535                                    lng: item.lng,
536                                    via: item.via
537                                };
538                            }));
539                        }
540                    });
541                },
542                select: function (event, ui) {
543                    var num_mapa = visor_actual.num_mapa;
544                    var Lat = ui.item.lat;
545                    var Lon = ui.item.lng;
546                    var lbl = ui.item.label;
547                    var via = ui.item.via;
548
549                    $("#observ_adr_" + num_mapa).val("");
550                    actualitza_adr(num_mapa);
551
552                    var num = lbl.replace(/\D/g, '');
553                    if (num.length < 1) {
554                        // Cerca de cruïlles
555                        $.get(`${serv_base_path_sig + path_sig}/DirData/cerca-cruilles?adr=${via}`, function (data) {
556                            var element = typeof data === "string" ? JSON.parse(data) : data;
557                            if (element.length > 0) {
558                                $(".cruilla").show();
559                                $('#cruilla_' + num_mapa).empty();
560                                $('#cruilla_' + num_mapa).append($('<option>').text("Selecciona un carrer").attr('value', "0/0"));
561                                for (var i = 0; i < element.length; i++) {
562                                    $('#cruilla_' + num_mapa).append($('<option>').text(element[i].label).attr('value', element[i].lat + "/" + element[i].lng));
563                                };
564                            } else {
565                                $(".cruilla").hide();
566                            }
567                        });
568                    } else {
569                        $(".cruilla").hide();
570                    }
571
572                    posiciona_marker(Lat, Lon, num_mapa);
573                    $("#carrer_" + num_mapa).val(lbl);
574
575                    return false;
576                }
577            };
578
579            var $inputCarrer = $("#carrer_" + visor_actual.num_mapa);
580
581            $inputCarrer.autocomplete(options);
582
583            // Sobreescrivim el disseny per posar la negreta a les coincidències
584            $inputCarrer.autocomplete("instance")._renderItem = function(ul, item) {
585                var termeEscapat = this.term.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, '\\$&');
586                var regex = new RegExp("(" + termeEscapat + ")", "gi");
587                var textAmbNegreta = item.label.replace(regex, "<strong>$1</strong>");
588
589                return $("<li>").append($("<div>").html(textAmbNegreta)).appendTo(ul);
590            };
591        } else if ($.fn.easyAutocomplete) {
592            var options = {
593                url: function (phrase) { return `${serv_base_path_sig + path_sig}/DirData/cerca-adreca?adr=${phrase}`; },
594                getValue: "label",
595                list: {
596                    caller_element: visor_actual.num_mapa,
597                    onChooseEvent: function () {
598                        var num_mapa = this.caller_element;
599                        var Lat = $("#carrer_" + num_mapa).getSelectedItemData().lat;
600                        var Lon = $("#carrer_" + num_mapa).getSelectedItemData().lng;
601                        var lbl = $("#carrer_" + num_mapa).getSelectedItemData().label;
602                        $("#observ_adr_" + num_mapa).val("");
603                        actualitza_adr(num_mapa);
604                        var num = lbl.replace(/\D/g, '');
605                        if (num.length < 1) {  // És una via sencera, activem la cerca de cruilles
606                            $.get(`${serv_base_path_sig + path_sig}/DirData/cerca-cruilles?adr=${$("#carrer_" + num_mapa).getSelectedItemData().via}`, function (data, status) {
607                                var element = eval(data);
608                                if (element.length > 0) {
609                                    $(".cruilla").show();
610                                    $('#cruilla_' + num_mapa + ' option').each(function () {
611                                        $(this).remove();
612                                    });
613                                    $('#cruilla_' + num_mapa).append($('<option>').text("Selecciona un carrer").attr('value', "0/0"));
614                                    for (var i = 0; i < element.length; i++) {
615                                        $('#cruilla_' + num_mapa).append($('<option>').text(element[i].label).attr('value', element[i].lat + "/" + element[i].lng));
616                                    };
617                                } else {
618                                    $(".cruilla").hide();
619                                }
620                            });
621                        } else {
622                            $(".cruilla").hide();
623                        }
624
625                        posiciona_marker(Lat, Lon, num_mapa);
626                    }
627                }
628            };
629
630            $("#carrer_" + visor_actual.num_mapa).easyAutocomplete(options);
631        } else {
632            console.warn("No s'ha trobat cap llibreria d'autocompletar carregada.");
633        }
634
635        //Cercar per coordenades longitud,latitud
636        $(".coordenades").children("div").children("input").each(function() {
637            $(this).on("input", () => {
638                var Lat = parseFloat($("#lat_" + num_mapa).val().replace(",","."));
639                var Lon = parseFloat($("#lon_" + num_mapa).val().replace(",","."));
640                if (!isNaN(Lat) && !isNaN(Lon)) {
641					$("#observ_adr_"+num_mapa).val( "");
642                    var pointlatlng = new L.LatLng(Lat, Lon);
643                    $("#x_" + num_mapa).val(pointlatlng.utm().toString({decimals: 3, format: '{x}'}));
644                    $("#y_" + num_mapa).val(pointlatlng.utm().toString({ decimals: 3, format: '{y}' }));
645                }           
646            });
647        });
648
649        //Cercar per coordenades X,Y
650        $(".coordenades_xy").children("div").children("input").each(function () {
651            $(this).on("input", () => {
652                var x = parseFloat($("#x_" + num_mapa).val().replace(",", "."));
653                var y = parseFloat($("#y_" + num_mapa).val().replace(",", "."));
654                if (!isNaN(x) && !isNaN(y)) {
655					$("#observ_adr_"+num_mapa).val( "");
656                    var pointXY = L.utm({ x: x, y: y, zone: 31, band: 'N' });
657                    var pointlatlng = pointXY.latLng();
658                    $("#lat_" + num_mapa).val(pointlatlng.lat.toFixed(8));
659                    $("#lon_" + num_mapa).val(pointlatlng.lng.toFixed(8));
660                }
661            });
662        });
663
664        //Botó per col·locar marcador
665        $("#cerca_punt_" + num_mapa).on("click", () => {
666            var Lat = parseFloat($("#lat_" + num_mapa).val().replace(",", "."));
667            var Lon = parseFloat($("#lon_" + num_mapa).val().replace(",", "."));
668            var x = parseFloat($("#x_" + num_mapa).val().replace(",", "."));
669            var y = parseFloat($("#y_" + num_mapa).val().replace(",", "."));
670            if (!isNaN(Lat) && !isNaN(Lon)) {
671                var pointlatlng = new L.LatLng(Lat, Lon);
672                posiciona_marker(Lat, Lon, num_mapa);
673//				alert(Lat + "/Lon=" + Lon);
674            }
675            else if (!isNaN(x) && !isNaN(y)) {
676                var pointXY = L.utm({ x: x, y: y, zone: 31, band: 'N' });
677                var pointlatlng = pointXY.latLng();
678                posiciona_marker(pointlatlng.lat, pointlatlng.lng, num_mapa);
679//				alert(x + "/y=" + y);
680            }
681        });
682
683        //Llegenda amb coordenades del punter
684        L.control.coordinates({
685            labelTemplateLat: "Latitud: {y}",
686            labelTemplateLng: "Longitud: {x}",
687            decimals: 8,
688        }).addTo(Visors[num_mapa].map);
689
690        //Afegir marcador al clicar (coordenades punter)        
691        var isDragging = false;
692        $(".map").on("mousedown", (e) => {
693/*            $(window).mousemove(() => {
694                isDragging = true;
695                $(window).unbind("mousemove");
696            });
697*/
698        })
699
700        Visors[num_mapa].map.on("click", (e) => {
701            const $target = $(e.originalEvent.target);
702            if ($target.closest(".leaflet-control-container").length)
703                return;
704            if ($target.hasClass("leaflet-marker-icon") || $target.hasClass("leaflet-popup-content") || $target.closest(".leaflet-popup").length)
705                return;
706
707            if (!estemMesurant) {
708                var Lat = $(".inputY").val();
709                var Lon = $(".inputX").val();
710                var pointlatlng = new L.LatLng(Lat, Lon);
711				CercaAdr(Lon, Lat, num_mapa);
712				posiciona_marker(Lat, Lon, num_mapa);
713            }
714            else {
715                mesurar(visor_actual.num_mapa);
716            }
717        });
718
719
720		if (visor_actual.conf_button_mesura) {
721			visor_actual.menu_button_mesura = L.control({
722				position: 'topright',
723				classe: 'menu_button_mesura',
724				classe2: 'menu_button_mesura' + visor_actual.num_mapa,
725				inner_HTML: '<button type="button" style="margin-bottom:5px" id="mesurar_dist' + visor_actual.num_mapa + '" onclick="javascript:toggleMesurar(' + visor_actual.num_mapa + ', \'dist\')">Mesurar distància</button><br />' +
726					'<div style="display:flex; justify-content:space-between">' +
727						'<label>Distància:</label>' +
728						'<input title="" type="" id="distancia_' + visor_actual.num_mapa + '" readonly="readonly" />' +
729					'</div><br />' +
730					'<button type="button" style="margin-bottom:5px" id="mesurar_area' + visor_actual.num_mapa + '" onclick="javascript:toggleMesurar(' + visor_actual.num_mapa + ', \'area\')">Mesurar àrea</button><br />' +
731					'<div style="display:flex; justify-content:space-between">' +
732						'<label>Àrea:</label>' +
733						'<input title="" type="" id="area_' + visor_actual.num_mapa + '" readonly="readonly" />' +
734					'</div>',
735				title: 'Mesurar distància o àrea' 
736			});
737
738			visor_actual.menu_button_mesura.onAdd = on_Add;
739
740			visor_actual.menu_button_mesura.addTo(visor_actual.map);
741		}
742
743        //L.control.locate({
744        //    strings: {
745        //		title: "Situa'm al mapa"
746        //	}
747        //}).addTo(map);
748		if (visor_actual.conf_button_mesura) {
749			visor_actual.menu_button_mesura.onAdd = on_Add;
750
751			visor_actual.menu_button_mesura.addTo(visor_actual.map);
752		}
753        if (visor_actual.conf_button_options) {
754            const mapes = await getMapesLeaflet(actived_map);
755            mapes.forEach(mapa => {
756                options_maps += `<option value="${mapa.value}" ${mapa.selected ? "selected" : ""}>${mapa.nom}</option>`;
757            });            
758
759			var inner_HTML_text = "<select id='Sel_" + visor_actual.num_mapa + "' class='obre_mapa'>" + options_maps + '</select>';
760			var isoc_amagat = "";
761			if (actived_map != "isocials") isoc_amagat = "style='display:none;'";
762			var mob_amagat = "";
763			if (actived_map != "mobilitat") mob_amagat = "style='display:none;'";
764			if (typeof codi_select_isocials != 'undefined') inner_HTML_text = inner_HTML_text + "<div class='inner_div isocials' " + isoc_amagat + ">" + codi_select_isocials + "</div>";
765			if (typeof codi_select_mobilitat_a != 'undefined') {
766				var dat_mapa = data_mapa.substr(6, 4) + "-" + data_mapa.substr(3, 2) + "-" + data_mapa.substr(0, 2); // Format YYYY-MM-DD
767				inner_HTML_text = inner_HTML_text + "<div class='inner_div mobilitat'" + mob_amagat + ">" + codi_select_mobilitat_a + dat_mapa + codi_select_mobilitat_b + "</div>";
768			}
769			inner_HTML_text = inner_HTML_text + "<input id='Acc_" + visor_actual.num_mapa + "' type='button' value='Acceptar' />";
770            const selectorMapa = `
771                <div class="selector-mapa">
772                    ${inner_HTML_text}
773                </div>
774            `;
775
776            const $accordion = $(visor_actual.AccordionLegend.getContainer());
777            $accordion.find('.header').after(selectorMapa);
778            $accordion.find('.selector-mapa').on('click dblclick mousedown mousewheel', function (e) {
779                e.stopPropagation();
780            });
781
782            var options_share = `
783                <option value="${actived_map}">Vista actual (per copiar enllaç)</option>
784                <option value="GoogleMaps">Google Maps</option>
785                <option value="Bing">Bing</option>
786            `;
787            var select_share = `
788                <select id='SelShare_${visor_actual.num_mapa}' class='obre_mapa'>${options_share}</select>
789                <input id='AccShare_${visor_actual.num_mapa}' type='button' value='Acceptar' />
790            `;
791            visor_actual.menu_button_options = L.control({
792                position: 'topright',
793                classe: 'menu_button_options',
794                classe2: 'menu_button_options' + visor_actual.num_mapa,
795                inner_HTML: select_share,
796                title: 'Comparteix / Obre amb'
797            });
798            visor_actual.menu_button_options.onAdd = on_Add;
799            visor_actual.menu_button_options.addTo(visor_actual.map);
800		}
801        $(`#Sel_${visor_actual.num_mapa}, #SelShare_${visor_actual.num_mapa}`).on('change', function () {
802            var $this = $(this);
803            var select = $this.find('option:selected').val();
804            if (select == "mobilitat") {
805                $this.parent().find('.mobilitat').show();
806            } else {
807                $this.parent().find('.mobilitat').hide();
808            }
809            if (select == "isocials") {
810                $this.parent().find('.isocials').show();
811            } else {
812                $this.parent().find('.isocials').hide();
813            }
814        });
815
816        $(`#Acc_${visor_actual.num_mapa}, #AccShare_${visor_actual.num_mapa}`).on("click", function () {
817            var $this = $(this);
818            try {
819                data_mapa = $this.parent().find(".data_mapa").val();
820                if (data_mapa.length == 10) {
821                    // Convertir format YYYY-MM-DD a DD-MM-YYYY
822                    data_mapa = data_mapa.substr(8, 2) + "-" + data_mapa.substr(5, 2) + "-" + data_mapa.substr(0, 4);
823                } else {
824                    data_mapa = "";
825                }
826            }
827            catch (err) {
828                data_mapa = "";
829            }
830            var select = $this.parent().find(".obre_mapa option:selected").val();
831            if (select == "isocials") {
832                var param = $this.parent().find(".isocials_map_selected option:selected").val();
833                Obre(select + "," + param);
834            } else {
835                Obre(select);
836            }
837        });
838
839        L.control.fullscreen({
840            position: 'topleft', title: 'Pantalla completa', titleCancel: 'Sortir de pantalla completa'
841        }).addTo(visor_actual.map);
842
843        var escalacontrol = new L.control.scale({ maxWidth: 250, position: 'bottomleft', imperial: false })
844        visor_actual.map.addControl(escalacontrol);
845
846        if (sel_mapa) {
847            visor_actual.map.button_save = L.control({
848                position: 'topright',
849                classe: 'button_save',
850                inner_HTML: '',
851                title: 'Guardar'
852            });
853
854            visor_actual.map.button_save.onAdd = function (map) {
855                this._div = L.DomUtil.create('div', this.options.classe + ' leaflet-bar'); // create a div with a class "..."
856                this._button = L.DomUtil.create('div', "lflt-panel-button active-block", this._div);
857                this._button.innerHTML = '<a onclick="javascript:Guarda(true);return false;" class="' + this.options.classe + '_img" title="' + this.options.title + '"></a>';
858                return this._div;
859            };
860
861            visor_actual.map.button_save.addTo(visor_actual.map);
862
863        }
864		
865    } // end if
866
867} // Fi Inicialitza_Mapa
868
869function carrerer_show(num_mapa) {
870    var LatLon = $("#cruilla_" + num_mapa).val();
871    var Lat_Lon = LatLon.split("/");
872    var Lat = Number(Lat_Lon[0]);
873    var Lon = Number(Lat_Lon[1]);
874//	alert("carrerer_show --> Lat="+ Lat + "/Lon=" + Lon);
875    posiciona_marker(Lat, Lon, num_mapa);
876}
877
878function situa_marker(Lat, Lon, num_mapa) {
879	var PosIcon = new L.icon({
880			iconUrl: URL_imatges_markers + 'marker-user-red-medium.png',
881			shadowUrl: URL_imatges_markers + 'shadow-med.png',
882			iconSize: [28, 36], // size of the icon
883			shadowSize: [50, 36], // size of the shadow
884			iconAnchor: [14, 36], // point of the icon which will correspond to marker's location
885			shadowAnchor: [14, 36],  // the same for the shadow
886			popupAnchor: [14, -36] // point from which the popup should open relative to the iconAnchor
887	});
888    esborra_marker(num_mapa);
889    PosMarker = new L.marker([Lat, Lon], { icon: PosIcon }).addTo(Visors[num_mapa].map).bindPopup(`Lon: ${Lon}<br/>Lat: ${Lat}`);
890//	alert("situa_marker --> Lat="+ Lat + "/Lon=" + Lon);
891}
892function posiciona_marker(Lat, Lon, num_mapa) {
893	var pointlatlng = new L.LatLng(Lat, Lon);
894	$("#lat_" + num_mapa).val(Lat);
895	$("#lon_" + num_mapa).val(Lon);
896	$("#x_" + num_mapa).val(pointlatlng.utm().toString({ decimals: 3, format: '{x}' }));
897	$("#y_" + num_mapa).val(pointlatlng.utm().toString({ decimals: 3, format: '{y}' }));
898	situa_marker(Lat, Lon, num_mapa);
899	Visors[num_mapa].map.flyTo(pointlatlng, max_Zoom);
900}
901
902function esborra_marker(num_mapa) {
903    if (typeof PosMarker != "undefined") Visors[num_mapa].map.removeLayer(PosMarker);
904}
905
906let numPunt = 1;
907let estemMesurant = false;
908let tipusMesura = "";
909let punts;
910const idsPunts = [];
911let marcadors = [];
912let polygon;
913let polyline;
914
915function toggleMesurar(num_mapa, opcio) {
916    if ($("#mesurar_" + opcio + num_mapa).html() == "Finalitzar mesura") {
917        $("#mesurar_" + opcio + num_mapa).html(`Mesurar ${opcio == "dist" ? "distància" : opcio == "area" ? "àrea" : ""}`);        
918        estemMesurant = false;
919        tipusMesura = opcio;
920        $(".map").css("cursor", "grab");
921        activarBotonsMesures(num_mapa);
922        idsPunts.splice(0, idsPunts.length);
923    }
924    else {
925        $("#mesurar_" + opcio + num_mapa).html("Finalitzar mesura");
926        estemMesurant = true;
927        tipusMesura = opcio;
928        $(".map").css("cursor", "pointer");
929        desactivarBotonsMesures(num_mapa);
930        esborra_marker(num_mapa);
931        if (numPunt > 1) {
932            Visors[num_mapa].map.removeLayer(punts);
933            marcadors = [];
934            numPunt = 1;
935            $("#distancia_" + num_mapa).val("");
936            $("#area_" + num_mapa).val("");
937        }
938    }
939}
940
941//Icones drag&drop del mapa
942document.addEventListener("DOMContentLoaded", function (event) {
943    $(".map").css("cursor", "grab");
944    $(".map").on("pointerdown", (event) => {
945        const to = setTimeout(() => $("html").css("cursor", "grabbing"), 200);
946        function onMouseMove(event) {
947            window.clearTimeout(to);
948            $(".map").css("cursor", "grabbing");
949        }
950        document.addEventListener('mousemove', onMouseMove);
951        document.onmouseup = function () {
952            window.clearTimeout(to);
953            document.removeEventListener('mousemove', onMouseMove);
954            document.onmouseup = null;
955            $(".map").css("cursor", "grab");
956            if (estemMesurant) {
957                $(".map").css("cursor", "pointer");
958            }
959        };
960    });
961    document.ondragstart = () => {
962        return false;
963    };
964});
965
966function activarBotonsMesures(num_mapa) {
967    $("#mesurar_dist" + num_mapa).prop("disabled", false);
968    $("#mesurar_area" + num_mapa).prop("disabled", false);
969}
970
971function desactivarBotonsMesures(num_mapa) {
972    if (tipusMesura == "dist") {
973        $("#mesurar_area" + num_mapa).prop("disabled", true);
974    }
975    else if (tipusMesura == "area") {
976        $("#mesurar_dist" + num_mapa).prop("disabled", true);
977    }
978}
979
980function mesurar(num_mapa) {
981    const icona = new L.icon({
982        iconUrl: URL_imatges_markers + 'punt.png',
983        iconAnchor: [7, 7], // point of the icon which will correspond to marker's location
984        popupAnchor: [0, 0] // point from which the popup should open relative to the iconAnchor
985    });
986
987    const Lat = $(".inputY").val();
988    const Lon = $(".inputX").val();
989    if (numPunt == 1) {
990        punts = L.layerGroup();
991        Visors[num_mapa].map.addLayer(punts);
992    }
993    const marcador = L.marker([Lat, Lon], { icon: icona }).bindPopup(`Lon: ${Lon}<br/>Lat: ${Lat}`).addTo(punts);
994
995    marcadors.push(punts.getLayer(marcador._leaflet_id)._latlng);
996    if (tipusMesura == "dist") {
997        if (polyline) {
998            visor_actual.map.removeLayer(polyline);
999        }
1000        polyline = L.polyline(marcadors).addTo(punts).showMeasurements();
1001    }
1002    else if (numPunt > 2 && tipusMesura == "area") {
1003        if (polygon) {
1004            visor_actual.map.removeLayer(polygon);
1005        }
1006        polygon = L.polygon(marcadors).addTo(punts).showMeasurements();
1007    }
1008
1009    idsPunts.push(marcador._leaflet_id);
1010    numPunt++;
1011
1012    const distanciaArea = calcularDistanciaArea(idsPunts);
1013    $("#distancia_" + num_mapa).val(distanciaArea.dist != 0 ? addDecimalPoints(distanciaArea.dist.toFixed(1).replace(".", ",")) + " m" : "");
1014    $("#area_" + num_mapa).val(distanciaArea.area != 0 ? addDecimalPoints(distanciaArea.area.toFixed(1).replace(".", ",")) + " m2" : "");
1015}
1016
1017function calcularDistanciaArea(idsPunts) {
1018    const coordenadesPunts = idsPunts.map((id) => new L.LatLng(punts.getLayer(id)._latlng.lat, punts.getLayer(id)._latlng.lng));
1019    const coordenadesXY = coordenadesPunts.map((punt) => (
1020        {
1021            x: punt.utm().toString({ decimals: 3, format: '{x}' }),
1022            y: punt.utm().toString({ decimals: 3, format: '{y}' })
1023        }
1024    ));
1025    if (coordenadesPunts.length >= 2) {
1026        let dist = 0;
1027        let area = 0;
1028        for (index = 0; index < coordenadesXY.length - 1; index++) {
1029            dist += Math.sqrt(Math.pow(Math.abs(coordenadesXY[index + 1].x - coordenadesXY[index].x), 2) + Math.pow(Math.abs(coordenadesXY[index + 1].y - coordenadesXY[index].y), 2));
1030        }
1031
1032        if (tipusMesura == "dist") {
1033            return { area: area, dist: dist };
1034        }
1035        else if (tipusMesura == "area") {
1036            return { area: calcularArea(coordenadesXY), dist: 0 };
1037        }
1038        return { area: 0, dist: 0 };
1039    }
1040    return { area: 0, dist: 0 };
1041}
1042
1043function addDecimalPoints(number) {
1044    var numberDecimals = number.split(",");
1045    var inputValue = numberDecimals[0].replace('.', '').split("").reverse().join("");
1046    var newValue = '';
1047    for (var i = 0; i < inputValue.length; i++) {
1048        if (i % 3 == 0 && i != 0) {
1049            newValue += '.';
1050        }
1051        newValue += inputValue[i];
1052    }
1053    return newValue.split("").reverse().join("") + (numberDecimals.length > 1 ? `,${numberDecimals[1]}` : "");
1054}
1055
1056function calcularArea(coords) {
1057    let area = 0;
1058
1059    for (let i = 0; i < coords.length; i++) {
1060        const [x1, y1] = [coords[i].x, coords[i].y];
1061        const [x2, y2] = [coords[(i + 1) % coords.length].x, coords[(i + 1) % coords.length].y];
1062
1063        area += x1 * y2 - x2 * y1
1064    }
1065
1066    return Math.abs(area) / 2;
1067}
1068
1069
1070function Obre(element) {
1071
1072    var parts = element.split(",");
1073    var mapa = parts[0];
1074
1075    if (mapa == "") ObreMapa("")
1076    else if ('*ciutat*comercial*educacio*esp_public*mobilitat*agenda*turisme*coneixer*acustic*cep*tributs*urbanisme*isocials*fira_nov*'.indexOf("*" + mapa + "*") > -1) {
1077        if (parts.length > 1)
1078            ObreMapa(mapa, parts[1]);
1079        else
1080            ObreMapa(mapa);
1081    } else {
1082        if (mapa == "GoogleMaps") ObreGoogleMaps()
1083        else if (mapa == "Bing") ObreBing()
1084        else alert("Opció no contemplada");
1085    }
1086
1087}
1088
1089function ObreMapa(tipus, n) {
1090    var centre = visor_actual.map.getCenter();
1091    var zoom = visor_actual.map.getZoom();
1092    var Lat = centre.lat;
1093    var Lon = centre.lng;
1094    var layers = active_layers();
1095
1096    var URL = URL_mapa + "?map=" + tipus + "&lat=" + Lat + "&lon=" + Lon + "&zoom=" + zoom + "&layers=" + layers;
1097
1098    if (sel_mapa) URL = URL + "&sel_mapa=true";
1099    if (typeof data_mapa != "undefined" && (data_mapa.length == 10)) URL = URL + "&data_mapa=" + data_mapa;
1100
1101    if (typeof n != 'undefined') URL = URL + "&n=" + n;
1102    window.location.href = URL;
1103}
1104
1105function ObreGoogleMaps() {
1106    var centre = visor_actual.map.getCenter();
1107    var Lat = centre.lat;
1108    var Lon = centre.lng;
1109    var URL = "https://www.google.cat/maps?q=" + Lat + "," + Lon + "&layer=c&cbll=" + Lat + "," + Lon + "&cbp=12,134.73,,0,0";
1110    var win = window.open(URL, "_blank");
1111}
1112
1113function ObreBing() {
1114    var centre = visor_actual.map.getCenter();
1115    var Lat = centre.lat;
1116    var Lon = centre.lng;
1117    var URL = "https://www.bing.com/maps?cp=" + Lat + "~" + Lon + "&lvl=20&v=2&sV=2&form=S00027";
1118    var win = window.open(URL, "_blank");
1119}
1120
1121function Canvia_Mapa_Fons(ciutat, mapa) {
1122    const idCapaCiutat = 1;
1123    const idCapaORTO = 2;
1124
1125    if (ciutat) {
1126        setEstatCapaPerCodi(mapa, idCapaORTO, 0);
1127        setEstatCapaPerCodi(mapa, idCapaCiutat, 1);
1128    } else {
1129        setEstatCapaPerCodi(mapa, idCapaCiutat, 0);
1130        setEstatCapaPerCodi(mapa, idCapaORTO, 1);
1131    }
1132};
1133
1134function trobaCheckboxPerCodi(mapa, idCapa) {
1135    const accordion = Visors[mapa].AccordionLegend;
1136    if (!accordion?.checkboxGroupApps)
1137        return null;
1138
1139    // 1. Trobar l'índex N on visor_actual.Id[N] === idCapa
1140    let numCapa = null;
1141    for (let i = 1; i <= visor_actual.NumCapes; i++) {
1142        if (String(visor_actual.Id[i]) === String(idCapa)) {
1143            numCapa = i;
1144            break;
1145        }
1146    }
1147    if (numCapa === null) {
1148        console.warn(`IdCapa "${idCapa}" no trobat a visor_actual`);
1149        return null;
1150    }
1151
1152    // 2. L'id del DOM és acc_layer_N
1153    const targetId = "acc_layer_" + numCapa;
1154
1155    // 3. Cercar en quina checkboxGroupApps hi ha aquest element
1156    for (const grup of accordion.checkboxGroupApps) {
1157        for (const cbEl of grup.$checkboxes) {
1158            const $cb = $(cbEl);
1159            if ($cb.attr("id") === targetId) {
1160                return { grup, $cb };
1161            }
1162        }
1163    }
1164    return null;
1165}
1166
1167function setEstatCapaPerCodi(mapa, idCapa, estat) {
1168    const result = trobaCheckboxPerCodi(mapa, idCapa);
1169    if (result) {
1170        result.grup.setBoxState(result.$cb, estat);
1171        return true;
1172    }
1173    console.warn(`No s'ha trobat cap capa amb IdCapa="${idCapa}" al mapa ${mapa}`);
1174    return false;
1175}
1176
1177function active_layers() {
1178    var actL = "";
1179    visor_actual.AccordionLegend.checkboxGroupApps.forEach(function (item, index) {
1180
1181        //	  alert(index);
1182        item.$checkboxes.each(function () {
1183            if (item.getBoxState($(this)) == true) {
1184                var idNode = this.id.substring(10, 14);
1185                var codiCapa = visor_actual.CodiCapa[idNode];
1186                var idCapa = visor_actual.Id[idNode];
1187
1188                if ((codiCapa != "ORTO_ICC") && (codiCapa != "TOPO_ICC") && (codiCapa != "CIUTAT") && (codiCapa != "CARR_MAPA,NUME_MAPA,TOPONIMIA_MAPA")) {
1189                    actL = actL + "," + idCapa;
1190                }
1191            };
1192        });
1193    });
1194    if (actL.substring(0, 1) == ",") {
1195        return actL.substring(1, 1000);
1196    } else {
1197        return actL;
1198    }
1199}
1200
1201function Guarda() {
1202    var layers = active_layers();
1203    var centre = Visors[0].map.getCenter();
1204    var lat = centre.lat;
1205    var lon = centre.lng;
1206    var zoom = Visors[0].map.getZoom();
1207    var t_situa = situa ? "S" : "N";
1208
1209    var dadesMap = {
1210        action: "actualitza_mapa",
1211        map: actived_map,
1212        layers: layers,
1213        lat: lat,
1214        lon: lon,
1215        zoom: zoom,
1216        situa: t_situa
1217    };
1218
1219    window.opener.postMessage(dadesMap, "*");
1220    window.close();
1221}
1222
1223function ObrePopUp(classe) {
1224    $('.' + classe + ' .lflt-panel-button').removeClass('active-block');
1225    $('.' + classe + ' .lflt-control-panel').addClass('active-block');
1226}
1227
1228function TancaPopUp(classe) {
1229    $('.' + classe + ' .lflt-panel-button').addClass('active-block');
1230    $('.' + classe + ' .lflt-control-panel').removeClass('active-block');
1231}
1232
1233function llistaElements(data, URLImatge, URLDetall, marker, cache, tipus) {
1234    const { id, name, title, img, fields } = data;
1235
1236    const idArray = String(id).split("; ");
1237    const nameArray = name ? String(name).split("; ") : String(title).split("; ");
1238    const imageArray = String(img || "").split("; ");
1239
1240    const fieldArrays = (fields || []).map(f => ({
1241        label: f?.label,
1242        values: f?.url
1243            ? [f?.url]
1244            : String(f?.value || "").split("; ").map(v => v.trim()).filter(Boolean),
1245        url: f?.url,
1246        urlText: f?.urlText
1247    }));
1248
1249    const renderField = (f, index) => {
1250        if (f.url) {
1251            const link = `<a href="${f.values[0]}" target="_blank">${f.urlText || f.label || f.values[0]}</a>`;
1252            return f.label ? `<strong>${f.label}:</strong> ${link}` : link;
1253        }
1254        const value = f.values[index] || "";
1255        if (!value)
1256            return "";
1257        return `<span>${f.label ? `<strong>${f.label}:</strong> ${value}` : value}</span>`;
1258    };
1259
1260    marker.on("popupclose", (e) => {
1261        if (e.target._icon) {
1262            if (tipus == "MobiliariCluster") {
1263				if (e.target._icon.classList.contains("relacionat")) {
1264					e.target._popup._content = e.target._popup._content.replace('background-image:url("./images/eye.png")', 'background-image:url("./images/eye-slash.png")');
1265					e.target._popup._content = e.target._popup._content.replace('Mostrar', 'Amagar');
1266				}
1267				else {
1268					e.target._popup._content = e.target._popup._content.replace('background-image:url("./images/eye-slash.png")', 'background-image:url("./images/eye.png")');
1269					e.target._popup._content = e.target._popup._content.replace('Amagar', 'Mostrar');
1270				}
1271			}
1272        }
1273    });
1274
1275    const scroll = idArray.length > 2 ? "; overflow-y:scroll'>" : "'>";
1276    const head = "<ul style='padding-left:0; list-style:none; max-height:45vh" + scroll;
1277    let llista = "";
1278    idArray.forEach((idElement, index) => {
1279        if (!idElement || idElement.trim() === "")
1280            return;
1281
1282        const contingut_bloc = (() => {
1283            const descCompleta = fieldArrays.map(f => renderField(f, index)).filter(Boolean).join("<br>");
1284            let out = "";
1285            if (imageArray[index]) {
1286                out += `<div class='pbody'><div class='desc'>${descCompleta}</div><div class='image'><img src='${URLImatge}\\${idElement}\\${imageArray[index]}'/></div></div>`;
1287            } else {
1288                out += `<div class='pbody'>${descCompleta}</div>`;
1289            }
1290            return out;
1291        })();
1292        var icona="";
1293        if (tipus == "MobiliariCluster") {
1294			icona = cache == "false" ? `<div class='icona' style='background-image:url("./images/eye.png"); height:16px; width:18px; background-repeat:no-repeat; margin-left:10px' onclick='buscarRelacions(this,${idElement})' title='Mostrar mobiliari relacionat'>&nbsp</div>` : "";
1295		}
1296        llista += `<li style='padding-block:2px;'><div style='display:flex; justify-content:space-between;'>`;
1297        llista += URLDetall ? `<a target='_blank' href='${URLDetall}${idElement.startsWith("null_") ? "" : idElement}'>` : "";
1298        llista += `<h3 style='margin:0;'>${nameArray[index]}</h3></a>${icona}</div>${contingut_bloc}</li>`;
1299    });
1300    const peu = "</ul>";
1301    return head + llista + peu;
1302};
1303
1304function buscarRelacions(element, id) {
1305    const desactivar = 'url("./images/eye-slash.png")' === element.style["background-image"];
1306
1307    const imatge = desactivar ? 'url("./images/eye.png")' : 'url("./images/eye-slash.png")';
1308    const text = desactivar ? "Mostrar mobiliari relacionat" : "Amagar mobiliari relacionat";
1309    element.style["background-image"] = imatge;
1310    element.setAttribute("title", text);
1311    const marcador = $(`img[title*='${id}']`);
1312
1313    $.ajax({
1314        dataType: 'json',
1315        url: `${serv_base_path_sig + path_sig}/DirData/mobiliari-relacions?id=${id}`,
1316        data: "",
1317        xhrFields: {
1318            'withCredentials': true
1319        },
1320        success: function (resposta) {
1321            if (resposta[0].relacio) {
1322                resposta[0].relacio.split(";").map((idRelacio) => {
1323                    const element = $(`img[title*='${idRelacio}']`);
1324                    if (element.length > 0) {
1325                        desactivar ? element.removeClass("ressaltar") : element.addClass("ressaltar");
1326                        desactivar ? marcador.removeClass("relacionat") : marcador.addClass("relacionat");
1327                    }
1328                });
1329            }
1330        },
1331        error: function (xhr, ajaxOptions, thrownError) {
1332            alert("Error " + xhr.status);
1333        }
1334    });
1335};
1336
1337async function Omple_dades(num_mapa) {
1338    var mem_grup = "";
1339    var my_layer = {};
1340    var grup = {};
1341    var cache = "true";
1342    var Visualitzador = new Object();
1343    Visualitzador[num_mapa] = new Object();
1344    Visualitzador[num_mapa] = await getCapesLeaflet(actived_map);
1345
1346    //DEBUG
1347    //debugCapes(Visualitzador[num_mapa], init_map_layers(actived_map));
1348
1349    Visualitzador[num_mapa].forEach(function (vis_group) {
1350        cache = "true";
1351        grup = {};
1352        grup.title = vis_group.NomGrup;
1353        grup.color = vis_group.ColorGrup;
1354        grup.color_text = vis_group.ColorText;
1355        grup.selectable = vis_group.Seleccionable;
1356        grup.layers = [];
1357
1358        vis_group.Capes.forEach(function (vis_layer) {
1359            my_layer = {};
1360            my_layer.type = "general";
1361            visor_actual.NumCapes = visor_actual.NumCapes + 1;
1362            my_layer.id = visor_actual.NumCapes;
1363            var s = "00000000000" + ((num_mapa * 10000) + visor_actual.NumCapes);
1364            my_layer.gid = s.substr(s.length - 10);
1365            visor_actual.NomCapa[visor_actual.NumCapes] = vis_layer.NomCapa;
1366            visor_actual.CodiCapa[visor_actual.NumCapes] = vis_layer.CodiCapa;
1367            visor_actual.Id[visor_actual.NumCapes] = vis_layer.Id;
1368            visor_actual.Llegenda[visor_actual.NumCapes] = vis_layer.Llegenda;
1369
1370            if (typeof vis_layer.Attribution != "undefined") {
1371                visor_actual.Attribution[visor_actual.NumCapes] = vis_layer.Attribution;
1372            } else {
1373                visor_actual.Attribution[visor_actual.NumCapes] = "&copy; Ajuntament de Vilanova i la Geltr&uacute;";
1374            }
1375
1376            if (typeof vis_layer.Activa != "undefined") {
1377                visor_actual.Activa[visor_actual.NumCapes] = vis_layer.Activa;
1378            } else {
1379                visor_actual.Activa[visor_actual.NumCapes] = false;
1380            }
1381
1382            visor_actual.Servidor[visor_actual.NumCapes] = vis_layer.Servidor;
1383
1384            if (typeof vis_layer.minZoom != "undefined") {
1385                visor_actual.minZoom[visor_actual.NumCapes] = vis_layer.minZoom;
1386            } else {
1387                visor_actual.minZoom[visor_actual.NumCapes] = min_Zoom;
1388            }
1389
1390            if (typeof vis_layer.maxZoom != "undefined") {
1391                visor_actual.maxZoom[visor_actual.NumCapes] = vis_layer.maxZoom;
1392            } else {
1393                visor_actual.maxZoom[visor_actual.NumCapes] = max_Zoom;
1394            }
1395
1396            visor_actual.NomGrup[visor_actual.NumCapes] = vis_layer.NomGrup;
1397            visor_actual.Tipus[visor_actual.NumCapes] = vis_layer.Tipus;
1398
1399            var nova_capa = {};
1400
1401            if (vis_layer.Tipus == "Tile") {
1402                nova_capa = new L.TileLayer(vis_layer.Servidor,
1403                    {
1404                        minZoom: vis_layer.minZoom,
1405                        maxZoom: vis_layer.maxZoom,
1406                        pane: "tilePane",
1407                        attribution: visor_actual.Attribution[visor_actual.NumCapes]
1408                    });
1409            } else if (vis_layer.Tipus == "TLWMS") {
1410                nova_capa = new L.tileLayer.wms(vis_layer.Servidor, {
1411                    minZoom: vis_layer.minZoom,
1412                    maxZoom: vis_layer.maxZoom,
1413                    layers: vis_layer.CodiCapa,
1414                    format: "image/png",
1415                    transparent: true,
1416                    pane: "intermig",
1417                    attribution: visor_actual.Attribution[visor_actual.NumCapes]
1418                });
1419            } else if (vis_layer.Configuracio) {
1420                my_layer.type = "no_slider";
1421
1422                const config = vis_layer.Configuracio;
1423                const URLImatge = config.imagePath || "";
1424                const URLDetall = config.detailUrl || "";
1425                const scriptTag = document.currentScript || document.querySelector("script[src*='mapa.v23.js']");                
1426                let URLServidorJSON = (serv_base_path_sig + config.urlTemplate) || "";
1427
1428                URLServidorJSON = URLServidorJSON
1429                    .replace("{codiCapa}", vis_layer.CodiCapa)
1430                    .replace("{dataMapa}", data_mapa)
1431                    .replace("{username}", (typeof IdUsuari !== 'undefined' && IdUsuari !== null) ? IdUsuari : "{username}");
1432
1433                const useCache = config.useCache !== undefined ? config.useCache : true;
1434
1435                nova_capa = new L.LayerJSON({
1436                    url: URLServidorJSON,
1437                    propertyTitle: "title",
1438                    pane: "markerPane",
1439                    propertyLoc: ["lat", "lng"],
1440                    minShift: 0,
1441                    caching: useCache,
1442                    buildIcon: function (data, title) {
1443                        let icona;
1444                        if (typeof data.icona != "undefined") {
1445                            icona = data.icona + ".png";
1446                        } else {
1447                            if (typeof data.quantitat != "undefined" && data.quantitat > 1) {
1448                                icona = vis_layer.URLIconaCluster;
1449                            } else {
1450                                icona = vis_layer.URLIcona;
1451                            }
1452                        }
1453                        return new L.icon({
1454                            iconUrl: URL_imatges_markers + icona,
1455                            shadowUrl: URL_imatges_markers + "shadow-med.png",
1456                            iconSize: [28, 36],
1457                            shadowSize: [50, 36],
1458                            iconAnchor: [14, 36],
1459                            shadowAnchor: [14, 36],
1460                            popupAnchor: [14, -36],
1461                        });
1462                    },
1463                    buildPopup: function (data, marker) {
1464                        return llistaElements(data, URLImatge, URLDetall, marker, useCache.toString(), vis_layer.Tipus);
1465                    }
1466                });
1467            } else if (vis_layer.Tipus == "WMS") {
1468                var sourceWMS = L.WMS.source(vis_layer.Servidor, {
1469                    "transparent": true,
1470                    "identify": false // evitar que, en fer-hi clic, tregui un popup
1471                });
1472                nova_capa = sourceWMS.getLayer(vis_layer.CodiCapa);
1473            } else if (vis_layer.Tipus == "WMS_T") {
1474                var sourceWMS = L.WMS.source(vis_layer.Servidor, {
1475                    "transparent": true,
1476                    "pane": "intermig_s",
1477                    "identify": false // evitar que, en fer-hi clic, tregui un popup
1478                });
1479                nova_capa = sourceWMS.getLayer(vis_layer.CodiCapa);
1480            }
1481
1482            visor_actual.Capa[visor_actual.NumCapes] = nova_capa;
1483            my_layer.layer = visor_actual.Capa[visor_actual.NumCapes];
1484            my_layer.title = vis_layer.NomCapa;
1485
1486            if ((my_layer.type != "no_slider") && (typeof vis_layer.OpacitatCapa != "undefined")) {
1487                my_layer.opacity = vis_layer.OpacitatCapa;
1488            } else {
1489                my_layer.opacity = 1;
1490            }
1491
1492            my_layer.legend = [];
1493            if (typeof visor_actual.Llegenda[visor_actual.NumCapes] != "undefined" && vis_layer.Llegenda?.length) {
1494                my_layer.legend = visor_actual.Llegenda[visor_actual.NumCapes];
1495            } else {
1496                if (typeof vis_layer.URLIcona != "undefined") {
1497                    my_layer.legend = [{ type: "image", url: vis_layer.URLIcona }]
1498                }
1499            }
1500
1501            my_layer.show = visor_actual.Activa[visor_actual.NumCapes];
1502            for (let i = 0; i < actived_layers.length; i++) {
1503                if (actived_layers[i] == vis_layer.CodiCapa || actived_layers[i] == vis_layer.Id) {
1504                    my_layer.show = true;
1505                }
1506            }
1507
1508            if (typeof vis_layer.Servidor2 != "undefined") {
1509                var sourceWMS2 = L.WMS.source(vis_layer.Servidor2, {
1510                    "transparent": true,
1511                    "identify": false // evitar que, en fer-hi clic, tregui un popup
1512                });
1513                var capaWMS2 = sourceWMS2.getLayer(vis_layer.Croquis ? "CROQUIS" : vis_layer.CodiCapa);
1514                var group = new L.LayerGroup([visor_actual.Capa[visor_actual.NumCapes], capaWMS2]);
1515                my_layer.group = group;
1516            }
1517
1518            grup.layers[my_layer.id] = my_layer;
1519        });
1520
1521        visor_actual.Grups_i_capes.push(grup);
1522    });
1523}
1524
1525function limit_propagation(classe) {
1526    // Disable events inside leaflet-control
1527
1528    a = $(classe);
1529    $.each(a, function (key, element) {
1530        limit_element_propagation(element);
1531    });
1532
1533    // End - Disable events inside accordion
1534
1535}
1536
1537function limit_element_propagation(element) {
1538    // Disable events inside leaflet-control
1539
1540    if (element.addEventListener) {
1541        // Disable dragging when user's cursor enters the element
1542        element.addEventListener('mouseover', function () { visor_actual.map.dragging.disable(); visor_actual.map.scrollWheelZoom.disable(); });
1543        // Re-enable dragging when user's cursor leaves the element
1544        element.addEventListener('mouseout', function () { visor_actual.map.dragging.enable(); visor_actual.map.scrollWheelZoom.enable(); });
1545
1546        element.addEventListener('mousedown', function () { visor_actual.map.dragging.disable(); visor_actual.map.scrollWheelZoom.disable(); });
1547        //		element.addEventListener('wheel', function () {map.dragging.disable();  map.scrollWheelZoom.disable()});	
1548        //		element.addEventListener('dblclick', function () {map.dragging.disable()});	
1549
1550    } else if (element.attachEvent) { // For IE < 9
1551        element.attachEvent('mouseover', function () { visor_actual.map.dragging.disable(); visor_actual.map.scrollWheelZoom.disable(); });
1552        element.attachEvent('mouseout', function () { visor_actual.map.dragging.enable(); visor_actual.map.scrollWheelZoom.enable(); });
1553        element.attachEvent('mousedown', function () { visor_actual.map.dragging.disable(); visor_actual.map.scrollWheelZoom.disable(); });
1554        //		element.attachEvent('mousewheel', function () {map.dragging.disable()});			
1555        //		element.attachEvent('dblclick', function () {map.dragging.disable()});			
1556    }
1557
1558    if (!L.Browser.touch) {
1559        L.DomEvent.disableClickPropagation(element);
1560        //		L.DomEvent.on(element, 'mousewheel', L.DomEvent.stopPropagation);
1561    } else {
1562        //		L.DomEvent.on(element, 'mouseover', L.DomEvent.stopPropagation);
1563        //		L.DomEvent.on(element, 'mousedown', L.DomEvent.stopPropagation);
1564        L.DomEvent.on(element, 'click', L.DomEvent.stopPropagation);
1565        L.DomEvent.on(element, 'dblclick', L.DomEvent.stopPropagation);
1566        L.DomEvent.on(element, 'touchstart', L.DomEvent.stopPropagation);
1567        L.DomEvent.on(element, 'touchmove', L.DomEvent.stopPropagation);
1568        L.DomEvent.on(element, 'touchend', L.DomEvent.stopPropagation);
1569    }
1570
1571
1572    // End 
1573
1574}

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.