Crude spherical photos
This commit is contained in:
parent
2650df69a3
commit
760fb3e960
2
.gitignore
vendored
2
.gitignore
vendored
@ -11,3 +11,5 @@ progetto_QGIS/
|
|||||||
conf.json
|
conf.json
|
||||||
shapefile
|
shapefile
|
||||||
config.js
|
config.js
|
||||||
|
# Don't track shperical photos
|
||||||
|
webgis/img/spherical/*.png
|
||||||
|
@ -155,4 +155,9 @@ a:visited {
|
|||||||
.docs-title {
|
.docs-title {
|
||||||
width: 300px;
|
width: 300px;
|
||||||
max-width: 300px;
|
max-width: 300px;
|
||||||
|
}
|
||||||
|
/* Panoramas */
|
||||||
|
#pano-viewer {
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
}
|
}
|
0
webgis/img/spherical/.keep
Normal file
0
webgis/img/spherical/.keep
Normal file
@ -6,6 +6,15 @@
|
|||||||
<link rel="stylesheet" href="../css/app.css" />
|
<link rel="stylesheet" href="../css/app.css" />
|
||||||
<link rel="stylesheet" href="js/vendor/spotlight.js/dist/css/spotlight.min.css" />
|
<link rel="stylesheet" href="js/vendor/spotlight.js/dist/css/spotlight.min.css" />
|
||||||
<link rel="stylesheet" href="js/vendor/@kalisio/leaflet-graphicscale/dist/Leaflet.GraphicScale.min.css" />
|
<link rel="stylesheet" href="js/vendor/@kalisio/leaflet-graphicscale/dist/Leaflet.GraphicScale.min.css" />
|
||||||
|
<link rel="stylesheet" href="js/vendor/@photo-sphere-viewer/core/index.css" />
|
||||||
|
<script type="importmap">
|
||||||
|
{
|
||||||
|
"imports": {
|
||||||
|
"three": "./js/vendor/three/build/three.module.js",
|
||||||
|
"@photo-sphere-viewer/core": "./js/vendor/@photo-sphere-viewer/core/index.module.js"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
<script src="js/vendor/leaflet/dist/leaflet.js"></script>
|
<script src="js/vendor/leaflet/dist/leaflet.js"></script>
|
||||||
<script src="js/vendor/@kalisio/leaflet-graphicscale/dist/Leaflet.GraphicScale.min.js"></script>
|
<script src="js/vendor/@kalisio/leaflet-graphicscale/dist/Leaflet.GraphicScale.min.js"></script>
|
||||||
<script src="js/index.js" type="module"></script>
|
<script src="js/index.js" type="module"></script>
|
||||||
@ -156,5 +165,13 @@
|
|||||||
</div>
|
</div>
|
||||||
<button class="modal-close is-large" aria-label="close"></button>
|
<button class="modal-close is-large" aria-label="close"></button>
|
||||||
</div>
|
</div>
|
||||||
|
<!-- Spherical photo modal -->
|
||||||
|
<div class="modal" id="spherical-modal">
|
||||||
|
<div class="modal-background"></div>
|
||||||
|
<div class="modal-content has-background-white" style="min-height: 95vh;">
|
||||||
|
<div id="pano-viewer"></div>
|
||||||
|
</div>
|
||||||
|
<button class="modal-close is-large" aria-label="close"></button>
|
||||||
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@ -65,7 +65,7 @@ export class NotConservedSheet {
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
this.biblioElements.push(`
|
this.biblioElements.push(`
|
||||||
<div class="p-2" id="ref-${record.id}">
|
<div class="p-2 mt-2" id="ref-${record.id}">
|
||||||
<p>${record.reference}</p>
|
<p>${record.reference}</p>
|
||||||
</div>
|
</div>
|
||||||
`
|
`
|
||||||
|
18
webgis/js/components/SphericalPhoto.js
Normal file
18
webgis/js/components/SphericalPhoto.js
Normal file
@ -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,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
191
webgis/js/gis.js
191
webgis/js/gis.js
@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
import UI from "./ui.js";
|
import UI from "./ui.js";
|
||||||
import API_CONFIG from "./config.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 MAPBOX_TOKEN = 'pk.eyJ1Ijoibmljb3BhIiwiYSI6ImNseWNwZjJjbjFidzcya3BoYTU0bHg4NnkifQ.3036JnCXZTEMt6jVgMzVRw';
|
||||||
const BASE_URL = location.href;
|
const BASE_URL = location.href;
|
||||||
@ -111,85 +113,22 @@ GIS.initMap = async function (mapId, zoomLevel = this.INIT_ZOOM) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
let map = L.map(mapId, {
|
let map = L.map(mapId, {
|
||||||
attributionControl: false,
|
//attributionControl: false,
|
||||||
minZoom: 2,
|
minZoom: 2,
|
||||||
}).setView(this.CENTER_COORDS, zoomLevel);
|
}).setView(this.CENTER_COORDS, zoomLevel);
|
||||||
|
|
||||||
map.crs = L.CRS.EPSG4326;
|
map.crs = L.CRS.EPSG4326;
|
||||||
|
|
||||||
const {baseMap, sitesGroup} = await this.initLayers(map);
|
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
|
// Add scale and ruler controls
|
||||||
L.control.scale({imperial: false}).addTo(map);
|
L.control.scale({imperial: false}).addTo(map);
|
||||||
L.control.graphicScale({fill: 'hollow', position: 'bottomright'}).addTo(map);
|
L.control.graphicScale({fill: 'hollow', position: 'bottomright'}).addTo(map);
|
||||||
|
|
||||||
let sitesMarkers = [];
|
let layerVincoli = await this.loadLayer('vincoli.geojson', optionsVincoli);
|
||||||
let siteIcon = L.icon(
|
let layerPaesistici = await this.loadLayer('paesistici.geojson', optionsPaesistici);
|
||||||
{
|
|
||||||
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 notConserved = [];
|
let markersGroup = await this.sitesMarkers(sitesGroup);
|
||||||
|
let notConservedGroup = await this.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);
|
|
||||||
|
|
||||||
const archeo = {
|
const archeo = {
|
||||||
'Beni archeologici (punti)' : markersGroup,
|
'Beni archeologici (punti)' : markersGroup,
|
||||||
@ -211,6 +150,68 @@ GIS.initMap = async function (mapId, zoomLevel = this.INIT_ZOOM) {
|
|||||||
// TODO Horrible?
|
// TODO Horrible?
|
||||||
return {map: map, sites: sitesGroup};
|
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) {
|
GIS._prepareLayers = async function(layer) {
|
||||||
const fromStorage = localStorage.getItem(layer.id);
|
const fromStorage = localStorage.getItem(layer.id);
|
||||||
@ -321,7 +322,51 @@ GIS.initLayers = async function(map) {
|
|||||||
return {baseMap, sitesGroup};
|
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 {string} geoJSON
|
||||||
* @param {{color, opacity, weight, fillColor, fillOpacity}} options Style options for features
|
* @param {{color, opacity, weight, fillColor, fillOpacity}} options Style options for features
|
||||||
* @param {boolean} popup Should the features have a popup?
|
* @param {boolean} popup Should the features have a popup?
|
||||||
@ -379,6 +424,14 @@ GIS.layerData = async function (layerId) {
|
|||||||
|
|
||||||
return data;
|
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
|
* Cache data from DB in local storage
|
||||||
* for a given layer
|
* for a given layer
|
||||||
|
26
webgis/js/icons.js
Normal file
26
webgis/js/icons.js
Normal file
@ -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;
|
@ -9,6 +9,8 @@ document.addEventListener('DOMContentLoaded', async () => {
|
|||||||
|
|
||||||
map._container.setAttribute('aria-busy', false);
|
map._container.setAttribute('aria-busy', false);
|
||||||
|
|
||||||
|
GIS.toggleSpherical(map);
|
||||||
|
|
||||||
UI.addCenterMapControl(map, GIS.CENTER_COORDS, GIS.INIT_ZOOM);
|
UI.addCenterMapControl(map, GIS.CENTER_COORDS, GIS.INIT_ZOOM);
|
||||||
UI.toggleMenu('siti');
|
UI.toggleMenu('siti');
|
||||||
UI.toggleBurger('navbar-burger');
|
UI.toggleBurger('navbar-burger');
|
||||||
|
Loading…
Reference in New Issue
Block a user