From 1911c0ce9fdc17d33e61203ab2b80e6fa2424784 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=B2=20P?= Date: Wed, 26 Mar 2025 16:44:48 +0100 Subject: [PATCH] Refactor with sites from DB... --- webgis/js/gis.js | 251 +++++++++++++---------------------------------- webgis/js/ui.js | 33 ------- 2 files changed, 69 insertions(+), 215 deletions(-) diff --git a/webgis/js/gis.js b/webgis/js/gis.js index ad6e034..344a00e 100644 --- a/webgis/js/gis.js +++ b/webgis/js/gis.js @@ -63,20 +63,6 @@ const optionsFabbricati = { fillColor: '#5b5d5f', fillOpacity: 0.8 }; -const MARKER_NAMES = { - sites: { - 'gradola' : 'Villa di Gradola', - 'damecuta' : 'Villa di Damecuta', - 'matermania' : 'Grotta di Matermania', - 'arsenale' : 'Grotta dell\'Arsenale', - 'tiberio' : 'Bagni di Tiberio', - 'mura' : 'Mura greche', - 'san_michele' : 'Villa San Michele', - 'scala_fenicia' : 'Scala Fenicia', - 'grotta_azzurra' : 'Grotta Azzurra', - 'lopozzo' : 'Località Lo Pozzo', - }, -}; const clusterOptions = { spiderfyOnMaxZoom: false, showCoverageOnHover: false, @@ -110,16 +96,6 @@ function capitalize(text) { * @returns {Map} */ GIS.initMap = async function (mapId, zoomLevel = this.INIT_ZOOM) { - L.LayerGroup.include({ - customGetLayer : function (id) { - for (let l in this._layers) { - if (this._layers[l].id === id) { - return this._layers[l]; - } - } - } - }); - let map = L.map(mapId, { //attributionControl: false, minZoom: GIS.MIN_ZOOM, @@ -127,16 +103,20 @@ GIS.initMap = async function (mapId, zoomLevel = this.INIT_ZOOM) { map.crs = L.CRS.EPSG4326; - const {baseMap, sitesGroup} = await this.initLayers(map); + const baseMap = await this.initLayers(map); // Add scale and ruler controls L.control.scale({imperial: false}).addTo(map); L.control.graphicScale({fill: 'hollow', position: 'bottomright'}).addTo(map); - let layerVincoli = await this.loadLayer('vincoli.geojson', optionsVincoli); - let layerPaesistici = await this.loadLayer('paesistici.geojson', optionsPaesistici); + let layerVincoli = await this.loadGeoJSON('vincoli.geojson', optionsVincoli); + let layerPaesistici = await this.loadGeoJSON('paesistici.geojson', optionsPaesistici); // Refactor with separate function... - this.sitesMarkers(sitesGroup).then(group => {group.addTo(map); window.Sites = group}); + this.sites().then(data => { + data.markers.addTo(map); + data.geom.addTo(map); + window.Sites = data.markers; + }); this.notConserved().then(group => {group.addTo(map); window.NotConserved = group}); this.findings().then(group => {group.addTo(map); window.Findings = group}); this.prehistoric().then(group => {group.addTo(map); window.Prehistoric = group}); @@ -145,55 +125,39 @@ GIS.initMap = async function (mapId, zoomLevel = this.INIT_ZOOM) { 'Vincoli archeologici' : layerVincoli, 'Vincoli paesistici' : layerPaesistici, }; - // TEMP!! Remove point for Lo Pozzo... - sitesGroup.removeLayer(sitesGroup.customGetLayer('lopozzo')); - - sitesGroup.addTo(map); - L.control.layers(baseMap, archeo).addTo(map); return map; } /** * Create markers for sites - * @param {L.LayerGroup} sitesGroup - * @returns {L.markerClusterGroup} + * @returns {{markers: L.markerClusterGroup, geom: L.LayerGroup}} */ -GIS.sitesMarkers = async function (sitesGroup) { - let sitesMarkers = L.markerClusterGroup( - clusterOptions - ); +GIS.sites = async function () { + let sitesData = await fetch(`${API_URL}/sites`) + .then(data => data.json()); - for (let id in MARKER_NAMES.sites) { - let layer = sitesGroup.customGetLayer(id); - let coords = layer?.getBounds().getCenter(); - const fromStorage = localStorage.getItem(id); - let data = {}; + let sites = L.markerClusterGroup(clusterOptions); + let geom = []; - if (fromStorage !== 'undefined') { - try { - data = JSON.parse(fromStorage); - const lat = data?.coordinates[0] ?? coords.lat; - const lon = data?.coordinates[1] ?? coords.lng; - coords = [lat, lon]; - } catch (error) { - console.log(error); - } - } else { - data = await GIS._fetchData('site/' + id); + for (let record of sitesData) { + if (record.geojson) { + const options = record.gisId === 'grotta_azzurra' ? + optionsGrotta : optionsSiti; + geom.push(await this.loadSiteLayer(record, options)); } - - const marker = L.marker(coords, { icon: Icons.site }) - .bindTooltip(MARKER_NAMES.sites[id] + '
(Clicca per aprire scheda)'); - - marker.id = id; - - marker.on('click', () => UI.openSiteModal(data, '#site-data')); - - sitesMarkers.addLayer(marker); + sites.addLayer(L.marker( + record.coordinates, + {icon: Icons.site} + ).bindTooltip(record.label + '
(Clicca per aprire scheda)') + .on( + 'click', + () => UI.openSiteModal(record, '#site-data') + ) + ); } - return sitesMarkers; + return {markers: sites, geom: L.layerGroup(geom)}; } /** * Create not conserved group @@ -272,103 +236,15 @@ GIS.prehistoric = async function () { } return prehistoric; - /* - const geo = await fetch(`${BASE_URL}/geojson/preistorici.geojson`) - .then(res => res.json()); - - let prehistoric = L.markerClusterGroup( - clusterOptions - ); - - L.geoJSON(geo, { - pointToLayer: function(geoJsonPoint, latlng) { - prehistoric.addLayer( - L.marker(latlng, { - icon: Icons.prehistoric - }).bindTooltip(geoJsonPoint.properties.denominazione) - .bindPopup(` - - - -
Denominazione:${geoJsonPoint.properties.denominazione}
Oggetto:${geoJsonPoint.properties.oggetto}
- `) - ); - }, - }); - - return prehistoric; - */ } -/* -GIS._prepareLayers = async function(layer) { - const fromStorage = localStorage.getItem(layer.id); - let data = {}; - let coords = layer.getBounds().getCenter(); - - if (fromStorage !== 'undefined') { - try { - data = JSON.parse(fromStorage); - const lat = data?.lat ?? coords[0]; - const lon = data?.lon ?? coords[1]; - coords = [lat, lon]; - } catch (error) { - console.log(error); - } - } else { - data = await GIS._fetchData(layer.id); - } - - // TODO: terrible! - if (!layer.id.includes('area')) { - const marker = L.marker(coords) - .addTo(map) - .bindTooltip( - Object.keys(archeo).find(k => archeo[k] === layer) - .replace(/\s\(.*$/, '') - ) - .openTooltip(); - - if (typeof data === 'object') { - marker.on('click', () => UI.openModal(data, '#site-data')); - } - } -} -*/ /** * Adds layers to map and returns an object * with {baseMap, archeoLayers, sitesLayerGroup} + * @todo Load areas for sites that have them!! * @param {L.Map} map - * @returns {{baseMap: {"OpenStreetMap": L.TileLayer}, archeo: object, sitesGroup: L.LayerGroup}} + * @returns {{baseMap: {"OpenStreetMap": L.TileLayer}}} */ GIS.initLayers = async function(map) { - // TODO Move all this to separate array / object! - let layerMater = await this.loadLayer('matermania.geojson', optionsSiti, false); - let layerMaterArea = await this.loadLayer('matermania_area.geojson', optionsSiti, false); - let layerArsenale = await this.loadLayer('arsenale.geojson', optionsSiti, false); - let layerArsenaleArea = await this.loadLayer('arsenale_area.geojson', optionsSiti, false); - let layerGradola = await this.loadLayer('gradola.geojson', optionsSiti, false); - let layerGradolaArea = await this.loadLayer('gradola_area.geojson', optionsSiti, false); - let layerMura = await this.loadLayer('mura.geojson', optionsSiti, false); - let layerSanMichele = await this.loadLayer('san_michele.geojson', optionsSiti, false); - let layerDamecuta = await this.loadLayer('damecuta.geojson', optionsSiti, false); - let layerTiberio = await this.loadLayer('tiberio.geojson', optionsSiti, false); - let layerScala = await this.loadLayer('scala_fenicia.geojson', optionsSiti, false); - let layerGrotta = await this.loadLayer('grotta_azzurra.geojson', optionsGrotta, false); - let layerLopozzo = await this.loadLayer('lopozzo.geojson', optionsSiti, false); - - layerMater.id = 'matermania'; - layerMaterArea.id = 'matermania_area'; - layerGradola.id = 'gradola'; - layerGradolaArea.id = 'gradola_area'; - layerArsenale.id = 'arsenale'; - layerArsenaleArea.id = 'arsenale_area'; - layerMura.id = 'mura'; - layerSanMichele.id = 'san_michele'; - layerDamecuta.id = 'damecuta'; - layerTiberio.id = 'tiberio'; - layerScala.id = 'scala_fenicia'; - layerGrotta.id = 'grotta_azzurra'; - layerLopozzo.id = 'lopozzo'; let osmap = new L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', { maxNativeZoom : GIS.MAX_ZOOM, @@ -383,25 +259,10 @@ GIS.initLayers = async function(map) { maxZoom: GIS.MAX_ZOOM, attribution: '© Mapbox' }); - let boundaries = await this.loadLayer('confini.geojson', {}, false); - let buildings = await this.loadLayer('fabbricati.geojson', optionsFabbricati, false); + let boundaries = await this.loadGeoJSON('confini.geojson', {}, false); + let buildings = await this.loadGeoJSON('fabbricati.geojson', optionsFabbricati, false); let baseCatasto = new L.LayerGroup([buildings, boundaries]); - const sitesGroup = new L.LayerGroup([ - layerMater, - layerMaterArea, - layerGradola, - layerGradolaArea, - layerArsenale, - layerArsenaleArea, - layerMura, - layerSanMichele, - layerDamecuta, - layerTiberio, - layerScala, - layerGrotta, - layerLopozzo - ]); const baseGroup = new L.LayerGroup([osmap]); baseGroup.addTo(map); const baseMap = { @@ -410,7 +271,7 @@ GIS.initLayers = async function(map) { "Cartografia catastale" : baseCatasto, }; - return {baseMap, sitesGroup}; + return baseMap; } /** * Toggle spherical photos on the map @@ -458,18 +319,43 @@ GIS.toggleSpherical = async function(map) { }); } /** - * @param {string} geoJSON + * @param {string} geoJSON geoJSON filename * @param {{color, opacity, weight, fillColor, fillOpacity}} options Style options for features * @param {boolean} popup Should the features have a popup? + * @returns {L.Layer} */ -GIS.loadLayer = async function (geoJSON, options, popup = true) { +GIS.loadGeoJSON = async function (geoJSON, options, popup = true) { const geo = await fetch(`${BASE_URL}/geojson/${geoJSON}`) .then(res => res.json()) .catch(error => console.error(`Can't load layer ${geoJSON}. Reason: ${error}`)); - const layerId = geoJSON.replace('.geojson', ''); + // Show data from feature in popUp? + const layer = new L.geoJson(geo, { + style: function () { + return options; + }, + onEachFeature: function (feature, layer) { + if (popup) { + layer.bindPopup(GIS.featurePopup(geoJSON, feature)); + } + } + }); + + return layer; +} +/** + * @param {object} site Site record from DB + * @param {{color, opacity, weight, fillColor, fillOpacity}} options Style options for features + * @param {boolean} popup Should the features have a popup? + * @returns {L.Layer} + */ +GIS.loadSiteLayer = async function (site, options, popup = true) { + const geoJSON = `${site.gisId}.geojson`; + const geo = await fetch(`${BASE_URL}/geojson/${geoJSON}`) + .then(res => res.json()) + .catch(error => console.error(`Can't load layer ${geoJSON}. Reason: ${error}`)); - this.cacheDBData(layerId); + this.cacheDBData(site.gisId, site.id); // Show data from feature in popUp? const layer = new L.geoJson(geo, { @@ -482,7 +368,7 @@ GIS.loadLayer = async function (geoJSON, options, popup = true) { } else { layer.on("click", async () => { - let data = GIS.layerData(layerId); + let data = GIS.layerData(site.gisId, site.id); if (typeof data === 'object') { UI.openSiteModal(data); @@ -497,9 +383,10 @@ GIS.loadLayer = async function (geoJSON, options, popup = true) { /** * Retrieves data for a given layer * @param {string} layerId + * @param {string} dbId * @returns {object} Data for this layer from DB or cache */ -GIS.layerData = async function (layerId) { +GIS.layerData = async function (layerId, dbId) { const fromStorage = localStorage.getItem(layerId); let data = {}; @@ -510,7 +397,7 @@ GIS.layerData = async function (layerId) { console.log(error); } } else { - data = await GIS._fetchData('site/' + layerId); + data = await GIS._fetchData('sites/' + dbId); } return data; @@ -528,8 +415,8 @@ GIS.getSpherical = async function (siteId) { * for a given layer * @param {string} layerId */ -GIS.cacheDBData = async function (layerId) { - const data = await this._fetchData('site/' + layerId); +GIS.cacheDBData = async function (layerId, dbId) { + const data = await this._fetchData('sites/' + dbId); localStorage.setItem(layerId, JSON.stringify(data)); } /** diff --git a/webgis/js/ui.js b/webgis/js/ui.js index 229012e..1611d27 100644 --- a/webgis/js/ui.js +++ b/webgis/js/ui.js @@ -208,39 +208,6 @@ UI.openPrehistModal = function (data, selector) { prehistoric.render().then(html => modal.querySelector('#prehist-sheet').innerHTML = html); modal.classList.add('is-active'); } -/** - * @param {string} menuListSel Menu list selector - * @param {L.Map} map - * @param {L.LayerGroup} sites - */ -UI.sitesMenu = function (menuListSel, map, sites) { - // Close menu if arrow button is clicked... - let markers = []; - - map.eachLayer(layer => { - if (layer instanceof L.Marker) { - markers.push(layer); - } - }) - - const menu = document.querySelector(menuListSel); - menu.addEventListener('click', async event => { - if (event.target.nodeName === 'A') { - const layerId = event.target.id; - const marker = markers.filter(m => m.id === layerId)[0]; - - // zoom to layer... - const layer = sites.customGetLayer(layerId); - map.setView( - layer.getBounds().getCenter(), - 19, - {animate: true, duration: 1, easeLinearity: 0.25} - ); - - marker.openTooltip(); - } - }); -} /** * Open Spotlight gallery * @param {string} galleryId The id of the trigger element