diff --git a/.gitignore b/.gitignore index 4385be4..1f1b0e9 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,5 @@ progetto_QGIS/ conf.json shapefile config.js +# Don't track shperical photos +webgis/img/spherical/*.png diff --git a/css/app.css b/css/app.css index ddda663..dc71ce6 100644 --- a/css/app.css +++ b/css/app.css @@ -155,4 +155,9 @@ a:visited { .docs-title { width: 300px; max-width: 300px; +} +/* Panoramas */ +#pano-viewer { + height: 100%; + width: 100%; } \ No newline at end of file diff --git a/webgis/img/spherical/.keep b/webgis/img/spherical/.keep new file mode 100644 index 0000000..e69de29 diff --git a/webgis/index.html b/webgis/index.html index 814b3d2..d6c0979 100644 --- a/webgis/index.html +++ b/webgis/index.html @@ -6,6 +6,15 @@ + + @@ -156,5 +165,13 @@ + + diff --git a/webgis/js/components/NotConservedSheet.js b/webgis/js/components/NotConservedSheet.js index 3c73c15..c7a7fcc 100644 --- a/webgis/js/components/NotConservedSheet.js +++ b/webgis/js/components/NotConservedSheet.js @@ -65,7 +65,7 @@ export class NotConservedSheet { `; this.biblioElements.push(` -
+

${record.reference}

` diff --git a/webgis/js/components/SphericalPhoto.js b/webgis/js/components/SphericalPhoto.js new file mode 100644 index 0000000..6a3cdde --- /dev/null +++ b/webgis/js/components/SphericalPhoto.js @@ -0,0 +1,18 @@ +import { Viewer } from '@photo-sphere-viewer/core'; +/** + * @class SphericalPhoto + */ +export class SphericalPhoto { + basePath = '/webgis/img/spherical'; + + /** + * @param {string} filename Name of the spherical image + */ + setViewer(filename) { + new Viewer({ + container: document.querySelector('#pano-viewer'), + panorama: `${this.basePath}/${filename}`, + defaultZoomLvl: 0, + }); + } +} diff --git a/webgis/js/gis.js b/webgis/js/gis.js index 851e0ef..a11baf6 100644 --- a/webgis/js/gis.js +++ b/webgis/js/gis.js @@ -2,6 +2,8 @@ import UI from "./ui.js"; import API_CONFIG from "./config.js"; +import Icons from "./icons.js"; +import { SphericalPhoto } from "./components/SphericalPhoto.js"; const MAPBOX_TOKEN = 'pk.eyJ1Ijoibmljb3BhIiwiYSI6ImNseWNwZjJjbjFidzcya3BoYTU0bHg4NnkifQ.3036JnCXZTEMt6jVgMzVRw'; const BASE_URL = location.href; @@ -111,85 +113,22 @@ GIS.initMap = async function (mapId, zoomLevel = this.INIT_ZOOM) { }); let map = L.map(mapId, { - attributionControl: false, + //attributionControl: false, minZoom: 2, }).setView(this.CENTER_COORDS, zoomLevel); map.crs = L.CRS.EPSG4326; const {baseMap, sitesGroup} = await this.initLayers(map); - - let layerVincoli = await this.loadLayer('vincoli.geojson', optionsVincoli); - let layerPaesistici = await this.loadLayer('paesistici.geojson', optionsPaesistici); - let notConserData = await fetch(`${API_URL}/not_conserved`) - .then(data => data.json()); - // Add scale and ruler controls L.control.scale({imperial: false}).addTo(map); L.control.graphicScale({fill: 'hollow', position: 'bottomright'}).addTo(map); - let sitesMarkers = []; - let siteIcon = L.icon( - { - iconUrl: 'img/icons/siti.png', - iconSize: [24, 36], - iconAnchor: [12, 32], - tooltipAnchor: [0, -26], - } - ); - let notConserIcon = L.icon( - { - iconUrl: 'img/icons/non_conserv.png', - iconSize: [24, 36], - iconAnchor: [12, 32], - tooltipAnchor: [0, -26], - } - ); + let layerVincoli = await this.loadLayer('vincoli.geojson', optionsVincoli); + let layerPaesistici = await this.loadLayer('paesistici.geojson', optionsPaesistici); - let notConserved = []; - - for (let record of notConserData.records) { - notConserved.push(L.marker( - record.coordinates, - {icon: notConserIcon} - ).bindTooltip(record.denomination) - .on( - 'click', - () => UI.openNotConserModal(record, '#not-conser-data') - ) - ); - } - - for (let id in MARKER_NAMES.sites) { - let layer = sitesGroup.customGetLayer(id); - let coords = layer.getBounds().getCenter(); - const fromStorage = localStorage.getItem(id); - let data = {}; - - 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); - } - - const marker = L.marker(coords, { icon: siteIcon }) - .bindTooltip(MARKER_NAMES.sites[id]) - .openTooltip(); - - marker.on('click', () => UI.openSiteModal(data, '#site-data')); - - sitesMarkers.push(marker); - } - - let markersGroup = L.layerGroup(sitesMarkers); - let notConservedGroup = L.layerGroup(notConserved); + let markersGroup = await this.sitesMarkers(sitesGroup); + let notConservedGroup = await this.notConserved(); const archeo = { 'Beni archeologici (punti)' : markersGroup, @@ -211,6 +150,68 @@ GIS.initMap = async function (mapId, zoomLevel = this.INIT_ZOOM) { // TODO Horrible? return {map: map, sites: sitesGroup}; } +/** + * Create markers for sites + * @param {L.LayerGroup} sitesGroup + * @returns {L.LayerGroup} + */ +GIS.sitesMarkers = async function (sitesGroup) { + let sitesMarkers = []; + + for (let id in MARKER_NAMES.sites) { + let layer = sitesGroup.customGetLayer(id); + let coords = layer.getBounds().getCenter(); + const fromStorage = localStorage.getItem(id); + let data = {}; + + 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); + } + + const marker = L.marker(coords, { icon: Icons.site }) + .bindTooltip(MARKER_NAMES.sites[id]) + .openTooltip(); + + marker.on('click', () => UI.openSiteModal(data, '#site-data')); + + sitesMarkers.push(marker); + } + + return L.layerGroup(sitesMarkers); +} +/** + * Create not conserved group + * @returns {L.LayerGroup} + */ +GIS.notConserved = async function () { + let notConserData = await fetch(`${API_URL}/not_conserved`) + .then(data => data.json()); + + let notConserved = []; + + for (let record of notConserData.records) { + notConserved.push(L.marker( + record.coordinates, + {icon: Icons.notConserved} + ).bindTooltip(record.denomination) + .on( + 'click', + () => UI.openNotConserModal(record, '#not-conser-data') + ) + ); + } + + return L.layerGroup(notConserved); +} /* GIS._prepareLayers = async function(layer) { const fromStorage = localStorage.getItem(layer.id); @@ -321,7 +322,51 @@ GIS.initLayers = async function(map) { return {baseMap, sitesGroup}; } /** - * @todo Distinguere tipo di geojson per contenuto popup + * Toggle spherical photos on the map + * based on zoom level + */ +GIS.toggleSpherical = async function(map) { + // TODO Create points layer + const spherical = await this._fetchData('spherical/by/gis/gradola'); + let sphereMarkers = []; + const sPhoto = new SphericalPhoto(); + + if (spherical) { + for (let pano of spherical) { + let marker = L.marker(pano.coordinates, { + icon: Icons.camera, + }); + + marker.bindTooltip('Apri foto sferica'); + marker.on('click', () => { + let modal = document.querySelector('#spherical-modal'); + let viewer = document.querySelector('#pano-viewer'); + viewer.innerHTML = ''; + modal.classList.add('is-active'); + modal.querySelector('.modal-background').addEventListener('click', () => { + modal.classList.remove('is-active'); + }); + modal.querySelector('.modal-close').addEventListener('click', () => { + modal.classList.remove('is-active'); + }) + sPhoto.setViewer(pano.filename); + }); + + sphereMarkers.push(marker); + } + } + + let group = L.layerGroup(sphereMarkers); + + map.on('zoomend', () => { + if (map.getZoom() >= 19) { + group.addTo(map); + } else { + group.remove(); + } + }); +} +/** * @param {string} geoJSON * @param {{color, opacity, weight, fillColor, fillOpacity}} options Style options for features * @param {boolean} popup Should the features have a popup? @@ -379,6 +424,14 @@ GIS.layerData = async function (layerId) { return data; } +/** + * Get spherical photos for a site + * @param {int} siteId + */ +GIS.getSpherical = async function (siteId) { + const data = await this._fetchData('spherical/' + siteId); +} + /** * Cache data from DB in local storage * for a given layer diff --git a/webgis/js/icons.js b/webgis/js/icons.js new file mode 100644 index 0000000..67e04fe --- /dev/null +++ b/webgis/js/icons.js @@ -0,0 +1,26 @@ +// Global leaflet +/** + * @namespace Icons + */ +const Icons = {}; + +Icons.site = L.icon( + { + iconUrl: 'img/icons/siti.png', + iconSize: [24, 36], + iconAnchor: [12, 32], + tooltipAnchor: [0, -26], + } +); +Icons.notConserved = L.icon( + { + iconUrl: 'img/icons/non_conserv.png', + iconSize: [24, 36], + iconAnchor: [12, 32], + tooltipAnchor: [0, -26], + } +); + +Icons.camera = L.divIcon({className: 'fa fa-2x fa-camera'}); + +export default Icons; \ No newline at end of file diff --git a/webgis/js/index.js b/webgis/js/index.js index 656061a..cd59600 100644 --- a/webgis/js/index.js +++ b/webgis/js/index.js @@ -9,6 +9,8 @@ document.addEventListener('DOMContentLoaded', async () => { map._container.setAttribute('aria-busy', false); + GIS.toggleSpherical(map); + UI.addCenterMapControl(map, GIS.CENTER_COORDS, GIS.INIT_ZOOM); UI.toggleMenu('siti'); UI.toggleBurger('navbar-burger');