Compare commits

..

61 Commits

Author SHA1 Message Date
6f632c3ee2 wms: layer added to map with control 2025-06-30 10:07:45 +02:00
09d5a31a07 wms: debugging reprojection 2025-06-30 08:57:31 +02:00
9873b22c4c Fix close button for cartography menu 2025-06-23 17:06:08 +02:00
8ebaea2ff8 Add cartography menu with image overlays (WIP) 2025-06-20 16:07:30 +02:00
ecd5db5b4c Add image overlays 2025-06-18 11:20:23 +02:00
632eb1bfc1 Update menu 2025-06-17 12:28:14 +02:00
afff222ac2 Update menu 2025-06-09 17:18:40 +02:00
c0d3aaa846 Don't show documentation field in site documents 2025-06-06 14:23:11 +02:00
71f111d5df Use labels everywhere + ordering for underwater... 2025-06-06 14:14:15 +02:00
b51d701830 Don't capitalize biblio citations
TODO: refactor bibliography UI logic...
2025-06-05 10:19:09 +02:00
0e979ca5c5 Don't use label span in menu item template 2025-06-04 13:39:57 +02:00
af9516dde0 Fix bug in menu ('Rinvenimenti') 2025-06-03 16:17:26 +02:00
b556ad66bb Refactor to generate menu dynamically 2025-06-03 15:36:42 +02:00
41dca4f563 Stub for dynamic menu (WIP) 2025-06-03 11:42:06 +02:00
5b5d0aeb3d Use GisState for biblio as well 2025-06-02 21:58:17 +02:00
c265e4aa94 Refactor everything to use GisState (WIP) 2025-06-02 09:42:26 +02:00
86d692381d Update README 2025-05-30 18:17:11 +02:00
e095270fb3 Use Stimulus values for maker#go 2025-05-30 18:01:05 +02:00
4d7bfb4bfa Add author field + update menu 2025-05-23 19:38:40 +02:00
7a1385d040 Add coords for Arsenale and Matermania 2025-05-14 16:55:49 +02:00
c15d10a7a8 Fix wrong gallery id 2025-05-07 16:49:15 +02:00
e422a1912a Fix missing controller 2025-05-07 16:41:50 +02:00
d35cc2e218 Prepare for images in prehistoric 2025-05-05 17:41:47 +02:00
5fe29463f7 Update menu 2025-05-01 10:35:22 +02:00
0d1a1394ea Add missing site 2025-05-01 10:06:43 +02:00
957bfd47cf Update prehistoric stuff... 2025-04-30 11:28:49 +02:00
9849ecc0bd Update menu 2025-04-29 15:57:38 +02:00
962ba93355 Add underwater sites 2025-04-29 11:59:39 +02:00
46a4efe760 Update not conserved and menu 2025-04-28 17:04:39 +02:00
50f474e49e Documents for not conserved 2025-04-28 15:55:34 +02:00
3f6d70f159 Reset tabs for not conserved 2025-04-28 13:17:08 +02:00
0ca98e2b6d Images for not conserved 2025-04-28 12:36:09 +02:00
334cab6e4f Add sites to menu + some CSS 2025-04-24 11:12:49 +02:00
1911c0ce9f Refactor with sites from DB... 2025-03-26 16:45:30 +01:00
1067d108e5 Configure min and max zoom 2025-02-28 16:03:33 +01:00
13d6004fe8 Refactor with less awaits (WIP) 2025-02-19 10:48:47 +01:00
64af485a54 No point layers in control; add visibility toggle in menu 2025-02-10 15:07:13 +01:00
be6398b1aa Move aside menu to right 2025-01-10 12:10:50 +01:00
0b5737a576 Add prehistoric icons... 2025-01-10 11:44:26 +01:00
73e804f303 Add prehistoric assets 2025-01-10 11:29:37 +01:00
058c83da65 Linked markers in modals 2024-12-07 10:13:52 +01:00
66e6cea020 Fix null image author 2024-12-06 15:31:05 +01:00
4c7cc44fb3 Update home 2024-12-06 12:27:30 +01:00
a5cb6c65e3 Modify credits and GIS menu 2024-12-06 11:51:43 +01:00
872dff3769 Add autoplay for videos 2024-12-05 18:19:34 +01:00
0051474202 Missing poster for video 2024-12-05 09:44:30 +01:00
1b8ef27c1e Add menu item + CSS 2024-12-05 07:58:47 +01:00
e32c695cf2 Fix biblio citations 2024-12-04 09:07:03 +01:00
0c33329582 Add not conserved point 2024-12-04 08:48:11 +01:00
46ef699fd4 Update menu 2024-12-03 17:35:36 +01:00
c16c2763e0 Add prehistoric sites 2024-12-02 16:48:40 +01:00
5dd1f3c77d Fix link to MIC 2024-12-02 11:42:35 +01:00
a524f63e34 Several updates and changes... 2024-12-02 11:39:24 +01:00
7f3f90db3a Finish home page 2024-12-02 10:11:04 +01:00
96ec738f6b Update home + site docs 2024-12-01 15:46:12 +01:00
0cb1f7a32d Villa San Michele 2024-12-01 10:32:01 +01:00
1393b779ff Support videos 2024-11-30 18:37:01 +01:00
c895894b0d Author in captions + images 2024-11-30 12:21:28 +01:00
165806ae05 Cluster options + images 2024-11-30 12:01:58 +01:00
07f8dd9a86 Update home page + icons 2024-11-29 17:47:03 +01:00
1a0c5c1766 Zoom levels for clusters 2024-11-29 17:30:07 +01:00
83 changed files with 1972 additions and 785 deletions

5
.gitignore vendored
View File

@@ -7,6 +7,7 @@
*.zip *.zip
*.pdf *.pdf
*.tif *.tif
*.mp4
vendor/ vendor/
progetto_QGIS/ progetto_QGIS/
conf.json conf.json
@@ -14,3 +15,7 @@ shapefile
config.js config.js
# Don't track shperical photos # Don't track shperical photos
webgis/img/spherical/*.png webgis/img/spherical/*.png
# Don't track georeferenced images
webgis/img/geo/*
!webgis/img/geo/.keep
*Zone*Identifier

View File

@@ -19,6 +19,22 @@ const API_CONFIG = {
export default API_CONFIG; export default API_CONFIG;
``` ```
## Struttura e funzionamento base
### Entry point
Il punto d'ingresso dell'applicazione è `webgis/js/index.js` che registra i controller Stimulus e inizializza alcune funzioni UI (che potrebbero essere migrate in un controller Stimulus dedicato in futuro).
### Mappa
La mappa è gestita con Leaflet dalle funzioni definite nel modulo `GIS` (`webgis/js/gis.js`) che carica i layer iniziali, inclusi i geoJSON necessari, interroga le API server per recuperare i dati dal database e crea i cluster di puntatori (_markers_) tramite il plugin `Leaflet.markercluster`.
### Pseudo-componenti HTML
Il contenuto HTML mostrato nei modali che si aprono cliccando sui puntatori è gestito dinamicamente da pseudo-componenti rappresentati da classi JavaScript che si trovano in `webgis/js/components`.
Potrebbe essere utile (o auspicabile) trasformarli in Web Components veri e propri, magari tramite [_Lit.js_](https://lit.dev/). In questo caso, bisognerebbe capire come gestire i dati dinamici all'interno dei template.
## Dipendenze ## Dipendenze
Le dipendenze sono gestite con `yarn`, per installarle è sufficiente eseguire `yarn` dalla cartella `webgis/js`, dove si trova `package.json`. Le dipendenze sono gestite con `yarn`, per installarle è sufficiente eseguire `yarn` dalla cartella `webgis/js`, dove si trova `package.json`.
@@ -35,6 +51,12 @@ Photo Sphere Viewer, Three.js (da cui dipende Photo Sphere Viewer) e Stimulus.
- [Leaflet](https://leafletjs.com) (mappa) - [Leaflet](https://leafletjs.com) (mappa)
- [kalisio/leaflet-graphicscale](https://github.com/kalisio/leaflet-graphicscale) (plugin Leaflet per scala mappa) - [kalisio/leaflet-graphicscale](https://github.com/kalisio/leaflet-graphicscale) (plugin Leaflet per scala mappa)
- [Leaflet/Leaflet.markercluster](https://github.com/Leaflet/Leaflet.markercluster) (plugin Leaflet per raggruppamenti puntatori)
- [Spotlight.js](https://nextapps-de.github.io/spotlight/) (gallery immagini) - [Spotlight.js](https://nextapps-de.github.io/spotlight/) (gallery immagini)
- [Photo Sphere Viewer](https://photo-sphere-viewer.js.org/) (foto sferiche / panorami) - [Photo Sphere Viewer](https://photo-sphere-viewer.js.org/) (foto sferiche / panorami)
- [Stimulus](https://stimulus.hotwired.dev) (UI) - [Stimulus](https://stimulus.hotwired.dev) (UI)
## TODO
- [ ] Auto-discovery per Stimulus?
- [ ] Refactor con app state per evitare oggetti globali

View File

@@ -120,8 +120,14 @@ a:visited {
.modal { .modal {
z-index: 1000; z-index: 1000;
} }
.modal-content { .modal-content,
.modal-card {
width: 60vw; width: 60vw;
min-height: 95vh;
}
.modal-card-body img {
max-height: 200px;
max-width: 200px;
} }
.has-bottom-border { .has-bottom-border {
border-bottom: 1px #aaa solid; border-bottom: 1px #aaa solid;
@@ -152,9 +158,13 @@ a:visited {
left: 35vw; left: 35vw;
} }
/* Menu overlay */ /* Menu overlay */
#menu { .menu-overlay {
z-index: 1000; z-index: 1000;
overflow-y: auto; overflow-y: auto;
margin-top: 54px;
}
.menu-overlay.is-overlay {
left: auto;
} }
/* Content in tabs */ /* Content in tabs */
.docs-title { .docs-title {

BIN
img/cartografia.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 733 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 513 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 717 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 555 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 659 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 818 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 528 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 638 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 668 KiB

BIN
img/credits.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

BIN
img/favicon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

BIN
img/logo_MIC.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 160 KiB

BIN
img/progetto.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 512 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 538 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 349 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 386 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 193 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 550 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

BIN
img/pubblicazioni.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

BIN
img/riconoscimenti.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

BIN
img/webgis.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 136 KiB

View File

@@ -3,9 +3,18 @@
<head> <head>
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<link rel="stylesheet" href="css/app.css" /> <link rel="stylesheet" href="css/app.css" />
<link rel="shortcut icon" type="image/png" href="/img/favicon.png">
<link rel="stylesheet" href="webgis/js/vendor/spotlight.js/dist/css/spotlight.min.css" />
<title>Carta Archeologica Isola di Capri</title> <title>Carta Archeologica Isola di Capri</title>
<script type="importmap">
{
"imports": {
"@hotwired/stimulus": "./webgis/js/vendor/@hotwired/stimulus/dist/stimulus.js"
}
}
</script>
</head> </head>
<body> <body data-controller="modal">
<nav class="navbar mb-2 p-3 has-bottom-border" role="navigation"> <nav class="navbar mb-2 p-3 has-bottom-border" role="navigation">
<div class="navbar-brand"> <div class="navbar-brand">
<a class="navbar-item" href="https://ispc.cnr.it" title="CNR-ISPC"> <a class="navbar-item" href="https://ispc.cnr.it" title="CNR-ISPC">
@@ -23,10 +32,10 @@
</div> </div>
<hr class="navbar-divider"> <hr class="navbar-divider">
<div class="navbar-end"> <div class="navbar-end">
<a href="#progetto" class="navbar-item">Il progetto</a> <a href="/webgis/" class="navbar-item">WebGIS</a>
<a href="#webgis" class="navbar-item">Il WebGIS</a> <a class="navbar-item" href="https://cultura.gov.it/" title="Ministero della Cultura">
<a href="#riconoscimenti" class="navbar-item">Riconoscimenti</a> <img class="image" src="img/logo_MIC.jpg" style="min-height: 88px;" />
<a href="#credits" class="navbar-item">Credits</a> </a>
<a class="navbar-item" href="https://www.comune.anacapri.na.it/" title="Comune di Anacapri"> <a class="navbar-item" href="https://www.comune.anacapri.na.it/" title="Comune di Anacapri">
<img class="image" src="img/logo_anacapri.svg" style="min-height: 88px;" /> <img class="image" src="img/logo_anacapri.svg" style="min-height: 88px;" />
</a> </a>
@@ -39,7 +48,7 @@
<h1 class="mt-6 title has-text-centered">La Carta Archeologica dell'Isola di Capri</h1> <h1 class="mt-6 title has-text-centered">La Carta Archeologica dell'Isola di Capri</h1>
<div class="columns"> <div class="columns">
<div class="column"></div> <div class="column"></div>
<div class="column is-three-quarters is-size-5"> <div class="column is-three-quarters is-size-5">
<section class="section pb-1 has-text-centered"> <section class="section pb-1 has-text-centered">
La carta archeologica di Capri è frutto di un lavoro condiviso tra il <a href="https://ispc.cnr.it">CNRISPC</a>, La carta archeologica di Capri è frutto di un lavoro condiviso tra il <a href="https://ispc.cnr.it">CNRISPC</a>,
la <a href="https://sabapmetropolitanana.cultura.gov.it/">Soprintendenza Archeologia Belle Arti e Paesaggio per l'Area Metropolitana di Napoli</a>, la <a href="https://sabapmetropolitanana.cultura.gov.it/">Soprintendenza Archeologia Belle Arti e Paesaggio per l'Area Metropolitana di Napoli</a>,
@@ -48,132 +57,519 @@
archeologici svolti, le ricerche archivistiche e bibliografiche sui beni archeologici oggi visibili e su quelli archeologici svolti, le ricerche archivistiche e bibliografiche sui beni archeologici oggi visibili e su quelli
non più esistenti, la raccolta della cartografia storica, contenuti multimediali e immagini storiche. non più esistenti, la raccolta della cartografia storica, contenuti multimediali e immagini storiche.
</section> </section>
<div class="columns mt-5 has-background-light is-fullwidth">
<div class="column has-text-centered is-one-third has-background-light">
<img class="image" src="img/progetto.jpg" />
<a href="" class="button is-link mt-3 is-large has-text-white">
Il progetto
</a>
</div>
<div class="column has-text-centered">
<a href="webgis/">
<img class="image" src="img/webgis.webp" />
</a>
<a href="webgis/" class="button is-link mt-3 is-large has-text-white">Accedi al WebGIS</a>
</div>
<div class="column card">
<div class="card-image">
<img class="image" src="" />
</div>
<div class="card-content has-text-centered">
<a href="" class="button is-link is-large has-text-white">Cartografia storica</a>
</div>
</div>
</div>
<div class="columns">
<div class="column is-one-third card">
<div class="card-image">
<img class="image" src="" />
</div>
<div class="card-content has-text-centered">
<a href="" class="button is-link is-large has-text-white">Pubblicazioni</a>
</div>
</div>
<div class="column card">
<div class="card-image">
<img class="image" src="img/credits.webp" />
</div>
<div class="card-content has-text-centered">
<a href="" class="button is-link is-large has-text-white">Credits</a>
</div>
</div>
<div class="column card">
<div class="card-image">
<img class="image" src="img/riconoscimenti.webp" />
</div>
<div class="card-content has-text-centered">
<a href="" class="button is-link is-large has-text-white">Riconoscimenti</a>
</div>
</div>
</div>
<section class="section pb-1">
<a id="progetto"></a>
<h3 class="has-text-centered">Il progetto</h3>
<p class="p-2 mt-2 mb-2">
Il progetto per la realizzazione della carta archeologica dellisola di Capri vede coinvolti, tramite appositi accordi di collaborazione e sotto la direzione scientifica della Soprintendenza Archeologia Belle Arti e Paesaggio per lArea Metropolitana di Napoli, i Comuni di Capri e di Anacapri, lIstituto di Scienze del Patrimonio Culturale (ISPC) del CNR e lAssociazione Culturale Apragopolis.
</p>
<p class="p-2 mt-2 mb-2">
Lobiettivo principale consiste nellacquisire conoscenze sulleffettiva estensione dei beni archeologici presenti sullisola, localizzarne i resti e approfondirne le funzioni e dimensioni originarie. La creazione di una mappa archeologica dellisola rappresenta lo strumento più idoneo per affrontare diverse esigenze, tra cui facilitare le azioni mirate alla protezione e valorizzazione del patrimonio culturale, oltre a fornire una corretta comprensione dellevoluzione territoriale. Questa comprensione è un presupposto fondamentale per ricostruire gli eventi storici dellarea e guidare la pianificazione territoriale.
</p>
<p class="p-2 mt-2 mb-2">
Il progetto sperimenta lutilizzo di metodi innovativi di rappresentazione dei monumenti per produrre nuovi contenuti scientifici e una documentazione grafica dettagliata utile allanalisi archeologica. Attraverso la creazione del webgis si consente a tutti i soggetti interessati di fruire liberamente ed in maniera condivisa delle informazioni storico-archeologiche appositamente raccolte e archiviate.
</p>
<p class="p-2 mt-2 mb-2">
Il contributo del CNR ha riguardato il censimento del noto, la raccolta e lo studio della cartografia storica, le attività di rilevamento archeologico dei siti di estensione maggiore scarsamente studiati e rappresentati, la schedatura e analisi delle murature e delle tecniche costruttive, ipotesi di ricostruzione e delle funzioni degli spazi, nonché la costruzione del sistema Web GIS.
</p>
<p class="p-2 mt-2 mb-2">
LAssociazione Culturale Apragopolis ha condotto attività di digitalizzazione e analisi della documentazione darchivio storico e corrente (documenti amministrativi, documentazione di scavo, disegni storici, planimetrie e fotografie), unitamente a ricognizioni sul campo con il coinvolgimento di esperti per lavvio dei rilievi subacquei e per la realizzazione di ricostruzioni virtuali.
</p>
</section>
<section class="section">
<a id="webgis"></a>
<h3 class="has-text-centered">Il WebGIS</h3>
<p>
Il WebGIS è una tipologia di mappa georeferenziata interattiva presentata
tramite il Web, quindi fruibile attraverso un qualsiasi browser moderno.
</p>
<p>
Il WebGIS relativo alla Carta Archeologica dell'Isola di Capri è stato realizzato
utilizzando esclusivamente tecnologie open-source, principalmente la libreria JavaScript
<a href="https://leafletjs.com">Leaflet</a> per il rendering della mappa con
i layer (livelli) georeferenziati contenenti i punti geografici e le strutture rilevate
dal progetto, e il framework PHP <a href="https://symfony.com">Symfony</a> per lo
sviluppo della API (lato server) che interagisce con il database per recuperare le informazioni
e i dati relativi ai punti da visualizzare sulla mappa.
</p>
<p>Il database stesso è stato costruito con il sistema <a href="https://www.postgresql.org/">PostgreSQL</a>, il quale - attraverso l'estensione
<a href="https://postgis.net/">PostGIS</a> - permette di rappresentare dati geografici e geometrici e fornisce un insieme di
funzionalità integrate per l'interazione e le operazioni con i dati geometrici, rendendolo quindi
particolarmente utile per applicazioni <abbr title="Geography Information Systems">GIS</abbr>.
</p>
<div class="card mt-6">
<a href="webgis/">
<img class="image" src="img/webgis.webp" />
</a>
<div class="card-content has-text-centered">
<a href="webgis/" class="button is-link is-large has-text-white">Accedi al WebGIS</a>
</div>
</div>
</section>
<section class="section">
<a id="riconoscimenti"></a>
<h2 class="m-4 has-text-centered">Riconoscimenti</h2>
<p>Lorem ipsum dolor sit, amet consectetur adipisicing elit. Et sed quidem atque? Delectus, blanditiis sint. Numquam tempora nemo perferendis ea modi. Pariatur voluptatibus ut consequatur? Sit reprehenderit in accusantium delectus.</p>
<p>Lorem ipsum dolor sit, amet consectetur adipisicing elit. Et sed quidem atque? Delectus, blanditiis sint. Numquam tempora nemo perferendis ea modi. Pariatur voluptatibus ut consequatur? Sit reprehenderit in accusantium delectus.</p>
<p>Lorem ipsum dolor sit, amet consectetur adipisicing elit. Et sed quidem atque? Delectus, blanditiis sint. Numquam tempora nemo perferendis ea modi. Pariatur voluptatibus ut consequatur? Sit reprehenderit in accusantium delectus.</p>
</section>
<section class="section has-text-centered">
<a id="credits"></a>
<h2 class="m-2">Credits</h2>
<h3 class="is-size-3">CNR ISPC</h3>
<p>Cecilia Giorgi</p>
<p>Giovanni Caratelli</p>
<p>Nicolò Paraciani</p>
<h3 class="is-size-3">Soprintendenza ecc...</h3>
<p>Giancarlo Di Martino</p>
</section>
</div> </div>
<div class="column"></div> <div class="column"></div>
</div> </div>
</div> <div class="level is-fullwidth mb-0 has-background-light">
<div class="columns mt-5 is-8" style="width: 80vw; margin-left: auto; margin-right: auto">
<div class="column card has-text-centered is-one-third"
data-id="progetto" data-action="click->modal#homeOpen">
<div class="card-image">
<img src="img/progetto.jpg" />
</div>
<div class="card-content">
<button class="button is-link mt-3 is-large has-text-white">
Il progetto
</button>
</div>
</div>
<div class="column card has-text-centered is-clickable"
data-id="webgis" data-action="click->modal#homeOpen">
<div class="card-image">
<img src="img/webgis.jpg" />
</div>
<div class="card-content">
<button class="button is-link mt-3 is-large has-text-white">
Il WebGIS
</button>
</div>
</div>
<div class="column card has-text-centered mb-5 is-clickable"
data-id="cartografia" data-action="click->modal#homeOpen">
<div class="card-image">
<img src="img/cartografia.jpg" />
</div>
<div class="card-content">
<button class="button is-link is-large mt-3 has-text-white">
Cartografia storica
</button>
</div>
</div>
</div>
</div>
<div class="level is-fullwidth mt-0 has-background-light">
<div class="columns is-8 pt-6 pb-6" style="width: 80vw; margin-left: auto; margin-right: auto">
<div class="column is-one-third card has-text-centered is-clickable"
data-id="pubblicazioni" data-action="click->modal#homeOpen">
<div class="card-image">
<img src="img/pubblicazioni.jpg" />
</div>
<div class="card-content">
<button class="button is-link is-large mt-3 has-text-white">Pubblicazioni</button>
</div>
</div>
<div class="column card has-text-centered is-clickable"
data-id="credits" data-action="click->modal#homeOpen">
<div class="card-image">
<img src="img/credits.jpg" />
</div>
<div class="card-content">
<button class="button is-link is-large mt-3 has-text-white">Credits</button>
</div>
</div>
<div class="column card mb-5 has-text-centered is-clickable"
data-id="riconoscimenti" data-action="click->modal#homeOpen">
<div class="card-image">
<img src="img/riconoscimenti.jpg" />
</div>
<div class="card-content">
<button class="button is-link is-large mt-3 has-text-white">Riconoscimenti</button>
</div>
</div>
</div>
</div>
</div>
<div class="modal" data-modal-target="modal" data-id="progetto">
<div class="modal-background" data-action="click->modal#homeClose" data-id="progetto"></div>
<div class="modal-card">
<header class="modal-card-head">
<h3 class="modal-card-title has-text-centered">Il progetto</h3>
<button class="delete" aria-label="close" data-action="modal#homeClose" data-id="progetto"></button>
</header>
<section class="modal-card-body">
<p class="p-2 mt-2 mb-2">
Il progetto per la realizzazione della carta archeologica dellisola di Capri vede coinvolti, tramite appositi accordi di collaborazione e sotto la direzione scientifica della Soprintendenza Archeologia Belle Arti e Paesaggio per lArea Metropolitana di Napoli, i Comuni di Capri e di Anacapri, lIstituto di Scienze del Patrimonio Culturale (ISPC) del CNR e lAssociazione Culturale Apragopolis.
</p>
<p class="p-2 mt-2 mb-2">
Lobiettivo principale consiste nellacquisire conoscenze sulleffettiva estensione dei beni archeologici presenti sullisola, localizzarne i resti e approfondirne le funzioni e dimensioni originarie. La creazione di una mappa archeologica dellisola rappresenta lo strumento più idoneo per affrontare diverse esigenze, tra cui facilitare le azioni mirate alla protezione e valorizzazione del patrimonio culturale, oltre a fornire una corretta comprensione dellevoluzione territoriale. Questa comprensione è un presupposto fondamentale per ricostruire gli eventi storici dellarea e guidare la pianificazione territoriale.
</p>
<p class="p-2 mt-2 mb-2">
Il progetto sperimenta lutilizzo di metodi innovativi di rappresentazione dei monumenti per produrre nuovi contenuti scientifici e una documentazione grafica dettagliata utile allanalisi archeologica. Attraverso la creazione del webgis si consente a tutti i soggetti interessati di fruire liberamente ed in maniera condivisa delle informazioni storico-archeologiche appositamente raccolte e archiviate.
</p>
<p class="p-2 mt-2 mb-2">
Il contributo del CNR ha riguardato il censimento del noto, la raccolta e lo studio della cartografia storica, le attività di rilevamento archeologico dei siti di estensione maggiore scarsamente studiati e rappresentati, la schedatura e analisi delle murature e delle tecniche costruttive, ipotesi di ricostruzione e delle funzioni degli spazi, nonché la costruzione del sistema Web GIS.
</p>
<p class="p-2 mt-2 mb-2">
LAssociazione Culturale Apragopolis ha condotto attività di digitalizzazione e analisi della documentazione darchivio storico e corrente (documenti amministrativi, documentazione di scavo, disegni storici, planimetrie e fotografie), unitamente a ricognizioni sul campo con il coinvolgimento di esperti per lavvio dei rilievi subacquei e per la realizzazione di ricostruzioni virtuali.
</p>
</section>
<footer class="modal-card-foot">
</footer>
</div>
</div>
<div class="modal" data-modal-target="modal" data-id="webgis">
<div class="modal-background" data-action="click->modal#homeClose" data-id="webgis"></div>
<div class="modal-card">
<header class="modal-card-head">
<h3 class="modal-card-title has-text-centered">Il WebGIS</h3>
<button class="delete" aria-label="close" data-action="modal#homeClose" data-id="webgis"></button>
</header>
<section class="modal-card-body">
<p class="has-text-centered">
<a href="webgis/" class="button mt-3 mb-6 is-link is-large has-text-white">Accedi al WebGIS</a>
</p>
<p>
Il WebGIS è una tipologia di mappa georeferenziata interattiva presentata
tramite il Web, quindi fruibile attraverso un qualsiasi browser moderno.
</p>
<p>
Il WebGIS relativo alla Carta Archeologica dell'Isola di Capri è stato realizzato
utilizzando esclusivamente tecnologie open-source, principalmente la libreria JavaScript
<a href="https://leafletjs.com">Leaflet</a> per il rendering della mappa con
i layer (livelli) georeferenziati contenenti i punti geografici e le strutture rilevate
dal progetto, e il framework PHP <a href="https://symfony.com">Symfony</a> per lo
sviluppo della API (lato server) che interagisce con il database per recuperare le informazioni
e i dati relativi ai punti da visualizzare sulla mappa.
</p>
<p>
Il database stesso è stato costruito con il sistema <a href="https://www.postgresql.org/">PostgreSQL</a>, il quale - attraverso l'estensione
<a href="https://postgis.net/">PostGIS</a> - permette di rappresentare dati geografici e geometrici e fornisce un insieme di
funzionalità integrate per l'interazione e le operazioni con i dati geometrici, rendendolo quindi
particolarmente utile per applicazioni <abbr title="Geography Information Systems">GIS</abbr>.
</p>
</section>
<footer class="modal-card-foot">
</footer>
</div>
</div>
<div class="modal" data-modal-target="modal" data-id="cartografia">
<div class="modal-background" data-action="click->modal#homeClose" data-id="cartografia"></div>
<div class="modal-card">
<header class="modal-card-head">
<h3 class="modal-card-title has-text-centered">Cartografia storica</h3>
<button class="delete" aria-label="close" data-action="modal#homeClose" data-id="cartografia"></button>
</header>
<section class="modal-card-body">
<p class="p-2 mt-2 mb-2">
La raccolta della cartografia dedicata al patrimonio archeologico dell'isola di Capri evidenzia
i principali contributi, al più recente al più antico, prodotti dal XV secolo fino agli anni Trenta del XX secolo.
</p>
<h4 class="has-text-weight-bold">Anni '30 del Novecento</h4>
<p class="p-2 mt-2 mb-1">
Paolino Mingazzini (1931) pubblica un foglio dell'Edizione archeologica della carta dItalia (1:100.000), sintetico e compilativo (49 schede per altrettanti punti di interesse archeologico) ma poco chiaro per uso pratico, visto il grande denominatore di scala impiegato.
</p>
<p class="p-2 mt-1 mb-2">
Immanuel Friedlaender (1938) elabora una carta (1:12.000) più dettagliata, con oltre 100 punti di interesse archeologico,
identificandoli mediante numeri ed estendendo la segnalazione ai “ruderi” di tutte le età (1-9: <em>antichità preistoriche</em>;
11-72: <em>antichità grecoromane</em>; 73-100: <em>opere medioevali e successive</em>), sulla base di un modernissimo approccio anticlassicistico,
inserendo anche segnalazioni naturalistiche.
</p>
<h4 class="has-text-weight-bold">Inizi del XX secolo</h4>
<p class="p-2 mt-2 mb-1">
La carta Richter & Co. (1901), anche se non si tratta di una carta archeologica, è un ottimo strumento di consultazione e di orientamento
topografico in generale, vista la scala di rappresentazione (1:10.000), che consente un'individuazione puntuale del costruito e delle strade, con l'abbondanza dei microtoponimi.
</p>
<p class="p-2 mt-1 mb-2">
Julius Beloch (fine XIX sec.) pubblica una carta dove registra soltanto
i resti più importanti dell'isola, ovvero le duodecim villae tiberiane di <em>tacitiana memoria</em>, riducendo l'ambito archeologico.
</p>
<h4 class="has-text-weight-bold">XIX secolo</h4>
<p class="p-2 mt-2 mb-1">
Rosario Mangoni, nel primo Ottocento, pubblica unopera corredata da una carta topografica dell'isola,
che in realtà riproduce quasi esattamente il Foglio 14 della <em>Carta topografica ed idrografica dei contorni di Napoli
levata per ordine di S. M. Ferdinando I, Re del Regno delle Due Sicilie, dagli uffiziali dello Stato Maggiore e
dagl'ingegneri topografi negli anni 1817, 1818, 1819</em>, disegnata ed incisa all'acquaforte nel Reale Officio Topografico
di Napoli (scala dettagliata 1:10.000 e 1:5.000). Questa carta straordinaria, composta da 15 fogli e continuamente
aggiornata fino al 1860, è considerata una delle migliori realizzazioni europee in campo cartografico, che si distingue per la bellezza della resa grafica e soprattutto per il dettaglio.
</p>
<p class="p-2 mt-1 mb-2">
Tra le imprese cartografiche del Reale Officio Topografico di Napoli, vanno segnalati anche l'<em>Atlante marittimo delle due
Sicilie</em> (1792), in 23 fogli più il frontespizio e l'indice, la <em>Carta del littorale di Napoli</em> (1793) e l'<em>Atlante geografico
del Regno di Napoli</em>, in 31 fogli, terminato nel 1812 ( scale 1:90.000 e 1:115.000), affidati a Antonio Rizzi Zannoni,
che produce mappe topografiche avanzate ma non archeologiche.
</p>
<h4 class="has-text-weight-bold">XVII-XVIII secolo</h4>
<p class="p-2 mt-2 mb-1">
Vincenzo Coronelli pubblica sul finire del XVII l'<em>Isolario dell'Atlante Veneto</em>, la monumentale raccolta di carte e
vedute di isole, dove è rappresentata anche Capri mediante una veduta da nord, corredata da una descrizione sintetica.
</p>
<p class="p-2 mt-1 mb-2">
Le pergamene aragonesi (XV-XVI sec.) stupiscono per precisione e toponomastica, influenzando la successiva
produzione cartografica.<br>
Documenti rilevanti sono i disegni non cartografici come lo schizzo di Jean-Jacques Bouchard (1632) e quello
di Fabio Giordano (XVI sec.) evidenziano il ruolo delle "anticaglie" e delle rovine imperiali nell'identificazione
storica di Capri.
</p>
<p class="mt-2 mb-2">
In conclusione, la cartografia ha riflettuto i mutamenti di interessi scientifici e culturali, dall'archeologia
classica a un approccio più sistematico e naturalistico.
</p>
<p class="mt-2 mb-2">
Per approfondimenti sullargomento si veda il contributo di Cecilia Giorgi e Giovanni Caratelli,
<a href="webgis/docs/Verso_una_nuova_carta_archeologica.pdf" title="Scarica PDF">
<em>Verso una nuova carta archeologica per lisola di Capri. Il contributo del CNR al progetto Masgaba</em>
</a>, in R. Bosso, L. Di Franco, G. Di Martino, S. Foresta, R. Perrella (a cura di),
<em>Archeologie borboniche. La ricerca sull'antico a Capri e nelle province di Napoli e Terra di Lavoro</em>.
Convegno Internazionale di Studi (Capri-Anacapri, 11-12 ottobre 2019), Roma 2020, pp. 21-41
</p>
<h4 class="mt-4 has-text-centered has-text-weight-bold is-size-4">Gallery</h4>
<div class="has-text-centered mt-4">
<figure class="is-relative is-clickable has-text-centered" id="gallery">
<img src="img/cartografia/FIG_01_1931_MINGAZZINI.jpg" width="400">
<div class="icon overlay is-flex is-justify-content-center is-align-items-center">
<i class="is-flex fa fa-2x fa-play-circle"></i>
</div>
</figure>
</div>
</section>
<footer class="modal-card-foot">
</footer>
</div>
</div>
<div class="modal" data-modal-target="modal" data-id="credits">
<div class="modal-background" data-action="click->modal#homeClose" data-id="credits"></div>
<div class="modal-card">
<header class="modal-card-head">
<h3 class="modal-card-title has-text-centered">Credits</h3>
<button class="delete" aria-label="close" data-action="modal#homeClose" data-id="credits"></button>
</header>
<section class="modal-card-body">
<article class="media">
<figure class="media-left">
<p class="image is-128x128">
<img src="img/logo-soprintendenza-abap-area-metropolitana-napoli-bianco-e1680166536285.webp" />
</p>
</figure>
<div class="media-content">
<div class="content">
<p>
<strong>
<a href="https://sabapmetropolitanana.cultura.gov.it/">
Soprintendenza Archeologia Belle Arti e Paesaggio per l'Area Metropolitana di Napoli
</a>
</strong>
</p>
<p>
<strong>Direzione scientifica:</strong> Luca Di Franco
<br />
<strong>Studiosi coinvolti:</strong> Rosaria Perrella, Giancarlo Di Martino, Ilaria Matarese, Carmen D'Anna, Raffaella Bosso
</p>
</div>
</div>
</article>
<article class="media">
<figure class="media-left">
<p class="image is-128x128">
<img src="img/logo_ispc_compatto.png" />
</p>
</figure>
<div class="media-content">
<div class="content">
<p>
<strong><a href="https://ispc.cnr.it">CNR-ISPC</a></strong>
</p>
<p>
<strong>Responsabile scientifico:</strong> Cecilia Giorgi
<br />
<strong>Ricercatori e tecnici coinvolti:</strong> Giovanni Caratelli, Nicolò Paraciani
</p>
<p>
Rilievo archeologico con analisi delle murature, schedatura e studio delle emergenze indagate,
documentazione grafica archeologica di cartografie, planimetrie, prospetti e sezioni,
modellazione 3D e video, creazione del <a href="webgis/">WebGIS</a> (elaborazione, struttura
logica dei contenuti, architettura e sviluppo software, grafica), ricerche bibliografiche,
raccolta e georeferenziazione dei vincoli archeologici e paesaggistici.
</p>
</div>
</div>
</article>
<article class="media">
<figure class="media-left">
<p class="image is-128x128">
<img src="img/logo_apragopolis.jpg" />
</p>
</figure>
<div class="media-content">
<div class="content">
<p>
<strong>Associazione Culturale Apragopolis</strong>
</p>
<p>
<strong>Presidente:</strong> Rosaria Perrella
</p>
<p>
Ricerche archivistiche e bibliografiche, schedatura dei siti e rinvenimenti archeologici, incarichi
a professionisti per rilievi subacquei e ricostruzioni virtuali, organizzazione di convegni e curatela
di pubblicazioni inerenti lo studio archeologico dellisola.
</p>
</div>
</div>
</article>
</section>
<footer class="modal-card-foot">
</footer>
</div>
</div>
<div class="modal" data-modal-target="modal" data-id="pubblicazioni">
<div class="modal-background" data-action="click->modal#homeClose" data-id="pubblicazioni"></div>
<div class="modal-card">
<header class="modal-card-head">
<h3 class="modal-card-title has-text-centered">Pubblicazioni</h3>
<button class="delete" aria-label="close" data-action="modal#homeClose" data-id="pubblicazioni"></button>
</header>
<section class="modal-card-body">
<p class="mt-4 mb-6">
Nellambito del progetto per la carta archeologica dellisola di Capri sono stati organizzati convegni
internazionali sullisola di Capri mirati a informare la cittadinanza e la comunità scientifica sui risultati
in itinere, comprese le ricerche dei ricercatori del CNR-ISPC, individuando tematiche che hanno coinvolto
le varie ricerche svolte sul territorio nazionale e nellambito del Mediterraneo, per incentivare dialoghi
e confronti su argomenti di carattere storico-archeologico:
</p>
<article class="media pb-6">
<figure class="media-left">
<p class="image is-128x128">
<img src="img/pub/1_copertina libro archeologie borboniche.png" />
</p>
</figure>
<div class="media-content">
<div class="content">
<p>
R. Bosso, L. Di Franco, G. Di Martino, S. Foresta, R. Perrella (a cura di),
<em>Archeologie borboniche. La ricerca sull'antico a Capri e nelle province di Napoli e Terra di Lavoro</em>,
Atti del Convegno Internazionale di Studi (Capri-Anacapri, 11-12 ottobre 2019), Roma 2020.
</p>
</div>
</div>
</article>
<article class="media mt-4 pb-6">
<figure class="media-left">
<p class="image is-128x128">
<img src="img/pub/2_copertina libro Le Grotte.png" />
</p>
</figure>
<div class="media-content">
<div class="content">
<p>
L. Di Franco, R. Perrella (a cura di),
<em>Le Grotte tra Preistoria, età classica e Medioevo: Capri, la Campania, il Mediterraneo</em>,
Atti del Convegno Internazionale di Studi (Capri-Anacapri, 7-9 ottobre 2021), Roma 2022
</p>
</div>
</div>
</article>
<p class="mt-4 mb-6">
Sono stati inoltre editi volumi di approfondimento sullarcheologia dellisola di Capri e del Golfo di Napoli:
</p>
<article class="media mt-4 pb-6">
<figure class="media-left">
<p class="image is-128x128">
<img src="img/pub/3_copertina libro Il Collezionismo.png" />
</p>
</figure>
<div class="media-content">
<div class="content">
<p>
L. Di Franco, G. Di Martino (a cura di), “Il collezionismo di antichità classiche a Capri tra Ottocento e primo Novecento”, Roma 2018
</p>
</div>
</div>
</article>
<article class="media mt-4 pb-6">
<figure class="media-left">
<p class="image is-128x128">
<img src="img/pub/4_copertina la ricereca archeologica.png" />
</p>
</figure>
<div class="media-content">
<div class="content">
<p>
L. Di Franco (a cura di), “La ricerca archeologica a Capri in età borbonica: siti, personaggi, documenti”, Roma 2021
</p>
</div>
</div>
</article>
<article class="media mt-4 pb-6">
<figure class="media-left">
<p class="image is-128x128">
<img src="img/pub/5_copertina Maiuri.png" />
</p>
</figure>
<div class="media-content">
<div class="content">
<p>
L. Di Franco, R. Perrella (a cura di), Amedeo Maiuri: l'archeologia e il paesaggio storico del Golfo di Napoli, Atti della Giornata di Studi (Capri, 28 ottobre 2022), Roma 2023
</p>
</div>
</div>
</article>
<p class="mt-4">
I convegni e i volumi sono stati curati dai membri dellAssociazione Culturale Apragopolis e sono stati pubblicati con il sostegno della Direzione Generale Educazione, Ricerca e Istituti Culturali, oltre al contributo del Porto Turistico di Capri.
</p>
<p class="mb-6">
Le ricerche del CNR-ISPC sono state presentate in occasione di Convegni Internazionali di Studio, pubblicando i seguenti contributi:
</p>
<article class="media mt-4 pb-6">
<figure class="media-left">
<p class="image is-128x128">
<img src="img/pub/6_copertina Metroarcheo.png" />
</p>
</figure>
<div class="media-content">
<div class="content">
<p>
G. Caratelli, C. Giorgi,
<em>A metrological approach to the study of ancient architecture.
The cases of the Grotta dell'Arsenale and the villas of Gradola and Damecuta in Capri</em>
in <em>2023 IMEKO International Conference on Metrology for Archaeology and Cultural Heritage</em>
(Roma 19-21 ottobre 2023) pp. 796-801
</p>
</div>
</div>
</article>
<article class="media mt-4 pb-6">
<figure class="media-left">
<p class="image is-128x128">
<img src="img/pub/7_copertina Akta Imeko.png" />
</p>
</figure>
<div class="media-content">
<div class="content">
<p>
G. Caratelli, C. Giorgi,
<em>
Laser scanner surveys on the Island of Capri. The contribution of a metrological approach to the understanding of ancient architecture
</em>,
in <em>Acta IMEKO</em>, 13, 2 (2024), pp. 1-9
</p>
</div>
</div>
</article>
</section>
<footer class="modal-card-foot">
</footer>
</div>
</div>
<div class="modal" data-modal-target="modal" data-id="riconoscimenti">
<div class="modal-background" data-action="click->modal#homeClose" data-id="riconoscimenti"></div>
<div class="modal-card">
<header class="modal-card-head">
<h3 class="modal-card-title has-text-centered">Riconoscimenti</h3>
<button class="delete" aria-label="close" data-action="modal#homeClose" data-id="riconoscimenti"></button>
</header>
<section class="modal-card-body">
<p>
Il progetto della carta archeologica dellisola di Capri è stato realizzato con il contributo dei
Comuni di Capri e Anacapri, i convegni internazionali e i relativi volumi sono stati svolti e pubblicati
con il sostegno della Direzione Generale Educazione, Ricerca e Istituti Culturali e del Porto Turistico di Capri.
</p>
<p class="has-text-centered mt-5">
<img src="img/logo_anacapri.svg">
</p>
<p class="has-text-centered mt-5">
<img src="img/logo_comune_capri.png">
</p>
<p class="has-text-centered mt-5">
<img src="img/logo direzione generale ricerca.png">
</p>
<p class="has-text-centered mt-5">
<img src="img/logo porto turistico.png">
</p>
</section>
<footer class="modal-card-foot">
</footer>
</div>
</div>
</div> </div>
<footer class="footer has-text-centered"> <footer class="footer has-text-centered">
<p>&copy; <span id="c-year"></span> CNR-ISPC Tutti i diritti riservati</p> <p>&copy; <span id="c-year"></span> CNR-ISPC Tutti i diritti riservati</p>
</footer> </footer>
<script type="text/javascript" defer> <script type="text/javascript" defer>
const year = new Date().getFullYear(); const year = new Date().getFullYear();
document.getElementById('c-year').innerText = year; document.getElementById('c-year').innerText = year;
</script> </script>
<script type="module">
import { Application } from '@hotwired/stimulus';
import ModalController from './webgis/js/controllers/modal_controller.js';
import Spotlight from './webgis/js/vendor/spotlight.js/src/js/spotlight.js';
window.Stimulus = Application.start();
Stimulus.register("modal", ModalController);
let gallery = document.querySelector('#gallery');
if (gallery) {
let images = [
{src: './img/cartografia/FIG_01_1931_MINGAZZINI.jpg'},
{src: './img/cartografia/FIG_02_1938_FRIEDLAENDER.jpg'},
{src: './img/cartografia/FIG_03_1901_GIANNOTTI.jpg'},
{src: './img/cartografia/FIG_04_1890_BELOCH.jpg'},
{src: './img/cartografia/FIG_07_1793_CARTA_LITTORALE.jpg'},
{src: './img/cartografia/FIG_08_1793_CARTA_LITTORALE_PARTICOLARE.jpg'},
{src: './img/cartografia/FIG_09_1794_HADRAWA_TAV_01.jpg'},
{src: './img/cartografia/FIG_10_1696_CORONELLI.jpg'},
{src: './img/cartografia/FIG_11_MAPPE_ARAGONESI.jpg'},
{src: './img/cartografia/FIG_12_1620_MAGINI.jpg'},
{src: './img/cartografia/FIG_13_BOUCHARD.jpg'},
{src: './img/cartografia/FIG_14_FABIO_GIORDANO.jpg'},
];
gallery.addEventListener('click', () => {
Spotlight.show(images);
});
}
</script>
</body> </body>
</html> </html>

View File

@@ -0,0 +1,19 @@
{
"type": "FeatureCollection",
"name": "preistorici",
"crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:OGC:1.3:CRS84" } },
"features": [
{ "type": "Feature", "properties": { "id": null, "denominazione": "Anacapri località Valletta di Cetrella", "oggetto": "Spargimento di frammenti ceramici" }, "geometry": { "type": "Point", "coordinates": [ 14.229480619506239, 40.549096057236518 ] } },
{ "type": "Feature", "properties": { "id": null, "denominazione": "Anacapri località Punta Capocchia", "oggetto": "Spargimento di frammenti ceramici" }, "geometry": { "type": "Point", "coordinates": [ 14.198744713836438, 40.554761782142606 ] } },
{ "type": "Feature", "properties": { "id": null, "denominazione": "Anacapri località Punta del Miglio", "oggetto": "Spargimento di frammenti ceramici" }, "geometry": { "type": "Point", "coordinates": [ 14.198699377122848, 40.556721558105025 ] } },
{ "type": "Feature", "properties": { "id": null, "denominazione": "Anacapri località Punta Campetiello", "oggetto": "Spargimento di frammenti ceramici e industria litica" }, "geometry": { "type": "Point", "coordinates": [ 14.198565753124916, 40.549317256129129 ] } },
{ "type": "Feature", "properties": { "id": null, "denominazione": "Anacapri località Rio Latino-Cala di Mezzo", "oggetto": "Spargimento di frammenti ceramici" }, "geometry": { "type": "Point", "coordinates": [ 14.199252962257196, 40.54739533970816 ] } },
{ "type": "Feature", "properties": { "id": null, "denominazione": "Anacapri località Pino", "oggetto": "Spargimento di frammenti ceramici" }, "geometry": { "type": "Point", "coordinates": [ 14.202236833854124, 40.546958367996154 ] } },
{ "type": "Feature", "properties": { "id": null, "denominazione": "Anacapri località Grotta del Pisco", "oggetto": "Concentrazione di frammenti ceramici" }, "geometry": { "type": "Point", "coordinates": [ 14.202644864276412, 40.543834209174214 ] } },
{ "type": "Feature", "properties": { "id": null, "denominazione": "Anacapri località Punta del Pino", "oggetto": "Concentrazione di frammenti ceramici" }, "geometry": { "type": "Point", "coordinates": [ 14.197557607783281, 40.541821470187763 ] } },
{ "type": "Feature", "properties": { "id": null, "denominazione": "Anacapri località Capo Ruglio-Limmo", "oggetto": "Concentrazione di frammenti ceramici" }, "geometry": { "type": "Point", "coordinates": [ 14.199714680892935, 40.538709765491753 ] } },
{ "type": "Feature", "properties": { "id": null, "denominazione": "Anacapri località Belvedere della Migliara", "oggetto": "Concentrazione di frammenti ceramici" }, "geometry": { "type": "Point", "coordinates": [ 14.209803292737673, 40.539939232521711 ] } },
{ "type": "Feature", "properties": { "id": null, "denominazione": "Anacapri località Punta Carena-Limmo", "oggetto": "Concentrazione di frammenti ceramici" }, "geometry": { "type": "Point", "coordinates": [ 14.199528561752958, 40.536773037148208 ] } },
{ "type": "Feature", "properties": { "id": null, "denominazione": "Anacapri località Punta dellArcera", "oggetto": "Affioramento materiale ceramico" }, "geometry": { "type": "Point", "coordinates": [ 14.200509266452157, 40.558637768309111 ] } }
]
}

BIN
webgis/img/DJI_0364.JPG Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 741 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 495 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 521 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 449 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1015 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 440 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 464 KiB

0
webgis/img/geo/.keep Normal file
View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.5 KiB

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 92 KiB

After

Width:  |  Height:  |  Size: 183 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 261 KiB

After

Width:  |  Height:  |  Size: 383 KiB

View File

@@ -9,22 +9,25 @@
<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" /> <link rel="stylesheet" href="js/vendor/@photo-sphere-viewer/core/index.css" />
<link rel="shortcut icon" type="image/png" href="/img/favicon.png">
<script type="importmap"> <script type="importmap">
{ {
"imports": { "imports": {
"three": "./js/vendor/three/build/three.module.js", "three": "./js/vendor/three/build/three.module.js",
"@photo-sphere-viewer/core": "./js/vendor/@photo-sphere-viewer/core/index.module.js", "@photo-sphere-viewer/core": "./js/vendor/@photo-sphere-viewer/core/index.module.js",
"@hotwired/stimulus": "./js/vendor/@hotwired/stimulus/dist/stimulus.js" "@hotwired/stimulus": "./js/vendor/@hotwired/stimulus/dist/stimulus.js"
} }
} }
</script> </script>
<script src="js/vendor/leaflet/dist/leaflet.js"></script> <script src="./js/vendor/proj4/dist/proj4.js"></script>
<script src="js/vendor/leaflet/dist/leaflet-src.js"></script>
<script src="js/vendor/leaflet.markercluster/dist/leaflet.markercluster.js"></script> <script src="js/vendor/leaflet.markercluster/dist/leaflet.markercluster.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>
<title>WebGIS Isola di Capri</title> <title>WebGIS Isola di Capri</title>
</head> </head>
<body data-controller="menu"> <body data-controller="menu"
data-action="menu-ready@document->menu#buildMenu menu-ready@document->menu#buildCartographyMenu">
<nav class="navbar mb-0" role="navigation"> <nav class="navbar mb-0" role="navigation">
<div class="navbar-brand"> <div class="navbar-brand">
<a href="/" class="navbar-item is-size-5 has-text-dark ml-4" title="Torna alla home page"> <a href="/" class="navbar-item is-size-5 has-text-dark ml-4" title="Torna alla home page">
@@ -45,12 +48,21 @@
<hr class="navbar-divider"> <hr class="navbar-divider">
<div class="navbar-end pb-1 pt-1" id="nav-menu"> <div class="navbar-end pb-1 pt-1" id="nav-menu">
<button class="navbar-item button is-size-5 is-white mr-3" role="button" <button class="navbar-item button is-size-5 is-white mr-3" role="button"
data-id="main"
data-action="menu#toggleMenu"> data-action="menu#toggleMenu">
<span class="icon mr-2"> <span class="icon mr-2">
<i class="fa fa-list"></i> <i class="fa fa-list"></i>
</span> </span>
Elenco beni Elenco beni
</button> </button>
<button class="navbar-item button is-size-5 is-white mr-3" role="button"
data-id="cartography"
data-action="menu#toggleMenu">
<span class="icon mr-2">
<i class="fa fa-map"></i>
</span>
Cartografia
</button>
<button class="button is-outlined is-rounded is-link mr-4 mt-1" id="howto" title="Istruzioni"> <button class="button is-outlined is-rounded is-link mr-4 mt-1" id="howto" title="Istruzioni">
<span class="icon is-large has-text-link"> <span class="icon is-large has-text-link">
<i class="fas fa-question fa-lg"></i> <i class="fas fa-question fa-lg"></i>
@@ -63,289 +75,242 @@
<div class="loading loading-lg"></div> <div class="loading loading-lg"></div>
</div> </div>
<div class="main columns"> <div class="main columns">
<div class="column is-hidden is-4 is-4-desktop is-5-mobile is-overlay has-background-white-ter" id="menu" <div class="column mb-0 pb-0 is-full is-relative">
data-menu-target="menu"> <div class="pb-0 is-relative" id="map" aria-describedby="map-progress" aria-busy="true">
<progress id="map-progress" class="p-2 progress is-medium is-link" aria-label="Map loading..." />
</div>
</div>
<div class="menu-overlay column is-hidden is-4 is-4-desktop is-5-mobile is-pulled-right is-overlay has-background-white-ter"
data-menu-target="menu" data-controller="layer">
<!-- Template to build menu items dynamically -->
<template id="menu-item-template">
<li>
<a class="is-block button"
data-controller="marker"
data-action="marker#go"
data-marker-coords-value=""
data-marker-group-value="">
</a>
</li>
</template>
<aside class="menu ml-4 mt-3"> <aside class="menu ml-4 mt-3">
<button title="Chiudi menu" class="delete is-pulled-right" data-action="menu#close"></button> <button title="Chiudi menu" class="delete is-pulled-right" data-action="menu#close"></button>
<p class="menu-label is-size-5 mt-2 is-clickable" data-action="click->menu#toggle" data-id="siti"> <p class="menu-label is-size-5 mt-2 is-clickable" data-id="sites">
<span class="icon pr-2"> <span role="button" class="icon pl-1 mr-2 is-small" title="Nascondi" data-layer-target="sites" data-action="click->layer#toggle">
<i class="fa fa-xs fa-eye-slash" data-layer-target="icon"></i>
</span>
<span class="icon pr-1">
<img class="image" src="img/icons/siti_menu.png"/> <img class="image" src="img/icons/siti_menu.png"/>
</span> </span>
Beni archeologici <span role="button" data-action="click->menu#toggle" data-id="sites">
<span class="icon pl-2"> Beni archeologici
<i class="fa fa-chevron-right" data-menu-target="icon" data-id="siti"></i> <span class="icon pl-2">
<i class="fa fa-chevron-right" data-menu-target="icon" data-id="sites"></i>
</span>
</span> </span>
</p> </p>
<ul class="menu-list is-hidden" id="siti-list" data-menu-target="list"data-controller="marker"> <ul class="menu-list is-hidden" id="sites-list" data-menu-target="list" data-controller="marker">
<li> <li data-list-id="sites-anacapri-sub">
<span class="is-clickable" data-action="click->menu#openSubList" data-list-id="siti-anacapri-sub"> <span role="button" class="is-clickable" data-action="click->menu#openSubList" data-list-id="sites-anacapri-sub">
Anacapri Anacapri
<span class="icon ml-2"> <span class="icon ml-2">
<i class="fa fa-chevron-right" data-menu-target="icon"></i> <i class="fa fa-chevron-right" data-menu-target="icon"></i>
</span> </span>
</span> </span>
<ul id="siti-anacapri-sub" class="is-hidden">
<li>
<a class="is-block button" title="Vai al sito Villa di Gradola" data-action="marker#go" data-coords="40.56094295 14.20573624">
Grotta Azzurra
</a>
</li>
<li>
<a class="button" title="Vai al sito Lo Pozzo" data-action="marker#go" data-coords="40.556601 14.213642">
Località Lo Pozzo
</a>
</li>
<li>
<a class="button" title="Vai al sito Scala Fenicia" data-action="marker#go" data-coords="40.5562963 14.2285935">
Scala Fenicia
</a>
</li>
<li>
<a class="button" title="Vai al sito Villa di Damecuta" data-action="marker#go" data-coords="40.55906 14.20055">
Villa di Damecuta
</a>
</li>
<li>
<a class="is-block button" title="Vai al sito Villa di Gradola" data-action="marker#go" data-coords="40.560834 14.205793">
Villa di Gradola
</a>
</li>
<li>
<a class="button" title="Vai al sito San Michele" data-action="marker#go" data-coords="">
Villa San Michele
</a>
</li>
</ul>
</li> </li>
<li class="mt-3"> <li class="mt-3" data-list-id="sites-capri-sub">
<span class="is-clickable" data-action="click->menu#openSubList" data-list-id="siti-capri-sub"> <span role="button" class="is-clickable" data-action="click->menu#openSubList" data-list-id="sites-capri-sub">
Capri Capri
<span class="icon ml-2"> <span class="icon ml-2">
<i class="fa fa-chevron-right" data-menu-target="icon"></i> <i class="fa fa-chevron-right" data-menu-target="icon"></i>
</span> </span>
</span> </span>
<ul id="siti-capri-sub" class="is-hidden">
<li>
<a class="button" id="tiberio">
Bagni di Tiberio
</a>
</li>
<li>
<a class="button" id="arsenale">
Grotta dell'Arsenale
</a>
</li>
<li>
<a class="button" title="Vai al sito Grotta di Matermania" id="matermania">
Grotta di Matermania
</a>
</li>
<li>
<a class="button" id="mura">
Mura greche
</a>
</li>
</ul>
</li> </li>
</ul> </ul>
<p class="menu-label is-size-5 is-clickable" data-action="click->menu#toggle" data-id="non-conser"> <p class="menu-label is-size-5 is-clickable" data-id="notConserved">
<span class="icon pr-2"> <span class="icon pl-1 mr-2 is-small" title="Nascondi" data-layer-target="notConserved"
data-action="click->layer#toggle" style="max-height: 10px">
<i class="fa fa-xs fa-eye-slash" data-layer-target="icon"></i>
</span>
<span class="icon pr-1">
<img class="image" src="img/icons/non_cons_menu.png"/> <img class="image" src="img/icons/non_cons_menu.png"/>
</span> </span>
Beni non conservati <span role="button" data-action="click->menu#toggle" data-id="notConserved">
<span class="icon pl-2"> Beni non conservati
<i class="fa fa-chevron-right" data-menu-target="icon" data-id="non-conser"></i> <span class="icon pl-2">
<i class="fa fa-chevron-right" data-menu-target="icon" data-id="notConserved"></i>
</span>
</span> </span>
</p> </p>
<ul class="menu-list is-hidden" id="non-conser-list" data-menu-target="list" data-controller="marker"> <ul class="menu-list is-hidden" id="notConserved-list" data-menu-target="list" data-controller="marker">
<li data-list-id="noncons-anacapri-sub"> <li data-list-id="notConserved-anacapri-sub">
<span class="is-clickable" data-action="click->menu#openSubList" data-list-id="noncons-anacapri-sub"> <span role="button" class="is-clickable" data-action="click->menu#openSubList" data-list-id="notConserved-anacapri-sub">
Anacapri Anacapri
<span class="icon ml-2 is-small" data-list-id="noncons-anacapri-sub"> <span class="icon ml-2 is-small" data-list-id="notConserved-anacapri-sub">
<i class="fa fa-chevron-right"></i>
</span>
</span>
</li>
<li class="mt-3" data-list-id="notConserved-capri-sub">
<span role="button" class="is-clickable" data-action="click->menu#openSubList" data-list-id="notConserved-capri-sub">
Capri
<span class="icon ml-2 is-small" data-list-id="notConserved-capri-sub">
<i class="fa fa-chevron-right"></i> <i class="fa fa-chevron-right"></i>
</span> </span>
</span> </span>
<ul id="noncons-anacapri-sub" class="is-hidden">
<li>
<a class="button" data-action="marker#go" data-coords="40.5595565 14.2003896">
Cala a mare - resti di ambienti
</a>
</li>
<li>
<a class="button" data-action="marker#go" data-coords="40.549026 14.196911">
Punta Campetiello - scala
</a>
</li>
<li>
<a class="button" data-action="marker#go" data-coords="40.5501214 14.2198544">
Castagnaro - area funeraria
</a>
</li>
<li>
<a class="button" data-action="marker#go" data-coords="40.55129683 14.21261142">
Ceselle - necropoli
</a>
</li>
<li>
<a class="button" data-action="marker#go" data-coords="40.5533744 14.2178754">
Località Piscina - complesso idraulico
</a>
</li>
<li>
<a class="button" data-action="marker#go" data-coords="40.5546467 14.2092143">
La Cera - ambienti voltati
</a>
</li>
<li>
<a class="button" data-action="marker#go" data-coords="40.5495555 14.2108741">
Cesa - complesso idraulico
</a>
</li>
<li>
<a class="button" data-action="marker#go" data-coords="40.5575337 14.2027513">
La Fabbrica - resti murari
</a>
</li>
<li>
<a class="button" data-action="marker#go" data-coords="40.5530655 14.201767">
Lupinaro - resti murari
</a>
</li>
<li>
<a class="button" data-action="marker#go" data-coords="40.5399801 14.2092552">
Migliara Belvedere - frammenti erratici
</a>
</li>
<li>
<a class="button" data-action="marker#go" data-coords="40.5451791 14.2233019">
Monte Solaro - vaso corinzio
</a>
</li>
<li>
<a class="button" data-action="marker#go" data-coords="40.5523988 14.2087281">
Monticello - “Vaso di Monticello”
</a>
</li>
<li>
<a class="button" data-action="marker#go" data-coords="40.5521975 14.2107296">
Monticello - “Villa di Monticello”
</a>
</li>
<li>
<a class="button" data-action="marker#go" data-coords="40.5559514 14.2197966">
Pastena - strutture murarie
</a>
</li>
<li>
<a class="button" data-action="marker#go" data-coords="40.546923 14.2173871">
Petracquale - ruderi indeterminati
</a>
</li>
<li>
<a class="button" data-action="marker#go" data-coords="40.55666444 14.21446043">
Timberino - impianto idraulico
</a>
</li>
<li>
<a class="button" data-action="marker#go" data-coords="40.5590486 14.1984242">
Vetereto - ambienti voltati
</a>
</li>
<li>
<a class="button" data-action="marker#go" data-coords="40.556597 14.214518">
Veterino - complesso residenziale
</a>
</li>
</ul>
</li> </li>
</ul> </ul>
<p class="menu-label is-size-5 is-clickable" data-action="click->menu#toggle" data-id="rinv"> <p class="menu-label is-size-5 is-clickable" data-id="findings">
<span class="icon pr-2"> <span class="icon pl-1 mr-2 is-small" data-layer-target="findings" data-action="click->layer#toggle">
<i class="fa fa-xs fa-eye-slash" data-layer-target="icon"></i>
</span>
<span class="icon pr-1">
<img class="image" src="img/icons/rinv_menu.png"/> <img class="image" src="img/icons/rinv_menu.png"/>
</span> </span>
Rinvenimenti <span role="button" data-action="click->menu#toggle" data-id="findings">
<span class="icon pl-2"> Reperti
<i class="fa fa-chevron-right" data-menu-target="icon" data-id="rinv"></i> <span class="icon pl-2">
<i class="fa fa-chevron-right" data-menu-target="icon" data-id="findings"></i>
</span>
</span> </span>
</p> </p>
<ul class="menu-list is-hidden" id="rinv-list" data-menu-target="list" data-controller="marker"> <ul class="menu-list is-hidden" id="findings-list" data-menu-target="list" data-controller="marker">
<li> <li data-list-id="findings-anacapri-sub">
<span class="is-clickable" data-action="click->menu#openSubList" data-list-id="rinv-anacapri-sub"> <span role="button" class="is-clickable" data-action="click->menu#openSubList" data-list-id="findings-anacapri-sub">
Anacapri Anacapri
<span class="icon ml-2"> <span class="icon ml-2">
<i class="fa fa-chevron-right" data-menu-target="icon"></i> <i class="fa fa-chevron-right" data-menu-target="icon"></i>
</span> </span>
</span> </span>
<ul id="rinv-anacapri-sub" class="is-hidden"> </li>
<li> <li class="mt-3" data-list-id="findings-capri-sub">
<a class="button" data-marker-target="coords" <span role="button" class="is-clickable" data-action="click->menu#openSubList" data-list-id="findings-capri-sub">
data-coords="40.55939119 14.20064002" data-action="marker#go"> Capri
Affresco Villa di Damecuta <span class="icon ml-2">
</a> <i class="fa fa-chevron-right" data-menu-target="icon"></i>
</li> </span>
<li> </span>
<a class="button" data-marker-target="coords" </li>
data-coords="40.5565536 14.2133073" data-action="marker#go"> </ul>
Base di candelabro - Lo Pozzo <p class="menu-label is-size-5 is-clickable" data-id="prehistoric">
</a> <span class="icon pl-1 mr-2 is-small" title="Nascondi" data-layer-target="prehistoric" data-action="click->layer#toggle">
</li> <i class="fa fa-xs fa-eye-slash" data-layer-target="icon"></i>
<li> </span>
<a class="button" data-marker-target="coords" <span class="icon pr-1">
data-coords="40.56061123 14.20569607" data-action="marker#go"> <img class="image" src="img/icons/preistorici.png"/>
Statua di Nettuno - Grotta Azzurra </span>
</a> <span role="button" data-action="click->menu#toggle" data-id="prehistoric">
</li> Aree di affioramento
<li> <span class="icon pl-2">
<a class="button" data-marker-target="coords" <i class="fa fa-chevron-right" data-menu-target="icon" data-id="prehistoric"></i>
data-coords="40.56070704 14.20588946" data-action="marker#go"> </span>
Statua di Tritone imberbe - Grotta Azzurra </span>
</a> </p>
</li> <ul class="menu-list is-hidden" id="prehistoric-list" data-menu-target="list" data-controller="marker">
<li> <li data-list-id="prehistoric-anacapri-sub">
<a class="button" data-marker-target="coords" <span role="button" class="is-clickable" data-action="click->menu#openSubList" data-list-id="prehistoric-anacapri-sub">
data-coords="40.56057044 14.20603369" data-action="marker#go"> Anacapri
Statua di Tritone barbato - Grotta Azzurra <span class="icon ml-2 is-small" data-list-id="prehistoric-anacapri-sub">
</a> <i class="fa fa-chevron-right"></i>
</li> </span>
<li> </span>
<a class="button" data-marker-target="coords" </li>
data-coords="40.56048101 14.20591339" data-action="marker#go"> <li class="mt-3" data-list-id="prehistoric-capri-sub">
Statua di Tritone - Grotta Azzurra <span role="button" class="is-clickable" data-action="click->menu#openSubList" data-list-id="prehistoric-capri-sub">
</a> Capri
</li> <span class="icon ml-2 is-small" data-list-id="prehistoric-capri-sub">
<li> <i class="fa fa-chevron-right"></i>
<a class="button" data-marker-target="coords" </span>
data-coords="40.5605702 14.20575881" data-action="marker#go"> </span>
Statua di peplophoros - Grotta Azzurra </li>
</a> </ul>
</li> <p class="menu-label is-size-5 is-clickable" data-id="underwater">
<li> <span class="icon pl-1 mr-2 is-small" title="Nascondi" data-layer-target="underwater" data-action="click->layer#toggle">
<a class="button" data-marker-target="coords" <i class="fa fa-xs fa-eye-slash" data-layer-target="icon"></i>
data-coords="40.5596847 14.2013025" data-action="marker#go"> </span>
Statua di fanciullo - Damecuta <span class="icon pr-1">
</a> <img class="image" src="img/icons/subacquei_menu.png"/>
</li> </span>
<li> <span role="button" data-action="click->menu#toggle" data-id="underwater">
<a class="button" data-marker-target="coords" Giacimenti subacquei
data-coords="40.5595088 14.2008549" data-action="marker#go"> <span class="icon pl-2">
Frammento di testa di Sileno - Damecuta <i class="fa fa-chevron-right" data-menu-target="icon" data-id="underwater"></i>
</a> </span>
</li> </span>
</ul> </p>
<ul class="menu-list is-hidden" id="underwater-list" data-menu-target="list" data-controller="marker">
<li>
<a class="button" data-action="marker#go" data-controller="marker" data-marker-coords-value="40.5511022 14.1910274">
Bocca Grande - relitto con carico
</a>
</li>
<li>
<a class="button" data-action="marker#go" data-controller="marker" data-marker-coords-value="40.5870549 14.2887986">
Bocca Piccola - relitto con carico
</a>
</li>
<li>
<a class="button" data-action="marker#go" data-controller="marker" data-marker-coords-value="40.5579004 14.2363139">
Marina Grande - strutture portuali
</a>
</li>
<li>
<a class="button" data-action="marker#go" data-controller="marker" data-marker-coords-value="40.54468634 14.23392751">
Marina Piccola, Scoglio delle Sirene - strutture portuali, approdo
</a>
</li>
<li>
<a class="button" data-action="marker#go" data-controller="marker" data-marker-coords-value="40.5649884 14.1940185">
Punta dellArcera - relitto con carico
</a>
</li> </li>
</ul> </ul>
</aside> </aside>
</div> </div>
<div class="column mb-0 pb-0 is-full is-relative"> <div class="menu-overlay column is-hidden is-3 is-3-desktop is-4-mobile is-pulled-right is-overlay has-background-white-ter"
<div class="pb-0" id="map" aria-describedby="map-progress" aria-busy="true" style="position: relative;"> data-menu-target="cartography">
<progress id="map-progress" class="p-2 progress is-medium is-link" aria-label="Map loading..." /> <!-- Template to build menu items dynamically -->
</div> <template id="cartography-item-template">
<li>
<label class="checkbox">
<input type="checkbox"
data-controller="layer"
data-action="layer#toggleCartography"
data-layer-id-value=""
data-layer-type-value=""
/>
</label>
</li>
</template>
<aside class="menu ml-4 mt-3" data-id="cartography-aside">
<button title="Chiudi menu" class="delete is-pulled-right" data-action="menu#closeCartography"></button>
<ul class="menu-list">
<li>
<input type="checkbox" data-controller="layer" data-action="layer#toggleCadastral" />
Catasto Agenzia delle Entrate (particelle e fabbricati)
</li>
</ul>
<p class="menu-label is-size-5 mt-4 is-clickable" data-id="historic">
<span role="button" data-action="click->menu#toggle" data-id="historic">
Catasto storico
<span class="icon pl-2">
<i class="fa fa-chevron-right" data-menu-target="icon" data-id="historic"></i>
</span>
</span>
</p>
</aside>
</div> </div>
</div> </div>
<!-- Bibliography citations template -->
<template id="biblio-item-template">
<span class="is-clickable has-text-link"
data-action="click->biblio#open">
</span>
</template>
<!-- Sites data modal --> <!-- Sites data modal -->
<div class="modal" id="site-data" data-controller="modal biblio tabs" data-modal-target="modal"> <div class="modal" id="site-data" data-controller="modal biblio tabs marker" data-modal-target="modal">
<div class="modal-background" data-action="click->modal#close click->tabs#reset"></div> <div class="modal-background" data-action="click->modal#close click->tabs#reset"></div>
<div class="modal-content has-background-white" style="min-height: 95vh;"> <div class="modal-content has-background-white">
<div class="tabs is-centered"> <div class="tabs is-centered">
<ul> <ul>
<li class="is-active" id="for-short-sheet" <li class="is-active" id="for-short-sheet"
@@ -391,17 +356,47 @@
<button class="modal-close is-large" aria-label="close" data-action="modal#close tabs#reset"></button> <button class="modal-close is-large" aria-label="close" data-action="modal#close tabs#reset"></button>
</div> </div>
<!-- Not conserved modal --> <!-- Not conserved modal -->
<div class="modal" id="not-conser-data" data-controller="modal biblio" data-modal-target="modal"> <div class="modal" id="not-conser-data" data-controller="modal biblio tabs marker" data-modal-target="modal">
<div class="modal-background" data-action="click->modal#close"></div> <div class="modal-background" data-action="click->modal#close click->tabs#reset"></div>
<div class="modal-content has-background-white" style="min-height: 95vh;"> <div class="modal-content has-background-white">
<div id="not-conser-sheet"></div> <div class="tabs is-centered">
<ul>
<li class="is-active" id="for-not-conserved-sheet" data-tabs-target="tab active" data-action="click->tabs#activate">
<a>
<span class="icon is-small"
><i class="fas fa-info-circle" aria-hidden="true"></i
></span>
<span>Scheda</span>
</a>
</li>
<li id="for-photos" data-tabs-target="tab" data-action="click->tabs#activate">
<a>
<span class="icon is-small"
><i class="fas fa-image" aria-hidden="true"></i
></span>
<span>Immagini</span>
</a>
</li>
<li id="for-documents" data-tabs-target="tab" data-action="click->tabs#activate">
<a>
<span class="icon is-small"
><i class="fas fa-book" aria-hidden="true"></i
></span>
<span>Documenti</span>
</a>
</li>
</ul>
</div>
<div class="data-tabs" id="not-conserved-sheet" data-tabs-target="content"></div>
<div class="data-tabs is-hidden" id="photos" data-tabs-target="content"></div>
<div class="data-tabs is-hidden" id="documents" data-tabs-target="content"></div>
</div> </div>
<button class="modal-close is-large" aria-label="close" data-action="modal#close"></button> <button class="modal-close is-large" aria-label="close" data-action="modal#close tabs#reset"></button>
</div> </div>
<!-- Finding modal --> <!-- Finding modal -->
<div class="modal" id="finding-data" data-controller="modal biblio tabs" data-modal-target="modal"> <div class="modal" id="finding-data" data-controller="modal biblio tabs marker" data-modal-target="modal">
<div class="modal-background" data-action="click->modal#close click->tabs#reset"></div> <div class="modal-background" data-action="click->modal#close click->tabs#reset"></div>
<div class="modal-content has-background-white" style="min-height: 95vh;"> <div class="modal-content has-background-white">
<div class="tabs is-centered"> <div class="tabs is-centered">
<ul> <ul>
<li class="is-active" id="for-finding-sheet" data-tabs-target="tab active" data-action="click->tabs#activate"> <li class="is-active" id="for-finding-sheet" data-tabs-target="tab active" data-action="click->tabs#activate">
@@ -427,10 +422,47 @@
</div> </div>
<button class="modal-close is-large" aria-label="close" data-action="modal#close tabs#reset"></button> <button class="modal-close is-large" aria-label="close" data-action="modal#close tabs#reset"></button>
</div> </div>
<!-- Prehistoric modal -->
<div class="modal" id="prehist-data" data-controller="modal biblio marker tabs" data-modal-target="modal">
<div class="modal-background" data-action="click->modal#close click->tabs#reset"></div>
<div class="modal-content has-background-white">
<div class="tabs is-centered">
<ul>
<li class="is-active" id="for-prehist-sheet" data-tabs-target="tab active" data-action="click->tabs#activate">
<a>
<span class="icon is-small"
><i class="fas fa-info-circle" aria-hidden="true"></i
></span>
<span>Scheda</span>
</a>
</li>
<li id="for-photos" data-tabs-target="tab" data-action="click->tabs#activate">
<a>
<span class="icon is-small"
><i class="fas fa-image" aria-hidden="true"></i
></span>
<span>Immagini</span>
</a>
</li>
</ul>
</div>
<div class="data-tabs" id="prehist-sheet" data-tabs-target="content"></div>
<div class="data-tabs is-hidden" id="photos" data-tabs-target="content"></div>
</div>
<button class="modal-close is-large" aria-label="close" data-action="modal#close tabs#reset"></button>
</div>
<!-- Underwater modal -->
<div class="modal" id="underwater-data" data-controller="modal biblio marker" data-modal-target="modal">
<div class="modal-background" data-action="click->modal#close"></div>
<div class="modal-content has-background-white">
<div id="underwater-sheet"></div>
</div>
<button class="modal-close is-large" aria-label="close" data-action="modal#close"></button>
</div>
<!-- Spherical photo modal --> <!-- Spherical photo modal -->
<div class="modal" id="spherical-modal"> <div class="modal" id="spherical-modal">
<div class="modal-background"></div> <div class="modal-background"></div>
<div class="modal-content has-background-white" style="min-height: 95vh;"> <div class="modal-content has-background-white">
<div id="pano-viewer"></div> <div id="pano-viewer"></div>
</div> </div>
<button class="modal-close is-large" aria-label="close"></button> <button class="modal-close is-large" aria-label="close"></button>

View File

@@ -1,3 +1,4 @@
import { GisState } from "../state.js";
/** /**
* @class Finding * @class Finding
*/ */
@@ -33,6 +34,10 @@ export class Finding {
<p class="p-2"> <p class="p-2">
<strong>Luogo di conservazione:</strong> ${this._data.conservationPlace} <strong>Luogo di conservazione:</strong> ${this._data.conservationPlace}
</p> </p>
<p class="mt-4 pl-2 pr-5">
<strong class="pb-3">Descrizione</strong></br>
${this._data.description}
</p>
<p class="mt-4 pl-2 pr-5"> <p class="mt-4 pl-2 pr-5">
<span class="icon has-text-link"> <span class="icon has-text-link">
<i class="fa fa-book"></i> <i class="fa fa-book"></i>
@@ -40,10 +45,6 @@ export class Finding {
<strong>Bibliografia:</strong> ${await this.biblio(this._data.id)} <strong>Bibliografia:</strong> ${await this.biblio(this._data.id)}
</p> </p>
<div class="notification is-light mx-3 mt-4 mb-0 p-2 is-hidden" data-biblio-target="biblio"></div> <div class="notification is-light mx-3 mt-4 mb-0 p-2 is-hidden" data-biblio-target="biblio"></div>
<p class="mt-4 pl-2 pr-5">
<strong class="pb-3">Descrizione</strong></br>
${this._data.description}
</p>
<p class="p-2 mb-4"> <p class="p-2 mb-4">
<strong>Autore scheda:</strong> ${this._data.author} <strong>Autore scheda:</strong> ${this._data.author}
</p> </p>
@@ -63,40 +64,44 @@ export class Finding {
</div> </div>
</figure> </figure>
</div> </div>
</div> </div>`;
`;
return content; return content;
} }
/**
async setImages() { * @param {HTMLElement} imageContainer
let record = await this.fetchData(`${window.API_URL}/finding/${this._data.id}`) * @param {Function} gallery
*/
async setImages(imageContainer, gallery) {
let record = await this.fetchData(`${GisState.apiUrl}/finding/${this._data.id}`)
if (record.images.length) { if (record.images.length) {
this.images = record.images; this.images = record.images;
imageContainer.innerHTML = this.renderImages();
gallery('finding-gallery', this.images);
} }
} }
/** /**
* @param {number} recordId * @param {number} recordId
*/ */
async biblio(recordId) { async biblio(recordId) {
let record = await this.fetchData(`${window.API_URL}/finding/${recordId}`); let finding = await this.fetchData(`${GisState.apiUrl}/finding/${recordId}`);
let citations = ''; let citations = '';
if (record.bibliography.length) { if (finding.bibliography.length) {
record.bibliography.forEach(biblio => { finding.bibliography.forEach(record => {
citations += ` citations += `
<span class="is-clickable is-capitalized has-text-link" <span class="is-clickable has-text-link"
data-action="click->biblio#open" data-action="click->biblio#open"
id="cit-${biblio.id}"> id="cit-${record.id}">
${biblio.citation.toLowerCase()}, ${record.citation}</span>`;
</span> ${biblio.pages};
`; citations += record.pages?.length ? `, ${record.pages};` : ';';
this.biblioElements.push(` this.biblioElements.push(`
<div class="p-2 mt-2" id="ref-${biblio.id}"> <div class="p-2 mt-2" id="ref-${record.id}">
<p class="p-3">${biblio.reference}</p> <p class="p-3">${record.reference}</p>
</div> </div>
`); `);
}); });

View File

@@ -0,0 +1,176 @@
import { GisState } from "../state.js";
/**
* Component to render data for not conserved assets
* @class NotConserved
*/
export class NotConserved {
biblioElements = [];
/**
* @param {object} data
*/
set data(data) {
this._data = data;
}
async render() {
return `
<div class="container px-4 pt-4">
<p class="p-2">
<span class="icon has-text-link">
<i class="fa fa-tag"></i>
</span>
<strong>Denominazione:</strong> ${this._data.denomination}
</p>
<p class="p-2">
<span class="icon has-text-link">
<i class="fa fa-hourglass"></i>
</span>
<strong>Periodo:</strong> ${this._data.period}
</p>
<p class="p-2">
<span class="icon has-text-link">
<i class="fa fa-map"></i>
</span>
<strong>Località generica:</strong> ${this._data.genericLocation}
</p>
<p class="mt-4 pl-2 pr-5">
<strong class="pb-3">Descrizione</strong></br>
${this._data.shortDescription}
</p>
<p class="mt-4 pl-2 pr-5">
<span class="icon has-text-link">
<i class="fa fa-book"></i>
</span>
<strong>Bibliografia:</strong> ${await this.biblio(this._data.id)}
</p>
<div class="notification is-light mx-3 mt-4 mb-0 p-2 is-hidden" data-biblio-target="biblio"></div>
<p class="p-2 mb-4">
<strong>Autore scheda:</strong> ${this._data.author}
</p>
</div>`;
}
renderImages() {
let content = `<div class="content has-text-centered">
<p class="is-size-5 mt-3">Immagini</p>`;
content += `
<div style="max-width: 70%; margin: 0 auto">
<p class="is-size-6 has-text-centered">Cliccare sull'immagine per aprire la gallery</p>
<figure class="is-relative is-clickable has-text-centered" id="not-conserved-gallery">
<img src="img/${this.images[0].filename}" width="300"/>
<div class="icon overlay is-flex is-justify-content-center is-align-items-center">
<i class="is-flex fa fa-2x fa-play-circle"></i>
</div>
</figure>
</div>
</div>`;
return content;
}
/**
* @param {HTMLElement} imageContainer
* @param {Function} gallery
*/
async setImages(imageContainer, gallery) {
if (this._data.images.length) {
this.images = this._data.images;
imageContainer.innerHTML = this.renderImages();
gallery('not-conserved-gallery', this.images);
} else
imageContainer.innerHTML = '<p class="has-text-centered">Nessuna risorsa visuale disponibile</p>';
}
async renderDocs() {
let record = await this.fetchData(`${GisState.apiUrl}/not_conserved/${this._data.id}`);
this.documentation = record.documents.filter(d => d.type === 'documentazione')
this.publications = record.documents.filter(d => d.type === 'pubblicazione');
let content = `
<div class="has-bottom-border">
<div class="p-2">
<table class="p-4 table is-fullwidth is-striped">
<thead>
<tr><th colspan=3 class="p-2 has-text-centered is-size-5">Documentazione di archivio</th>
<tr><th>Titolo</th><th>Luogo di conservazione</th><th>Download</th></tr>
</thead>
<tbody>
`;
for (const doc of this.documentation) {
content += `
<tr><td>${doc.title}</td><td>${doc.conservationPlace}</td><td><a class="button is-link has-text-white" href="docs/${doc.filename}">
<i class="fa fa-download mr-2"></i> PDF
</a></td></tr>
`;
}
if (this.publications.length) {
content += `
</tbody>
<thead>
<tr><th colspan=3 class="p-2 has-text-centered is-size-5">Pubblicazioni del progetto Carta Archeologica</th>
<tr><th>Titolo</th><th>Autori</th><th>Download</th></tr>
</thead>
<tbody>
`;
for (const doc of this.publications) {
content += `
<tr><td>${doc.title}</td><td>${doc.authors}</td><td><a class="button is-link has-text-white" href="docs/${doc.filename}">
<i class="fa fa-download mr-2"></i> PDF
</a></td></tr>
`;
}
}
content += `
</tbody>
</table>
</div>
</div>
`;
if (!this.publications.length && !this.documentation.length) {
content = '<p class="has-text-centered">Nessun documento disponibile.</p>';
}
return content;
}
async biblio(recordId) {
let record = await this.fetchData(`${GisState.apiUrl}/not_conserved/${recordId}`);
let citations = '';
if (record.bibliography.length) {
record.bibliography.forEach(record => {
citations += `
<span class="is-clickable has-text-link"
data-action="click->biblio#open"
id="cit-${record.id}">
${record.citation.trim()}</span>`;
citations += record.pages?.length ? `, ${record.pages};` : ';';
this.biblioElements.push(`
<div class="p-2 mt-2" id="ref-${record.id}">
<p class="p-3">${record.reference}</p>
</div>
`
);
});
}
return citations.trim().slice(0, -1);
}
getReference(id) {
return this.biblioElements.find(ref => {
let regex = new RegExp('ref-'+id+'"');
return ref.match(regex);
});
}
async fetchData(url) {
return await fetch(url).then(res => res.json());
}
}

View File

@@ -1,16 +1,18 @@
import { GisState } from "../state.js";
/** /**
* Component to render data for not conserved assets sheet * @class Prehistoric
* @class NotConservedSheet
*/ */
export class NotConservedSheet { export class Prehistoric {
biblioElements = []; biblioElements = [];
/**
* @param {object} data set data(data) {
*/
set siteData(data) {
this._data = data; this._data = data;
} }
/**
*
* @todo Biblio
* @returns {string} The HTML
*/
async render() { async render() {
return ` return `
<div class="container px-4 pt-4"> <div class="container px-4 pt-4">
@@ -30,12 +32,22 @@ export class NotConservedSheet {
<span class="icon has-text-link"> <span class="icon has-text-link">
<i class="fa fa-map"></i> <i class="fa fa-map"></i>
</span> </span>
<strong>Località generica:</strong> ${this._data.genericLocation} <strong>Località generica:</strong> ${this._data.genericPlace}
</p> </p>
<p class="mt-4 pl-2 pr-5"> <p class="mt-4 pl-2 pr-5">
<strong class="pb-3">Descrizione</strong></br> <strong class="pb-3">Descrizione breve</strong></br>
${this._data.shortDescription} ${this._data.description}
</p> </p>
<p class="p-2">
<strong>Conservazione:</strong> ${this._data.conservation}
</p>
<p class="p-2 mb-4">
<strong>Autore scheda:</strong> ${this._data.author}
</p>
</div>`;
/*
<p class="mt-4 pl-2 pr-5"> <p class="mt-4 pl-2 pr-5">
<span class="icon has-text-link"> <span class="icon has-text-link">
<i class="fa fa-book"></i> <i class="fa fa-book"></i>
@@ -43,33 +55,61 @@ export class NotConservedSheet {
<strong>Bibliografia:</strong> ${await this.biblio(this._data.id)} <strong>Bibliografia:</strong> ${await this.biblio(this._data.id)}
</p> </p>
<div class="notification is-light mx-3 mt-4 mb-0 p-2 is-hidden" data-biblio-target="biblio"></div> <div class="notification is-light mx-3 mt-4 mb-0 p-2 is-hidden" data-biblio-target="biblio"></div>
<p class="p-2 mb-4"> */
<strong>Autore scheda:</strong> ${this._data.author}
</p>
</div>`;
} }
renderImages() {
let content = `<div class="content has-text-centered">
<p class="is-size-5 mt-3">Immagini</p>`;
content += `
<div style="max-width: 70%; margin: 0 auto">
<p class="is-size-6 has-text-centered">Cliccare sull'immagine per aprire la gallery</p>
<figure class="is-relative is-clickable has-text-centered" id="prehist-gallery">
<img src="img/${this.images[0].filename}" width="300"/>
<div class="icon overlay is-flex is-justify-content-center is-align-items-center">
<i class="is-flex fa fa-2x fa-play-circle"></i>
</div>
</figure>
</div>
</div>`;
return content;
}
/**
* @param {HTMLElement} imageContainer
* @param {Function} gallery
*/
async setImages(imageContainer, gallery) {
if (this._data.images.length) {
this.images = this._data.images;
imageContainer.innerHTML = this.renderImages();
gallery('prehist-gallery', this.images);
} else
imageContainer.innerHTML = '<p class="has-text-centered">Nessuna risorsa visuale disponibile</p>';
}
/**
* @param {number} recordId
*/
async biblio(recordId) { async biblio(recordId) {
let record = await this.fetchData(`${window.API_URL}/not_conserved/${recordId}`); let finding = await this.fetchData(`${GisState.apiUrl}/prehistoric/${recordId}`);
let citations = ''; let citations = '';
if (record.bibliography.length) { if (finding.bibliography.length) {
record.bibliography.forEach(record => { finding.bibliography.forEach(record => {
citations += ` citations += `
<span class="is-clickable is-capitalized has-text-link" <span class="is-clickable has-text-link"
data-action="click->biblio#open" data-action="click->biblio#open"
id="cit-${record.id}"> id="cit-${record.id}">
${record.citation.toLowerCase()}, ${record.citation}</span>`;
</span> ${record.pages};
`; citations += record.pages?.length ? `, ${record.pages};` : ';';
this.biblioElements.push(` this.biblioElements.push(`
<div class="p-2 mt-2" id="ref-${record.id}"> <div class="p-2 mt-2" id="ref-${record.id}">
<p class="p-3">${record.reference}</p> <p class="p-3">${record.reference}</p>
</div> </div>
` `);
);
}); });
} }

View File

@@ -13,6 +13,14 @@ export class SiteDocuments {
} }
render() { render() {
if (this._siteData.documents.length === 0) {
return `
<p class="p-2 has-text-centered mt-3 mb-3">
Nessuna documentazione disponibile.
</p>
`;
}
this.documentation = this._siteData.documents this.documentation = this._siteData.documents
.filter(d => d.type === 'documentazione') .filter(d => d.type === 'documentazione')

View File

@@ -0,0 +1,46 @@
/**
* Component to render data for site media (photos and videos)
* @class SiteMedia
*/
export class SiteMedia {
/**
* @param {object} data
*/
set siteData(data) {
this._siteData = data;
}
renderPhotos() {
return `
<div class="content has-text-centered mb-5 pb-5">
<p class="is-size-5 mt-3">Fotografie</p>
<div style="max-width: 70%; margin: 0 auto">
<p class="is-size-6">Cliccare sull'immagine per aprire la gallery</p>
<figure class="is-relative is-clickable has-text-centered" id="gallery-2">
<img src="img/${this._siteData.filename}" width="300"/>
<div class="icon overlay is-flex is-justify-content-center is-align-items-center">
<i class="is-flex fa fa-2x fa-play-circle"></i>
</div>
</figure>
</div>
</div>
`;
}
renderVideos() {
return `
<div class="content has-text-centered mb-5 pb-5">
<p class="is-size-5 mt-3">Video</p>
<div style="max-width: 70%; margin: 0 auto">
<p class="is-size-6 has-text-centered">Gallery video</p>
<figure class="is-relative is-clickable has-text-centered" id="gallery-video">
<img src="video/${this._siteData.filename.replace('mp4', 'png')}" width="300"/>
<div class="icon overlay is-flex is-justify-content-center is-align-items-center">
<i class="is-flex fa fa-2x fa-play-circle"></i>
</div>
</figure>
</div>
</div>
`;
}
}

View File

@@ -1,31 +0,0 @@
/**
* Component to render data for site photos
* @class SitePhotos
*/
export class SitePhotos {
/**
* @param {object} data
*/
set siteData(data) {
this._siteData = data;
}
render() {
let content = `<div class="content has-text-centered">
<p class="is-size-5 mt-3">Fotografie</p>`;
content += `
<div style="max-width: 70%; margin: 0 auto">
<p class="is-size-6 has-text-centered">Cliccare sull'immagine per aprire la gallery</p>
<figure class="is-relative is-clickable has-text-centered" id="gallery-2">
<img src="img/${this._siteData.filename}" width="300"/>
<div class="icon overlay is-flex is-justify-content-center is-align-items-center">
<i class="is-flex fa fa-2x fa-play-circle"></i>
</div>
</figure>
</div>
</div>
`;
return content;
}
}

View File

@@ -41,6 +41,10 @@ export class SiteSheet {
<tr><th>Anno di ritrovamento</th><td>${this._siteData.finding}</td></tr> <tr><th>Anno di ritrovamento</th><td>${this._siteData.finding}</td></tr>
<tr><th>Materiali rinvenuti</th><td>${this._siteData.materials}</td></tr> <tr><th>Materiali rinvenuti</th><td>${this._siteData.materials}</td></tr>
<tr><th>Luogo custodia materiali</th><td>${this._siteData.conservationPlace}</td></tr> <tr><th>Luogo custodia materiali</th><td>${this._siteData.conservationPlace}</td></tr>
<tr class="is-link"><th class="is-size-5 has-text-centered" colspan=2>Rilievi</th></tr>
<tr><td colspan=2>${this._siteData.surveys ?? 'Nessun rilievo'}</td></tr>
<tr class="is-link"><th class="is-size-5 has-text-centered" colspan=2>Descrizione</th></tr>
<tr><td class="pr-6 pl-6 pt-3" colspan="2">${this._siteData.description}</td></tr>
<tr class="is-link"><th class="is-size-5 has-text-centered" colspan=2>Bibliografia</th></tr> <tr class="is-link"><th class="is-size-5 has-text-centered" colspan=2>Bibliografia</th></tr>
<tr> <tr>
<td colspan=2> <td colspan=2>
@@ -48,9 +52,10 @@ export class SiteSheet {
<div class="notification is-light mx-3 mt-4 mb-0 p-2 is-hidden" id="biblio-detail" data-biblio-target="biblio"></div> <div class="notification is-light mx-3 mt-4 mb-0 p-2 is-hidden" id="biblio-detail" data-biblio-target="biblio"></div>
</td> </td>
</tr> </tr>
<tr class="is-link"><th class="is-size-5 has-text-centered" colspan=2>Descrizione</th></tr>
<tr><td class="pr-6 pl-6 pt-3" colspan="2">${this._siteData.description}</td></tr>
</table> </table>
<p class="pl-4 mb-4">
<strong>Autore scheda:</strong> ${this._siteData.author}
</p>
</div>`; </div>`;
} }
@@ -75,6 +80,9 @@ export class SiteSheet {
</span> </span>
<strong>Località generica:</strong> ${this._siteData.genericPlace} <strong>Località generica:</strong> ${this._siteData.genericPlace}
</p> </p>
<p class="mt-4 pl-2 pr-5">
${this._siteData.shortDescription}
</p>
<p class="mt-4 pl-2 pr-5"> <p class="mt-4 pl-2 pr-5">
<span class="icon has-text-link"> <span class="icon has-text-link">
<i class="fa fa-book"></i> <i class="fa fa-book"></i>
@@ -82,9 +90,6 @@ export class SiteSheet {
<strong>Bibliografia:</strong> ${this.biblio()} <strong>Bibliografia:</strong> ${this.biblio()}
</p> </p>
<div class="notification is-light mx-3 mt-4 mb-0 p-2 is-hidden" data-biblio-target="biblio"></div> <div class="notification is-light mx-3 mt-4 mb-0 p-2 is-hidden" data-biblio-target="biblio"></div>
<p class="mt-4 pl-2 pr-5">
${this._siteData.shortDescription}
</p>
<p class="p-2"> <p class="p-2">
<strong>Autore scheda:</strong> ${this._siteData.author} <strong>Autore scheda:</strong> ${this._siteData.author}
</p> </p>
@@ -97,12 +102,12 @@ export class SiteSheet {
if (this._siteData.bibliography.length) { if (this._siteData.bibliography.length) {
this._siteData.bibliography.forEach(record => { this._siteData.bibliography.forEach(record => {
citations += ` citations += `
<span class="is-clickable is-capitalized has-text-link" <span class="is-clickable has-text-link"
data-action="click->biblio#open" data-action="click->biblio#open"
id="cit-${record.id}"> id="cit-${record.id}">
${record.citation.toLowerCase().trim()}, ${record.citation.trim()}</span>`;
</span> ${record.pages};
`; citations += record.pages?.length ? `, ${record.pages};` : ';';
this.biblioElements.push(` this.biblioElements.push(`
<div class="p-2 mt-2" id="ref-${record.id}"> <div class="p-2 mt-2" id="ref-${record.id}">
@@ -122,4 +127,4 @@ export class SiteSheet {
return ref.match(regex); return ref.match(regex);
}); });
} }
} }

View File

@@ -11,21 +11,19 @@ export class SiteSurveys {
} }
render() { render() {
let content = `<div class="has-text-centered has-bottom-border mb-5 pb-5"> return `
<p class="is-size-5 mt-3">Rilievi CNR-ISPC, elaborazioni grafiche</p>`; <div class="has-text-centered mb-5 pb-5">
content += ` <p class="is-size-5 mt-3 mb-3">Rilievi, disegni ed elaborazioni grafiche</p>
<div style="max-width: 70%; margin: 0 auto"> <div style="max-width: 70%; margin: 0 auto">
<p class="is-size-6 has-text-centered">Cliccare sull'immagine per aprire la gallery</p> <p class="is-size-6 mb-2">Cliccare sull'immagine per aprire la gallery</p>
<figure class="is-relative has-text-centered is-clickable" id="gallery-1"> <figure class="is-relative has-text-centered is-clickable" id="gallery-1">
<img src="img/${this._siteData.filename}" width="300"/> <img src="img/${this._siteData.filename}" width="300"/>
<div class="icon overlay is-flex is-justify-content-center is-align-items-center"> <div class="icon overlay is-flex is-justify-content-center is-align-items-center">
<i class="is-flex fa fa-2x fa-play-circle"></i> <i class="is-flex fa fa-2x fa-play-circle"></i>
</div> </div>
</figure> </figure>
</div>
</div> </div>
</div>
`; `;
return content;
} }
} }

View File

@@ -0,0 +1,41 @@
/**
* @class Underwater
*/
export class Underwater {
/**
* @param {object} data
*/
set data(data) {
this._data = data;
}
async render() {
return `
<div class="container px-4 pt-4">
<p class="p-2">
<strong>Denominazione:</strong> ${this._data.denomination}
</p>
<p class="p-2">
<strong>Località generica:</strong> ${this._data.genericPlace}
</p>
<p class="p-2">
<strong>Periodo:</strong> ${this._data.period}
</p>
<p class="p-2">
<strong>Stato di conservazione:</strong> ${this._data.conservationState}
</p>
<p class="mt-4 pl-2 pr-5">
<strong class="pb-3">Descrizione breve</strong></br>
${this._data.shortDescription}
</p>
<p class="p-2 mb-4">
<strong>Autore scheda:</strong> ${this._data.author}
</p>
</div>`;
}
async fetchData(url) {
return await fetch(url).then(res => res.json());
}
}

View File

@@ -1,10 +1,11 @@
import { Controller } from "@hotwired/stimulus" import { Controller } from "@hotwired/stimulus"
import { GisState } from "../state.js";
export default class extends Controller { export default class extends Controller {
static targets = ['biblio', 'cit', 'ref', 'close']; static targets = ['biblio', 'cit', 'ref', 'close'];
open(event) { open(event) {
const biblio = window.Biblio; const biblio = GisState.bibliography;
this.trigger = event.currentTarget; this.trigger = event.currentTarget;
const id = this.trigger.id.replace('cit-', ''); const id = this.trigger.id.replace('cit-', '');
this.ref = this.biblioTarget; this.ref = this.biblioTarget;

View File

@@ -0,0 +1,77 @@
import { Controller } from "@hotwired/stimulus";
import { GisState } from "../state.js";
import GIS from "../gis.js";
export default class extends Controller {
static targets = [
'sites',
'findings',
'notconserved',
'prehist',
];
static values = {
'id': Number,
'type': String,
};
async toggleCartography() {
const map = GisState.map;
const id = this.idValue;
let currentLayer = await GIS.getImageOverlay(id);
let hasLayer = false;
map.eachLayer(function (layer) {
if (layer.options.label === currentLayer.options.label) {
hasLayer |= true;
currentLayer = layer;
}
});
if (!hasLayer) currentLayer.addTo(map);
else map.removeLayer(currentLayer);
}
toggleCadastral() {
const map = GisState.map;
const wms = GisState.cartography.cadastral;
if (!map.hasLayer(wms)) map.addLayer(wms);
else map.removeLayer(wms);
}
/**
* @todo Use Stimulus values?
* @param {Event} event
*/
toggle(event) {
let map = GisState.map;
let target = event.currentTarget;
const id = target.parentElement.getAttribute('data-id');
this.toggleIcon(event.currentTarget);
let group = GisState.layers[id];
if (map.hasLayer(group)) {
map.removeLayer(group);
target.title = "Mostra";
}
else {
map.addLayer(group);
target.title = "Nascondi";
}
}
/**
* Toggle visibility icon...
* @param {HTMLElement} target
*/
toggleIcon(target) {
const icon = target.firstElementChild;
const className = icon.className;
icon.className = className.includes('slash') ?
className.replace('-slash', '') :
className.replace('eye', 'eye-slash');
}
}

View File

@@ -1,37 +1,52 @@
import { Controller } from "@hotwired/stimulus" import { Controller } from "@hotwired/stimulus";
import { GisState, getMarkerByCoords } from "../state.js";
export default class extends Controller { export default class extends Controller {
static targets = ['coords']; static values = {
END_ZOOM = 20; 'coords': String,
'group': String,
'id': String,
};
END_ZOOM = 19;
// Animation breaks automatic tooltip opening...
mapAnimate = { mapAnimate = {
animate: true, animate: true,
duration: 1, duration: 1,
easeLinearity: 0.25 easeLinearity: 0.25
}; };
go(event) { /**
let map = window.LMap; * @param {Event} event
const coords = event.currentTarget.getAttribute('data-coords').split(' '); */
go() {
let map = GisState.map;
const coords = this.coordsValue.split(' ');
map.setView( map.setView(
coords, coords,
this.END_ZOOM, this.END_ZOOM,
this.mapAnimate {animate: false}
); );
let marker = this.getMarker(map, coords); let marker = this.getMarker(map, coords);
marker.openTooltip(); // DEBUG for sites
if (this.groupValue) marker = getMarkerByCoords(coords, this.groupValue);
marker?.openTooltip();
} }
/**
* @param {L.Map} map
* @param {Array<String>} coords
* @returns {L.Marker}
*/
getMarker(map, coords) { getMarker(map, coords) {
let marker; let marker;
map.eachLayer(l => { map.eachLayer(layer => {
if (l instanceof L.Marker) { if (layer instanceof L.Marker) {
const latLng = l.getLatLng(); const latLng = layer.getLatLng();
const lat = latLng['lat']; const {lat, lng} = latLng;
const lng = latLng['lng'];
if (lat === Number(coords[0]) && lng === Number(coords[1])) { if (lat === Number(coords[0]) && lng === Number(coords[1])) {
marker = l; marker = layer;
return; return;
} }
} }
@@ -40,4 +55,3 @@ export default class extends Controller {
return marker; return marker;
} }
} }

View File

@@ -1,16 +1,115 @@
import { Controller } from "@hotwired/stimulus" import { Controller } from "@hotwired/stimulus"
import { GisState } from '../state.js';
export default class extends Controller { export default class extends Controller {
static targets = ['list', 'menu', 'icon']; static targets = [
'list',
'menu',
'cartography',
'icon'
];
toggleMenu() { static values = {
this.menuTarget.classList.toggle('is-hidden'); 'cartography' : String,
'main' : String,
};
buildMenu() {
const groups = Object.keys(GisState.markers);
const municipalities = ['Anacapri', 'Capri'];
// TODO refactor with Stimulus values?
for (let group of groups) {
for (let municipality of municipalities) {
let ul = this.renderMenuItems(group, municipality);
document.querySelector(`[data-list-id="${group}-${municipality.toLowerCase()}-sub"]`)
?.appendChild(ul);
}
}
}
/**
*
* @param {String} group
* @param {String} municipality
*/
renderMenuItems(group, municipality) {
const ul = document.createElement('ul');
ul.className = 'is-hidden';
ul.id = `${group}-${municipality.toLowerCase()}-sub`;
const template = document.getElementById('menu-item-template');
for (let key in GisState.markers[group]) {
const marker = GisState.markers[group][key];
if (marker.options.municipality === municipality) {
const clone = template.content.cloneNode(true);
const link = clone.querySelector('a');
link.dataset.markerCoordsValue = key;
link.dataset.markerGroupValue = group;
link.textContent = marker.options.label;
ul.appendChild(clone);
}
}
return ul;
}
buildCartographyMenu() {
const historicCadastre = GisState.cartography.historic;
const template = document.getElementById('cartography-item-template');
const ul = document.createElement('ul');
ul.className = 'menu-list';
ul.id = 'historic-sub';
const aside = document.querySelector('[data-id="cartography-aside"]');
for (let geoImage of historicCadastre) {
const clone = template.content.cloneNode(true);
const label = clone.querySelector('label');
const checkbox = clone.querySelector('input[type="checkbox"]');
checkbox.dataset.layerIdValue = geoImage.id;
checkbox.dataset.layerTypeValue = 'historic';
const span = document.createElement('span');
span.className = 'pl-3';
span.textContent = geoImage.label;
label.appendChild(span);
ul.appendChild(clone);
}
aside.appendChild(ul);
}
toggleMenu(event) {
const menuId = event.target.dataset.id;
// Stupid...
if (menuId === 'main') {
this.menuTarget.classList.toggle('is-hidden');
if (!this.cartographyTarget.classList.contains('is-hidden')) {
this.cartographyTarget.classList.add('is-hidden');
}
}
if (menuId === 'cartography') {
this.cartographyTarget.classList.toggle('is-hidden');
if (!this.menuTarget.classList.contains('is-hidden')) {
this.menuTarget.classList.add('is-hidden');
}
}
} }
close() { close() {
this.menuTarget.classList.add('is-hidden'); this.menuTarget.classList.add('is-hidden');
} }
closeCartography() {
this.cartographyTarget.classList.add('is-hidden');
}
toggleList(id) { toggleList(id) {
document.querySelector(`#${id}`).classList.toggle('is-hidden'); document.querySelector(`#${id}`).classList.toggle('is-hidden');
} }

View File

@@ -3,6 +3,24 @@ import { Controller } from "@hotwired/stimulus"
export default class extends Controller { export default class extends Controller {
static targets = ['close', 'modal']; static targets = ['close', 'modal'];
current(id) {
return this.modalTargets.find(m => m.getAttribute('data-id') === id);
}
homeOpen(event) {
const id = event.currentTarget.getAttribute('data-id');
const current = this.current(id);
current.classList.add('is-active');
}
homeClose(event) {
const id = event.currentTarget.getAttribute('data-id');
const current = this.current(id);
current.classList.remove('is-active');
}
open() { open() {
this.modalTarget.classList.add('is-active'); this.modalTarget.classList.add('is-active');
} }

View File

@@ -4,20 +4,20 @@ import UI from "./ui.js";
import API_CONFIG from "./config.js"; import API_CONFIG from "./config.js";
import Icons from "./icons.js"; import Icons from "./icons.js";
import { SphericalPhoto } from "./components/SphericalPhoto.js"; import { SphericalPhoto } from "./components/SphericalPhoto.js";
import { GisState } from "./state.js";
const MAPBOX_TOKEN = 'pk.eyJ1Ijoibmljb3BhIiwiYSI6ImNseWNwZjJjbjFidzcya3BoYTU0bHg4NnkifQ.3036JnCXZTEMt6jVgMzVRw'; const MAPBOX_TOKEN = 'pk.eyJ1Ijoibmljb3BhIiwiYSI6ImNseWNwZjJjbjFidzcya3BoYTU0bHg4NnkifQ.3036JnCXZTEMt6jVgMzVRw';
const BASE_URL = location.href; const BASE_URL = location.href;
let API_URL = ''; let API_URL = API_CONFIG.prod;
if (BASE_URL.includes('localhost')) {
if (!BASE_URL.includes('cnr.it')) {
API_URL = API_CONFIG.dev; API_URL = API_CONFIG.dev;
} else {
API_URL = API_CONFIG.prod;
} }
window.API_URL = API_URL; GisState.apiUrl = API_URL;
// Global leaflet // Global leaflet and proj4
/** /**
* @namespace GIS * @namespace GIS
*/ */
@@ -25,6 +25,9 @@ const GIS = {};
GIS.CENTER_COORDS = [40.5492, 14.2317]; GIS.CENTER_COORDS = [40.5492, 14.2317];
GIS.INIT_ZOOM = 14; GIS.INIT_ZOOM = 14;
GIS.MIN_ZOOM = 11;
GIS.MAX_ZOOM = 24;
const optionsVincoli = { const optionsVincoli = {
color: '#222', color: '#222',
opacity: 0.8, opacity: 0.8,
@@ -60,20 +63,10 @@ const optionsFabbricati = {
fillColor: '#5b5d5f', fillColor: '#5b5d5f',
fillOpacity: 0.8 fillOpacity: 0.8
}; };
const clusterOptions = {
const MARKER_NAMES = { spiderfyOnMaxZoom: false,
sites: { showCoverageOnHover: false,
'gradola' : 'Villa di Gradola', disableClusteringAtZoom: 19,
'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',
},
}; };
/** /**
@@ -100,103 +93,155 @@ function capitalize(text) {
/** /**
* @param {string} mapId * @param {string} mapId
* @param {number} zoomLevel * @param {number} zoomLevel
* @returns {{map: Map, sites: Layer}} * @returns {L.Map}
*/ */
GIS.initMap = async function (mapId, zoomLevel = this.INIT_ZOOM) { 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, { let map = L.map(mapId, {
//attributionControl: false, //attributionControl: false,
minZoom: 2, minZoom: GIS.MIN_ZOOM,
}).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 = await this.initLayers(map);
// 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 layerVincoli = await this.loadLayer('vincoli.geojson', optionsVincoli); let layerVincoli = await this.loadGeoJSON('vincoli.geojson', optionsVincoli);
let layerPaesistici = await this.loadLayer('paesistici.geojson', optionsPaesistici); let layerPaesistici = await this.loadGeoJSON('paesistici.geojson', optionsPaesistici);
let markersGroup = await this.sitesMarkers(sitesGroup); await this.addLayerGroups(map);
let notConservedGroup = await this.notConserved(); await this.fetchCartographyLayers();
let findingsGroup = await this.findings();
const archeo = { const archeo = {
'Beni archeologici (punti)' : markersGroup,
'Beni archeologici (strutture)' : sitesGroup,
'Beni non conservati' : notConservedGroup,
'Rinvenimenti' : findingsGroup,
'Vincoli archeologici' : layerVincoli, 'Vincoli archeologici' : layerVincoli,
'Vincoli paesistici' : layerPaesistici, 'Vincoli paesistici' : layerPaesistici,
//'Catasto storico' : historicCadastre,
}; };
L.control.layers(baseMap, archeo).addTo(map);
markersGroup.addTo(map); GisState.map = map;
sitesGroup.addTo(map);
notConservedGroup.addTo(map);
findingsGroup.addTo(map);
L.control.layers( const reprojectedWMSLayer = GIS.reprojectWMS();
baseMap, const wmsLayer = new reprojectedWMSLayer(
archeo, 'https://wms.cartografia.agenziaentrate.gov.it/inspire/wms/ows01.php?',
).addTo(map); {
layers: 'CP.CadastralParcel,fabbricati',
transparent: true,
format: 'image/png',
version: '1.1.1',
minZoom: 15,
maxZoom: this.MAX_ZOOM,
tileSize: 1024,
opacity: 0.6,
}
);
// TEMP!! Remove point for Lo Pozzo... GisState.cartography.cadastral = wmsLayer;
map.removeLayer(sitesGroup.customGetLayer('lopozzo'));
// TODO Horrible? return map;
return {map: map, sites: sitesGroup}; }
/**
* Fetches references to cartography layers
* and updates GisState
*/
GIS.fetchCartographyLayers = async function () {
const data = await this._fetchData('geoimages/menu')
.catch(error => console.error(`Could not fetch data for geo images: ${error}`));
for (let item of data) {
let {id, label} = item;
GisState.cartography.historic.push({id, label});
}
}
/**
* Load georeferenced image overlays layer group
* @param {Number} imageId - The API id of the georeferenced image
* @returns {L.ImageOverlay}
*/
GIS.getImageOverlay = async function (imageId) {
const imageData = await this._fetchData(`geoimages/${imageId}`)
.catch(error => console.error(`Could not fetch data for geo image ${imageId}: ${error}`));
let polygonCoords = JSON.parse(imageData.polygon).coordinates[0];
// Image rectangle bounds are SE and NW coordinates from the PostGIS polygon
// with long/lat swapped...
const se = [polygonCoords[0][1], polygonCoords[0][0]];
const nw = [polygonCoords[2][1], polygonCoords[2][0]];
const bounds = [se, nw];
const imageOverlay = L.imageOverlay(
`/webgis/img/geo/${imageData.filename}`,
bounds,
{
opacity: 0.6,
alt: `Immagine georeferita (${imageData.label})`,
label: `geoimage:${imageData.id}:${imageData.label}`,
}
);
return imageOverlay;
}
/**
* Add layer groups to map
*/
GIS.addLayerGroups = async function (map) {
// Can be included in Promise.all
// if it returns only one group...
const sites = await this.sites();
sites.markers.addTo(map);
sites.geom.addTo(map);
const groups = await Promise.all(
[
this.notConserved(),
this.findings(),
this.prehistoric(),
this.underwater(),
]
);
groups.forEach(group => group.addTo(map));
} }
/** /**
* Create markers for sites * Create markers for sites
* @param {L.LayerGroup} sitesGroup * @returns {{markers: L.markerClusterGroup, geom: L.LayerGroup}}
* @returns {L.markerClusterGroup}
*/ */
GIS.sitesMarkers = async function (sitesGroup) { GIS.sites = async function () {
let sitesMarkers = L.markerClusterGroup({ let sitesData = await fetch(`${API_URL}/sites`)
showCoverageOnHover: false .then(data => data.json());
});
for (let id in MARKER_NAMES.sites) { let sites = L.markerClusterGroup(clusterOptions);
let layer = sitesGroup.customGetLayer(id); let geom = [];
let coords = layer.getBounds().getCenter();
const fromStorage = localStorage.getItem(id);
let data = {};
if (fromStorage !== 'undefined') { for (let record of sitesData) {
try { if (record.geojson) {
data = JSON.parse(fromStorage); const options = record.gisId === 'grotta_azzurra' ?
const lat = data?.coordinates[0] ?? coords.lat; optionsGrotta : optionsSiti;
const lon = data?.coordinates[1] ?? coords.lng; geom.push(await this.loadSiteLayer(record, options));
coords = [lat, lon];
} catch (error) {
console.log(error);
}
} else {
data = await GIS._fetchData('site/' + id);
} }
const marker = L.marker(coords, { icon: Icons.site }) const marker = L.marker(
.bindTooltip(MARKER_NAMES.sites[id] + '<br>(Clicca per aprire scheda)'); record.coordinates,
{icon: Icons.site, label: record.label}
)
.bindTooltip(record.label)
.on(
'click',
() => UI.openSiteModal(record, '#site-data')
);
marker.id = id; sites.addLayer(marker);
// Populate app state for reuse and avoid window.Sites etc.
marker.on('click', () => UI.openSiteModal(data, '#site-data')); // Municipality (Capri, Anacapri) added for reuse in dynamic menu
marker.options.municipality = record.municipality;
sitesMarkers.addLayer(marker); const markerIndex = `${record.coordinates[0]} ${record.coordinates[1]}`;
GisState.markers.sites[markerIndex] = marker;
} }
return sitesMarkers; GisState.layers.sites = sites;
return {markers: sites, geom: L.layerGroup(geom)};
} }
/** /**
* Create not conserved group * Create not conserved group
@@ -206,22 +251,25 @@ GIS.notConserved = async function () {
let notConserData = await fetch(`${API_URL}/not_conserved`) let notConserData = await fetch(`${API_URL}/not_conserved`)
.then(data => data.json()); .then(data => data.json());
let notConserved = L.markerClusterGroup({ let notConserved = L.markerClusterGroup(clusterOptions);
showCoverageOnHover: false
});
for (let record of notConserData.records) { for (let record of notConserData.records) {
notConserved.addLayer(L.marker( const marker = L.marker(
record.coordinates, record.coordinates,
{icon: Icons.notConserved} {icon: Icons.notConserved, label: record.label}
).bindTooltip(record.denomination)
.on(
'click',
() => UI.openNotConserModal(record, '#not-conser-data')
) )
); .bindTooltip(record.label)
.on('click', () => UI.openNotConserModal(record, '#not-conser-data'));
notConserved.addLayer(marker);
// Populate app state for reuse and avoid window.Sites etc.
const markerLabel = `${record.coordinates[0]} ${record.coordinates[1]}`;
marker.options.municipality = record.municipality;
GisState.markers.notConserved[markerLabel] = marker;
} }
GisState.layers.notConserved = notConserved;
return notConserved; return notConserved;
} }
/** /**
@@ -232,127 +280,119 @@ GIS.findings = async function () {
let findingsData = await fetch(`${API_URL}/finding`) let findingsData = await fetch(`${API_URL}/finding`)
.then(data => data.json()); .then(data => data.json());
let findings = L.markerClusterGroup({ let findings = L.markerClusterGroup(
showCoverageOnHover: false clusterOptions
}); );
for (let record of findingsData) { for (let record of findingsData) {
findings.addLayer(L.marker( const marker = L.marker(
record.coordinates, record.coordinates,
{icon: Icons.finding} {icon: Icons.finding, label: record.label}
).bindTooltip(record.object) ).bindTooltip(record.label)
.on( .on(
'click', 'click',
() => UI.openFindingModal(record, '#finding-data') () => UI.openFindingModal(record, '#finding-data')
) );
);
findings.addLayer(marker);
const markerLabel = `${record.coordinates[0]} ${record.coordinates[1]}`;
marker.options.municipality = record.municipality;
GisState.markers.findings[markerLabel] = marker;
} }
GisState.layers.findings = findings;
return findings; return findings;
} }
/* /**
GIS._prepareLayers = async function(layer) { * Create group for prehistoric sites
const fromStorage = localStorage.getItem(layer.id); *
let data = {}; */
let coords = layer.getBounds().getCenter(); GIS.prehistoric = async function () {
let data = await fetch(`${API_URL}/prehistoric`)
.then(data => data.json());
if (fromStorage !== 'undefined') { let prehistoric = L.markerClusterGroup(
try { clusterOptions
data = JSON.parse(fromStorage); );
const lat = data?.lat ?? coords[0];
const lon = data?.lon ?? coords[1]; for (let record of data.records) {
coords = [lat, lon]; const marker = L.marker(
} catch (error) { record.coordinates,
console.log(error); {icon: Icons.prehistoric, label: record.label}
} ).bindTooltip(record.label)
} else { .on(
data = await GIS._fetchData(layer.id); 'click',
() => UI.openPrehistModal(record, '#prehist-data')
);
const markerLabel = `${record.coordinates[0]} ${record.coordinates[1]}`;
marker.options.municipality = record.municipality;
GisState.markers.prehistoric[markerLabel] = marker;
prehistoric.addLayer(marker);
} }
// TODO: terrible! GisState.layers.prehistoric = prehistoric;
if (!layer.id.includes('area')) {
const marker = L.marker(coords) return prehistoric;
.addTo(map) }
.bindTooltip( /**
Object.keys(archeo).find(k => archeo[k] === layer) * Create underwater sites group
.replace(/\s\(.*$/, '') * @returns {L.MarkerClusterGroup}
) */
.openTooltip(); GIS.underwater = async function () {
let underwaterData = await fetch(`${API_URL}/underwater`)
if (typeof data === 'object') { .then(data => data.json());
marker.on('click', () => UI.openModal(data, '#site-data'));
} let underwater = L.markerClusterGroup(clusterOptions);
}
for (let record of underwaterData.records) {
const marker = L.marker(
record.coordinates,
{icon: Icons.underwater}
).bindTooltip(record.label)
.on(
'click',
() => UI.openUnderwaterModal(record, '#underwater-data')
);
const markerLabel = `${record.coordinates[0]} ${record.coordinates[1]}`;
GisState.markers.prehistoric[markerLabel] = marker;
underwater.addLayer(marker);
}
GisState.layers.underwater = underwater;
return underwater;
} }
*/
/** /**
* Adds layers to map and returns an object * Adds layers to map and returns an object
* with {baseMap, archeoLayers, sitesLayerGroup} * with {baseMap, archeoLayers, sitesLayerGroup}
* @todo Load areas for sites that have them!!
* @param {L.Map} map * @param {L.Map} map
* @returns {{baseMap: {"OpenStreetMap": L.TileLayer}, archeo: object, sitesGroup: L.LayerGroup}} * @returns {{baseMap: {"OpenStreetMap": L.TileLayer}}}
*/ */
GIS.initLayers = async function(map) { 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', { let osmap = new L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxNativeZoom : 22, maxNativeZoom : GIS.MAX_ZOOM,
maxZoom: 22, maxZoom: GIS.MAX_ZOOM,
attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors' attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
}); });
let mapbox = new L.tileLayer(`https://api.mapbox.com/v4/{id}/{z}/{x}/{y}@2x.jpg90?access_token=${MAPBOX_TOKEN}`, { let mapbox = new L.tileLayer(`https://api.mapbox.com/v4/{id}/{z}/{x}/{y}@2x.jpg90?access_token=${MAPBOX_TOKEN}`, {
id : 'mapbox.satellite', id : 'mapbox.satellite',
tileSize : 512, tileSize : 512,
zoomOffset : -1, zoomOffset : -1,
maxNativeZoom : 22, maxNativeZoom : GIS.MAX_ZOOM,
maxZoom: 22, maxZoom: GIS.MAX_ZOOM,
attribution: '&copy; Mapbox' attribution: '&copy; Mapbox'
}); });
let boundaries = await this.loadLayer('confini.geojson', {}, false); let boundaries = await this.loadGeoJSON('confini.geojson', {}, false);
let buildings = await this.loadLayer('fabbricati.geojson', optionsFabbricati, false); let buildings = await this.loadGeoJSON('fabbricati.geojson', optionsFabbricati, false);
let baseCatasto = new L.LayerGroup([buildings, boundaries]); 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]); const baseGroup = new L.LayerGroup([osmap]);
baseGroup.addTo(map); baseGroup.addTo(map);
const baseMap = { const baseMap = {
@@ -361,7 +401,7 @@ GIS.initLayers = async function(map) {
"Cartografia catastale" : baseCatasto, "Cartografia catastale" : baseCatasto,
}; };
return {baseMap, sitesGroup}; return baseMap;
} }
/** /**
* Toggle spherical photos on the map * Toggle spherical photos on the map
@@ -409,18 +449,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 {{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?
* @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}`) const geo = await fetch(`${BASE_URL}/geojson/${geoJSON}`)
.then(res => res.json()) .then(res => res.json())
.catch(error => console.error(`Can't load layer ${geoJSON}. Reason: ${error}`)); .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? // Show data from feature in popUp?
const layer = new L.geoJson(geo, { const layer = new L.geoJson(geo, {
@@ -433,7 +498,7 @@ GIS.loadLayer = async function (geoJSON, options, popup = true) {
} }
else { else {
layer.on("click", async () => { layer.on("click", async () => {
let data = GIS.layerData(layerId); let data = GIS.layerData(site.gisId, site.id);
if (typeof data === 'object') { if (typeof data === 'object') {
UI.openSiteModal(data); UI.openSiteModal(data);
@@ -448,9 +513,10 @@ GIS.loadLayer = async function (geoJSON, options, popup = true) {
/** /**
* Retrieves data for a given layer * Retrieves data for a given layer
* @param {string} layerId * @param {string} layerId
* @param {string} dbId
* @returns {object} Data for this layer from DB or cache * @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); const fromStorage = localStorage.getItem(layerId);
let data = {}; let data = {};
@@ -461,7 +527,7 @@ GIS.layerData = async function (layerId) {
console.log(error); console.log(error);
} }
} else { } else {
data = await GIS._fetchData('site/' + layerId); data = await GIS._fetchData('sites/' + dbId);
} }
return data; return data;
@@ -479,8 +545,8 @@ GIS.getSpherical = async function (siteId) {
* for a given layer * for a given layer
* @param {string} layerId * @param {string} layerId
*/ */
GIS.cacheDBData = async function (layerId) { GIS.cacheDBData = async function (layerId, dbId) {
const data = await this._fetchData('site/' + layerId); const data = await this._fetchData('sites/' + dbId);
localStorage.setItem(layerId, JSON.stringify(data)); localStorage.setItem(layerId, JSON.stringify(data));
} }
/** /**
@@ -509,11 +575,56 @@ GIS.featurePopup = function (layerName, feature) {
return content[layerName]; return content[layerName];
} }
/** /**
* Fetch data from API * Reproject WMS layer to map's CRS
* @param {string} recordId * @todo Parametrize CRS?
* @returns {L.TileLayer.WMS}
*/ */
GIS._fetchData = async function (recordId) { GIS.reprojectWMS = function (crs = 'EPSG:4258') {
const data = await fetch(`${API_URL}/${recordId}`) // Define EPSG:4258
proj4.defs('EPSG:4258', "+proj=longlat +ellps=GRS80 +no_defs +type=crs");
const reprojectedWMSLayer = L.TileLayer.WMS.extend({
getTileUrl(tilePoint) {
const map = GisState.map;
//const crs = map.options.crs;
const tileSize = this.getTileSize();
//const geoPoint = L.point(tilePoint.x, tilePoint.y);
const nwPoint = L.point(
tilePoint.x * tileSize.x,
tilePoint.y * tileSize.y,
)
const sePoint = nwPoint.add(L.point(tileSize));
const nw = map.unproject(nwPoint, tilePoint.z);
const se = map.unproject(sePoint, tilePoint.z);
const [minX, minY] = proj4('EPSG:4326', 'EPSG:4258', [nw.lng, se.lat]);
const [maxX, maxY] = proj4('EPSG:4326', 'EPSG:4258', [se.lng, nw.lat]);
const bbox = [minX, minY, maxX, maxY].join(',');
return this._url + L.Util.getParamString({
...this.wmsParams,
bbox,
width: tileSize.x,
height: tileSize.y,
srs: 'EPSG:4258'
},
this._url,
true
);
}
});
return reprojectedWMSLayer;
}
/**
* Fetch data from API
* @param {string} recordUri The URI to be appendend to the API's base URL
*/
GIS._fetchData = async function (recordUri) {
const data = await fetch(`${API_URL}/${recordUri}`)
.then(res => res.json()) .then(res => res.json())
.catch(err => console.log('Error fetching data from DB: ' + err)); .catch(err => console.log('Error fetching data from DB: ' + err));

View File

@@ -30,6 +30,24 @@ Icons.finding = L.icon(
} }
); );
Icons.prehistoric = L.icon(
{
iconUrl: 'img/icons/preistorici.png',
iconSize: [18, 27],
iconAnchor: [10, 24],
tooltipAnchor: [0, -22],
}
);
Icons.underwater = L.icon(
{
iconUrl: 'img/icons/subacquei.png',
iconSize: [18, 27],
iconAnchor: [10, 24],
tooltipAnchor: [0, -22],
}
);
Icons.camera = L.divIcon({className: 'fa fa-camera'}); Icons.camera = L.divIcon({className: 'fa fa-camera'});
export default Icons; export default Icons;

View File

@@ -6,24 +6,26 @@ import ModalController from './controllers/modal_controller.js';
import MarkerController from './controllers/marker_controller.js'; import MarkerController from './controllers/marker_controller.js';
import BiblioController from './controllers/biblio_controller.js'; import BiblioController from './controllers/biblio_controller.js';
import TabsController from './controllers/tabs_controller.js'; import TabsController from './controllers/tabs_controller.js';
import LayerController from './controllers/layer_controller.js';
document.addEventListener('DOMContentLoaded', async () => { document.addEventListener('DOMContentLoaded', async () => {
// Register Stimulus controllers // Register Stimulus controllers
initStimulus(); initStimulus();
let progress = document.querySelector('progress'); let progress = document.querySelector('progress');
const init = await GIS.initMap('map'); const map = await GIS.initMap('map');
progress.classList.add('is-hidden'); progress.classList.add('is-hidden');
let {map, sites} = init;
map._container.setAttribute('aria-busy', false); map._container.setAttribute('aria-busy', false);
// Trigger Stimulus buildMenu method...
const menuEvent = new Event('menu-ready');
document.dispatchEvent(menuEvent);
GIS.toggleSpherical(map); GIS.toggleSpherical(map);
UI.addCenterMapControl(map, GIS.CENTER_COORDS, GIS.INIT_ZOOM); UI.addCenterMapControl(map, GIS.CENTER_COORDS, GIS.INIT_ZOOM);
UI.toggleBurger('navbar-burger'); UI.toggleBurger('navbar-burger');
window.LMap = map;
}); });
function initStimulus() { function initStimulus() {
@@ -33,4 +35,5 @@ function initStimulus() {
Stimulus.register("marker", MarkerController); Stimulus.register("marker", MarkerController);
Stimulus.register("biblio", BiblioController); Stimulus.register("biblio", BiblioController);
Stimulus.register("tabs", TabsController); Stimulus.register("tabs", TabsController);
Stimulus.register("layer", LayerController);
} }

View File

@@ -12,6 +12,7 @@
"fontawesome-free": "^1.0.4", "fontawesome-free": "^1.0.4",
"leaflet": "^1.9.4", "leaflet": "^1.9.4",
"leaflet.markercluster": "^1.5.3", "leaflet.markercluster": "^1.5.3",
"proj4": "^2.9.4",
"spotlight.js": "^0.7.8" "spotlight.js": "^0.7.8"
}, },
"devDependencies": {} "devDependencies": {}

53
webgis/js/state.js Normal file
View File

@@ -0,0 +1,53 @@
/**
* @typedef {Object.<string, L.Marker>} MarkerLookup
* A lookup table of markers keyed by 'lat lng' (no groupings)
*/
/**
* @typedef {Object.<string, L.LayerGroup>} LayerGroupLookup
* A lookup table of Leaflet layer groups by category
*/
/**
* @typedef {Object} GisStateType
* @property {L.Map|null} map
* @property {MarkerLookup} markers
* @property {LayerGroupLookup} layers
* @property {Object|null} bibliography
* @property {String|null} apiUrl
* @property {Object} cartography
*/
/** @type {GisStateType} */
export const GisState = {
map: null,
markers: {
sites: {},
notConserved: {},
findings: {},
prehistoric: {},
underwater: {},
},
layers: {
sites: {},
notConserved: {},
findings: {},
prehistoric: {},
underwater: {},
},
bibliography: null,
apiUrl : null,
cartography : {
historic: [],
cadastral: null,
}
}
/**
* @param {array} coords - ['lat', 'lng']
* @param {string} group
* @returns {L.Marker|undefined}
*/
export function getMarkerByCoords(coords, group) {
return GisState.markers[group][`${coords[0]} ${coords[1]}`];
}

View File

@@ -4,10 +4,12 @@ import Spotlight from './vendor/spotlight.js/src/js/spotlight.js';
import { SiteSheet } from './components/SiteSheet.js'; import { SiteSheet } from './components/SiteSheet.js';
import { SiteDocuments } from './components/SiteDocuments.js'; import { SiteDocuments } from './components/SiteDocuments.js';
import { SiteSurveys } from './components/SiteSurveys.js'; import { SiteSurveys } from './components/SiteSurveys.js';
import { SitePhotos } from './components/SitePhotos.js'; import { SiteMedia } from './components/SiteMedia.js';
import { NotConservedSheet } from './components/NotConservedSheet.js'; import { NotConserved } from './components/NotConserved.js';
import GIS from './gis.js';
import { Finding } from './components/Finding.js'; import { Finding } from './components/Finding.js';
import { Prehistoric } from './components/Prehistoric.js';
import { Underwater } from './components/Underwater.js';
import { GisState } from "./state.js";
/** /**
* @namespace UI * @namespace UI
@@ -66,49 +68,22 @@ UI.toggleBurger = function(burgerClass) {
document.querySelector(`#${menuId}`).classList.toggle('is-active'); document.querySelector(`#${menuId}`).classList.toggle('is-active');
}); });
} }
/**
* Toggle side menu
* @param {string} triggerId The ID of the trigger element
* @param {?string} listId The ID of the menu list to open (if any)
*/
UI.toggleMenu = function (triggerId, listId = null) {
const trigger = document.querySelector(`#${triggerId}`);
const menu = document.querySelector('#menu');
trigger.addEventListener('click', () => {
menu.classList.remove('is-hidden');
//menu.classList.add('is-3');
const lists = menu.querySelectorAll('ul');
if (listId !== null) {
const list = document.querySelector(`#${listId}`);
list.classList.remove('is-hidden');
for (let ul of lists) {
if (ul.id !== listId && !ul.id.includes('sub')) {
ul.classList.add('is-hidden');
}
}
}
});
}
/** /**
* Open a modal with DB site data * Open a modal with DB site data
* @param {object} data The data retrieved from the DB to display as modal content * @param {object} data The data retrieved from the DB to display as modal content
* @param {string} selector The modal selector * @param {string} selector The modal selector
*/ */
UI.openSiteModal = async function (data, selector) { UI.openSiteModal = function (data, selector) {
const modal = document.querySelector(selector); const modal = document.querySelector(selector);
let dataTabs = modal.querySelectorAll('.data-tabs'); let dataTabs = modal.querySelectorAll('.data-tabs');
// Reset data tabs content // Reset data tabs content
for (let tab of dataTabs) { for (let tab of dataTabs) tab.innerHTML = '';
tab.innerHTML = '';
}
let siteSheet = new SiteSheet(); let siteSheet = new SiteSheet();
siteSheet.siteData = data; siteSheet.siteData = data;
window.Biblio = siteSheet; GisState.bibliography = siteSheet;
modal.querySelector('#short-sheet').innerHTML = siteSheet.renderShort(); modal.querySelector('#short-sheet').innerHTML = siteSheet.renderShort();
if (data.description) { if (data.description) {
@@ -116,118 +91,145 @@ UI.openSiteModal = async function (data, selector) {
} }
let images = modal.querySelector('#photos'); let images = modal.querySelector('#photos');
let docs = modal.querySelector('#documents');
if (data.documents?.length) { let siteDocs = new SiteDocuments;
let siteDocs = new SiteDocuments; siteDocs.siteData = data;
siteDocs.siteData = data; docs.innerHTML = siteDocs.render();
modal.querySelector('#documents').innerHTML = siteDocs.render();
}
let surveys = data.images.filter(i => i.type === 'Survey'); let surveys = data.images.filter(i => i.type === 'Survey');
let photos = data.images.filter(i => i.type === 'Photo'); let photos = data.images.filter(i => i.type === 'Photo');
let videos = data.images.filter(i => i.type === 'Video');
if (surveys.length === 0 && photos.length === 0 && videos.length === 0) {
images.innerHTML = '<p class="has-text-centered">Nessuna risorsa visuale disponibile</p>';
}
if (images.innerHTML.length === 0) { if (images.innerHTML.length === 0) {
let siteSurveys = new SiteSurveys; let siteSurveys = new SiteSurveys;
siteSurveys.siteData = surveys[0] ?? undefined; siteSurveys.siteData = surveys[0] ?? undefined;
images.innerHTML += surveys[0] ? siteSurveys.render() : ''; images.innerHTML += surveys[0] ? siteSurveys.render() : '';
let sitePhotos = new SitePhotos; let siteMedia = new SiteMedia;
sitePhotos.siteData = photos[0] ?? undefined; siteMedia.siteData = photos[0] ?? undefined;
images.innerHTML += photos[0] ? sitePhotos.render() : ''; images.innerHTML += photos[0] ? siteMedia.renderPhotos() : '';
siteMedia.siteData = videos[0] ?? undefined;
images.innerHTML += videos[0] ? siteMedia.renderVideos() : '';
} }
modal.classList.add('is-active'); modal.classList.add('is-active');
this.imageGallery('gallery-1', surveys); this.imageGallery('gallery-1', surveys);
this.imageGallery('gallery-2', photos); this.imageGallery('gallery-2', photos);
this.imageGallery('gallery-video', videos, true);
} }
/** /**
* @param {object} data The data retrieved from the DB to display as modal content * @param {object} data The data retrieved from the DB to display as modal content
* @param {string} selector The modal selector * @param {string} selector The modal selector
*/ */
UI.openNotConserModal = async function (data, selector) { UI.openNotConserModal = function (data, selector) {
const modal = document.querySelector(selector); const modal = document.querySelector(selector);
let dataTabs = modal.querySelectorAll('.data-tabs');
// Reset data tabs content
for (let tab of dataTabs) tab.innerHTML = '';
let sheet = new NotConservedSheet(); let notConserved = new NotConserved();
sheet.siteData = data; notConserved.data = data;
// For Stimulus biblio_controller // For Stimulus biblio_controller
window.Biblio = sheet; GisState.bibliography = notConserved;
modal.querySelector('#not-conser-sheet').innerHTML = await sheet.render(); notConserved.render().then(html => modal.querySelector('#not-conserved-sheet').innerHTML = html);
notConserved.renderDocs().then(html => modal.querySelector('#documents').innerHTML = html);
notConserved.setImages(modal.querySelector('#photos'), this.imageGallery);
modal.classList.add('is-active'); modal.classList.add('is-active');
} }
/** /**
* @param {object} data The data retrieved from the DB to display as modal content * @param {object} data The data retrieved from the DB to display as modal content
* @param {string} selector The modal selector * @param {string} selector The modal selector
*/ */
UI.openFindingModal = async function (data, selector) { UI.openFindingModal = function (data, selector) {
const modal = document.querySelector(selector); const modal = document.querySelector(selector);
let dataTabs = modal.querySelectorAll('.data-tabs'); let dataTabs = modal.querySelectorAll('.data-tabs');
// Reset data tabs content // Reset data tabs content
for (let tab of dataTabs) { for (let tab of dataTabs) tab.innerHTML = '';
tab.innerHTML = '';
}
let finding = new Finding(); let finding = new Finding();
finding.data = data; finding.data = data;
// For Stimulus biblio_controller // For Stimulus biblio_controller
window.Biblio = finding; GisState.bibliography = finding;
finding.render().then(html => modal.querySelector('#finding-sheet').innerHTML = html);
finding.setImages(modal.querySelector('#photos'), this.imageGallery);
finding.setImages();
modal.querySelector('#finding-sheet').innerHTML = await finding.render();
if (finding.images) {
modal.querySelector('#photos').innerHTML = finding.renderImages();
this.imageGallery('finding-gallery', finding.images);
}
modal.classList.add('is-active'); modal.classList.add('is-active');
} }
/** /**
* @param {string} menuListSel Menu list selector * @todo Biblio
* @param {L.Map} map * @param {object} data The data retrieved from the DB to display as modal content
* @param {L.LayerGroup} sites * @param {string} selector The modal selector
*/ */
UI.sitesMenu = function (menuListSel, map, sites) { UI.openPrehistModal = function (data, selector) {
// Close menu if arrow button is clicked... const modal = document.querySelector(selector);
let markers = []; let dataTabs = modal.querySelectorAll('.data-tabs');
// Reset data tabs content
for (let tab of dataTabs) tab.innerHTML = '';
map.eachLayer(layer => { let prehistoric = new Prehistoric();
if (layer instanceof L.Marker) { prehistoric.data = data;
markers.push(layer);
}
})
const menu = document.querySelector(menuListSel); // For Stimulus biblio_controller
menu.addEventListener('click', async event => { //GisState.bibliography = prehistoric;
if (event.target.nodeName === 'A') { prehistoric.render().then(html => modal.querySelector('#prehist-sheet').innerHTML = html);
const layerId = event.target.id; prehistoric.setImages(modal.querySelector('#photos'), this.imageGallery);
const marker = markers.filter(m => m.id === layerId)[0]; modal.classList.add('is-active');
}
/**
* @todo Biblio?
* @param {object} data The data retrieved from the DB to display as modal content
* @param {string} selector The modal selector
*/
UI.openUnderwaterModal = function (data, selector) {
const modal = document.querySelector(selector);
let underwater = new Underwater();
underwater.data = data;
// zoom to layer... // For Stimulus biblio_controller
const layer = sites.customGetLayer(layerId); //GisState.bibliography = underwater;
map.setView( underwater.render().then(html => modal.querySelector('#underwater-sheet').innerHTML = html);
layer.getBounds().getCenter(), modal.classList.add('is-active');
19,
{animate: true, duration: 1, easeLinearity: 0.25}
);
marker.openTooltip();
}
});
} }
/** /**
* Open Spotlight gallery * Open Spotlight gallery
* @param {string} galleryId The id of the trigger element * @param {string} galleryId The id of the trigger element
* @param {Array<Object>} images Array of image objects from DB * @param {Array<Object>} items Array of image objects from DB
* @param {boolean} video Is this a video gallery?
*/ */
UI.imageGallery = function (galleryId, images) { UI.imageGallery = function (galleryId, items, video = false) {
const element = document.querySelector(`#${galleryId}`); const element = document.querySelector(`#${galleryId}`);
if (element) { if (element) {
let gallery = []; let gallery = [];
for (let img of images) { for (let media of items) {
gallery.push({src: `img/${img.filename}`, description: img.caption}); let author = media.author ? ` (${media.author})` : '';
let mediaObj = {
description: media.caption + author
};
if (video) {
mediaObj.media = 'video';
mediaObj["src-mp4"] = `video/${media.filename}`;
mediaObj.poster = `video/${media.filename.replace('mp4', 'png')}`;
mediaObj.autoplay = true;
} else {
mediaObj.src = `img/${media.filename}`;
}
gallery.push(mediaObj);
} }
document.querySelector(`#${galleryId}`).addEventListener('click', () => { document.querySelector(`#${galleryId}`).addEventListener('click', () => {

View File

@@ -39,6 +39,19 @@ leaflet@^1.9.4:
resolved "https://registry.yarnpkg.com/leaflet/-/leaflet-1.9.4.tgz#23fae724e282fa25745aff82ca4d394748db7d8d" resolved "https://registry.yarnpkg.com/leaflet/-/leaflet-1.9.4.tgz#23fae724e282fa25745aff82ca4d394748db7d8d"
integrity sha512-nxS1ynzJOmOlHp+iL3FyWqK89GtNL8U8rvlMOsQdTTssxZwCXh8N2NB3GDQOL+YR3XnWyZAxwQixURb+FA74PA== integrity sha512-nxS1ynzJOmOlHp+iL3FyWqK89GtNL8U8rvlMOsQdTTssxZwCXh8N2NB3GDQOL+YR3XnWyZAxwQixURb+FA74PA==
mgrs@1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/mgrs/-/mgrs-1.0.0.tgz#fb91588e78c90025672395cb40b25f7cd6ad1829"
integrity sha512-awNbTOqCxK1DBGjalK3xqWIstBZgN6fxsMSiXLs9/spqWkF2pAhb2rrYCFSsr1/tT7PhcDGjZndG8SWYn0byYA==
proj4@^2.9.4:
version "2.19.4"
resolved "https://registry.yarnpkg.com/proj4/-/proj4-2.19.4.tgz#38cf347309f523309ead94d565788de94f07098f"
integrity sha512-1l6JiJ2ZOzXIoo6k64diOQVOvHIF0IACMrHTaFHrEQmuo1tY1vb73mrWfTSyPH+muc0Lut4zuj5encvB1Ccuhg==
dependencies:
mgrs "1.0.0"
wkt-parser "^1.5.1"
spotlight.js@^0.7.8: spotlight.js@^0.7.8:
version "0.7.8" version "0.7.8"
resolved "https://registry.yarnpkg.com/spotlight.js/-/spotlight.js-0.7.8.tgz#0620371701508222d736e0658e8db3fbe9ddc53b" resolved "https://registry.yarnpkg.com/spotlight.js/-/spotlight.js-0.7.8.tgz#0620371701508222d736e0658e8db3fbe9ddc53b"
@@ -48,3 +61,8 @@ three@^0.169.0:
version "0.169.0" version "0.169.0"
resolved "https://registry.yarnpkg.com/three/-/three-0.169.0.tgz#4a62114988ad9728d73526d1f1de6760c56b4adc" resolved "https://registry.yarnpkg.com/three/-/three-0.169.0.tgz#4a62114988ad9728d73526d1f1de6760c56b4adc"
integrity sha512-Ed906MA3dR4TS5riErd4QBsRGPcx+HBDX2O5yYE5GqJeFQTPU+M56Va/f/Oph9X7uZo3W3o4l2ZhBZ6f6qUv0w== integrity sha512-Ed906MA3dR4TS5riErd4QBsRGPcx+HBDX2O5yYE5GqJeFQTPU+M56Va/f/Oph9X7uZo3W3o4l2ZhBZ6f6qUv0w==
wkt-parser@^1.5.1:
version "1.5.2"
resolved "https://registry.yarnpkg.com/wkt-parser/-/wkt-parser-1.5.2.tgz#a8eaf86ac2cc1d0a2e6a8082a930f5c7ebdb5771"
integrity sha512-1ZUiV1FTwSiSrgWzV9KXJuOF2BVW91KY/mau04BhnmgOdroRQea7Q0s5TVqwGLm0D2tZwObd/tBYXW49sSxp3Q==

0
webgis/video/.keep Normal file
View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 330 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 403 KiB