@panoramax/web-viewer 3.1.1 → 3.2.0-develop-8f79d734

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.
Files changed (38) hide show
  1. package/CHANGELOG.md +26 -1
  2. package/build/index.css +2 -2
  3. package/build/index.css.map +1 -1
  4. package/build/index.js +6 -6
  5. package/build/index.js.map +1 -1
  6. package/docs/02_Usage.md +267 -224
  7. package/docs/03_URL_settings.md +10 -1
  8. package/docs/05_Compatibility.md +1 -0
  9. package/package.json +4 -3
  10. package/src/Viewer.js +51 -3
  11. package/src/components/CoreView.css +6 -0
  12. package/src/components/CoreView.js +25 -10
  13. package/src/components/Map.js +41 -2
  14. package/src/components/Photo.css +5 -0
  15. package/src/translations/de.json +28 -11
  16. package/src/translations/en.json +22 -11
  17. package/src/translations/es.json +23 -11
  18. package/src/translations/fr.json +22 -11
  19. package/src/translations/hu.json +117 -73
  20. package/src/translations/nl.json +73 -1
  21. package/src/translations/pl.json +1 -0
  22. package/src/translations/zh_Hant.json +53 -9
  23. package/src/utils/API.js +20 -3
  24. package/src/utils/Exif.js +5 -10
  25. package/src/utils/Map.js +56 -10
  26. package/src/utils/Utils.js +68 -24
  27. package/src/utils/Widgets.js +64 -2
  28. package/src/viewer/URLHash.js +18 -3
  29. package/src/viewer/Widgets.css +139 -0
  30. package/src/viewer/Widgets.js +207 -42
  31. package/tests/Viewer.test.js +1 -0
  32. package/tests/__snapshots__/Editor.test.js.snap +1 -5
  33. package/tests/components/__snapshots__/Photo.test.js.snap +2 -10
  34. package/tests/utils/Exif.test.js +10 -10
  35. package/tests/utils/Map.test.js +8 -0
  36. package/tests/utils/__snapshots__/API.test.js.snap +5 -0
  37. package/tests/utils/__snapshots__/Widgets.test.js.snap +1 -1
  38. package/tests/viewer/__snapshots__/Widgets.test.js.snap +39 -29
@@ -116,13 +116,22 @@ The camera make and model to filter shown pictures and sequences on map (if map
116
116
  - `camera=gopro%20max` will only show pictures taken with a _GoPro Max_ camera
117
117
  - `camera=max` will not shown any picture on map, as it doesn't match any camera make
118
118
 
119
+ ### :medal: `pic_score`: filter map data by quality score
120
+
121
+ The pictures quality level wanted for map display (if map is enabled). Values are `A`, `B`, `C`, `D`, `E` and can be used that way:
122
+
123
+ - `pic_score=A` for only best pictures
124
+ - `pic_score=ABC` for A, B or C-grade pictures
125
+
126
+
119
127
  ### :material-format-paint: `theme`: map colouring for pictures and sequences
120
128
 
121
129
  The map theme to use for displaying pictures and sequences (if map is enabled). Available themes are:
122
130
 
123
131
  - `theme=default` (or no setting defined): single color for display (no classification)
124
132
  - `theme=age`: color based on picture/sequence age (red = recent, yellow = 2+ years old)
125
- - `theme=type`: color based on camera type (orange = classic, green = 360°)
133
+ - `theme=type`: color based on camera type (orange = classic, green = 360°)
134
+ - `theme=score`: color based on quality score (green = best quality, yellow = worst)
126
135
 
127
136
  ### :material-nature-people: `background`: map background
128
137
 
@@ -83,6 +83,7 @@ A supplementary layer _grid_ can be made available for low-zoom overview:
83
83
 
84
84
  - Available on zoom levels < 6
85
85
  - Available properties: `id` (grid cell ID), `nb_pictures` (amount of pictures), `coef` (value from 0 to 1, relative quantity of available pictures)
86
+ - Optional properties: `nb_360_pictures`, `coef_360_pictures`, `nb_flat_pictures`, `coef_flat_pictures` (similar to `nb_pictures` and `coef` but separated by picture type)
86
87
 
87
88
  ### Labels translation
88
89
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@panoramax/web-viewer",
3
- "version": "3.1.1",
3
+ "version": "3.2.0-develop-8f79d734",
4
4
  "description": "Panoramax web viewer for geolocated pictures",
5
5
  "main": "build/index.js",
6
6
  "author": "Panoramax team",
@@ -88,8 +88,9 @@
88
88
  "workbox-webpack-plugin": "^6.5.4"
89
89
  },
90
90
  "dependencies": {
91
- "@fortawesome/fontawesome-svg-core": "^6.4.0",
92
- "@fortawesome/free-solid-svg-icons": "^6.4.0",
91
+ "@fortawesome/fontawesome-svg-core": "^6.6.0",
92
+ "@fortawesome/free-regular-svg-icons": "^6.6.0",
93
+ "@fortawesome/free-solid-svg-icons": "^6.6.0",
93
94
  "@photo-sphere-viewer/core": "5.11.0-beta.1",
94
95
  "@photo-sphere-viewer/equirectangular-tiles-adapter": "5.11.0-beta.1",
95
96
  "@photo-sphere-viewer/gallery-plugin": "5.11.0-beta.1",
package/src/Viewer.js CHANGED
@@ -2,11 +2,11 @@ import "./Viewer.css";
2
2
  import { SYSTEM as PSSystem, DEFAULTS as PSDefaults } from "@photo-sphere-viewer/core";
3
3
  import Widgets from "./viewer/Widgets";
4
4
  import URLHash from "./viewer/URLHash";
5
- import { COLORS, josmBboxParameters, linkMapAndPhoto } from "./utils/Utils";
5
+ import { COLORS, QUALITYSCORE_VALUES, josmBboxParameters, linkMapAndPhoto } from "./utils/Utils";
6
6
  import CoreView from "./components/CoreView";
7
7
  import Photo, { PSV_DEFAULT_ZOOM, PSV_ANIM_DURATION, PIC_MAX_STAY_DURATION } from "./components/Photo";
8
8
  import Map from "./components/Map";
9
- import { TILES_PICTURES_ZOOM } from "./utils/Map";
9
+ import { TILES_PICTURES_ZOOM, MAP_EXPR_QUALITYSCORE } from "./utils/Map";
10
10
  import { enableCopyButton, fa } from "./utils/Widgets";
11
11
  import { faXmark } from "@fortawesome/free-solid-svg-icons/faXmark";
12
12
 
@@ -20,6 +20,7 @@ const MAP_THEMES = {
20
20
  DEFAULT: "default",
21
21
  AGE: "age",
22
22
  TYPE: "type",
23
+ SCORE: "score",
23
24
  };
24
25
 
25
26
 
@@ -234,10 +235,18 @@ class Viewer extends CoreView {
234
235
  const userSearchField = document.getElementById("gvs-filter-search-user").querySelector("input");
235
236
  if(userSearchField) {
236
237
  userSearchField.setItem(userNames);
238
+ userSearchField.parentNode.classList.add("gvs-filter-active");
237
239
  }
238
240
  }).catch(e => console.warn("Error when looking up for user names", e));
239
241
  }
240
242
  }
243
+
244
+ // Dismiss popup with Escape
245
+ document.addEventListener("keyup", e => {
246
+ if(e.key === "Escape" && !this.popupContainer.classList.contains("gvs-hidden")) {
247
+ this.setPopup(false);
248
+ }
249
+ });
241
250
  };
242
251
 
243
252
  this._api.onceReady().then(() => {
@@ -809,6 +818,15 @@ class Viewer extends CoreView {
809
818
  COLORS.QUALI_2
810
819
  );
811
820
  }
821
+ else if(this._mapTheme == MAP_THEMES.SCORE) {
822
+ s.push(
823
+ ["==", MAP_EXPR_QUALITYSCORE, 5], QUALITYSCORE_VALUES[0].color,
824
+ ["==", MAP_EXPR_QUALITYSCORE, 4], QUALITYSCORE_VALUES[1].color,
825
+ ["==", MAP_EXPR_QUALITYSCORE, 3], QUALITYSCORE_VALUES[2].color,
826
+ ["==", MAP_EXPR_QUALITYSCORE, 2], QUALITYSCORE_VALUES[3].color,
827
+ QUALITYSCORE_VALUES[4].color,
828
+ );
829
+ }
812
830
  else {
813
831
  s.push(COLORS.BASE);
814
832
  }
@@ -827,6 +845,7 @@ class Viewer extends CoreView {
827
845
  // - 20-80 : custom ranges
828
846
  // - 10 : basic feature
829
847
  // - 0 : on bottom / feature with undefined property
848
+
830
849
  // Hidden style
831
850
  const s = ["case",
832
851
  ["==", ["get", "hidden"], true], 90
@@ -859,6 +878,15 @@ class Viewer extends CoreView {
859
878
  ["==", ["get", "type"], "equirectangular"], 50,
860
879
  );
861
880
  }
881
+ else if(this._mapTheme == MAP_THEMES.SCORE) {
882
+ s.push(
883
+ ["==", MAP_EXPR_QUALITYSCORE, 5], 80,
884
+ ["==", MAP_EXPR_QUALITYSCORE, 4], 65,
885
+ ["==", MAP_EXPR_QUALITYSCORE, 3], 50,
886
+ ["==", MAP_EXPR_QUALITYSCORE, 2], 35,
887
+ ["==", MAP_EXPR_QUALITYSCORE, 1], 20,
888
+ );
889
+ }
862
890
 
863
891
  s.push(10);
864
892
  return s;
@@ -1076,11 +1104,13 @@ class Viewer extends CoreView {
1076
1104
  * @param {string} [filters.type] Type of picture to keep (flat, equirectangular)
1077
1105
  * @param {string} [filters.camera] Camera make and model to keep
1078
1106
  * @param {string} [filters.theme] Map theme to use
1107
+ * @param {number[]} [filters.qualityscore] QualityScore values, as a list of 1 to 5 grades
1079
1108
  * @param {boolean} [skipZoomIn=false] If true, doesn't force zoom in to map level >= 7
1080
1109
  */
1081
1110
  setFilters(filters, skipZoomIn = false) {
1082
1111
  let mapSeqFilters = [];
1083
1112
  let mapPicFilters = [];
1113
+ let reloadMapStyle = false;
1084
1114
  this._mapFilters = {};
1085
1115
 
1086
1116
  if(filters.minDate && filters.minDate !== "") {
@@ -1088,6 +1118,7 @@ class Viewer extends CoreView {
1088
1118
  mapSeqFilters.push([">=", ["get", "date"], filters.minDate]);
1089
1119
  mapPicFilters.push([">=", ["get", "ts"], filters.minDate]);
1090
1120
  }
1121
+
1091
1122
  if(filters.maxDate && filters.maxDate !== "") {
1092
1123
  this._mapFilters.maxDate = filters.maxDate;
1093
1124
  mapSeqFilters.push(["<=", ["get", "date"], filters.maxDate]);
@@ -1099,11 +1130,16 @@ class Viewer extends CoreView {
1099
1130
  d = d.toISOString().split("T")[0];
1100
1131
  mapPicFilters.push(["<=", ["get", "ts"], d]);
1101
1132
  }
1133
+
1102
1134
  if(filters.type && filters.type !== "") {
1103
1135
  this._mapFilters.type = filters.type;
1104
1136
  mapSeqFilters.push(["==", ["get", "type"], filters.type]);
1105
1137
  mapPicFilters.push(["==", ["get", "type"], filters.type]);
1106
1138
  }
1139
+ if(this.map?._hasGridStats()) {
1140
+ reloadMapStyle = true;
1141
+ }
1142
+
1107
1143
  if(filters.camera && filters.camera !== "") {
1108
1144
  this._mapFilters.camera = filters.camera;
1109
1145
  // low/high model hack : to enable fuzzy filtering of camera make and model
@@ -1116,11 +1152,17 @@ class Viewer extends CoreView {
1116
1152
  mapPicFilters.push(["<=", ["get", "model"], highModel, collator]);
1117
1153
  }
1118
1154
 
1155
+ if(filters.qualityscore && filters.qualityscore.length > 0) {
1156
+ this._mapFilters.qualityscore = filters.qualityscore;
1157
+ mapSeqFilters.push(["in", MAP_EXPR_QUALITYSCORE, ["literal", this._mapFilters.qualityscore]]);
1158
+ mapPicFilters.push(["in", MAP_EXPR_QUALITYSCORE, ["literal", this._mapFilters.qualityscore]]);
1159
+ }
1160
+
1119
1161
  if(filters.theme && Object.values(MAP_THEMES).includes(filters.theme)) {
1120
1162
  this._mapFilters.theme = filters.theme;
1121
1163
  if(this.map) {
1122
1164
  this._mapTheme = this._mapFilters.theme;
1123
- this.map.reloadLayersStyles();
1165
+ reloadMapStyle = true;
1124
1166
  }
1125
1167
  }
1126
1168
 
@@ -1139,6 +1181,10 @@ class Viewer extends CoreView {
1139
1181
  }
1140
1182
 
1141
1183
  if(this.map) {
1184
+ if(reloadMapStyle) {
1185
+ this.map.reloadLayersStyles();
1186
+ }
1187
+
1142
1188
  const allUsers = this.map.getVisibleUsers().includes("geovisio");
1143
1189
  if(mapSeqFilters && allUsers) {
1144
1190
  mapSeqFilters = ["step", ["zoom"],
@@ -1158,6 +1204,7 @@ class Viewer extends CoreView {
1158
1204
  )
1159
1205
  && allUsers
1160
1206
  && this.map.getZoom() < 7
1207
+ && !this.map._hasGridStats()
1161
1208
  ) {
1162
1209
  this.map.easeTo({ zoom: 7 });
1163
1210
  }
@@ -1175,6 +1222,7 @@ class Viewer extends CoreView {
1175
1222
  * @property {string} [detail.type] Camera type (equirectangular, flat, null/empty string for both)
1176
1223
  * @property {string} [detail.camera] Camera make and model
1177
1224
  * @property {string} [detail.theme] Map theme
1225
+ * @property {number[]} [detail.qualityscore] QualityScore values, as a list of 1 to 5 grades
1178
1226
  */
1179
1227
  const event = new CustomEvent("filters-changed", { detail: Object.assign({}, this._mapFilters) });
1180
1228
  this.dispatchEvent(event);
@@ -53,6 +53,12 @@
53
53
  margin-right: 2px;
54
54
  }
55
55
 
56
+ .gvs h4 a svg {
57
+ height: 16px;
58
+ vertical-align: sub;
59
+ margin-left: 2px;
60
+ }
61
+
56
62
  /* Hidden elements on mobile */
57
63
  @container (max-width: 576px) {
58
64
  .gvs-mobile-hidden { display: none !important; }
@@ -68,16 +68,31 @@ export default class CoreView extends EventTarget {
68
68
  this.container.appendChild(this.loaderContainer);
69
69
  this._loader = new Loader(this, this.loaderContainer);
70
70
 
71
- // API init
72
- endpoint = endpoint.replace("/api/search", "/api");
73
- this._api = new API(endpoint, {
74
- users: this._options.users,
75
- fetch: this._options?.fetchOptions,
76
- style: this._options.style,
77
- });
78
- this._api.onceReady()
79
- .then(() => console.info(`🌐 Connected to API "${this._api._metadata.name}" (${this._api._endpoint})\nℹ️ API runs STAC ${this._api._metadata.stac_version} & GeoVisio ${this._api._metadata.geovisio_version}`))
80
- .catch(e => this._loader.dismiss(e, this._t.gvs.error_api));
71
+ // API init)
72
+ endpoint = (endpoint || "").replace("/api/search", "/api");
73
+ try {
74
+ this._api = new API(endpoint, {
75
+ users: this._options.users,
76
+ fetch: this._options?.fetchOptions,
77
+ style: this._options.style,
78
+ });
79
+ this._api.onceReady()
80
+ .then(() => {
81
+ let unavailable = this._api.getUnavailableFeatures();
82
+ let available = this._api.getAvailableFeatures();
83
+ available = unavailable.length === 0 ? "✅ All features available" : "✅ Available features: "+available.join(", ");
84
+ unavailable = unavailable.length === 0 ? "" : "🚫 Unavailable features: "+unavailable.join(", ");
85
+ console.info(`🌐 Connected to API "${this._api._metadata.name}" (${this._api._endpoint})
86
+ ℹ️ API runs STAC ${this._api._metadata.stac_version} ${this._api._metadata.geovisio_version ? "& GeoVisio "+this._api._metadata.geovisio_version : ""}
87
+ ${available}
88
+ ${unavailable}
89
+ `.trim());
90
+ })
91
+ .catch(e => this._loader.dismiss(e, this._t.gvs.error_api));
92
+ }
93
+ catch(e) {
94
+ this._loader.dismiss(e, this._t.gvs.error_api);
95
+ }
81
96
  }
82
97
 
83
98
  /**
@@ -2,7 +2,7 @@ import "./Map.css";
2
2
  import {
3
3
  forwardGeocodingBAN, forwardGeocodingNominatim, VECTOR_STYLES,
4
4
  TILES_PICTURES_ZOOM, getThumbGif, RASTER_LAYER_ID, combineStyles,
5
- getMissingLayerStyles, isLabelLayer, getUserLayerId, getUserSourceId,
5
+ getMissingLayerStyles, isLabelLayer, getUserLayerId, getUserSourceId, switchCoefValue,
6
6
  } from "../utils/Map";
7
7
  import { COLORS } from "../utils/Utils";
8
8
  import MarkerBaseSVG from "../img/marker.svg";
@@ -187,6 +187,25 @@ export default class Map extends maplibregl.Map {
187
187
  });
188
188
  }
189
189
 
190
+ /**
191
+ * Is Quality Score available in vector tiles ?
192
+ * @private
193
+ */
194
+ _hasQualityScore() {
195
+ const fields = this.getStyle()?.metadata?.["panoramax:fields"] || {};
196
+ return fields?.pictures?.includes("gps_accuracy") && fields?.pictures?.includes("h_pixel_density");
197
+ }
198
+
199
+ /**
200
+ * Are 360/flat pictures stats available in vector tiles for grid layer ?
201
+ * @private
202
+ */
203
+ _hasGridStats() {
204
+ const fields = this.getStyle()?.metadata?.["panoramax:fields"] || {};
205
+ return fields?.grid?.includes("nb_360_pictures") && fields?.grid?.includes("nb_flat_pictures")
206
+ && fields?.grid?.includes("coef_360_pictures") && fields?.grid?.includes("coef_flat_pictures");
207
+ }
208
+
190
209
  /**
191
210
  * Force refresh of vector tiles data
192
211
  */
@@ -352,6 +371,25 @@ export default class Map extends maplibregl.Map {
352
371
  ["pictures", "pictures_symbols", "sequences"].forEach(l => {
353
372
  updateStyle(l, this._getLayerStyleProperties(l));
354
373
  });
374
+
375
+ // Also handle the grid stats
376
+ if(this._hasGridStats() && this._parent?._mapFilters) {
377
+ let newType = "coef";
378
+ if(this._parent._mapFilters?.type) {
379
+ newType = this._parent._mapFilters.type == "flat" ? "coef_flat_pictures" : "coef_360_pictures";
380
+ }
381
+ this.getStyle().layers
382
+ .filter(l => l.id.endsWith("_grid"))
383
+ .forEach(l => {
384
+ const newl = switchCoefValue(l, newType);
385
+ for(let p in newl.layout) {
386
+ this.setLayoutProperty(l.id, p, newl.layout[p]);
387
+ }
388
+ for(let p in newl.paint) {
389
+ this.setPaintProperty(l.id, p, newl.paint[p]);
390
+ }
391
+ });
392
+ }
355
393
  }
356
394
 
357
395
  /**
@@ -641,7 +679,8 @@ export default class Map extends maplibregl.Map {
641
679
  }
642
680
  }
643
681
  else {
644
- this._picPopup.setHTML(`<i>${this._parent._t.map.no_thumbnail}</i>`);
682
+ this._picPopup.remove();
683
+ //this._picPopup.setHTML(`<i>${this._parent._t.map.no_thumbnail}</i>`);
645
684
  }
646
685
  }
647
686
  };
@@ -33,4 +33,9 @@
33
33
  .gvs-psv-tour-arrows svg {
34
34
  width: 100%;
35
35
  height: auto;
36
+ }
37
+
38
+ /* No virtual tour arrows if photo is reduced */
39
+ .gvs-mini .gvs-psv .psv-virtual-tour-arrows {
40
+ display: none;
36
41
  }
@@ -36,7 +36,7 @@
36
36
  "moveDown": "Nach unten",
37
37
  "moveRight": "Nach rechts",
38
38
  "moveMiddle": "Sicht zentrieren",
39
- "map_theme_age": "Nach Aufnahmedatum",
39
+ "map_theme_age": "Aufnahmedatum",
40
40
  "expand": "Vergrößern",
41
41
  "expand_info": "Widget im Vollbild anzeigen",
42
42
  "show_psv": "Bildbetrachter anzeigen",
@@ -46,7 +46,6 @@
46
46
  "picture_flat": "Klassisch",
47
47
  "picture_360": "360°",
48
48
  "filter_camera_model": "Nach Kameramodell",
49
- "filter_reset": "Filter löschen",
50
49
  "map_background": "Kartenhintergrund",
51
50
  "map_background_aerial": "Satelliten",
52
51
  "map_background_streets": "Straßen",
@@ -55,7 +54,7 @@
55
54
  "metadata_exif_value": "Wert",
56
55
  "map_theme_age_2": "<2 Jahre",
57
56
  "map_theme_age_3": "<1 Jahr",
58
- "map_theme_type": "Nach Kameratyp",
57
+ "map_theme_type": "Kameratyp",
59
58
  "contrast": "Höheren Bildkontrast aktivieren",
60
59
  "metadata": "Bildmetadaten",
61
60
  "metadata_general_seqid": "Sequenzidentifier",
@@ -67,7 +66,8 @@
67
66
  "🔍 EXIF Metadaten analysieren",
68
67
  "🏘️ 3D-Rendering",
69
68
  "📷 360° Fotos initialisieren",
70
- "🟠 Farben balancieren"
69
+ "🟠 Farben balancieren",
70
+ "💯 Berechnung der Qualitätsbewertung ©"
71
71
  ],
72
72
  "search_address": "Suchen sie eine Adresse, Stadt, …",
73
73
  "share_image": "HD Bild",
@@ -94,10 +94,10 @@
94
94
  "error_api": "Foto-Server ist nicht verfügbar",
95
95
  "error_josm": "JOSM reagiert nicht, ist es geöffnet und die Remote eingeschaltet?",
96
96
  "error_api_compatibility": "Der Foto-Server ist nicht mit dieser Version des Betrachters kompatibel",
97
- "filter_date": "Nach Datum",
98
- "filter_user": "Nach Benutzer",
99
- "filter_picture": "Nach Foto-Art",
100
- "map_theme_default": "Nach standard",
97
+ "filter_date": "Datum",
98
+ "filter_user": "Benutzer",
99
+ "filter_picture": "Foto-Art",
100
+ "map_theme_default": "Klassisch",
101
101
  "map_theme_age_1": ">2 Jahre",
102
102
  "metadata_general_seqid_link": "Zur JSON-Beschreibung der Sequenz gehen",
103
103
  "metadata_general_author": "Autor",
@@ -143,7 +143,24 @@
143
143
  "report_submit": "Absenden",
144
144
  "report_success": "Ihr Report wurde erfolgreich gesendet. Er wird so schnell wie möglich überprüft.",
145
145
  "report_failure": "Ein Fehler ist bei der Erstellung des Reports aufgetreten: {e}. Bitte versuchen sie es erneut.",
146
- "report": "Foto melden"
146
+ "report": "Foto melden",
147
+ "legend_title": "Zeige Bilderdetails",
148
+ "report_wait": "Bericht senden…",
149
+ "error_click": "Klicken um fortzufahren",
150
+ "error_retry": "Bitte später erneut versuchen",
151
+ "metadata_camera_resolution": "Auflösung",
152
+ "filter_user_mypics": "Meine Fotos",
153
+ "metadata_quality_missing": "kein Wert im Foto gesetzt",
154
+ "filter_date_1month": "1 Monat",
155
+ "filter_date_1year": "1 Jahr",
156
+ "filter_qualityscore": "Qualitätswert",
157
+ "filter_qualityscore_help": "Klicken, um zu aktivieren oder deaktivieren",
158
+ "map_theme_score": "Qualitätswert",
159
+ "metadata_quality": "Qualitätswert",
160
+ "metadata_quality_help": "Erfahre mehr über den Qualitätswert",
161
+ "metadata_quality_resolution_score": "Auflösungswertung",
162
+ "metadata_quality_gps_score": "Positionswertung",
163
+ "metadata_quality_score": "Gesamtwertung"
147
164
  },
148
165
  "psv": {
149
166
  "twoFingers": "Nutzen sie zwei Finger zum navigieren",
@@ -152,9 +169,9 @@
152
169
  },
153
170
  "map": {
154
171
  "thumbnail": "Vorschau des marktierten Fotos",
155
- "no_thumbnail": "Keine Vorschau",
156
172
  "not_public": "Nicht öffentlich sichtbar",
157
- "loading": "Laden…"
173
+ "loading": "Laden…",
174
+ "slow_loading": "Die Karte wird nur langsam geladen und könnte fehlerhaft erscheinen"
158
175
  },
159
176
  "maplibre": {
160
177
  "GeolocateControl.FindMyLocation": "Meinen Standort finden",
@@ -62,7 +62,8 @@
62
62
  "🔍 Analyzing EXIF metadata",
63
63
  "🏘️ 3D rendering",
64
64
  "📷 Initializing 360° pictures",
65
- "🟠 Colour balancing"
65
+ "🟠 Colour balancing",
66
+ "💯 Computing Quality Score ©"
66
67
  ],
67
68
  "loading_labels_fun": [
68
69
  "🦌 Deer crossing sign detection",
@@ -91,25 +92,29 @@
91
92
  "error_webgl": "WebGL is not supported on this browser",
92
93
  "error_josm": "JOSM doesn't respond, is it running and is remote enabled?",
93
94
  "error_api_compatibility": "The pictures server is not compatible with this viewer version",
94
- "filter_date": "By date",
95
- "filter_user": "By user",
96
- "filter_picture": "By picture type",
95
+ "filter_date": "Date",
96
+ "filter_date_1month": "1 month",
97
+ "filter_date_1year": "1 year",
98
+ "filter_user": "User",
99
+ "filter_user_mypics": "My pictures",
100
+ "filter_picture": "Picture type",
97
101
  "filter_zoom_in": "Zoom-in for filters to be visible",
98
102
  "picture_flat": "Classic",
99
103
  "picture_360": "360°",
100
- "filter_camera_model": "By camera model",
101
- "filter_reset": "Clear filters",
104
+ "filter_qualityscore": "Quality score",
105
+ "filter_qualityscore_help": "Click to enable or disable",
102
106
  "map_background": "Map background",
103
107
  "map_background_aerial": "Aerial",
104
108
  "map_background_streets": "Streets",
105
109
  "map_theme": "Map theme",
106
- "map_theme_default": "By default",
107
- "map_theme_age": "By capture date",
110
+ "map_theme_default": "Classic",
111
+ "map_theme_age": "Capture date",
108
112
  "map_theme_age_1": "> 2 years",
109
113
  "map_theme_age_2": "< 2 years",
110
114
  "map_theme_age_3": "< 1 year",
111
115
  "map_theme_age_4": "< 1 month",
112
- "map_theme_type": "By camera type",
116
+ "map_theme_type": "Camera type",
117
+ "map_theme_score": "Quality score",
113
118
  "contrast": "Enable higher image contrast",
114
119
  "metadata": "Picture metadata",
115
120
  "metadata_general_picid": "Picture identifier",
@@ -124,12 +129,19 @@
124
129
  "metadata_camera_make": "Make",
125
130
  "metadata_camera_model": "Model",
126
131
  "metadata_camera_type": "Type",
132
+ "metadata_camera_resolution": "Resolution",
127
133
  "metadata_camera_focal_length": "Focal length",
128
134
  "metadata_location": "Location",
129
135
  "metadata_location_longitude": "Longitude",
130
136
  "metadata_location_latitude": "Latitude",
131
137
  "metadata_location_orientation": "Capture direction",
132
138
  "metadata_location_precision": "Positioning precision",
139
+ "metadata_quality": "Quality score",
140
+ "metadata_quality_help": "Know more about Quality Score",
141
+ "metadata_quality_score": "Global score",
142
+ "metadata_quality_gps_score": "Positioning score",
143
+ "metadata_quality_resolution_score": "Resolution score",
144
+ "metadata_quality_missing": "no value set in picture",
133
145
  "metadata_exif": "EXIF / XMP",
134
146
  "metadata_exif_name": "Tag",
135
147
  "metadata_exif_value": "Value",
@@ -153,14 +165,13 @@
153
165
  "report_email": "Your email",
154
166
  "report_email_placeholder": "Optional",
155
167
  "report_submit": "Submit",
156
- "report_wait": "Sending report...",
168
+ "report_wait": "Sending report",
157
169
  "report_success": "Report has been successfully sent. It will be reviewed as soon as possible.",
158
170
  "report_failure": "An error occurred when creating report: {e}. Please try again later."
159
171
  },
160
172
  "map": {
161
173
  "loading": "Loading…",
162
174
  "thumbnail": "Thumbnail of hovered picture",
163
- "no_thumbnail": "No thumbnail",
164
175
  "not_public": "Not publicly visible",
165
176
  "slow_loading": "Map is slow to load and could appear broken"
166
177
  }
@@ -28,10 +28,11 @@
28
28
  "🔍 Analizando metadatos EXIF",
29
29
  "🏘️ Renderizado 3D",
30
30
  "📷 Preparando imágenes 360°",
31
- "🟠 Ajustando balance de color"
31
+ "🟠 Ajustando balance de color",
32
+ "💯 Cálculo del nivel de calidad ©"
32
33
  ],
33
34
  "metadata": "Metadatos de la imagen",
34
- "map_theme_type": "Por tipo de cámara",
35
+ "map_theme_type": "Tipo de cámara",
35
36
  "contrast": "Dar más contraste a la imagen",
36
37
  "zoom": "Acercar/alejar",
37
38
  "zoomOut": "Alejar",
@@ -103,19 +104,18 @@
103
104
  "error_webgl": "Este navegador no admite WebGL",
104
105
  "error_josm": "JOSM no responde. ¿Está abierto, y admite el modo de Control Remoto?",
105
106
  "error_api_compatibility": "El servidor de imágenes no es compatible con esta versión del visor",
106
- "filter_date": "Por fecha",
107
- "filter_user": "Por usuario",
108
- "filter_picture": "Por tipo de imagen",
107
+ "filter_date": "Fecha",
108
+ "filter_user": "Usuario",
109
+ "filter_picture": "Tipo de imagen",
109
110
  "filter_zoom_in": "Acércate para poder ver filtros",
110
111
  "picture_flat": "Clásico",
111
112
  "picture_360": "360°",
112
113
  "filter_camera_model": "Por modelo de cámara",
113
- "filter_reset": "Quitar filtros",
114
114
  "map_background": "Fondo de mapa",
115
115
  "map_background_aerial": "Vista aérea",
116
116
  "map_theme": "Tema de mapa",
117
- "map_theme_default": "Por defecto",
118
- "map_theme_age": "Por fecha de toma de imagen",
117
+ "map_theme_default": "Clásico",
118
+ "map_theme_age": "Fecha de toma de imagen",
119
119
  "map_theme_age_1": "Más de dos años",
120
120
  "map_theme_age_2": "Menos de dos años",
121
121
  "map_theme_age_3": "Menos de un año",
@@ -144,7 +144,19 @@
144
144
  "report_email_placeholder": "Opcional",
145
145
  "report_submit": "Enviar",
146
146
  "report_success": "La denuncia se ha enviado correctamente. Será revisada lo antes posible.",
147
- "report_failure": "Ocurrió un error al crear la denuncia: {e}. Por favor, inténtalo más tarde."
147
+ "report_failure": "Ocurrió un error al crear la denuncia: {e}. Por favor, inténtalo más tarde.",
148
+ "map_theme_score": "Nivel de calidad",
149
+ "filter_qualityscore": "Nivel de calidad",
150
+ "filter_qualityscore_help": "Haga clic para habilitar o deshabilitar",
151
+ "legend_title": "Ver detalles de la imagen",
152
+ "metadata_camera_resolution": "Resolución",
153
+ "metadata_quality": "Puntuación de calidad",
154
+ "metadata_quality_help": "Más información sobre el nivel de calidad",
155
+ "metadata_quality_score": "Valoración general",
156
+ "metadata_quality_gps_score": "Puntuación de posicionamiento",
157
+ "metadata_quality_resolution_score": "Puntuación de resolución",
158
+ "metadata_quality_missing": "no hay información en la imagen",
159
+ "report_wait": "Envío del informe…"
148
160
  },
149
161
  "psv": {
150
162
  "ctrlZoom": "Utiliza Control+rueda de desplazamiento para acercar/alejar",
@@ -158,7 +170,7 @@
158
170
  "map": {
159
171
  "loading": "Cargando…",
160
172
  "thumbnail": "Vista previa de la imagen bajo el cursor",
161
- "no_thumbnail": "No hay vista previa",
162
- "not_public": "No es visible públicamente"
173
+ "not_public": "No es visible públicamente",
174
+ "slow_loading": "La mapa tarda mucho en cargarse y puede parecer rota"
163
175
  }
164
176
  }