@panoramax/web-viewer 3.2.3-develop-732b95dd → 3.2.3-develop-48da552a

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@panoramax/web-viewer",
3
- "version": "3.2.3-develop-732b95dd",
3
+ "version": "3.2.3-develop-48da552a",
4
4
  "description": "Panoramax web viewer for geolocated pictures",
5
5
  "main": "build/index.js",
6
6
  "author": "Panoramax team",
@@ -526,13 +526,17 @@ export default class Viewer extends PhotoViewer {
526
526
  const mapFiltersMenu = querySelectorDeep("#pnx-map-filters-menu");
527
527
  const fMinDate = mapFiltersMenu?.shadowRoot.getElementById("pnx-filter-date-from");
528
528
  const fMaxDate = mapFiltersMenu?.shadowRoot.getElementById("pnx-filter-date-end");
529
- const fTypeFlat = mapFiltersMenu?.shadowRoot.getElementById("pnx-filter-type-flat");
530
- const fType360 = mapFiltersMenu?.shadowRoot.getElementById("pnx-filter-type-360");
529
+ const fTypes = mapFiltersMenu?.shadowRoot.querySelectorAll("input[name='pnx-filter-type']");
531
530
  const fMapTheme = querySelectorDeep("#pnx-map-theme");
532
531
 
533
532
  let type = "";
534
- if(fType360?.checked && !fTypeFlat?.checked) { type = "equirectangular"; }
535
- if(!fType360?.checked && fTypeFlat?.checked) { type = "flat"; }
533
+ for(let fTypeId = 0 ; fTypeId < fTypes.length; fTypeId++) {
534
+ const fType = fTypes[fTypeId];
535
+ if(fType.checked) {
536
+ type = fType.value;
537
+ break;
538
+ }
539
+ }
536
540
 
537
541
  let qualityscore = [];
538
542
  if(this.map?._hasQualityScore()) {
@@ -2,7 +2,6 @@ import { LitElement, html, css } from "lit";
2
2
  import { classMap } from "lit/directives/class-map.js";
3
3
 
4
4
  const OPENNESS_Y_PCT = { "opened": 0, "half-opened": 0.7, "closed": 1 };
5
- const OPENNESS_Y_PCT_RANGE = { "opened": [0, 0.4], "half-opened": [0.4, 0.8], "closed": [0.8, 1] };
6
5
 
7
6
  /**
8
7
  * BottomDrawer layout offers a mobile-like drawer menu, coming from bottom of the screen.
@@ -27,6 +26,7 @@ export default class BottomDrawer extends LitElement {
27
26
  width: 100%;
28
27
  z-index: 130;
29
28
  pointer-events: none;
29
+ touch-action: none;
30
30
  }
31
31
 
32
32
  .drawer {
@@ -38,7 +38,7 @@ export default class BottomDrawer extends LitElement {
38
38
  flex-direction: column;
39
39
  transition: transform 0.3s ease;
40
40
  will-change: transform;
41
- touch-action: none;
41
+ touch-action: auto;
42
42
  pointer-events: auto;
43
43
  }
44
44
 
@@ -53,9 +53,7 @@ export default class BottomDrawer extends LitElement {
53
53
  display: flex;
54
54
  align-items: center;
55
55
  justify-content: center;
56
- cursor: grab;
57
- touch-action: none;
58
- pointer-events: auto;
56
+ cursor: pointer;
59
57
  }
60
58
 
61
59
  .handle-bar {
@@ -99,7 +97,7 @@ export default class BottomDrawer extends LitElement {
99
97
  this._boundTouchEnd = this._onTouchEnd.bind(this);
100
98
 
101
99
  this._drawerHeight = window.innerHeight - 30;
102
- const drawer = this.shadowRoot?.querySelector(".drawer");
100
+ const drawer = this._getDrawer();
103
101
  if (!drawer) { return; }
104
102
  drawer.style.height = `${this._drawerHeight}px`;
105
103
  drawer.style.maxHeight = `${this._drawerHeight}px`;
@@ -109,9 +107,16 @@ export default class BottomDrawer extends LitElement {
109
107
  attributeChangedCallback(name, old, value) {
110
108
  super.attributeChangedCallback(name, old, value);
111
109
 
112
- if(name === "openness" && value !== "opened") {
113
- const content = this.shadowRoot.querySelector(".content");
114
- if(content) { content.scrollTop = 0; }
110
+ if(name === "openness") {
111
+ // If not fully opened, force content scroll back to top
112
+ if(value !== "opened") {
113
+ const content = this.shadowRoot.querySelector(".content");
114
+ if(content) { content.scrollTop = 0; }
115
+ }
116
+
117
+ // Remove hand-defined transform
118
+ const drawer = this._getDrawer();
119
+ if (drawer) { drawer.style.transform = null; }
115
120
  }
116
121
  }
117
122
 
@@ -121,10 +126,16 @@ export default class BottomDrawer extends LitElement {
121
126
  this._cleanupTouchListeners();
122
127
  }
123
128
 
129
+ /** @private */
130
+ _getDrawer() {
131
+ return this.shadowRoot?.querySelector(".drawer");
132
+ }
133
+
124
134
  /** @private */
125
135
  _onHandleClick() {
126
- if(this.openness === "opened" || this.openness === "closed") { this.openness = "half-opened"; }
136
+ if(this.openness === "opened") { this.openness = "closed"; }
127
137
  else if(this.openness === "half-opened") { this.openness = "opened"; }
138
+ else if(this.openness === "closed") { this.openness = "half-opened"; }
128
139
  }
129
140
 
130
141
  /** @private */
@@ -154,10 +165,19 @@ export default class BottomDrawer extends LitElement {
154
165
  }
155
166
 
156
167
  /** @private */
157
- _onTouchEnd() {
158
- if (!this._isDragging) return;
168
+ _onTouchEnd(e) {
169
+ // Touchend is also called when "clicking" on mobile
170
+ if ((!this._isDragging || Math.abs(this._deltaFingerY) < 30) && !e.target.closest(".handle")) { return; }
171
+ e.preventDefault();
172
+
159
173
  this._isDragging = false;
160
- this._updateDrawerTransform(this._drawerY + this._deltaFingerY, true);
174
+
175
+ if(this._deltaFingerY === 0 && this.openness === "closed") {
176
+ this.openness = "half-opened";
177
+ }
178
+ else {
179
+ this._updateDrawerTransform(this._drawerY + this._deltaFingerY, true);
180
+ }
161
181
 
162
182
  this._cleanupTouchListeners();
163
183
  this._startFingerY = null;
@@ -173,25 +193,32 @@ export default class BottomDrawer extends LitElement {
173
193
 
174
194
  /** @private */
175
195
  _updateDrawerTransform(y, snap = false) {
176
- const drawer = this.shadowRoot?.querySelector(".drawer");
196
+ const drawer = this._getDrawer();
177
197
  if (!drawer) { return; }
178
198
 
179
199
  y = Math.max(0, Math.min(y, this._drawerHeight - 30));
180
200
 
181
201
  // Snap to nearest static position
182
202
  if(snap) {
183
-
184
- const pct = y / (this._drawerHeight - 30);
185
- if(pct > OPENNESS_Y_PCT_RANGE.opened[0] && pct <= OPENNESS_Y_PCT_RANGE.opened[1]) { this.openness = "opened"; }
186
- if(pct > OPENNESS_Y_PCT_RANGE["half-opened"][0] && pct <= OPENNESS_Y_PCT_RANGE["half-opened"][1]) { this.openness = "half-opened"; }
187
- if(pct > OPENNESS_Y_PCT_RANGE.closed[0] && pct <= OPENNESS_Y_PCT_RANGE.closed[1]) { this.openness = "closed"; }
203
+ // Gesture goes up
204
+ if(this._deltaFingerY < 0) {
205
+ if(this.openness === "closed") {
206
+ // How much it goes up ?
207
+ if(Math.abs(this._deltaFingerY) > this._drawerHeight * (1-OPENNESS_Y_PCT["half-opened"])) {
208
+ this.openness = "opened";
209
+ }
210
+ else { this.openness = "half-opened"; }
211
+ }
212
+ else { this.openness = "opened"; }
213
+ }
214
+ // Gesture goes down
215
+ else { this.openness = "closed"; }
216
+
188
217
  this._drawerY = null;
189
- drawer.style.transform = null;
190
- }
191
- // Live drag
192
- else {
193
- drawer.style.transform = `translateY(${y}px)`;
218
+ y = Math.max(0, Math.min(OPENNESS_Y_PCT[this.openness] * this._drawerHeight, this._drawerHeight - 30));
194
219
  }
220
+
221
+ drawer.style.transform = `translateY(${y}px)`;
195
222
  }
196
223
 
197
224
  /** @private */
@@ -5,7 +5,6 @@ import { faSvg, titles } from "../styles";
5
5
  import { faImage } from "@fortawesome/free-solid-svg-icons/faImage";
6
6
  import { faCalendar } from "@fortawesome/free-solid-svg-icons/faCalendar";
7
7
  import { faArrowRight } from "@fortawesome/free-solid-svg-icons/faArrowRight";
8
- import { faPanorama } from "@fortawesome/free-solid-svg-icons/faPanorama";
9
8
  import { faMedal } from "@fortawesome/free-solid-svg-icons/faMedal";
10
9
  import { faInfoCircle } from "@fortawesome/free-solid-svg-icons/faInfoCircle";
11
10
  import { faUser } from "@fortawesome/free-solid-svg-icons/faUser";
@@ -90,10 +89,8 @@ export default class MapFilters extends LitElement {
90
89
  }
91
90
  .pnx-input-shortcuts button {
92
91
  border: none;
93
- height: 20px;
94
- line-height: 20px;
95
- font-size: 0.8em;
96
- padding: 0 8px;
92
+ font-size: 0.75em;
93
+ padding: 2px 6px;
97
94
  vertical-align: middle;
98
95
  background-color: var(--grey-pale);
99
96
  color: var(--black);
@@ -132,12 +129,12 @@ export default class MapFilters extends LitElement {
132
129
  border-top-right-radius: 8px;
133
130
  border-bottom-right-radius: 8px;
134
131
  }
135
- .pnx-checkbox-btns input[type="checkbox"] { display: none; }
136
- .pnx-checkbox-btns input[type="checkbox"]:checked + label {
132
+ .pnx-checkbox-btns input[type="radio"] { display: none; }
133
+ .pnx-checkbox-btns input[type="radio"]:checked + label {
137
134
  background-color: var(--widget-bg-active);
138
135
  color: var(--widget-font-active);
139
136
  }
140
- .pnx-checkbox-btns input[type="checkbox"]:checked + label:first-of-type {
137
+ .pnx-checkbox-btns input[type="radio"]:checked + label:first-of-type {
141
138
  border-right-color: white;
142
139
  }
143
140
 
@@ -158,8 +155,7 @@ export default class MapFilters extends LitElement {
158
155
  showZoomIn: {state: true},
159
156
  minDate: {state: true},
160
157
  maxDate: {state: true},
161
- typeFlat: {state: true},
162
- type360: {state: true},
158
+ type: {state: true},
163
159
  score: {state: true},
164
160
  user: {state: true},
165
161
  };
@@ -217,14 +213,9 @@ export default class MapFilters extends LitElement {
217
213
 
218
214
  this.score = e?.qualityscore?.length < 5 ? e.qualityscore.join(",") : "";
219
215
 
216
+ this.type = "";
220
217
  if(e?.pic_type && e.pic_type != "") {
221
- this.type360 = e.pic_type == "equirectangular";
222
- this.typeFlat = e.pic_type == "flat";
223
- }
224
-
225
- if(this.type360 === this.typeFlat) {
226
- this.type360 = false;
227
- this.typeFlat = false;
218
+ this.type = e.pic_type == "flat" ? "flat" : "equirectangular";
228
219
  }
229
220
  }
230
221
 
@@ -265,8 +256,7 @@ export default class MapFilters extends LitElement {
265
256
  this.shadowRoot.querySelector("#pnx-filter-search-user")?.reset();
266
257
  this.minDate = null;
267
258
  this.maxDate = null;
268
- this.typeFlat = null;
269
- this.type360 = null;
259
+ this.type = "";
270
260
  this.score = null;
271
261
  this.user = null;
272
262
  this._onFormChange();
@@ -302,6 +292,9 @@ export default class MapFilters extends LitElement {
302
292
  <button
303
293
  @click=${this._onShortcutClick("pnx-filter-date-from", new Date(new Date().setMonth(new Date().getMonth() - 1)).toISOString().split("T")[0])}
304
294
  >${this._parent?._t.pnx.filter_date_1month}</button>
295
+ <button
296
+ @click=${this._onShortcutClick("pnx-filter-date-from", new Date(new Date().setMonth(new Date().getMonth() - 6)).toISOString().split("T")[0])}
297
+ >${this._parent?._t.pnx.filter_date_6months}</button>
305
298
  <button
306
299
  @click=${this._onShortcutClick("pnx-filter-date-from", new Date(new Date().setFullYear(new Date().getFullYear() - 1)).toISOString().split("T")[0])}
307
300
  >${this._parent?._t.pnx.filter_date_1year}</button>
@@ -327,19 +320,29 @@ export default class MapFilters extends LitElement {
327
320
  <h4>${fa(faImage)} ${this._parent?._t.pnx.filter_picture}</h4>
328
321
  <div class="pnx-input-group pnx-checkbox-btns" style="justify-content: center;">
329
322
  <input
330
- type="checkbox"
323
+ type="radio"
324
+ id="pnx-filter-type-all"
325
+ name="pnx-filter-type"
326
+ value=""
327
+ .checked=${!this.type || this.type === ""}
328
+ />
329
+ <label for="pnx-filter-type-all">${this._parent?._t.pnx.picture_all}</label>
330
+ <input
331
+ type="radio"
331
332
  id="pnx-filter-type-flat"
332
- name="flat"
333
- .checked=${this.typeFlat}
333
+ name="pnx-filter-type"
334
+ value="flat"
335
+ .checked=${this.type === "flat"}
334
336
  />
335
- <label for="pnx-filter-type-flat">${fa(faImage)} ${this._parent?._t.pnx.picture_flat}</label>
337
+ <label for="pnx-filter-type-flat">${this._parent?._t.pnx.picture_flat}</label>
336
338
  <input
337
- type="checkbox"
339
+ type="radio"
338
340
  id="pnx-filter-type-360"
339
- name="360"
340
- .checked=${this.type360}
341
+ name="pnx-filter-type"
342
+ value="equirectangular"
343
+ .checked=${this.type === "equirectangular"}
341
344
  />
342
- <label for="pnx-filter-type-360">${fa(faPanorama)} ${this._parent?._t.pnx.picture_360}</label>
345
+ <label for="pnx-filter-type-360">${this._parent?._t.pnx.picture_360}</label>
343
346
  </div>
344
347
  </div>
345
348
 
@@ -235,9 +235,9 @@ export default class MapMore extends Map {
235
235
  }
236
236
 
237
237
  if(filters.pic_type && filters.pic_type !== "") {
238
- this._mapFilters.pic_type = filters.pic_type;
239
- mapSeqFilters.push(["==", ["get", "type"], filters.pic_type]);
240
- mapPicFilters.push(["==", ["get", "type"], filters.pic_type]);
238
+ this._mapFilters.pic_type = filters.pic_type === "flat" ? "flat" : "equirectangular";
239
+ mapSeqFilters.push(["==", ["get", "type"], this._mapFilters.pic_type]);
240
+ mapPicFilters.push(["==", ["get", "type"], this._mapFilters.pic_type]);
241
241
  }
242
242
  if(this._hasGridStats()) {
243
243
  reloadMapStyle = true;
@@ -105,11 +105,13 @@
105
105
  "error_api_compatibility": "The pictures server is not compatible with this viewer version",
106
106
  "filter_date": "Date",
107
107
  "filter_date_1month": "1 month",
108
+ "filter_date_6months": "6 months",
108
109
  "filter_date_1year": "1 year",
109
110
  "filter_user": "User",
110
111
  "filter_user_mypics": "My pictures",
111
112
  "filter_picture": "Picture type",
112
- "filter_zoom_in": "Zoom-in to see this filter",
113
+ "filter_zoom_in": "Zoom-in the map to see this filter",
114
+ "picture_all": "All",
113
115
  "picture_flat": "Classic",
114
116
  "picture_360": "360°",
115
117
  "picture_flat_long": "Classic picture",
@@ -105,10 +105,12 @@
105
105
  "error_api_compatibility": "Le serveur de photos n'est pas compatible avec cette visionneuse",
106
106
  "filter_date": "Date",
107
107
  "filter_date_1month": "1 mois",
108
+ "filter_date_6months": "6 mois",
108
109
  "filter_date_1year": "1 an",
109
110
  "filter_user": "Utilisateur",
110
111
  "filter_user_mypics": "Mes photos",
111
112
  "filter_picture": "Type d'image",
113
+ "picture_all": "Tout",
112
114
  "picture_flat": "Classique",
113
115
  "picture_360": "360°",
114
116
  "picture_flat_long": "Photo classique",
@@ -120,7 +122,7 @@
120
122
  "qualityscore_doc_2": "Le score est affiché sous la forme d'une lettre A/B/C/D/E (A étant le meilleur, E le moins bon), et visualisable grâce à cette échelle :",
121
123
  "qualityscore_doc_3": "Il est calculé en fonction de la précision du GPS ainsi que la résolution de la photo. Un matériel professionnel aura une note de A, une caméra sportive 360° une note de B, et un smartphone une note de C à E.",
122
124
  "qualityscore_doc_link": "En savoir plus sur le Score de Qualité",
123
- "filter_zoom_in": "Zoomez plus pour voir ce filtre",
125
+ "filter_zoom_in": "Zoomez la carte pour voir ce filtre",
124
126
  "map_background": "Fond de carte",
125
127
  "map_background_aerial": "Satellite",
126
128
  "map_background_streets": "Plan",
@@ -18,7 +18,7 @@
18
18
  "search_user": "Cerca un nome utente…",
19
19
  "share": "Condividi",
20
20
  "share_links": "Collegamenti",
21
- "share_page": "Collegamento a questa pagina",
21
+ "share_page": "Collegamento a questa immagine",
22
22
  "share_image": "Immagine HD",
23
23
  "share_embed": "Incorpora nel tuo sito web",
24
24
  "share_embed_docs": "Scopri di più sulla configurazione della incorporazione",
@@ -42,7 +42,10 @@
42
42
  "🏘️ Creazione del rendering 3D",
43
43
  "📷 Inizializzazione delle foto a 360°",
44
44
  "🟠 Bilanciamento del colore",
45
- "💯 Calcolo del punteggio della qualità ©"
45
+ "💯 Calcolo del punteggio della qualità ©",
46
+ "📡 Scaricamento degli aggiornamenti",
47
+ "🌍 Recupero dei tasselli della mappa",
48
+ "📸 Elaborazione delle ombre"
46
49
  ],
47
50
  "loading_labels_fun": [
48
51
  "🦌 Rilevazione dei cartelli di attraversamento dei cervi",
@@ -62,7 +65,13 @@
62
65
  "👥 Scrittura delle persone",
63
66
  "🐟 Ricerca dei negozi di patatine fritte",
64
67
  "🧑‍💻 Debug dell’interfaccia",
65
- "📈 Incremento delle statistiche"
68
+ "📈 Incremento delle statistiche",
69
+ "🤖 Apprendimento della semantica",
70
+ "🎨 Riprogettazione dell’interfaccia",
71
+ "📅 Pianificazione di eventi di photo-mapping",
72
+ "🧀 Affinamento dei formaggi",
73
+ "🌄 Calcolo della nebbia in Valpadana",
74
+ "🌊 Misurazione delle grandi maree"
66
75
  ],
67
76
  "error_psv": "Il visualizzatore delle foto sferiche non si sta caricando correttamente",
68
77
  "error_pic": "La foto richiesta non è stata trovata",
@@ -92,7 +101,7 @@
92
101
  "map_theme_score": "Punteggio della qualità",
93
102
  "contrast": "Abilita un maggiore contrasto della foto",
94
103
  "metadata": "Metadata della foto",
95
- "metadata_general_picid": "Identificatore della foto",
104
+ "metadata_general_picid": "Foto",
96
105
  "metadata_general_picid_link": "Vai alla descrizione JSON della foto",
97
106
  "metadata_general_seqid_link": "Vai alla descrizione JSON della sequenza",
98
107
  "metadata_general_author": "Autore",
@@ -107,11 +116,11 @@
107
116
  "metadata_location_longitude": "Longitudine",
108
117
  "metadata_location_latitude": "Latitudine",
109
118
  "metadata_location_precision": "Precisione della posizione",
110
- "metadata_quality": "Punteggio della qualità",
119
+ "metadata_quality": "Qualità",
111
120
  "metadata_quality_score": "Punteggio globale",
112
121
  "metadata_quality_gps_score": "Punteggio sulla posizione",
113
122
  "metadata_quality_resolution_score": "Punteggio della risoluzione",
114
- "metadata_exif": "EXIF / XMP",
123
+ "metadata_exif": "EXIF",
115
124
  "metadata_exif_name": "Attributo",
116
125
  "report_auth": "Questa segnalazione verrà inviata usando la tua utenza “{a}”",
117
126
  "report_nature_label": "Natura del problema",
@@ -146,15 +155,15 @@
146
155
  "sequence_prev": "Foto precedente della sequenza",
147
156
  "sequence_more": "Altre opzioni di riproduzione",
148
157
  "josm_live": "Abilita la sincronizzazione automatica di JOSM al caricamento delle foto",
149
- "metadata_general_seqid": "Identificatore della sequenza",
158
+ "metadata_general_seqid": "Sequenza",
150
159
  "metadata_camera_focal_length": "Lunghezza focale",
151
160
  "filter_user": "Utente",
152
- "metadata_location_orientation": "Direzione dello scatto",
161
+ "metadata_location_orientation": "Direzione",
153
162
  "filter_qualityscore": "Punteggio della qualità",
154
163
  "metadata_quality_help": "Per saperne di più sul punteggio di qualità",
155
164
  "metadata_quality_missing": "Nessun valore impostato nella foto",
156
165
  "metadata_exif_value": "Valore",
157
- "report": "Segnala foto",
166
+ "report": "Segnala",
158
167
  "report_details_placeholder": "Facoltativo, puoi aggiungere dei dettagli sul problema e sul perché lo ritieni rilevante",
159
168
  "report_success": "La segnalazione è stata inviata correttamente. Non appena possibile verrà esaminata.",
160
169
  "minimize_short": "Nascondi",
@@ -162,7 +171,17 @@
162
171
  "qualityscore_doc_1": "Panoramax propone un Punteggio della qualità per ogni foto. Ciò permette di filtrare facilmente la mappa e mostrare le foto di alta qualità disponibili.",
163
172
  "qualityscore_doc_2": "Il voto è mostrato agli utenti con un valore tipo A/B/C/D/E (A è il voto migliore, E il peggiore) e graficamente viene mostrato con la seguente scala:",
164
173
  "qualityscore_doc_link": "Nella nostra documentazione sono presenti maggiori dettagli sul calcolo del Punteggio della qualità.",
165
- "qualityscore_doc_3": "Esso è calcolato basandosi sulla precisione del GPS e sulla risoluzione della foto. Un sistema professionale avrà un punteggio A, un action camera a 360° avrà un punteggio B e uno smartphone verrà classificato come C, D o E."
174
+ "qualityscore_doc_3": "Esso è calcolato basandosi sulla precisione del GPS e sulla risoluzione della foto. Un sistema professionale avrà un punteggio A, un action camera a 360° avrà un punteggio B e uno smartphone verrà classificato come C, D o E.",
175
+ "metadata_general_instance": "Istanza di origine",
176
+ "josm": "JOSM",
177
+ "picture_flat_long": "Foto classica",
178
+ "picture_360_long": "Foto panoramica",
179
+ "metadata_summary": "Sintesi",
180
+ "metadata_general_copy_id": "Copia l’ID",
181
+ "metadata_general_copy_picid": "Copia l’ID della foto",
182
+ "id": "iD",
183
+ "contribute_id": "Contribuisci a OpenStreetMap con l’editor iD",
184
+ "geo_uri": "App esterna"
166
185
  },
167
186
  "psv": {
168
187
  "loadError": "Impossibile caricare l’immagine panoramica",
@@ -177,6 +196,8 @@
177
196
  "loading": "Caricamento…",
178
197
  "thumbnail": "Miniatura della foto passata con il mouse",
179
198
  "not_public": "Non pubblicamente visibile",
180
- "slow_loading": "La mappa impiega troppo tempo a caricarsi e potrebbe apparire a pezzi"
199
+ "slow_loading": "La mappa impiega troppo tempo a caricarsi e potrebbe apparire a pezzi",
200
+ "map_data": "Dati cartografici:",
201
+ "more_panoramax": "Per saperne di più su Panoramax"
181
202
  }
182
203
  }