PageSourceSearch

https://meteoguilleries.cat/js/public/webcamsMap.js

js meteoguilleries.cat collected 2026-10-06 17:47:14 UTC 6,427 bytes, 157 lines download raw bytes

1(function (window, $) {
2  'use strict';
3
4  var mapInstance;
5  var markersLayer;
6  var cameraIcon;
7  var defaultView = { lat: 41.95, lng: 2.36, zoom: 9 };
8
9  function ensureMap() {
10    if (mapInstance) { return true; }
11    if (typeof L === 'undefined') { return false; }
12    var element = document.getElementById('MapaWebcams');
13    if (!element) { return false; }
14
15    mapInstance = L.map(element, {
16      scrollWheelZoom: false,
17      worldCopyJump: true
18    }).setView([defaultView.lat, defaultView.lng], defaultView.zoom);
19
20    if (!cameraIcon) {
21      cameraIcon = L.icon({
22        iconUrl: '/img/icones/img_cameres.png',
23        iconSize: [36, 34],
24        iconAnchor: [24, 44],
25        tooltipAnchor: [0, -40],
26        popupAnchor: [0, -40]
27      });
28    }
29
30    var OpenTopoMap = L.tileLayer('https://{s}.tile.opentopomap.org/{z}/{x}/{y}.png', {
31      maxZoom: 17,
32      className: 'tiles-suau',
33      attribution: 'Map data: &copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors, <a href="http://viewfinderpanoramas.org">SRTM</a> | Map style: &copy; <a href="https://opentopomap.org">OpenTopoMap</a> (<a href="https://creativecommons.org/licenses/by-sa/3.0/">CC-BY-SA</a>)'
34    });
35    var OpenStreetMap_CAT = L.tileLayer('https://tile.openstreetmap.bzh/ca/{z}/{x}/{y}.png', {
36      maxZoom: 19,
37      attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors, Tiles courtesy of <a href="https://www.openstreetmap.cat" target="_blank">Breton OpenStreetMap Team</a>'
38    });
39    var Esri_WorldTopoMap = L.tileLayer('https://server.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer/tile/{z}/{y}/{x}', {
40      attribution: 'Tiles &copy; Esri &mdash; Esri, DeLorme, NAVTEQ, TomTom, Intermap, iPC, USGS, FAO, NPS, NRCAN, GeoBase, Kadaster NL, Ordnance Survey, Esri Japan, METI, Esri China (Hong Kong), and the GIS User Community'
41    });
42    var Esri_WorldImagery = L.tileLayer('https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}', {
43      attribution: 'Tiles &copy; Esri &mdash; Source: Esri, i-cubed, USDA, USGS, AEX, GeoEye, Getmapping, Aerogrid, IGN, IGP, UPR-EGP, and the GIS User Community'
44    });
45    var baseLayers = {
46      'OpenTopoMap': OpenTopoMap,
47      'OpenStreetMap CAT': OpenStreetMap_CAT,
48      'Esri World Topo Map': Esri_WorldTopoMap,
49      'Esri World Imagery': Esri_WorldImagery
50    };
51
52    OpenTopoMap.addTo(mapInstance);
53    L.control.layers(baseLayers, null, { position: 'topleft', collapsed: true }).addTo(mapInstance);
54
55    markersLayer = L.layerGroup().addTo(mapInstance);
56    return true;
57  }
58
59  function convertirGMSaGD(graus, minuts, segons, direccio) {
60    var dd = parseFloat(graus || 0) + parseFloat(minuts || 0) / 60 + parseFloat(segons || 0) / 3600;
61    if (direccio === 'S' || direccio === 'W') {
62      dd = dd * -1;
63    }
64    return dd;
65  }
66
67  function parseCoords(raw) {
68    if (!raw) { return null; }
69    var value = String(raw).trim();
70    if (!value) { return null; }
71
72    var decimalMatch = value.match(/([-+]?\d+(?:\.\d+)?)[,\s]+([-+]?\d+(?:\.\d+)?)/);
73    if (decimalMatch) {
74      var lat = parseFloat(decimalMatch[1]);
75      var lng = parseFloat(decimalMatch[2]);
76      if (!isNaN(lat) && !isNaN(lng)) {
77        return { lat: lat, lng: lng };
78      }
79    }
80
81    var parts = value.split(/[^0-9A-Za-z]+/).filter(Boolean);
82    if (parts.length >= 8) {
83      var lat = convertirGMSaGD(parts[0], parts[1], parts[2], parts[3]);
84      var lng = convertirGMSaGD(parts[4], parts[5], parts[6], parts[7]);
85      if (!isNaN(lat) && !isNaN(lng)) {
86        return { lat: lat, lng: lng };
87      }
88    }
89    return null;
90  }
91
92  function buildTooltip(item) {
93    var name = item && item.nom ? item.nom : 'Webcam';
94    var municipi = item && item.ubicacio ? item.ubicacio : '';
95    return municipi ? name + ' - ' + municipi : name;
96  }
97
98  function openCameraFromMarker(item, cameraId) {
99    // Si estem a la pàgina de webcams i MVOpenWebcam està disponible, utilitzar-la
100    if (typeof window.MVOpenWebcam === 'function') {
101      var particlesFlag = (typeof window.MVDetectParticlesFromRecord === 'function') ? window.MVDetectParticlesFromRecord(item) : (item && Object.prototype.hasOwnProperty.call(item, 'teParticules') && String(item.teParticules).toUpperCase() === 'S');
102      var panoramicFlag = !!(item && item.ubicacioTransparencia && String(item.ubicacioTransparencia).trim() !== '');
103      window.MVOpenWebcam(cameraId, {
104        timelapseUrl: item && item.timelapse ? item.timelapse : '',
105        preferTimelapse: false,
106        scrollToCard: true,
107        hasPanoramic: panoramicFlag,
108        hasParticles: particlesFlag
109      });
110    } else {
111      // Si no està disponible (estem a la home), redirigir a la pàgina de webcams
112      var lang = (typeof jsi18MVC !== 'undefined' && jsi18MVC.jsi18MVCLang) ? jsi18MVC.jsi18MVCLang : '/ca/';
113      var timelapseParam = (item && item.timelapse) ? '&mode=timelapse' : '';
114      window.location.href = lang + '/webcams.html?cam=' + cameraId + timelapseParam;
115    }
116  }
117
118  window.MVWebcamsMap = {
119    update: function (list) {
120      if (!Array.isArray(list) || list.length === 0) {
121        if (markersLayer) {
122          markersLayer.clearLayers();
123        }
124        return;
125      }
126
127      if (!ensureMap()) {
128        return;
129      }
130
131      mapInstance.invalidateSize();
132      markersLayer.clearLayers();
133      var bounds = [];
134
135      list.forEach(function (item) {
136        var cameraId = item && (item.idCameres || item.id);
137        if (!cameraId) { return; }
138        var coords = parseCoords(item && item.posicioGPS);
139        if (!coords) { return; }
140
141        var marker = L.marker([coords.lat, coords.lng], { icon: cameraIcon });
142        marker.bindTooltip(buildTooltip(item), { direction: 'top', offset: [0, -12] });
143        marker.on('click', function () {
144          openCameraFromMarker(item, cameraId);
145        });
146        marker.addTo(markersLayer);
147        bounds.push([coords.lat, coords.lng]);
148      });
149
150      if (bounds.length) {
151        mapInstance.fitBounds(bounds, { padding: [24, 24] });
152      } else {
153        mapInstance.setView([defaultView.lat, defaultView.lng], defaultView.zoom);
154      }
155    }
156  };
157})(window, window.jQuery);

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.