Compare commits

..

42 Commits

Author SHA1 Message Date
1a3c95487f Temp search form 2025-11-21 17:54:50 +01:00
b0915d0973 Simplify marker regex + link CSS 2025-11-12 17:16:53 +01:00
ebea10059e Prevent null in captions... 2025-11-10 10:15:11 +01:00
249a31d11a More marker changes... 2025-11-07 11:41:35 +01:00
4d95aa7fce More markers in site sheet... 2025-11-03 10:11:09 +01:00
e7f1ed7a98 Markers in localization 2025-10-30 15:27:25 +01:00
5cf42ff4be Update marker parsing regex 2025-10-30 09:36:53 +01:00
0f16af95e7 Update for internal links 2025-10-30 08:52:16 +01:00
13550078cb Open modal for internal links (WIP) 2025-10-29 18:23:41 +01:00
262540e735 Bloody whitespace... 2025-10-24 15:31:47 +02:00
c8de489ead Parse markers for other record types 2025-10-24 15:24:39 +02:00
952dc3f841 Parse marker shortcodes (WIP) 2025-10-24 10:27:28 +02:00
00cedfeb85 Fix undefined bug... 2025-09-03 15:54:34 +02:00
53c3f6c6b2 More refactoring components (minus Site) 2025-09-02 09:59:02 +02:00
77d42a2c27 Refactor components (WIP) 2025-09-01 17:20:47 +02:00
40cc2ef88b Update main menu 2025-08-25 11:15:22 +02:00
e6578225ec Populate biblio state for reuse data 2025-08-08 16:28:22 +02:00
986c4b0a75 Images for Reuse 2025-08-08 14:17:01 +02:00
f849f885f9 Add Reuse asset type 2025-08-08 12:06:38 +02:00
9196653c0d Another feature popup fix... 2025-07-15 16:11:44 +02:00
e3a3b30ade Merge branch 'master' of https://git.electricmandarine.cloud/nicolo/caprigis 2025-07-15 16:08:38 +02:00
065e49ccb2 Update GeoJSON layer and feature popup 2025-07-15 16:07:27 +02:00
106c8f60bc Update GeoJSON layers 2025-07-14 10:17:13 +02:00
e3d98c2e5d Move boundaries to base map control 2025-07-08 14:44:01 +02:00
377447f63a Fix stupid bug... 2025-07-08 12:21:10 +02:00
cfcd1e8e80 Render 3D reconstructions for sites 2025-07-08 12:07:08 +02:00
378e14d56a Add Villa Bismarck geojson; refactor layer options 2025-07-07 13:19:06 +02:00
f68216c84c WMS in layers control 2025-06-30 11:18:13 +02:00
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
28 changed files with 1380 additions and 991 deletions

3
.gitignore vendored
View File

@@ -15,4 +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 *Zone*Identifier

View File

@@ -158,12 +158,12 @@ 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; margin-top: 54px;
} }
#menu.is-overlay { .menu-overlay.is-overlay {
left: auto; left: auto;
} }
/* Content in tabs */ /* Content in tabs */

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

View File

@@ -13,19 +13,21 @@
<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 modal"
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">
@@ -46,15 +48,31 @@
<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="button is-outlined is-rounded is-link mr-4 mt-1" id="howto" title="Istruzioni"> <button class="navbar-item button is-size-5 is-white mr-3" role="button"
<span class="icon is-large has-text-link"> data-id="cartography"
<i class="fas fa-question fa-lg"></i> data-action="menu#toggleMenu">
<span class="icon mr-2">
<i class="fa fa-map"></i>
</span>
Catasto storico
</button>
<button class="button is-white mr-2 mt-1" title="Cerca"
data-id="search"
data-action="modal#open">
<span class="icon">
<i class="fa fa-search"></i>
</span>
</button>
<button class="button is-outlined is-rounded mr-4 mt-1" id="howto" title="Istruzioni">
<span class="icon has-text-black">
<i class="fas fa-question"></i>
</span> </span>
</button> </button>
</div> </div>
@@ -69,651 +87,321 @@
<progress id="map-progress" class="p-2 progress is-medium is-link" aria-label="Map loading..." /> <progress id="map-progress" class="p-2 progress is-medium is-link" aria-label="Map loading..." />
</div> </div>
</div> </div>
<div class="column is-hidden is-4 is-4-desktop is-5-mobile is-pulled-right is-overlay has-background-white-ter" id="menu" <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"> 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-id="siti"> <p class="menu-label is-size-5 mt-2 is-clickable" data-id="sites">
<span class="icon pl-1 mr-2 is-small" title="Nascondi" data-layer-target="siti" data-action="click->layer#toggle"> <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> <i class="fa fa-xs fa-eye-slash" data-layer-target="icon"></i>
</span> </span>
<span class="icon pr-1"> <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>
<span data-action="click->menu#toggle" data-id="siti"> <span role="button" data-action="click->menu#toggle" data-id="sites">
Beni archeologici Beni archeologici
<span class="icon pl-2"> <span class="icon pl-2">
<i class="fa fa-chevron-right" data-menu-target="icon" data-id="siti"></i> <i class="fa fa-chevron-right" data-menu-target="icon" data-id="sites"></i>
</span> </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-controller="marker" data-marker-coords-value="40.56094295 14.20573624"
data-marker-group-value="sites">
Grotta Azzurra
</a>
</li>
<li>
<a class="button" title="Vai al sito Grotta del Pisco"
data-action="marker#go" data-controller="marker" data-marker-coords-value="40.543768 14.202657"
data-marker-group-value="sites">
Grotta del Pisco
</a>
</li>
<li>
<a class="button" title="Vai al sito Lo Pozzo"
data-action="marker#go" data-controller="marker" data-marker-coords-value="40.556601 14.213642"
data-marker-group-value="sites">
Località Lo Pozzo
</a>
</li>
<li>
<a class="button" title="Vai al sito Scala Fenicia"
data-action="marker#go" data-controller="marker" data-marker-coords-value="40.5562963 14.2285935"
data-marker-group-value="sites">
Scala Fenicia
</a>
</li>
<li>
<a class="button" title="Vai al sito Villa di Damecuta"
data-action="marker#go" data-controller="marker" data-marker-coords-value="40.55906 14.20055"
data-marker-group-value="sites">
Villa di Damecuta
</a>
</li>
<li>
<a class="button" title="Vai al sito Villa di Gradola"
data-action="marker#go" data-controller="marker" data-marker-coords-value="40.560834 14.205793"
data-marker-group-value="sites">
Villa di Gradola
</a>
</li>
<li>
<a class="button" title="Vai al sito San Michele"
data-action="marker#go" data-controller="marker" data-marker-coords-value="40.55738 14.225806"
data-marker-group-value="sites">
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" data-controller="marker"
data-marker-coords-value="40.54972 14.24669"
data-marker-group-value="sites"
data-action="marker#go">
Camerelle
</a>
</li>
<li>
<a class="button" data-controller="marker"
data-marker-group-value="sites"
data-marker-coords-value="40.54652 14.24288" data-action="marker#go">
Grotta dell'Arsenale
</a>
</li>
<li>
<a class="button" title="Vai al sito Grotta di Matermania" data-controller="marker"
data-marker-group-value="sites"
data-marker-coords-value="40.54942 14.25583" data-action="marker#go">
Grotta di Matermania
</a>
</li>
<li>
<a class="button" title="Vai al sito Grotta delle Felci" data-controller="marker"
data-marker-group-value="sites"
data-marker-coords-value="40.543644 14.230008" data-action="marker#go">
Grotta delle Felci
</a>
</li>
<li>
<a class="button" title="Vai al sito Grotta del Castiglione" data-controller="marker"
data-marker-group-value="sites"
data-marker-coords-value="40.54687 14.24023" data-action="marker#go">
Grotta del Castiglione
</a>
</li>
<li>
<a class="button" data-controller="marker" data-marker-coords-value="40.5515 14.24327"
data-marker-group-value="sites"
data-action="marker#go">
Mura greche
</a>
</li>
<li>
<a class="button" data-controller="marker" data-marker-coords-value="40.55325 14.24761" data-action="marker#go">
Monte San Michele
</a>
</li>
<li>
<a class="button" data-controller="marker" data-marker-coords-value="40.55641 14.23503" data-action="marker#go">
San Costanzo
</a>
</li>
<li>
<a class="button" data-controller="marker" data-marker-coords-value="40.549 14.24801" data-action="marker#go">
Tragara (strada)
</a>
</li>
<li>
<a class="button" data-controller="marker" data-marker-coords-value="40.54695 14.24962" data-action="marker#go">
Tragara (area residenziale)
</a>
</li>
<li>
<a class="button" data-controller="marker" data-marker-coords-value="40.543719 14.252836" data-action="marker#go">
Tragara, approdo
</a>
</li>
<li>
<a class="button" data-controller="marker" data-marker-coords-value="40.55791 14.26253" data-action="marker#go">
Villa Jovis
</a>
</li>
</ul>
</li> </li>
</ul> </ul>
<p class="menu-label is-size-5 is-clickable" data-id="non-conser"> <p class="menu-label is-size-5 is-clickable" data-id="notConserved">
<span class="icon pl-1 mr-2 is-small" title="Nascondi" data-layer-target="non-conser" <span class="icon pl-1 mr-2 is-small" title="Nascondi" data-layer-target="notConserved"
data-action="click->layer#toggle" style="max-height: 10px"> data-action="click->layer#toggle" style="max-height: 10px">
<i class="fa fa-xs fa-eye-slash" data-layer-target="icon"></i> <i class="fa fa-xs fa-eye-slash" data-layer-target="icon"></i>
</span> </span>
<span class="icon pr-1"> <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>
<span data-action="click->menu#toggle" data-id="non-conser"> <span role="button" data-action="click->menu#toggle" data-id="notConserved">
Beni non conservati Beni non conservati
<span class="icon pl-2"> <span class="icon pl-2">
<i class="fa fa-chevron-right" data-menu-target="icon" data-id="non-conser"></i> <i class="fa fa-chevron-right" data-menu-target="icon" data-id="notConserved"></i>
</span> </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> <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-controller="marker" data-marker-coords-value="40.5595565 14.2003896">
Cala a mare - resti di ambienti
</a>
</li>
<li>
<a class="button" data-action="marker#go" data-controller="marker" data-marker-coords-value="40.549026 14.196911">
Punta Campetiello - scala
</a>
</li>
<li>
<a class="button" data-action="marker#go" data-controller="marker" data-marker-coords-value="40.5501214 14.2198544">
Castagnaro - area funeraria
</a>
</li>
<li>
<a class="button" data-action="marker#go" data-controller="marker" data-marker-coords-value="40.55129683 14.21261142">
Ceselle - necropoli
</a>
</li>
<li>
<a class="button" data-action="marker#go" data-controller="marker" data-marker-coords-value="40.5533744 14.2178754">
Località Piscina - complesso idraulico
</a>
</li>
<li>
<a class="button" data-action="marker#go" data-controller="marker" data-marker-coords-value="40.5546467 14.2092143">
La Cera - ambienti voltati
</a>
</li>
<li>
<a class="button" data-action="marker#go" data-controller="marker" data-marker-coords-value="40.5495555 14.2108741">
Cesa - complesso idraulico
</a>
</li>
<li>
<a class="button" data-action="marker#go" data-controller="marker" data-marker-coords-value="40.5575337 14.2027513">
La Fabbrica - resti murari
</a>
</li>
<li>
<a class="button" data-action="marker#go" data-controller="marker" data-marker-coords-value="40.5543028 14.2129861">
Le Boffe - Frammenti scultorei
</a>
</li>
<li>
<a class="button" data-action="marker#go" data-controller="marker" data-marker-coords-value="40.5530655 14.201767">
Lupinaro - resti murari
</a>
</li>
<li>
<a class="button" data-action="marker#go" data-controller="marker" data-marker-coords-value="40.5399801 14.2092552">
Migliara Belvedere - frammenti erratici
</a>
</li>
<li>
<a class="button" data-action="marker#go" data-controller="marker" data-marker-coords-value="40.5451791 14.2233019">
Monte Solaro - vaso corinzio
</a>
</li>
<li>
<a class="button" data-action="marker#go" data-controller="marker" data-marker-coords-value="40.5523988 14.2087281">
Monticello - “Vaso di Monticello”
</a>
</li>
<li>
<a class="button" data-action="marker#go" data-controller="marker" data-marker-coords-value="40.5521975 14.2107296">
Monticello - “Villa di Monticello”
</a>
</li>
<li>
<a class="button" data-action="marker#go" data-controller="marker" data-marker-coords-value="40.5559514 14.2197966">
Pastena - strutture murarie
</a>
</li>
<li>
<a class="button" data-action="marker#go" data-controller="marker" data-marker-coords-value="40.546923 14.2173871">
Petracquale - ruderi indeterminati
</a>
</li>
<li>
<a class="button" data-action="marker#go" data-controller="marker" data-marker-coords-value="40.55666444 14.21446043">
Timberino - impianto idraulico
</a>
</li>
<li>
<a class="button" data-action="marker#go" data-controller="marker" data-marker-coords-value="40.5590486 14.1984242">
Vetereto - ambienti voltati
</a>
</li>
<li>
<a class="button" data-action="marker#go" data-controller="marker" data-marker-coords-value="40.556597 14.214518">
Veterino - complesso residenziale
</a>
</li>
</ul>
</li> </li>
<li class="mt-3" data-list-id="noncons-capri-sub"> <li class="mt-3" data-list-id="notConserved-capri-sub">
<span class="is-clickable" data-action="click->menu#openSubList" data-list-id="noncons-capri-sub"> <span role="button" class="is-clickable" data-action="click->menu#openSubList" data-list-id="notConserved-capri-sub">
Capri Capri
<span class="icon ml-2 is-small" data-list-id="noncons-capri-sub"> <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-capri-sub" class="is-hidden">
<li>
<a class="button" data-action="marker#go" data-controller="marker" data-marker-coords-value="40.5511089 14.2362655">
Le Parate - necropoli
</a>
</li>
<li>
<a class="button" data-action="marker#go" data-controller="marker" data-marker-coords-value="40.5532513 14.2538048">
Moneta - impianti idraulici e struttura residenziale a Moneta
</a>
</li>
<li>
<li>
<a class="button" data-action="marker#go" data-controller="marker" data-marker-coords-value="40.5533825 14.2385025">
Sant'Antonio - necropoli
</a>
</li>
<a class="button" data-action="marker#go" data-controller="marker" data-marker-coords-value="40.5484525 14.2478183">
Unghia Marina - complesso residenziale
</a>
</li>
<li>
<a class="button" data-action="marker#go" data-controller="marker" data-marker-coords-value="40.5473155 14.2405834">
Villa Imperiale del Castiglione
</a>
</li>
<li>
<a class="button" data-action="marker#go" data-controller="marker" data-marker-coords-value="40.5480487 14.2420423">
Villa imperiale del Castiglione, scavi Hadrawa
</a>
</li>
<li>
<a class="button" data-action="marker#go" data-controller="marker" data-marker-coords-value="40.5492126 14.2438121">
Villa imperiale del Castiglione, Li Campi
</a>
</li>
<li>
<a class="button" data-action="marker#go" data-controller="marker" data-marker-coords-value="40.5493422 14.2430196">
Villa imperiale del Castiglione, Località Valentino
</a>
</li>
<li>
<a class="button" data-action="marker#go" data-controller="marker" data-marker-coords-value="40.5489398 14.2408126">
Villa imperiale del Castiglione, mura via Castello
</a>
</li>
</ul>
</li> </li>
</ul> </ul>
<p class="menu-label is-size-5 is-clickable" data-id="rinv"> <p class="menu-label is-size-5 is-clickable" data-id="findings">
<span class="icon pl-1 mr-2 is-small" data-layer-target="rinv" data-action="click->layer#toggle"> <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> <i class="fa fa-xs fa-eye-slash" data-layer-target="icon"></i>
</span> </span>
<span class="icon pr-1"> <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>
<span data-action="click->menu#toggle" data-id="rinv"> <span role="button" data-action="click->menu#toggle" data-id="findings">
Rinvenimenti Reperti
<span class="icon pl-2"> <span class="icon pl-2">
<i class="fa fa-chevron-right" data-menu-target="icon" data-id="rinv"></i> <i class="fa fa-chevron-right" data-menu-target="icon" data-id="findings"></i>
</span> </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-controller="marker" data-marker-coords-value="40.55939119 14.20064002" data-action="marker#go"> Capri
Affresco di IV stile - Villa 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"
data-controller="marker" data-marker-coords-value="40.5596847 14.2013025" data-action="marker#go">
Statua di fanciullo - Villa Damecuta
</a>
</li>
<li>
<a class="button" data-marker-target="coords"
data-controller="marker" data-marker-coords-value="40.5595088 14.2008549" data-action="marker#go">
Frammento di testa di Sileno - Villa Damecuta
</a>
</li>
<li>
<a class="button" data-marker-target="coords"
data-controller="marker" data-marker-coords-value="40.5565536 14.2133073" data-action="marker#go">
Base di candelabro - Lo Pozzo
</a>
</li>
<li>
<a class="button" data-marker-target="coords"
data-controller="marker" data-marker-coords-value="40.56061123 14.20569607" data-action="marker#go">
Statua di Nettuno - Grotta Azzurra
</a>
</li>
<li>
<a class="button" data-marker-target="coords"
data-controller="marker" data-marker-coords-value="40.56070704 14.20588946" data-action="marker#go">
Statua di Tritone imberbe - Grotta Azzurra
</a>
</li>
<li>
<a class="button" data-marker-target="coords"
data-controller="marker" data-marker-coords-value="40.56057044 14.20603369" data-action="marker#go">
Statua di Tritone barbato - Grotta Azzurra
</a>
</li>
<li>
<a class="button" data-marker-target="coords"
data-controller="marker" data-marker-coords-value="40.56048101 14.20591339" data-action="marker#go">
Statua di Tritone - Grotta Azzurra
</a>
</li>
<li>
<a class="button" data-marker-target="coords"
data-controller="marker" data-marker-coords-value="40.5605702 14.20575881" data-action="marker#go">
Statua di peplophoros - Grotta Azzurra
</a>
</li>
</ul>
</li> </li>
</ul> </ul>
<p class="menu-label is-size-5 is-clickable" data-id="preist"> <p class="menu-label is-size-5 is-clickable" data-id="reuse">
<span class="icon pl-1 mr-2 is-small" title="Nascondi" data-layer-target="preist" data-action="click->layer#toggle"> <span class="icon pl-1 mr-2 is-small" data-layer-target="reuse" 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/reimpiego_menu.png"/>
</span>
<span role="button" data-action="click->menu#toggle" data-id="reuse">
Reimpiego
<span class="icon pl-2">
<i class="fa fa-chevron-right" data-menu-target="icon" data-id="reuse"></i>
</span>
</span>
</p>
<ul class="menu-list is-hidden" id="reuse-list" data-menu-target="list" data-controller="marker">
<li data-list-id="reuse-capri-sub">
<span role="button" class="is-clickable" data-action="click->menu#openSubList" data-list-id="reuse-capri-sub">
Capri
<span class="icon ml-2">
<i class="fa fa-chevron-right" data-menu-target="icon"></i>
</span>
</span>
</li>
</ul>
<p class="menu-label is-size-5 is-clickable" data-id="prehistoric">
<span class="icon pl-1 mr-2 is-small" title="Nascondi" data-layer-target="prehistoric" data-action="click->layer#toggle">
<i class="fa fa-xs fa-eye-slash" data-layer-target="icon"></i> <i class="fa fa-xs fa-eye-slash" data-layer-target="icon"></i>
</span> </span>
<span class="icon pr-1"> <span class="icon pr-1">
<img class="image" src="img/icons/preistorici.png"/> <img class="image" src="img/icons/preistorici.png"/>
</span> </span>
<span data-action="click->menu#toggle" data-id="preist"> <span role="button" data-action="click->menu#toggle" data-id="prehistoric">
Aree di affioramento Aree di affioramento
<span class="icon pl-2"> <span class="icon pl-2">
<i class="fa fa-chevron-right" data-menu-target="icon" data-id="preist"></i> <i class="fa fa-chevron-right" data-menu-target="icon" data-id="prehistoric"></i>
</span> </span>
</span> </span>
</p> </p>
<ul class="menu-list is-hidden" id="preist-list" data-menu-target="list" data-controller="marker"> <ul class="menu-list is-hidden" id="prehistoric-list" data-menu-target="list" data-controller="marker">
<li data-list-id="preist-anacapri-sub"> <li data-list-id="prehistoric-anacapri-sub">
<span class="is-clickable" data-action="click->menu#openSubList" data-list-id="preist-anacapri-sub"> <span role="button" class="is-clickable" data-action="click->menu#openSubList" data-list-id="prehistoric-anacapri-sub">
Anacapri Anacapri
<span class="icon ml-2 is-small" data-list-id="preist-anacapri-sub"> <span class="icon ml-2 is-small" data-list-id="prehistoric-anacapri-sub">
<i class="fa fa-chevron-right"></i> <i class="fa fa-chevron-right"></i>
</span> </span>
</span> </span>
<ul id="preist-anacapri-sub" class="is-hidden">
<li>
<a class="button" data-action="marker#go" data-controller="marker" data-marker-coords-value="40.548922 14.229593">
Cetrella
</a>
</li>
<li>
<a class="button" data-action="marker#go" data-controller="marker" data-marker-coords-value="40.554641 14.198711">
Punta Capocchia
</a>
</li>
<li>
<a class="button" data-action="marker#go" data-controller="marker" data-marker-coords-value="40.556512 14.198711">
Punta del Miglio
</a>
</li>
<li>
<a class="button" data-action="marker#go" data-controller="marker" data-marker-coords-value="40.549190 14.198606">
Punta Campetiello
</a>
</li>
<li>
<a class="button" data-action="marker#go" data-controller="marker" data-marker-coords-value="40.5473633 14.1992508">
Rio Latino - Cala di Mezzo
</a>
</li>
<li>
<a class="button" data-action="marker#go" data-controller="marker" data-marker-coords-value="40.5469179 14.2022463">
Località Pino
</a>
</li>
<li>
<a class="button" data-action="marker#go" data-controller="marker" data-marker-coords-value="40.541755 14.197580">
Punta del Pino
</a>
</li>
<li>
<a class="button" data-action="marker#go" data-controller="marker" data-marker-coords-value="40.5386677 14.1997139">
Capo Ruglio-Limmo
</a>
</li>
<li>
<a class="button" data-action="marker#go" data-controller="marker" data-marker-coords-value="40.5399062 14.2098143">
Belvedere della Migliara
</a>
</li>
<li>
<a class="button" data-action="marker#go" data-controller="marker" data-marker-coords-value="40.5367431 14.1995263">
Punta Carena-Limmo
</a>
</li>
<li>
<a class="button" data-action="marker#go" data-controller="marker" data-marker-coords-value="40.558507 14.200558">
Punta dell'Arcera
</a>
</li>
<li>
<a class="button" data-action="marker#go" data-controller="marker" data-marker-coords-value="40.542092 14.223073">
Monte Solaro
</a>
</li>
<li>
<a class="button" data-action="marker#go" data-controller="marker" data-marker-coords-value="40.5425792 14.2299374">
Punta Mulo
</a>
</li>
</ul>
</li> </li>
<li class="mt-3" data-list-id="preist-capri-sub"> <li class="mt-3" data-list-id="prehistoric-capri-sub">
<span class="is-clickable" data-action="click->menu#openSubList" data-list-id="preist-capri-sub"> <span role="button" class="is-clickable" data-action="click->menu#openSubList" data-list-id="prehistoric-capri-sub">
Capri Capri
<span class="icon ml-2 is-small" data-list-id="preist-capri-sub"> <span class="icon ml-2 is-small" data-list-id="prehistoric-capri-sub">
<i class="fa fa-chevron-right"></i> <i class="fa fa-chevron-right"></i>
</span> </span>
</span> </span>
<ul id="preist-capri-sub" class="is-hidden">
<li>
<a class="button" data-action="marker#go" data-controller="marker" data-marker-coords-value="40.558602 14.2233">
Artimo
</a>
</li>
<li>
<a class="button" data-action="marker#go" data-controller="marker" data-marker-coords-value="40.552006 14.2300939">
Calcara
</a>
</li>
<li>
<a class="button" data-action="marker#go" data-controller="marker" data-marker-coords-value="40.5495598 14.2442728">
Camerelle, Hotel Quisisana
</a>
</li>
<li>
<a class="button" data-action="marker#go" data-controller="marker" data-marker-coords-value="40.5512194 14.2487155">
Croce
</a>
</li>
<li>
<a class="button" data-action="marker#go" data-controller="marker" data-marker-coords-value="40.5516843 14.2514713">
Fondo Mongiardino
</a>
</li>
<li>
<a class="button" data-action="marker#go" data-controller="marker" data-marker-coords-value="40.5489554 14.2347825">
La Torina
</a>
</li>
<li>
<a class="button" data-action="marker#go" data-controller="marker" data-marker-coords-value="40.5500081 14.2377156">
Le Parate
</a>
</li>
<li>
<a class="button" data-action="marker#go" data-controller="marker" data-marker-coords-value="40.55918 14.259928">
Lo Capo
</a>
</li>
<li>
<a class="button" data-action="marker#go" data-controller="marker" data-marker-coords-value="40.5517999 14.2283005">
LAnginola
</a>
</li>
<li>
<a class="button" data-action="marker#go" data-controller="marker" data-marker-coords-value="40.5562267 14.2350889">
Marina Grande, Chiesa di S. Costanzo
</a>
</li>
<li>
<a class="button" data-action="marker#go" data-controller="marker" data-marker-coords-value="40.5474502 14.2533369">
Tragara
</a>
</li>
<li>
<a class="button" data-action="marker#go" data-controller="marker" data-marker-coords-value="40.5534825 14.2329379">
Veruotto
</a>
</li>
<li>
<a class="button" data-action="marker#go" data-controller="marker" data-marker-coords-value="40.5504548 14.2340138">
Via Aiano di Sopra
</a>
</li>
<li>
<a class="button" data-action="marker#go" data-controller="marker" data-marker-coords-value="40.54917684 14.23908714">
Via Castiglione snc
</a>
</li>
<li>
<a class="button" data-action="marker#go" data-controller="marker" data-marker-coords-value="40.546096 14.240045">
Via Krupp
</a>
</li>
</ul>
</li> </li>
</ul> </ul>
<p class="menu-label is-size-5 is-clickable" data-id="subacquei"> <p class="menu-label is-size-5 is-clickable" data-id="underwater">
<span class="icon pl-1 mr-2 is-small" title="Nascondi" data-layer-target="underwater" data-action="click->layer#toggle"> <span class="icon pl-1 mr-2 is-small" title="Nascondi" data-layer-target="underwater" data-action="click->layer#toggle">
<i class="fa fa-xs fa-eye-slash" data-layer-target="icon"></i> <i class="fa fa-xs fa-eye-slash" data-layer-target="icon"></i>
</span> </span>
<span class="icon pr-1"> <span class="icon pr-1">
<img class="image" src="img/icons/subacquei_menu.png"/> <img class="image" src="img/icons/subacquei_menu.png"/>
</span> </span>
<span data-action="click->menu#toggle" data-id="subacquei"> <span role="button" data-action="click->menu#toggle" data-id="underwater">
Giacimenti subacquei Giacimenti subacquei
<span class="icon pl-2"> <span class="icon pl-2">
<i class="fa fa-chevron-right" data-menu-target="icon" data-id="subacquei"></i> <i class="fa fa-chevron-right" data-menu-target="icon" data-id="underwater"></i>
</span> </span>
</span> </span>
</p> </p>
<ul class="menu-list is-hidden" id="subacquei-list" data-menu-target="list" data-controller="marker"> <ul class="menu-list is-hidden" id="underwater-list" data-menu-target="list" data-controller="marker">
<li> <li>
<a class="button" data-action="marker#go" data-controller="marker" data-marker-coords-value="40.5511022 14.1910274"> <a class="button" data-action="marker#go" data-controller="marker" data-marker-coords-value="40.5511022 14.1910274">
Bocca Grande - relitto con carico Bocca Grande - relitto con carico
</a> </a>
</li> </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.5649884 14.1940185">
Punta dellArcera - relitto con carico
</a>
</li>
<li> <li>
<a class="button" data-action="marker#go" data-controller="marker" data-marker-coords-value="40.5870549 14.2887986"> <a class="button" data-action="marker#go" data-controller="marker" data-marker-coords-value="40.5870549 14.2887986">
Bocca Piccola - relitto con carico Bocca Piccola - relitto con carico
</a> </a>
</li> </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> <li>
<a class="button" data-action="marker#go" data-controller="marker" data-marker-coords-value="40.54468634 14.23392751"> <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 Marina Piccola, Scoglio delle Sirene - strutture portuali, approdo
</a> </a>
</li> </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>
</ul> </ul>
</aside> </aside>
</div> </div>
<div class="menu-overlay column is-hidden is-3 is-3-desktop is-4-mobile is-pulled-right is-overlay has-background-white-ter"
data-menu-target="cartography">
<!-- Template to build menu items dynamically -->
<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>
</aside>
</div>
<!-- Search modal -->
<div class="modal" id="search" data-modal-target="modal">
<div class="modal-background" data-action="click->modal#close click->tabs#reset"></div>
<div class="modal-content has-background-white pt-4 mr-4 ml-4 pl-4 pr-4" style="min-height: 400px;">
<h1 class="is-size-4 has-text-centered">Ricerca</h1>
<div class="field">
<label class="label">Testo libero</label>
<div class="control is-full-width">
<input class="input" type="text" placeholder="Inserire parole chiave">
</div>
</div>
<div class="columns mt-5 pt-3">
<div class="field column">
<label class="label">Categoria sito</label>
<div class="control">
<div class="select">
<select>
<option default>-- Scegliere la categoria del sito --</option>
<option>Sito conservato</option>
<option>Sito non conservato</option>
</select>
</div>
</div>
</div>
<div class="field column">
<label class="label">Categoria reperto</label>
<div class="control">
<div class="select">
<select>
<option default>-- Scegliere la categoria del reperto --</option>
<option>Scultura</option>
<option>Epigrafe</option>
<option>Elemento architettonico</option>
<option>Decorazione parietale</option>
<option>Pavimentazione</option>
<option>Arredo</option>
<option>Abbigliamento e ornamenti personali</option>
</select>
</div>
</div>
</div>
<div class="field column">
<label class="label">Tecnica muraria</label>
<div class="control">
<div class="select">
<select>
<option default>-- Scegliere tecnica --</option>
<option>Opera poligonale</option>
<option>Opera incerta</option>
<option>Opera reticolata</option>
<option>Opera laterizia</option>
<option>Opera mista</option>
<option>Opera cementizia</option>
</select>
</div>
</div>
</div>
</div>
<div class="field is-grouped mt-5 has-text-right">
<div class="control">
<button class="button is-link">
<span>Cerca</span>
<span class="icon is-small">
<i class="fa fa-search"></i>
</span>
</button>
</div>
<div class="control">
<button class="button is-link is-light">
<span>Cancella filtri</span>
<span class="icon is-small">
<i class="fa fa-times"></i>
</span>
</button>
</div>
</div>
</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 marker" 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>
@@ -859,12 +547,63 @@
<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>
<!-- Underwater modal --> <!-- Underwater modal -->
<div class="modal" id="underwater-data" data-controller="modal biblio marker" data-modal-target="modal"> <div class="modal" id="underwater-data" data-controller="modal 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"> <div class="modal-content has-background-white">
<div id="underwater-sheet"></div> <div class="tabs is-centered">
<ul>
<li class="is-active" id="for-underwater-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="underwater-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>
<!-- Reuse modal -->
<div class="modal" id="reuse-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-content has-background-white">
<div class="tabs is-centered">
<ul>
<li class="is-active" id="for-reuse-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="reuse-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> </div>
<!-- Spherical photo modal --> <!-- Spherical photo modal -->
<div class="modal" id="spherical-modal"> <div class="modal" id="spherical-modal">

View File

@@ -1,4 +1,4 @@
import { GisState } from "../state.js"; import Utils from "./utils.js";
/** /**
* @class Finding * @class Finding
*/ */
@@ -23,7 +23,7 @@ export class Finding {
<strong>Misure:</strong> ${this._data.measurements} <strong>Misure:</strong> ${this._data.measurements}
</p> </p>
<p class="p-2"> <p class="p-2">
<strong>Luogo e anno rinvenimento:</strong> ${this._data.place}. ${this._data.year} <strong>Luogo e anno rinvenimento:</strong> ${Utils.parseMarkers(this._data.place)}. ${this._data.year}
</p> </p>
<p class="p-2"> <p class="p-2">
<strong>Datazione:</strong> ${this._data.dating} <strong>Datazione:</strong> ${this._data.dating}
@@ -36,7 +36,7 @@ export class Finding {
</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</strong></br>
${this._data.description} ${Utils.parseMarkers(this._data.description)}
</p> </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">
@@ -50,64 +50,25 @@ export class Finding {
</p> </p>
</div>`; </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="finding-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 {HTMLElement} imageContainer
* @param {Function} gallery * @param {Function} gallery
*/ */
async setImages(imageContainer, gallery) { async setImages(imageContainer, gallery) {
let record = await this.fetchData(`${GisState.apiUrl}/finding/${this._data.id}`) if (this._data.images?.length) {
imageContainer.innerHTML = Utils.renderImages('finding-gallery', this._data.images);
if (record.images.length) { gallery('finding-gallery', this._data.images);
this.images = record.images; } else
imageContainer.innerHTML = this.renderImages(); imageContainer.innerHTML = '<p class="has-text-centered">Nessuna risorsa visuale disponibile</p>';
gallery('finding-gallery', this.images);
}
} }
/** /**
* @param {number} recordId * @param {number} recordId
*/ */
async biblio(recordId) { async biblio(recordId) {
let finding = await this.fetchData(`${GisState.apiUrl}/finding/${recordId}`); let {citations, biblioElements} = await Utils.buildBibliography('finding', recordId);
this.biblioElements = biblioElements;
let citations = ''; return citations;
if (finding.bibliography.length) {
finding.bibliography.forEach(record => {
citations += `
<span class="is-clickable is-capitalized has-text-link"
data-action="click->biblio#open"
id="cit-${record.id}">
${record.citation.toLowerCase()}</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) { getReference(id) {
@@ -116,8 +77,4 @@ export class Finding {
return ref.match(regex); return ref.match(regex);
}); });
} }
async fetchData(url) {
return await fetch(url).then(res => res.json());
}
} }

View File

@@ -1,4 +1,4 @@
import { GisState } from "../state.js"; import Utils from "./utils.js";
/** /**
* Component to render data for not conserved assets * Component to render data for not conserved assets
@@ -32,11 +32,11 @@ export class NotConserved {
<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> ${Utils.parseMarkers(this._data.genericLocation)}
</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</strong></br>
${this._data.shortDescription} ${Utils.parseMarkers(this._data.shortDescription)}
</p> </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">
@@ -51,116 +51,27 @@ export class NotConserved {
</div>`; </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 {HTMLElement} imageContainer
* @param {Function} gallery * @param {Function} gallery
*/ */
async setImages(imageContainer, gallery) { setImages(imageContainer, gallery) {
if (this._data.images.length) { if (this._data.images?.length) {
this.images = this._data.images; imageContainer.innerHTML = Utils.renderImages('not-conserved-gallery', this._data.images);
imageContainer.innerHTML = this.renderImages(); gallery('not-conserved-gallery', this._data.images);
gallery('not-conserved-gallery', this.images);
} else } else
imageContainer.innerHTML = '<p class="has-text-centered">Nessuna risorsa visuale disponibile</p>'; imageContainer.innerHTML = '<p class="has-text-centered">Nessuna risorsa visuale disponibile</p>';
} }
async renderDocs() { async renderDocs() {
let record = await this.fetchData(`${GisState.apiUrl}/not_conserved/${this._data.id}`); return await Utils.generateDocsTable(this._data, 'not_conserved');
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) { async biblio(recordId) {
let record = await this.fetchData(`${GisState.apiUrl}/not_conserved/${recordId}`); let {citations, biblioElements} = await Utils.buildBibliography('not_conserved', recordId);
this.biblioElements = biblioElements;
let citations = ''; return citations;
if (record.bibliography.length) {
record.bibliography.forEach(record => {
citations += `
<span class="is-clickable is-capitalized has-text-link"
data-action="click->biblio#open"
id="cit-${record.id}">
${record.citation.toLowerCase().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) { getReference(id) {
@@ -169,8 +80,4 @@ export class NotConserved {
return ref.match(regex); return ref.match(regex);
}); });
} }
async fetchData(url) {
return await fetch(url).then(res => res.json());
}
} }

View File

@@ -1,4 +1,4 @@
import { GisState } from "../state.js"; import Utils from "./utils.js";
/** /**
* @class Prehistoric * @class Prehistoric
*/ */
@@ -32,11 +32,11 @@ export class Prehistoric {
<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.genericPlace} <strong>Località generica:</strong> ${Utils.parseMarkers(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 breve</strong></br> <strong class="pb-3">Descrizione breve</strong></br>
${this._data.description} ${Utils.parseMarkers(this._data.description)}
</p> </p>
<p class="p-2"> <p class="p-2">
<strong>Conservazione:</strong> ${this._data.conservation} <strong>Conservazione:</strong> ${this._data.conservation}
@@ -47,7 +47,6 @@ export class Prehistoric {
</div>`; </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>
@@ -58,32 +57,14 @@ export class Prehistoric {
*/ */
} }
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 {HTMLElement} imageContainer
* @param {Function} gallery * @param {Function} gallery
*/ */
async setImages(imageContainer, gallery) { async setImages(imageContainer, gallery) {
if (this._data.images.length) { if (this._data.images?.length) {
this.images = this._data.images; imageContainer.innerHTML = Utils.renderImages('prehist-gallery', this._data.images);
imageContainer.innerHTML = this.renderImages(); gallery('prehist-gallery', this._data.images);
gallery('prehist-gallery', this.images);
} else } else
imageContainer.innerHTML = '<p class="has-text-centered">Nessuna risorsa visuale disponibile</p>'; imageContainer.innerHTML = '<p class="has-text-centered">Nessuna risorsa visuale disponibile</p>';
} }
@@ -91,29 +72,10 @@ export class Prehistoric {
* @param {number} recordId * @param {number} recordId
*/ */
async biblio(recordId) { async biblio(recordId) {
let finding = await this.fetchData(`${GisState.apiUrl}/prehistoric/${recordId}`); let {citations, biblioElements} = await Utils.buildBibliography('prehistoric', recordId);
this.biblioElements = biblioElements;
let citations = ''; return citations;
if (finding.bibliography.length) {
finding.bibliography.forEach(record => {
citations += `
<span class="is-clickable is-capitalized has-text-link"
data-action="click->biblio#open"
id="cit-${record.id}">
${record.citation.toLowerCase()}</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) { getReference(id) {
@@ -122,8 +84,4 @@ export class Prehistoric {
return ref.match(regex); return ref.match(regex);
}); });
} }
async fetchData(url) {
return await fetch(url).then(res => res.json());
}
} }

View File

@@ -0,0 +1,81 @@
import Utils from "./utils.js";
/**
* @class Reuse
*/
export class Reuse {
biblioElements = [];
images = null;
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>Materia:</strong> ${this._data.material}
</p>
<p class="p-2">
<strong>Misure:</strong> ${this._data.measurements}
</p>
<p class="p-2">
<strong>Luogo di conservazione:</strong> ${this._data.conservationPlace}
</p>
<p class="p-2">
<strong>Stato di conservazione:</strong> ${this._data.conservationState}
</p>
<p class="p-2">
<strong>Luogo e anno rinvenimento:</strong> ${Utils.parseMarkers(this._data.finding)}
</p>
<p class="p-2">
<strong>Datazione:</strong> ${this._data.dating}
</p>
<p class="mt-4 pl-2 pr-5">
<strong class="pb-3">Descrizione</strong></br>
${Utils.parseMarkers(this._data.description)}
</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>`;
}
/**
* @param {HTMLElement} imageContainer
* @param {Function} gallery
*/
async setImages(imageContainer, gallery) {
if (this._data.images?.length) {
imageContainer.innerHTML = Utils.renderImages('reuse-gallery', this._data.images);
gallery('reuse-gallery', this._data.images);
} else
imageContainer.innerHTML = '<p class="has-text-centered">Nessuna risorsa visuale disponibile</p>';
}
/**
* @param {Number} recordId
*/
async biblio(recordId) {
let {citations, biblioElements} = await Utils.buildBibliography('reuse', recordId);
this.biblioElements = biblioElements;
return citations;
}
getReference(id) {
return this.biblioElements.find(ref => {
let regex = new RegExp('ref-'+id+'"');
return ref.match(regex);
});
}
}

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')
@@ -20,9 +28,6 @@ export class SiteDocuments {
let content = ` let content = `
<div class="has-bottom-border"> <div class="has-bottom-border">
<p class="p-2 has-text-centered mt-3 mb-3">
${this._siteData.documentation}
</p>
<div class="p-2"> <div class="p-2">
<table class="p-4 table is-fullwidth is-striped"> <table class="p-4 table is-fullwidth is-striped">
<thead> <thead>

View File

@@ -43,4 +43,21 @@ export class SiteMedia {
</div> </div>
`; `;
} }
renderReconstructions() {
return `
<div class="content has-text-centered mb-5 pb-5">
<p class="is-size-5 mt-3">Ricostruzioni 3D</p>
<div style="max-width: 70%; margin: 0 auto">
<p class="is-size-6 has-text-centered">Gallery ricostruzioni 3D</p>
<figure class="is-relative is-clickable has-text-centered" id="gallery-3d">
<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>
`;
}
} }

View File

@@ -1,14 +1,10 @@
import Utils from "./utils.js";
/** /**
* Component to render data for site sheet * Component to render data for site sheet
* @class SiteSheet * @class SiteSheet
*/ */
export class SiteSheet { export class SiteSheet {
biblioElements = []; biblioElements = [];
/*
constructor(data) {
this._siteData = data;
}
*/
/** /**
* @param {object} data * @param {object} data
*/ */
@@ -16,9 +12,13 @@ export class SiteSheet {
this._siteData = data; this._siteData = data;
} }
/** /**
* @todo Refactor!
* @returns {string} HTML * @returns {string} HTML
*/ */
render() { render() {
const description = Utils.parseMarkers(this._siteData.description);
const localization = Utils.parseMarkers(this._siteData.localization);
return `<div class="container has-bottom-border"> return `<div class="container has-bottom-border">
<table class="table is-fullwidth is-striped"> <table class="table is-fullwidth is-striped">
<tr class="is-link"><th class="is-size-5 has-text-centered" colspan=2>Identificazione</th></tr> <tr class="is-link"><th class="is-size-5 has-text-centered" colspan=2>Identificazione</th></tr>
@@ -28,7 +28,7 @@ export class SiteSheet {
<tr><th>Comune</th><td>${this._siteData.municipality}</td></tr> <tr><th>Comune</th><td>${this._siteData.municipality}</td></tr>
<tr><th>Indirizzo</th><td>${this._siteData.address}</td></tr> <tr><th>Indirizzo</th><td>${this._siteData.address}</td></tr>
<tr><th>Località</th><td>${this._siteData.place}</td></tr> <tr><th>Località</th><td>${this._siteData.place}</td></tr>
<tr><th>Localizzazione</th><td>${this._siteData.localization}</td></tr> <tr><th>Localizzazione</th><td>${localization}</td></tr>
<tr class="is-link"><th class="is-size-5 has-text-centered" colspan=2>Cronologia</th></tr> <tr class="is-link"><th class="is-size-5 has-text-centered" colspan=2>Cronologia</th></tr>
<tr><th>Periodo</th><td>${this._siteData.period}</td></tr> <tr><th>Periodo</th><td>${this._siteData.period}</td></tr>
<tr><th>Fase</th><td>${this._siteData.phase}</td></tr> <tr><th>Fase</th><td>${this._siteData.phase}</td></tr>
@@ -38,13 +38,13 @@ export class SiteSheet {
<tr><th>Stato di conservazione</th><td>${this._siteData.conservationState}</td></tr> <tr><th>Stato di conservazione</th><td>${this._siteData.conservationState}</td></tr>
<tr><th>Tecniche edilizie impiegate:</th><td>${this._siteData.techniques}</td></tr> <tr><th>Tecniche edilizie impiegate:</th><td>${this._siteData.techniques}</td></tr>
<tr class="is-link"><th class="is-size-5 has-text-centered" colspan=2>Ritrovamento e materiali</th></tr> <tr class="is-link"><th class="is-size-5 has-text-centered" colspan=2>Ritrovamento e materiali</th></tr>
<tr><th>Anno di ritrovamento</th><td>${this._siteData.finding}</td></tr> <tr><th>Modalità e anno di ritrovamento</th><td>${Utils.parseMarkers(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>${Utils.parseMarkers(this._siteData.conservationPlace)}</td></tr>
<tr class="is-link"><th class="is-size-5 has-text-centered" colspan=2>Rilievi</th></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><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 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><td class="pr-6 pl-6 pt-3" colspan="2">${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>
@@ -60,6 +60,8 @@ export class SiteSheet {
} }
renderShort() { renderShort() {
const shortDesc = Utils.parseMarkers(this._siteData.shortDescription);
return ` return `
<div class="container p-3"> <div class="container p-3">
<p class="p-2"> <p class="p-2">
@@ -81,7 +83,7 @@ export class SiteSheet {
<strong>Località generica:</strong> ${this._siteData.genericPlace} <strong>Località generica:</strong> ${this._siteData.genericPlace}
</p> </p>
<p class="mt-4 pl-2 pr-5"> <p class="mt-4 pl-2 pr-5">
${this._siteData.shortDescription} ${shortDesc}
</p> </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">
@@ -102,10 +104,10 @@ 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()}</span>`; ${record.citation.trim()}</span>`;
citations += record.pages?.length ? `, ${record.pages};` : ';'; citations += record.pages?.length ? `, ${record.pages};` : ';';

View File

@@ -1,3 +1,4 @@
import Utils from "./utils.js";
/** /**
* @class Underwater * @class Underwater
*/ */
@@ -27,15 +28,26 @@ export class Underwater {
</p> </p>
<p class="mt-4 pl-2 pr-5"> <p class="mt-4 pl-2 pr-5">
<strong class="pb-3">Descrizione breve</strong></br> <strong class="pb-3">Descrizione breve</strong></br>
${this._data.shortDescription} ${Utils.parseMarkers(this._data.shortDescription)}
</p> </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>
</div>`; </div>`;
} }
/**
* @param {HTMLElement} imageContainer
* @param {Function} gallery
*/
setImages(imageContainer, gallery) {
if (this._data.images?.length) {
imageContainer.innerHTML = Utils.renderImages('underwater-gallery', this._data.images);
gallery('underwater-gallery', this._data.images);
} else
imageContainer.innerHTML = '<p class="has-text-centered">Nessuna risorsa visuale disponibile</p>';
}
async fetchData(url) { async renderDocs() {
return await fetch(url).then(res => res.json()); return await Utils.generateDocsTable(this._data, 'underwater');
} }
} }

View File

@@ -0,0 +1,175 @@
import { GisState } from "../state.js";
/**
* @namespace Utils
*/
const Utils = {};
/**
*
* @param {string} galleryId The image gallery's id
* @param {Object} imagesData
* @returns {string}
*/
Utils.renderImages = function (galleryId, imagesData) {
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="${galleryId}">
<img src="img/${imagesData[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 {Object} imagesData
* @param {HTMLElement} imageContainer
* @param {Function} galleryGenerator The function that creates the image gallery
* @param {string} galleryId The image gallery's id
*/
Utils.setImages = function(imagesData, imageContainer, galleryGenerator, galleryId) {
imageContainer.innerHTML = Utils.renderImages(galleryId);
galleryGenerator(galleryId, imagesData);
}
/**
*
* @param {Object} data The component's data
* @param {String} resourceUri The resource URI to be used for API calls
* @returns {String} The table HTML
*/
Utils.generateDocsTable = async function(data, resourceUri) {
let record = await Utils.fetchData(`${GisState.apiUrl}/${resourceUri}/${data.id}`);
// TODO Horrible??
if (record instanceof Error) return '<p class="has-text-centered">Nessun documento disponibile.</p>';
const documentation = record.documents.filter(d => d.type === 'documentazione')
const 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 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 (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 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 (publications.length === 0 && documentation.length === 0) {
content = '<p class="has-text-centered">Nessun documento disponibile.</p>';
}
return content;
}
/**
*
* @param {String} recordUri The record URI used for API calls
* @param {Number} recordId This record's ID
* @returns {{citations:String,biblioElements:String[]}}
*/
Utils.buildBibliography = async function(recordUri, recordId) {
let record = await Utils.fetchData(`${GisState.apiUrl}/${recordUri}/${recordId}`);
let biblioElements = [];
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};` : ';';
biblioElements.push(`
<div class="p-2 mt-2" id="ref-${record.id}">
<p class="p-3">${record.reference}</p>
</div>
`
);
});
}
const bibliography = {
citations: citations.trim().slice(0, -1),
biblioElements
}
return bibliography;
}
/**
* Parse marker strings (pseudo-shortcodes) and convert them
* to Stimulus links
* @param {String} text - The content text from database
*/
Utils.parseMarkers = function(text) {
const regex = /(?<marker>\[marker coords=\"(?<coords>[\d\s\.]+)\"\ ?(group=\"(?<group>\w+)\")?](?<content>[\s\S]+?)\[\/marker\])/mig;
if (!text) return text;
let matches = [...text.matchAll(regex)];
if (matches.length) {
matches.forEach(match => {
const replacement = `<a class="has-text-link" data-action="marker#go modal#close tabs#reset marker#goAndOpen" data-controller="marker"
data-marker-coords-value="${match.groups.coords}"
data-marker-group-value="${match.groups.group}">${match.groups.content.trim()}</a>`;
text = text.replace(match.groups.marker, replacement.trim());
});
}
return text;
}
Utils.fetchData = async function(url) {
return await fetch(url).then(res => res.ok ? res.json() : new Error())
.catch(err => console.log(err));
}
export default Utils;

View File

@@ -1,8 +1,45 @@
import { Controller } from "@hotwired/stimulus"; import { Controller } from "@hotwired/stimulus";
import { GisState } from "../state.js"; import { GisState } from "../state.js";
import GIS from "../gis.js";
export default class extends Controller { export default class extends Controller {
static targets = ['sites', 'findings', 'notconserved', 'prehist',]; 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? * @todo Use Stimulus values?
@@ -12,17 +49,10 @@ export default class extends Controller {
let map = GisState.map; let map = GisState.map;
let target = event.currentTarget; let target = event.currentTarget;
const id = target.parentElement.getAttribute('data-id'); const id = target.parentElement.getAttribute('data-id');
const layers = {
'siti': GisState.layers.sites,
'non-conser': GisState.layers.notConserved,
'rinv': GisState.layers.findings,
'preist': GisState.layers.prehistoric,
'subacquei': GisState.layers.underwater,
}
let group = layers[id];
this.toggleIcon(event.currentTarget); this.toggleIcon(event.currentTarget);
let group = GisState.layers[id];
if (map.hasLayer(group)) { if (map.hasLayer(group)) {
map.removeLayer(group); map.removeLayer(group);
target.title = "Mostra"; target.title = "Mostra";

View File

@@ -1,5 +1,6 @@
import { Controller } from "@hotwired/stimulus"; import { Controller } from "@hotwired/stimulus";
import { GisState, getMarkerByCoords } from "../state.js"; import { GisState, getMarkerByCoords } from "../state.js";
import UI from "../ui.js";
export default class extends Controller { export default class extends Controller {
static values = { static values = {
@@ -8,17 +9,16 @@ export default class extends Controller {
'id': String, 'id': String,
}; };
END_ZOOM = 19; uiModals = {
// Animation breaks automatic tooltip opening... sites: '#site-data',
mapAnimate = { notConserved: '#not-conser-data',
animate: true, finding: '#finding-data',
duration: 1, prehist: '#prehist-data',
easeLinearity: 0.25 reuse: '#reuse-data',
}; };
/** END_ZOOM = 19;
* @param {Event} event
*/
go() { go() {
let map = GisState.map; let map = GisState.map;
const coords = this.coordsValue.split(' '); const coords = this.coordsValue.split(' ');
@@ -31,8 +31,40 @@ export default class extends Controller {
let marker = this.getMarker(map, coords); let marker = this.getMarker(map, coords);
// DEBUG for sites // DEBUG for sites
if (this.groupValue) marker = getMarkerByCoords(coords, this.groupValue); //if (this.groupValue) marker = getMarkerByCoords(coords, this.groupValue);
marker?.openTooltip(); marker?.openTooltip();
return marker;
}
/**
* Go to a marker location on the map
* and open its modal
*/
goAndOpen() {
const marker = this.go();
const selector = this.uiModals[this.groupValue];
const data = marker.options.data;
switch(this.groupValue) {
case 'sites':
UI.openSiteModal(data, selector);
break;
case 'notConserved':
UI.openNotConserModal(data, selector);
break;
case 'finding':
UI.openFindingModal(data, selector);
break;
case 'prehist':
UI.openPrehistModal(data, selector);
break;
case 'reuse':
UI.openReuseModal(data, selector);
break;
default:
console.log('Cannot open modal...');
break;
}
} }
/** /**
* @param {L.Map} map * @param {L.Map} map

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

@@ -5,20 +5,20 @@ 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"; import { GisState } from "./state.js";
import Options from "./layer_options.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;
} }
GisState.apiUrl = API_URL; GisState.apiUrl = API_URL;
// Global leaflet // Global leaflet and proj4
/** /**
* @namespace GIS * @namespace GIS
*/ */
@@ -29,47 +29,6 @@ GIS.INIT_ZOOM = 14;
GIS.MIN_ZOOM = 11; GIS.MIN_ZOOM = 11;
GIS.MAX_ZOOM = 24; GIS.MAX_ZOOM = 24;
const optionsVincoli = {
color: '#222',
opacity: 0.8,
weight: 1,
fillColor: '#fa7861',
fillOpacity: 0.8
};
const optionsSiti = {
color: '#800040',
opacity: 1,
weight: 1.5,
fillColor: '#800040',
fillOpacity: 0.8
};
const optionsGrotta = {
color: '#205dac',
opacity: 1,
weight: 1.5,
fillColor: '#205dac',
fillOpacity: 0.8
}
const optionsPaesistici = {
color: '#222',
opacity: 1,
weight: 1.5,
fillColor: '#88d28d',
fillOpacity: 0.8
};
const optionsFabbricati = {
color: '#222',
opacity: 1,
weight: 1.5,
fillColor: '#5b5d5f',
fillOpacity: 0.8
};
const clusterOptions = {
spiderfyOnMaxZoom: false,
showCoverageOnHover: false,
disableClusteringAtZoom: 19,
};
/** /**
* Capitalize a text string * Capitalize a text string
* @todo Move to utils * @todo Move to utils
@@ -109,40 +68,100 @@ GIS.initMap = async function (mapId, zoomLevel = this.INIT_ZOOM) {
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.loadGeoJSON('vincoli.geojson', optionsVincoli); let layerVincoli = await this.loadGeoJSON('vincoli.geojson', Options.constraintsArch);
let layerPaesistici = await this.loadGeoJSON('paesistici.geojson', optionsPaesistici); let layerPaesistici = await this.loadGeoJSON('paesistici.geojson', Options.constraintsLand);
let buildings = await this.loadGeoJSON('fabbricati.geojson', Options.buildings, false);
this.addLayerGroups(map); await this.addLayerGroups(map);
await this.fetchCartographyLayers();
const archeo = { const reprojectedWMSLayer = GIS.reprojectWMS();
const wmsLayer = new reprojectedWMSLayer(
'https://wms.cartografia.agenziaentrate.gov.it/inspire/wms/ows01.php?',
{
layers: 'CP.CadastralParcel,codice_plla,fabbricati',
transparent: true,
format: 'image/png',
version: '1.1.1',
minZoom: this.INIT_ZOOM,
maxZoom: this.MAX_ZOOM,
tileSize: 1024,
opacity: 0.6,
}
);
const cartography = {
'Catasto Agenzia delle Entrate (zoom per visualizzare)' : wmsLayer,
'Fabbricati' : buildings,
'Vincoli archeologici' : layerVincoli, 'Vincoli archeologici' : layerVincoli,
'Vincoli paesistici' : layerPaesistici, 'Vincoli archeologici indiretti' : layerPaesistici,
}; };
L.control.layers(baseMap, archeo).addTo(map); L.control.layers(baseMap, cartography).addTo(map);
GisState.map = map; GisState.map = map;
return map; return map;
} }
/**
* 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 * Add layer groups to map
*/ */
GIS.addLayerGroups = function (map) { GIS.addLayerGroups = async function (map) {
// Can be included in Promise.all // Can be included in Promise.all
// if it returns only one group... // if it returns only one group...
this.sites().then(data => { const sites = await this.sites();
data.markers.addTo(map); sites.markers.addTo(map);
data.geom.addTo(map); sites.geom.addTo(map);
});
Promise.all( const groups = await Promise.all(
[ [
this.notConserved(), this.notConserved(),
this.findings(), this.findings(),
this.prehistoric(), this.prehistoric(),
this.underwater(), this.underwater(),
this.reuse(),
] ]
) );
.then(groups => groups.forEach(group => group.addTo(map))); groups.forEach(group => group.addTo(map));
} }
/** /**
* Create markers for sites * Create markers for sites
@@ -152,21 +171,26 @@ GIS.sites = async function () {
let sitesData = await fetch(`${API_URL}/sites`) let sitesData = await fetch(`${API_URL}/sites`)
.then(data => data.json()); .then(data => data.json());
let sites = L.markerClusterGroup(clusterOptions); let sites = L.markerClusterGroup(Options.cluster);
let geom = []; let geom = [];
for (let record of sitesData) { for (let record of sitesData) {
if (record.geojson) { if (record.geojson) {
const options = record.gisId === 'grotta_azzurra' ? const options = record.gisId === 'grotta_azzurra' ?
optionsGrotta : optionsSiti; Options.grotta : Options.site;
geom.push(await this.loadSiteLayer(record, options)); geom.push(await this.loadSiteLayer(record, options));
} }
if (record.area) {
const options = record.gisId === 'villa_bismarck' ?
Options.bismarck : Options.site;
geom.push(await this.loadSiteLayer(record, options, false, true));
}
const marker = L.marker( const marker = L.marker(
record.coordinates, record.coordinates,
{icon: Icons.site, label: record.label} {icon: Icons.site, label: record.label}
) )
.bindTooltip(record.label + '<br>(Clicca per aprire scheda)') .bindTooltip(record.label)
.on( .on(
'click', 'click',
() => UI.openSiteModal(record, '#site-data') () => UI.openSiteModal(record, '#site-data')
@@ -175,7 +199,8 @@ GIS.sites = async function () {
sites.addLayer(marker); sites.addLayer(marker);
// Populate app state for reuse and avoid window.Sites etc. // Populate app state for reuse and avoid window.Sites etc.
// Municipality (Capri, Anacapri) added for reuse in dynamic menu // Municipality (Capri, Anacapri) added for reuse in dynamic menu
marker.options.municipalilty = record.municipalilty; marker.options.municipality = record.municipality;
marker.options.data = record;
const markerIndex = `${record.coordinates[0]} ${record.coordinates[1]}`; const markerIndex = `${record.coordinates[0]} ${record.coordinates[1]}`;
GisState.markers.sites[markerIndex] = marker; GisState.markers.sites[markerIndex] = marker;
} }
@@ -192,16 +217,21 @@ 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(clusterOptions); let notConserved = L.markerClusterGroup(Options.cluster);
for (let record of notConserData.records) { for (let record of notConserData.records) {
const marker = L.marker(record.coordinates, {icon: Icons.notConserved}) const marker = L.marker(
.bindTooltip(record.denomination) record.coordinates,
{icon: Icons.notConserved, label: record.label}
)
.bindTooltip(record.label)
.on('click', () => UI.openNotConserModal(record, '#not-conser-data')); .on('click', () => UI.openNotConserModal(record, '#not-conser-data'));
notConserved.addLayer(marker); notConserved.addLayer(marker);
// Populate app state for reuse and avoid window.Sites etc. // Populate app state for reuse and avoid window.Sites etc.
const markerLabel = `${record.coordinates[0]} ${record.coordinates[1]}`; const markerLabel = `${record.coordinates[0]} ${record.coordinates[1]}`;
marker.options.municipality = record.municipality;
marker.options.data = record;
GisState.markers.notConserved[markerLabel] = marker; GisState.markers.notConserved[markerLabel] = marker;
} }
@@ -218,12 +248,14 @@ GIS.findings = async function () {
.then(data => data.json()); .then(data => data.json());
let findings = L.markerClusterGroup( let findings = L.markerClusterGroup(
clusterOptions Options.cluster
); );
for (let record of findingsData) { for (let record of findingsData) {
const marker = L.marker(record.coordinates, {icon: Icons.finding} const marker = L.marker(
).bindTooltip(record.object) record.coordinates,
{icon: Icons.finding, label: record.label}
).bindTooltip(record.label)
.on( .on(
'click', 'click',
() => UI.openFindingModal(record, '#finding-data') () => UI.openFindingModal(record, '#finding-data')
@@ -231,6 +263,8 @@ GIS.findings = async function () {
findings.addLayer(marker); findings.addLayer(marker);
const markerLabel = `${record.coordinates[0]} ${record.coordinates[1]}`; const markerLabel = `${record.coordinates[0]} ${record.coordinates[1]}`;
marker.options.municipality = record.municipality;
marker.options.data = record;
GisState.markers.findings[markerLabel] = marker; GisState.markers.findings[markerLabel] = marker;
} }
@@ -247,20 +281,22 @@ GIS.prehistoric = async function () {
.then(data => data.json()); .then(data => data.json());
let prehistoric = L.markerClusterGroup( let prehistoric = L.markerClusterGroup(
clusterOptions Options.cluster
); );
for (let record of data.records) { for (let record of data.records) {
const marker = L.marker( const marker = L.marker(
record.coordinates, record.coordinates,
{icon: Icons.prehistoric} {icon: Icons.prehistoric, label: record.label}
).bindTooltip(record.denomination) ).bindTooltip(record.label)
.on( .on(
'click', 'click',
() => UI.openPrehistModal(record, '#prehist-data') () => UI.openPrehistModal(record, '#prehist-data')
); );
const markerLabel = `${record.coordinates[0]} ${record.coordinates[1]}`; const markerLabel = `${record.coordinates[0]} ${record.coordinates[1]}`;
marker.options.municipality = record.municipality;
marker.options.data = record;
GisState.markers.prehistoric[markerLabel] = marker; GisState.markers.prehistoric[markerLabel] = marker;
prehistoric.addLayer(marker); prehistoric.addLayer(marker);
@@ -278,20 +314,21 @@ GIS.underwater = async function () {
let underwaterData = await fetch(`${API_URL}/underwater`) let underwaterData = await fetch(`${API_URL}/underwater`)
.then(data => data.json()); .then(data => data.json());
let underwater = L.markerClusterGroup(clusterOptions); let underwater = L.markerClusterGroup(Options.cluster);
for (let record of underwaterData.records) { for (let record of underwaterData.records) {
const marker = L.marker( const marker = L.marker(
record.coordinates, record.coordinates,
{icon: Icons.underwater} {icon: Icons.underwater}
).bindTooltip(record.denomination) ).bindTooltip(record.label)
.on( .on(
'click', 'click',
() => UI.openUnderwaterModal(record, '#underwater-data') () => UI.openUnderwaterModal(record, '#underwater-data')
); );
const markerLabel = `${record.coordinates[0]} ${record.coordinates[1]}`; const markerLabel = `${record.coordinates[0]} ${record.coordinates[1]}`;
GisState.markers.prehistoric[markerLabel] = marker; marker.options.data = record;
GisState.markers.underwater[markerLabel] = marker;
underwater.addLayer(marker); underwater.addLayer(marker);
} }
@@ -300,10 +337,42 @@ GIS.underwater = async function () {
return underwater; return underwater;
} }
/**
* Create reused sites group ('reimpiego')
* @returns {L.MarkerClusterGroup}
*/
GIS.reuse = async function () {
let reuseData = await fetch(`${API_URL}/reuse`)
.then(data => data.json());
let reuse = L.markerClusterGroup(Options.cluster);
for (let record of reuseData.records) {
const marker = L.marker(
record.coordinates,
{icon: Icons.reuse}
).bindTooltip(record.label)
.on(
'click',
() => UI.openReuseModal(record, '#reuse-data')
);
const markerLabel = `${record.coordinates[0]} ${record.coordinates[1]}`;
marker.options.municipality = record.municipality;
marker.options.label = record.label;
marker.options.data = record;
GisState.markers.reuse[markerLabel] = marker;
reuse.addLayer(marker);
}
GisState.layers.reuse = reuse;
return reuse;
}
/** /**
* 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}}} * @returns {{baseMap: {"OpenStreetMap": L.TileLayer}}}
*/ */
@@ -322,16 +391,15 @@ GIS.initLayers = async function(map) {
maxZoom: GIS.MAX_ZOOM, maxZoom: GIS.MAX_ZOOM,
attribution: '&copy; Mapbox' attribution: '&copy; Mapbox'
}); });
let boundaries = await this.loadGeoJSON('confini.geojson', {}, false); let boundaries = await this.loadGeoJSON('confini.geojson', {}, false);
let buildings = await this.loadGeoJSON('fabbricati.geojson', optionsFabbricati, false);
let baseCatasto = new L.LayerGroup([buildings, boundaries]);
const baseGroup = new L.LayerGroup([osmap]); const baseGroup = new L.LayerGroup([osmap]);
baseGroup.addTo(map); baseGroup.addTo(map);
const baseMap = { const baseMap = {
"OpenStreetMap" : osmap, "OpenStreetMap" : osmap,
"Satellite" : mapbox, "Satellite" : mapbox,
"Cartografia catastale" : baseCatasto, 'Limiti amministrativi' : boundaries,
}; };
return baseMap; return baseMap;
@@ -412,9 +480,10 @@ GIS.loadGeoJSON = async function (geoJSON, options, popup = true) {
* @param {boolean} popup Should the features have a popup? * @param {boolean} popup Should the features have a popup?
* @returns {L.Layer} * @returns {L.Layer}
*/ */
GIS.loadSiteLayer = async function (site, options, popup = true) { GIS.loadSiteLayer = async function (site, options, popup = true, area = false) {
const geoJSON = `${site.gisId}.geojson`; let geoJSON = site.gisId;
const geo = await fetch(`${BASE_URL}/geojson/${geoJSON}`) geoJSON += area ? '_area.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}`));
@@ -493,11 +562,13 @@ GIS.cacheDBData = async function (layerId, dbId) {
GIS.featurePopup = function (layerName, feature) { GIS.featurePopup = function (layerName, feature) {
const html = ` const html = `
<table class="table is-striped is-size-6 m-2"> <table class="table is-striped is-size-6 m-2">
<tr><th>Oggetto</th><td>${feature.properties.OGGETTO}</td></tr> <tr><th>Oggetto</th><td>${feature.properties.OGGETTO ?? 'n.d.'}</td></tr>
<tr><th>Anno</th><td>${feature.properties.ANNO}</td></tr> <tr><th>Anno</th><td>${feature.properties.ANNO}</td></tr>
<tr><th>Comune</th><td>${capitalize(feature.properties.COMUNE)}</td></tr> <tr><th>Comune</th><td>${capitalize(feature.properties.COMUNE)}</td></tr>
<tr><th>Località</th><td>${capitalize(feature.properties.LOCALITA)}</td></tr> <tr><th>Località</th><td>${capitalize(feature.properties.LOCALITA) ?? 'n.d.'}</td></tr>
<tr><th>Proprietà</th><td>${capitalize(feature.properties.PROPRIETA)}</td></tr> <tr><th>Proprietà</th><td>${capitalize(feature.properties.PROPRIETA) ?? 'n.d.'}</td></tr>
<tr><th>Foglio</th><td>${feature.properties.FOGLIO}</td></tr>
<tr><th>Particella</th><td>${feature.properties.PART_BIS ?? 'n.d.'}</td></tr>
</table> </table>
`; `;
const content = { const content = {
@@ -508,11 +579,54 @@ 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 tileSize = this.getTileSize();
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

@@ -48,6 +48,15 @@ Icons.underwater = L.icon(
} }
); );
Icons.reuse = L.icon(
{
iconUrl: 'img/icons/reimpiego.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

@@ -18,6 +18,10 @@ document.addEventListener('DOMContentLoaded', async () => {
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);

View File

@@ -0,0 +1,54 @@
/**
* @namespace Options
*/
let Options = {};
Options.constraintsArch = {
color: '#222',
opacity: 0.8,
weight: 1,
fillColor: '#fa7861',
fillOpacity: 0.8
};
Options.site = {
color: '#800040',
opacity: 1,
weight: 1.5,
fillColor: '#800040',
fillOpacity: 0.8
};
Options.grotta = {
color: '#205dac',
opacity: 1,
weight: 1.5,
fillColor: '#205dac',
fillOpacity: 0.8
}
Options.bismarck = {
color: '#a4a79a',
opacity: 1,
weight: 1.5,
fillColor: '#a4a79a',
fillOpacity: 0.8
}
Options.constraintsLand = {
color: '#222',
opacity: 1,
weight: 1.5,
fillColor: '#88d28d',
fillOpacity: 0.8
};
Options.buildings = {
color: '#222',
opacity: 1,
weight: 1.5,
fillColor: '#5b5d5f',
fillOpacity: 0.8
};
Options.cluster = {
spiderfyOnMaxZoom: false,
showCoverageOnHover: false,
disableClusteringAtZoom: 19,
};
export default Options;

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": {}

View File

@@ -11,10 +11,11 @@
/** /**
* @typedef {Object} GisStateType * @typedef {Object} GisStateType
* @property {L.Map|null} map * @property {L.Map|null} map
* @property {String|null} apiUrl
* @property {MarkerLookup} markers * @property {MarkerLookup} markers
* @property {LayerGroupLookup} layers * @property {LayerGroupLookup} layers
* @property {Object|null} bibliography * @property {Object|null} bibliography
* @property {String|null} apiUrl
* @property {Object} cartography
*/ */
/** @type {GisStateType} */ /** @type {GisStateType} */
@@ -26,6 +27,7 @@ export const GisState = {
findings: {}, findings: {},
prehistoric: {}, prehistoric: {},
underwater: {}, underwater: {},
reuse: {},
}, },
layers: { layers: {
sites: {}, sites: {},
@@ -33,9 +35,14 @@ export const GisState = {
findings: {}, findings: {},
prehistoric: {}, prehistoric: {},
underwater: {}, underwater: {},
reuse: {},
}, },
bibliography: null, bibliography: null,
apiUrl : null, apiUrl : null,
cartography : {
historic: [],
cadastral: null,
}
} }
/** /**

View File

@@ -10,6 +10,7 @@ import { Finding } from './components/Finding.js';
import { Prehistoric } from './components/Prehistoric.js'; import { Prehistoric } from './components/Prehistoric.js';
import { Underwater } from './components/Underwater.js'; import { Underwater } from './components/Underwater.js';
import { GisState } from "./state.js"; import { GisState } from "./state.js";
import { Reuse } from './components/Reuse.js';
/** /**
* @namespace UI * @namespace UI
@@ -68,31 +69,6 @@ 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
@@ -118,23 +94,21 @@ UI.openSiteModal = function (data, selector) {
let images = modal.querySelector('#photos'); let images = modal.querySelector('#photos');
let docs = modal.querySelector('#documents'); 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();
docs.innerHTML = siteDocs.render();
} else {
docs.innerHTML = `
<p class="has-text-centered">
${data.documentation}
</p>
`;
}
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'); let videos = data.images.filter(i => i.type === 'Video');
let reconstructions = data.images.filter(i => i.type === 'Reconstruction');
if (surveys.length === 0 && photos.length === 0 && videos.length === 0) { const noMedia = surveys.length === 0
&& photos.length === 0
&& reconstructions.length === 0
&& videos.length === 0;
if (noMedia) {
images.innerHTML = '<p class="has-text-centered">Nessuna risorsa visuale disponibile</p>'; images.innerHTML = '<p class="has-text-centered">Nessuna risorsa visuale disponibile</p>';
} }
@@ -147,6 +121,9 @@ UI.openSiteModal = function (data, selector) {
siteMedia.siteData = photos[0] ?? undefined; siteMedia.siteData = photos[0] ?? undefined;
images.innerHTML += photos[0] ? siteMedia.renderPhotos() : ''; images.innerHTML += photos[0] ? siteMedia.renderPhotos() : '';
siteMedia.siteData = reconstructions[0] ?? undefined;
images.innerHTML += reconstructions[0] ? siteMedia.renderReconstructions() : '';
siteMedia.siteData = videos[0] ?? undefined; siteMedia.siteData = videos[0] ?? undefined;
images.innerHTML += videos[0] ? siteMedia.renderVideos() : ''; images.innerHTML += videos[0] ? siteMedia.renderVideos() : '';
} }
@@ -155,6 +132,7 @@ UI.openSiteModal = function (data, selector) {
this.imageGallery('gallery-1', surveys); this.imageGallery('gallery-1', surveys);
this.imageGallery('gallery-2', photos); this.imageGallery('gallery-2', photos);
this.imageGallery('gallery-3d', reconstructions);
this.imageGallery('gallery-video', videos, true); this.imageGallery('gallery-video', videos, true);
} }
/** /**
@@ -234,6 +212,27 @@ UI.openUnderwaterModal = function (data, selector) {
// For Stimulus biblio_controller // For Stimulus biblio_controller
//GisState.bibliography = underwater; //GisState.bibliography = underwater;
underwater.render().then(html => modal.querySelector('#underwater-sheet').innerHTML = html); underwater.render().then(html => modal.querySelector('#underwater-sheet').innerHTML = html);
underwater.renderDocs().then(html => modal.querySelector('#documents').innerHTML = html);
underwater.setImages(modal.querySelector('#photos'), this.imageGallery);
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.openReuseModal = function (data, selector) {
const modal = document.querySelector(selector);
let reuse = new Reuse();
reuse.data = data;
GisState.bibliography = reuse;
// For Stimulus biblio_controller
//GisState.bibliography = underwater;
reuse.render().then(html => modal.querySelector('#reuse-sheet').innerHTML = html);
reuse.setImages(modal.querySelector('#photos'), this.imageGallery);
modal.classList.add('is-active'); modal.classList.add('is-active');
} }
/** /**
@@ -249,8 +248,9 @@ UI.imageGallery = function (galleryId, items, video = false) {
let gallery = []; let gallery = [];
for (let media of items) { for (let media of items) {
let author = media.author ? ` (${media.author})` : ''; let author = media.author ? ` (${media.author})` : '';
let caption = media.caption ?? '';
let mediaObj = { let mediaObj = {
description: media.caption + author description: caption + author
}; };
if (video) { if (video) {

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==