@panoramax/web-viewer 4.0.2 → 4.0.3-develop-d59993ce

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 (57) hide show
  1. package/CHANGELOG.md +18 -1
  2. package/build/index.css +2 -2
  3. package/build/index.css.map +1 -1
  4. package/build/index.js +287 -72
  5. package/build/index.js.map +1 -1
  6. package/config/jest/mocks.js +5 -0
  7. package/docs/09_Develop.md +6 -0
  8. package/docs/reference/components/core/PhotoViewer.md +1 -0
  9. package/docs/reference/components/core/Viewer.md +2 -1
  10. package/docs/reference/components/menus/AnnotationsList.md +16 -0
  11. package/docs/reference/components/ui/HashTags.md +15 -0
  12. package/docs/reference/components/ui/ListItem.md +38 -0
  13. package/docs/reference/components/ui/Photo.md +78 -1
  14. package/docs/reference/components/ui/SemanticsTable.md +32 -0
  15. package/docs/reference/components/ui/widgets/GeoSearch.md +5 -1
  16. package/docs/reference/utils/PresetsManager.md +35 -0
  17. package/docs/reference.md +4 -0
  18. package/mkdocs.yml +4 -0
  19. package/package.json +2 -1
  20. package/src/components/core/Basic.css +2 -0
  21. package/src/components/core/PhotoViewer.js +11 -0
  22. package/src/components/core/Viewer.js +8 -1
  23. package/src/components/layout/Tabs.js +1 -1
  24. package/src/components/menus/AnnotationsList.js +151 -0
  25. package/src/components/menus/PictureLegend.js +6 -5
  26. package/src/components/menus/PictureMetadata.js +80 -8
  27. package/src/components/menus/index.js +1 -0
  28. package/src/components/styles.js +34 -0
  29. package/src/components/ui/HashTags.js +98 -0
  30. package/src/components/ui/ListItem.js +83 -0
  31. package/src/components/ui/Photo.js +188 -0
  32. package/src/components/ui/SemanticsTable.js +87 -0
  33. package/src/components/ui/index.js +3 -0
  34. package/src/components/ui/widgets/GeoSearch.js +13 -5
  35. package/src/img/osm.svg +49 -0
  36. package/src/img/wd.svg +1 -0
  37. package/src/translations/en.json +23 -0
  38. package/src/translations/fr.json +21 -0
  39. package/src/translations/it.json +28 -1
  40. package/src/translations/nl.json +14 -4
  41. package/src/translations/zh_Hant.json +6 -1
  42. package/src/utils/PresetsManager.js +137 -0
  43. package/src/utils/URLHandler.js +1 -1
  44. package/src/utils/geocoder.js +135 -83
  45. package/src/utils/index.js +3 -1
  46. package/src/utils/picture.js +28 -0
  47. package/src/utils/semantics.js +162 -0
  48. package/src/utils/services.js +39 -1
  49. package/src/utils/widgets.js +18 -1
  50. package/tests/components/core/__snapshots__/PhotoViewer.test.js.snap +10 -0
  51. package/tests/components/core/__snapshots__/Viewer.test.js.snap +10 -0
  52. package/tests/data/Map_geocoder_nominatim.json +25 -40
  53. package/tests/utils/PresetsManager.test.js +123 -0
  54. package/tests/utils/URLHandler.test.js +42 -0
  55. package/tests/utils/__snapshots__/geocoder.test.js.snap +5 -16
  56. package/tests/utils/geocoder.test.js +1 -1
  57. package/tests/utils/semantics.test.js +125 -0
@@ -14,6 +14,7 @@ import "@photo-sphere-viewer/gallery-plugin/index.css";
14
14
  import "@photo-sphere-viewer/markers-plugin/index.css";
15
15
  import { Viewer as PSViewer } from "@photo-sphere-viewer/core";
16
16
  import { VirtualTourPlugin } from "@photo-sphere-viewer/virtual-tour-plugin";
17
+ import { MarkersPlugin } from "@photo-sphere-viewer/markers-plugin";
17
18
  import PhotoAdapter from "../../utils/PhotoAdapter";
18
19
 
19
20
 
@@ -77,6 +78,9 @@ PSViewer.useNewAnglesOrder = true;
77
78
  * @fires Panoramax.components.ui.Photo#sequence-stopped
78
79
  * @fires Panoramax.components.ui.Photo#pictures-navigation-changed
79
80
  * @fires Panoramax.components.ui.Photo#ready
81
+ * @fires Panoramax.components.ui.Photo#annotations-toggled
82
+ * @fires Panoramax.components.ui.Photo#annotation-click
83
+ * @fires Panoramax.components.ui.Photo#annotations-unfocused
80
84
  * @example
81
85
  * const psv = new Panoramax.components.ui.Photo(viewer, psvNode, {transitionDuration: 500})
82
86
  */
@@ -112,6 +116,7 @@ export default class Photo extends PSViewer {
112
116
  linkOverlapAngle: Math.PI / 6,
113
117
  }
114
118
  }],
119
+ [MarkersPlugin, {}],
115
120
  ],
116
121
  ...options
117
122
  });
@@ -126,6 +131,8 @@ export default class Photo extends PSViewer {
126
131
  this._myVTour.config.transitionOptions = this._psvNodeTransition.bind(this);
127
132
  this._clearArrows = this._myVTour.arrowsRenderer.clear.bind(this._myVTour.arrowsRenderer);
128
133
  this._myVTour.arrowsRenderer.clear = () => {};
134
+ this._myMarkers = this.getPlugin(MarkersPlugin);
135
+ this._annotationsVisible = false;
129
136
  this._sequencePlaying = false;
130
137
  this._picturesNavigation = this._options.picturesNavigation || "any";
131
138
 
@@ -136,8 +143,10 @@ export default class Photo extends PSViewer {
136
143
  this._myVTour.addEventListener("enter-arrow", this._onEnterArrow.bind(this));
137
144
  this._myVTour.addEventListener("leave-arrow", this._onLeaveArrow.bind(this));
138
145
  this._myVTour.addEventListener("node-changed", this._onNodeChanged.bind(this));
146
+ this._myMarkers.addEventListener("select-marker", this._onSelectMarker.bind(this));
139
147
  this.addEventListener("position-updated", this._onPositionUpdated.bind(this));
140
148
  this.addEventListener("zoom-updated", this._onZoomUpdated.bind(this));
149
+ this.addEventListener("dblclick", this._onDoubleClick.bind(this));
141
150
  this._parent.addEventListener("select", this._onSelect.bind(this));
142
151
 
143
152
  // Fix for loader circle background not showing up
@@ -410,6 +419,14 @@ export default class Photo extends PSViewer {
410
419
  this._onTilesStartLoading();
411
420
  }
412
421
 
422
+ /**
423
+ * Event handler for double click
424
+ * @private
425
+ */
426
+ _onDoubleClick() {
427
+ this.unfocusAnnotation();
428
+ }
429
+
413
430
  /**
414
431
  * Event handler for node change in PSV.
415
432
  * Allows to send a custom "picture-loaded" event.
@@ -463,11 +480,35 @@ export default class Photo extends PSViewer {
463
480
  else {
464
481
  this.setOption("downloadUrl", null);
465
482
  }
483
+
484
+ // Show annotations
485
+ if(this._annotationsVisible) {
486
+ this.toggleAllAnnotations(true);
487
+ }
466
488
  }
467
489
 
468
490
  this._onTilesStartLoading();
469
491
  }
470
492
 
493
+ /**
494
+ * Event handler for marker select
495
+ * @memberof Panoramax.components.ui.Photo#
496
+ * @private
497
+ */
498
+ _onSelectMarker(e) {
499
+ if(!e.marker) { return; }
500
+ if(e.marker.id?.startsWith("annotation-")) {
501
+ /**
502
+ * Event launched on annotation click over picture
503
+ * @event Panoramax.components.ui.Photo#annotation-click
504
+ * @type {CustomEvent}
505
+ * @property {string} detail.annotationId The annotation UUID
506
+ */
507
+ const event = new CustomEvent("annotation-click", { detail: { annotationId: e.marker.data.id }});
508
+ this.dispatchEvent(event);
509
+ }
510
+ }
511
+
471
512
  /**
472
513
  * Event handler for loading a new range of tiles
473
514
  * @memberof Panoramax.components.ui.Photo#
@@ -888,6 +929,153 @@ export default class Photo extends PSViewer {
888
929
  }
889
930
  }
890
931
 
932
+ /**
933
+ * Are there any picture annotations shown ?
934
+ * @returns {boolean} True if annotations are visible
935
+ * @memberof Panoramax.components.ui.Photo#
936
+ */
937
+ areAnnotationsVisible() {
938
+ return this._annotationsVisible;
939
+ }
940
+
941
+ /**
942
+ * Toggle visibility of picture annotations
943
+ * @param {boolean} visible True to make visible, false to hide
944
+ * @memberof Panoramax.components.ui.Photo#
945
+ */
946
+ toggleAllAnnotations(visible) {
947
+ const meta = this.getPictureMetadata();
948
+ if(!meta) {
949
+ this._myMarkers.clearMarkers();
950
+ throw new Error("No picture currently selected");
951
+ }
952
+
953
+ if(!visible) { this._myMarkers.clearMarkers(); }
954
+ else {
955
+ let annotations = meta.properties.annotations;
956
+ if(annotations.length === 0) { console.warn("No annotation available on picture", meta.id); }
957
+
958
+ const picBData = this.state.textureData.panoData?.baseData;
959
+
960
+ annotations = annotations.map(a => {
961
+ // Get original HD picture dimensions
962
+ const origPicDim = this.getPictureMetadata().properties["pers:interior_orientation"].sensor_array_dimensions;
963
+
964
+ if(!origPicDim) {
965
+ console.warn("Picture lacks pers:interior_orientation.sensor_array_dimensions property, can't compute marker");
966
+ return null;
967
+ }
968
+
969
+ const shape = a.shape.coordinates.map(c1 => c1.map(c2 => {
970
+ // Px coordinates in shown image
971
+ const pxShown = [
972
+ c2[0] * picBData.croppedWidth / origPicDim[0],
973
+ c2[1] * picBData.croppedHeight / origPicDim[1]
974
+ ];
975
+
976
+ // Coords in %
977
+ const pct = [
978
+ (picBData.croppedX + pxShown[0]) / picBData.fullWidth,
979
+ (picBData.croppedY + pxShown[1]) / picBData.fullHeight
980
+ ];
981
+
982
+ // Coords in radians as center offset
983
+ return [
984
+ (pct[0] - 0.5) * 2 * Math.PI,
985
+ (0.5 - pct[1]) * Math.PI,
986
+ ];
987
+ }));
988
+
989
+ return {
990
+ id: `annotation-${a.id}`,
991
+ polygon: shape,
992
+ data: { id: a.id },
993
+ svgStyle: {
994
+ stroke: "var(--orange)",
995
+ strokeWidth: "3px",
996
+ fill: "var(--orange-transparent)",
997
+ cursor: "pointer",
998
+ },
999
+ tooltip: this._parent._t.pnx.semantics_annotation_tooltip,
1000
+ };
1001
+ });
1002
+ this._myMarkers.setMarkers(annotations);
1003
+ }
1004
+
1005
+ const sendEvent = this._annotationsVisible != visible;
1006
+ this._annotationsVisible = visible;
1007
+
1008
+ if(sendEvent) {
1009
+ /**
1010
+ * Event for pictures annotation visibility change
1011
+ * @event Panoramax.components.ui.Photo#annotations-toggled
1012
+ * @type {CustomEvent}
1013
+ * @property {boolean} detail.visible True if they are visible
1014
+ */
1015
+ this.dispatchEvent(new CustomEvent("annotations-toggled", { detail: { visible } }));
1016
+ }
1017
+ }
1018
+
1019
+ /**
1020
+ * Make view centered and zoomed on given annotation.
1021
+ * @param {string} id The annotation UUID
1022
+ * @memberof Panoramax.components.ui.Photo#
1023
+ */
1024
+ focusOnAnnotation(id) {
1025
+ if(!this.areAnnotationsVisible()) { this.toggleAllAnnotations(true); }
1026
+ this.unfocusAnnotation(true);
1027
+
1028
+ const annotationId = `annotation-${id}`;
1029
+ this._myMarkers.updateMarker({
1030
+ id: annotationId,
1031
+ svgStyle: {
1032
+ stroke: "var(--red)",
1033
+ strokeWidth: "3px",
1034
+ fill: "var(--red-transparent)",
1035
+ },
1036
+ data: {
1037
+ selected: true,
1038
+ }
1039
+ });
1040
+ this._myMarkers.gotoMarker(annotationId, 0);
1041
+ this.zoom(65);
1042
+ }
1043
+
1044
+ /**
1045
+ * Remove focus styling on annotations.
1046
+ * @memberof Panoramax.components.ui.Photo#
1047
+ * @param {boolean} [skipEvent=false] Set to true to avoid launching annotations-unfocused event
1048
+ */
1049
+ unfocusAnnotation(skipEvent = false) {
1050
+ const selectedAnnotations = Object.keys(this._myMarkers.markers)
1051
+ .filter(id => id.startsWith("annotation-") && this._myMarkers.markers[id]?.config?.data?.selected);
1052
+
1053
+ if(selectedAnnotations.length > 0) {
1054
+ selectedAnnotations.forEach(id => {
1055
+ this._myMarkers.updateMarker({
1056
+ id,
1057
+ svgStyle: {
1058
+ stroke: "var(--orange)",
1059
+ strokeWidth: "3px",
1060
+ fill: "var(--orange-transparent)",
1061
+ },
1062
+ data: {
1063
+ selected: false,
1064
+ }
1065
+ });
1066
+ });
1067
+
1068
+ if(!skipEvent) {
1069
+ /**
1070
+ * Event for pictures annotation unfocus
1071
+ * @event Panoramax.components.ui.Photo#annotations-unfocused
1072
+ * @type {Event}
1073
+ */
1074
+ this.dispatchEvent(new Event("annotations-unfocused"));
1075
+ }
1076
+ }
1077
+ }
1078
+
891
1079
  /**
892
1080
  * Force reload of texture and tiles.
893
1081
  * @memberof Panoramax.components.ui.Photo#
@@ -0,0 +1,87 @@
1
+ import { LitElement, html, css, nothing } from "lit";
2
+ import { table } from "../styles";
3
+ import { groupByPrefix } from "../../utils/semantics";
4
+
5
+ /**
6
+ * Semantics Tables display all semantics tags from either a picture or an annotation.
7
+ *
8
+ * @class Panoramax.components.ui.SemanticsTable
9
+ * @element pnx-semantics-table
10
+ * @extends [lit.LitElement](https://lit.dev/docs/api/LitElement/)
11
+ * @example
12
+ * ```html
13
+ * <pnx-semantics-table source=${picture.properties} ._t=${viewer._t} />
14
+ * ```
15
+ */
16
+ export default class SemanticsTable extends LitElement {
17
+ /** @private */
18
+ static styles = [ table, css`
19
+ th:first-child, td:first-child { width: 30%; }
20
+ td { vertical-align: top; }
21
+
22
+ td small { color: var(--grey-semi-dark); }
23
+ .qualifiers { margin-top: 5px; }
24
+ .qualifiers > b { margin: 8px 0; }
25
+ .qualifiers ul {
26
+ list-style: none;
27
+ margin: 0px 0px 0px 15px;
28
+ padding: 0;
29
+ }
30
+
31
+ img.prefix-logo {
32
+ max-width: 15px;
33
+ max-height: 15px;
34
+ aspect-ratio: 1;
35
+ vertical-align: middle;
36
+ }
37
+ ` ];
38
+
39
+ /**
40
+ * Component properties.
41
+ * @memberof Panoramax.components.ui.SemanticsTable#
42
+ * @type {Object}
43
+ * @property {object} [source] The picture or annotation feature (having a `semantics` property)
44
+ */
45
+ static properties = {
46
+ source: {type: Object},
47
+ };
48
+
49
+ render() {
50
+ /* eslint-disable indent */
51
+ if(!this.source) { return nothing; }
52
+
53
+ const groups = groupByPrefix(this.source.semantics);
54
+
55
+ return html`<table>
56
+ <thead>
57
+ <tr><th>${this._t.pnx.semantics_key}</th><th>${this._t.pnx.semantics_value}</th></tr>
58
+ </thead>
59
+ <tbody>
60
+ ${groups.map(g => g.tags.map(tag => html`
61
+ <tr>
62
+ <td>
63
+ ${g.prefix != ""
64
+ ? (g.logo
65
+ ? html`<img src=${g.logo} class="prefix-logo" alt=${g.prefix} title=${g.title} />`
66
+ : html`<small>(${g.prefix})</small>`)
67
+ : nothing
68
+ }
69
+ ${g.key_transform ? g.key_transform(tag, this._t) : tag.key}
70
+ </td>
71
+ <td>
72
+ ${g.value_transform ? g.value_transform(tag, this._t) : tag.value}
73
+ ${tag.qualifiers ? html`<div class="qualifiers">
74
+ <b>${this._t.pnx.semantics_qualifiers}</b>
75
+ <ul>
76
+ ${tag.qualifiers.map(q => html`<li>${q.subkey} = ${q.value}</li>`)}
77
+ </ul>
78
+ </div>` : nothing}
79
+ </td>
80
+ </tr>
81
+ `))}
82
+ </tbody>
83
+ </table>`;
84
+ }
85
+ }
86
+
87
+ customElements.define("pnx-semantics-table", SemanticsTable);
@@ -7,8 +7,10 @@ export {default as ButtonGroup} from "./ButtonGroup";
7
7
  export {default as Button} from "./Button";
8
8
  export {default as CopyButton} from "./CopyButton";
9
9
  export {default as Grade} from "./Grade";
10
+ export {default as HashTags} from "./HashTags";
10
11
  export {default as LinkButton} from "./LinkButton";
11
12
  export {default as ListGroup} from "./ListGroup";
13
+ export {default as ListItem} from "./ListItem";
12
14
  export {default as Loader} from "./Loader";
13
15
  export {default as Map} from "./Map";
14
16
  export {default as MapMore} from "./MapMore";
@@ -17,6 +19,7 @@ export {default as Popup} from "./Popup";
17
19
  export {default as ProgressBar} from "./ProgressBar";
18
20
  export {default as QualityScore} from "./QualityScore";
19
21
  export {default as SearchBar} from "./SearchBar";
22
+ export {default as SemanticsTable} from "./SemanticsTable";
20
23
  export {default as TogglableGroup} from "./TogglableGroup";
21
24
  import * as widgets from "./widgets";
22
25
  export {widgets};
@@ -2,10 +2,14 @@
2
2
  import maplibregl from "!maplibre-gl";
3
3
 
4
4
  import { LitElement, html } from "lit";
5
- import { forwardGeocodingBAN, forwardGeocodingNominatim } from "../../../utils/geocoder";
5
+ import { forwardGeocodingBAN, forwardGeocodingStandard, forwardGeocodingNominatim } from "../../../utils/geocoder";
6
6
  import "./GeoSearch.css";
7
7
 
8
- const GEOCODER_ENGINES = { "ban": forwardGeocodingBAN, "nominatim": forwardGeocodingNominatim };
8
+ const GEOCODER_ENGINES = {
9
+ "ban": forwardGeocodingBAN,
10
+ "standard": forwardGeocodingStandard,
11
+ "nominatim": forwardGeocodingNominatim
12
+ };
9
13
 
10
14
  /**
11
15
  * Ready-to-use geocoder search bar.
@@ -14,7 +18,11 @@ const GEOCODER_ENGINES = { "ban": forwardGeocodingBAN, "nominatim": forwardGeoco
14
18
  * @extends [lit.LitElement](https://lit.dev/docs/api/LitElement/)
15
19
  * @example
16
20
  * ```html
21
+ * <!-- Default geocoder -->
17
22
  * <pnx-widget-geosearch _parent=${viewer} />
23
+ *
24
+ * <!-- Custom-URL geocoder -->
25
+ * <pnx-widget-geosearch geocoder="https://photon.komoot.io/api" _parent=${viewer} />
18
26
  * ```
19
27
  */
20
28
  export default class GeoSearch extends LitElement {
@@ -22,7 +30,7 @@ export default class GeoSearch extends LitElement {
22
30
  * Component properties.
23
31
  * @memberof Panoramax.components.ui.widgets.GeoSearch#
24
32
  * @type {Object}
25
- * @property {string} [geocoder=nominatim] The geocoder engine to use (nominatim, ban)
33
+ * @property {string} [geocoder=nominatim] The geocoder engine to use (nominatim, ban, or URL to a standard [GeocodeJSON-compliant](https://github.com/geocoders/geocodejson-spec/blob/master/draft/README.md) API)
26
34
  */
27
35
  static properties = {
28
36
  geocoder: {type: String},
@@ -54,7 +62,7 @@ export default class GeoSearch extends LitElement {
54
62
  connectedCallback() {
55
63
  super.connectedCallback();
56
64
 
57
- this._geocoderEngine = GEOCODER_ENGINES[this.geocoder];
65
+ this._geocoderEngine = GEOCODER_ENGINES[this.geocoder] || (config => GEOCODER_ENGINES.standard(config, this.geocoder));
58
66
  this._parent?.onceMapReady?.().then(() => {
59
67
  this._geolocate = this._geolocateCtrl.onAdd(this._parent.map);
60
68
  this._geolocate.setAttribute("slot", "pre");
@@ -84,7 +92,7 @@ export default class GeoSearch extends LitElement {
84
92
  else {
85
93
  return this._geocoderEngine({
86
94
  query,
87
- limit: 3,
95
+ limit: 5,
88
96
  //bbox: this._parent.map.getBounds().toArray().map(d => d.join(",")).join(","),
89
97
  proximity: this._parent.map.getCenter().lat+","+this._parent.map.getCenter().lng,
90
98
  }).then(data => {
@@ -0,0 +1,49 @@
1
+ <?xml version="1.0" encoding="UTF-8" standalone="no"?>
2
+ <!-- Created with Inkscape (http://www.inkscape.org/) -->
3
+
4
+ <svg
5
+ width="240mm"
6
+ height="239.99869mm"
7
+ viewBox="0 0 240 239.99869"
8
+ id="svg6743"
9
+ version="1.1"
10
+ xmlns="http://www.w3.org/2000/svg"
11
+ xmlns:svg="http://www.w3.org/2000/svg">
12
+ <defs
13
+ id="defs1" />
14
+ <g
15
+ id="layer1"
16
+ transform="translate(-30,-27.000656)">
17
+ <g
18
+ id="g7426"
19
+ transform="translate(322.142,-53.972906)">
20
+ <path
21
+ style="display:inline;fill:#76c551;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3.61532"
22
+ id="path33449"
23
+ d="m -81.063095,208.94609 c -11.906339,9.92421 -27.194885,15.8987 -43.860635,15.8987 -4.95854,0 -9.78728,-0.55158 -14.45059,-1.55504 l -4.79842,5.8446 c -10.66449,-2.85736 -20.38429,-7.94043 -28.6326,-14.74578 l -12.89559,12.92212 1.58177,9.54347 -47.96347,47.98965 4.63827,1.7685 45.04032,-17.15658 45.0402,17.15658 45.040312,-17.15658 17.158544,-45.03976 z" />
24
+ <path
25
+ d="m -272.48495,89.294626 17.1585,45.040274 -17.1585,45.03993 17.1585,45.03972 -17.1585,45.03977 10.53634,4.02267 57.2385,-57.21102 10.26764,1.58169 12.46673,-12.46669 c -7.35519,-8.52221 -12.86173,-18.6902 -15.87027,-29.92032 l 5.8446,-4.79842 c -1.00531,-4.66323 -1.55503,-9.49189 -1.55503,-14.45044 0,-24.76984 13.21043,-46.53472 32.94893,-58.606534 l -21.79693,-8.31063 -45.04019,17.158544 z"
26
+ id="path33447"
27
+ style="display:inline;fill:#76c551;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3.61532" />
28
+ <path
29
+ style="display:inline;fill:#59a336;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3.61532"
30
+ id="path33451"
31
+ d="m -81.063095,208.94609 c -11.906339,9.92421 -27.194885,15.8987 -43.860635,15.8987 -4.95854,0 -9.78728,-0.55158 -14.45059,-1.55504 l -4.79842,5.8446 -28.67744,-15.11228 -12.85075,13.28862 1.58177,9.54347 46.85284,7.05799 -0.0982,42.70016 45.040313,-17.15658 17.158544,-45.03976 z" />
32
+ <ellipse
33
+ style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:12.7048;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none"
34
+ id="ellipse33453"
35
+ cx="-122.83165"
36
+ cy="155.70955"
37
+ rx="59.801929"
38
+ ry="60.929199" />
39
+ <path
40
+ style="opacity:1;fill:#cccccc;fill-opacity:1;stroke:none;stroke-width:12.7048;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none"
41
+ d="m -70.867543,179.77128 c -4.021615,-66.77094 -70.182367,-83.311142 -110.499567,-45.77004 21.03677,-28.56709 48.05279,-46.045197 78.56638,-33.40602 30.51362,12.63913 41.797793,45.98173 31.933187,79.17606 z"
42
+ id="path33455" />
43
+ <path
44
+ id="path33457"
45
+ d="m -73.395575,102.22726 c -28.338185,-28.338264 -74.283665,-28.338264 -102.621895,0 -17.93779,17.93776 -24.48523,42.91327 -19.71413,66.02883 l -11.27485,8.16937 c 5.13477,13.61756 12.1317,21.8574 16.91241,26.2963 l -10.22839,10.22834 h -10.80252 l -81.01705,81.01654 27.00583,27.00561 81.01701,-81.01683 v -10.80225 l 10.19464,-10.19425 c 4.56162,4.75244 12.69997,11.38138 25.75686,16.30469 l 7.86543,-10.90386 c 23.35858,5.12197 48.742245,-1.34701 66.906498,-19.5115 28.338386,-28.33732 28.33819,-74.28276 1.57e-4,-102.62099 z m -12.962835,12.96296 c 21.179095,21.17921 21.179095,55.51685 0,76.69579 -21.17902,21.17897 -55.51721,21.17897 -76.6963,0 -21.17898,-21.17894 -21.17898,-55.51658 0,-76.69579 21.17929,-21.179216 55.51728,-21.179216 76.6963,0 z"
46
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#2f2f2f;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:7.76059;marker:none;enable-background:accumulate" />
47
+ </g>
48
+ </g>
49
+ </svg>
package/src/img/wd.svg ADDED
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 18"><path d="M2.5 1h1v16h-1zm2 0h3v16h-3zm4 0h3v16h-3z" fill="#900"/><path d="M12.5 1h1v16h-1zm2 0h1v16h-1zm12 0h1v16h-1zm2 0h1v16h-1z" fill="#396"/><path d="M16.5 1h3v16h-3zm4 0h1v16h-1zm2 0h3v16h-3z" fill="#069"/></svg>
@@ -173,6 +173,29 @@
173
173
  "metadata_exif_value": "Value",
174
174
  "metadata_exif_doc": "Docs for EXIF tags",
175
175
  "metadata_exif_doc_title": "Go to Exiv2 documentation to have full details on EXIF and XMP tags definitions",
176
+ "semantics_title": "Tags",
177
+ "semantics_tags": "{nb} tags",
178
+ "semantics_features": "Detected features",
179
+ "semantics_features_none": "No feature has been detected or annotated in this picture yet.",
180
+ "semantics_features_default_title": "Feature #{nb}",
181
+ "semantics_features_subtitle": "{nb} associated properties",
182
+ "semantics_annotation_tooltip": "Click to see details",
183
+ "semantics_show_all_tags": "Show all tags",
184
+ "semantics_hide_all_tags": "Hide all tags",
185
+ "semantics_key": "Key",
186
+ "semantics_value": "Value",
187
+ "semantics_key_doc": "Know more about this key",
188
+ "semantics_value_doc": "Know more about this tag",
189
+ "semantics_tags_picture": "Picture tags",
190
+ "semantics_tags_picture_none": "No tags has been set for this picture yet.",
191
+ "semantics_qualifiers": "Qualifiers",
192
+ "semantics_show_annotations": "Display picture annotations",
193
+ "semantics_hide_annotations": "Hide picture annotations",
194
+ "semantics_wikidata_properties": {
195
+ "P31": "instance of",
196
+ "P279": "subclass of",
197
+ "P361": "part of"
198
+ },
176
199
  "report": "Report",
177
200
  "report_auth": "This report will be sent using your account \"{a}\"",
178
201
  "report_nature_label": "Nature of the issue",
@@ -173,6 +173,27 @@
173
173
  "metadata_exif_value": "Valeur",
174
174
  "metadata_exif_doc": "Doc des attributs EXIF",
175
175
  "metadata_exif_doc_title": "Acééder à la doc Exiv2 pour en savoir plus sur les attributs EXIF et XMP",
176
+ "semantics_title": "Tags",
177
+ "semantics_tags": "{nb} attributs",
178
+ "semantics_features": "Objets détectés",
179
+ "semantics_features_none": "Aucun objet n'a été détecté ou annoté dans cette photo pour l'instant.",
180
+ "semantics_features_default_title": "Objet #{nb}",
181
+ "semantics_features_subtitle": "{nb} attributs associés",
182
+ "semantics_annotation_tooltip": "Cliquez pour voir les détails",
183
+ "semantics_show_all_tags": "Voir tous les attributs",
184
+ "semantics_hide_all_tags": "Masquer les attributs",
185
+ "semantics_key": "Clé",
186
+ "semantics_value": "Valeur",
187
+ "semantics_key_doc": "En savoir plus à propos de cette clé",
188
+ "semantics_value_doc": "En savoir plus à propos de cet attribut",
189
+ "semantics_tags_picture": "Attributs de la photo",
190
+ "semantics_tags_picture_none": "Aucun attribut n'a été défini pour cette photo pour l'instant.",
191
+ "semantics_qualifiers": "Qualificateurs",
192
+ "semantics_wikidata_properties": {
193
+ "P31": "instance de",
194
+ "P279": "sous-classe de",
195
+ "P361": "partie de"
196
+ },
176
197
  "report": "Signaler",
177
198
  "report_auth": "Ce signalement sera envoyé en utilisant votre compte \"{a}\"",
178
199
  "report_nature_label": "Nature du problème",
@@ -185,7 +185,34 @@
185
185
  "filter_date_6months": "6 mesi",
186
186
  "picture_all": "Tutte",
187
187
  "metadata_exif_doc": "Doc per gli attributi EXIF",
188
- "metadata_exif_doc_title": "Vai alla documentazione di Exiv2 per i dettagli completi sulle definizioni degli attributi EXIF e XMP"
188
+ "metadata_exif_doc_title": "Vai alla documentazione di Exiv2 per i dettagli completi sulle definizioni degli attributi EXIF e XMP",
189
+ "semantics_value": "Valore",
190
+ "semantics_key_doc": "Per saperne di più su questa chiave",
191
+ "semantics_title": "Etichette",
192
+ "semantics_features": "Oggetti rilevati",
193
+ "semantics_features_none": "Non è ancora stato rilevato alcun oggetto in questa foto.",
194
+ "semantics_features_default_title": "Oggetto #{nb}",
195
+ "semantics_features_subtitle": "{nb} proprietà associate",
196
+ "semantics_tags": "{nb} attributi",
197
+ "semantics_show_all_tags": "Mostra tutti gli attributi",
198
+ "semantics_hide_all_tags": "Nascondi tutti gli attributi",
199
+ "semantics_key": "Chiave",
200
+ "semantics_value_doc": "Per saperne di più su questa etichetta",
201
+ "semantics_wikidata_properties": {
202
+ "P361": "parte di",
203
+ "P31": "instanza di",
204
+ "P279": "sottoclasse di"
205
+ },
206
+ "semantics_hide_annotations": "Nascondi le annotazioni della foto",
207
+ "semantics_tags_picture": "Etichette della foto",
208
+ "semantics_show_annotations": "Mostra le annotazioni della foto",
209
+ "semantics_annotation_tooltip": "Clicca per vedere i dettagli",
210
+ "semantics_tags_picture_none": "Non è stata ancora aggiunta alcuna etichetta su questa foto.",
211
+ "semantics_qualifiers": "Qualificatori",
212
+ "metadata_location_coordinates": "Coordinate (longitudine, latitudine)",
213
+ "metadata_location_copy": "Copia {v}",
214
+ "metadata_location_copy_more": "Ulteriori opzioni per la copia delle coordinate",
215
+ "whats_panoramax": "Panoramax è la geo-commons per le foto dei territori."
189
216
  },
190
217
  "psv": {
191
218
  "loadError": "Impossibile caricare l’immagine panoramica",
@@ -15,7 +15,10 @@
15
15
  "🏘️ 3D-rendering",
16
16
  "📷 360° afbeelden initialiseren",
17
17
  "🟠 Kleur balancering",
18
- "💯 Bereken kwaliteits-score ©"
18
+ "💯 Bereken kwaliteits-score ©",
19
+ "📡 Updates downloaden",
20
+ "🌍 Kaarttegels ophalen",
21
+ "📸 Schaduwen verwerken"
19
22
  ],
20
23
  "share_embed_docs": "Lees meer over embedded instellingen",
21
24
  "sequence_pause": "Pauzeer sequentie",
@@ -39,7 +42,7 @@
39
42
  "search_address": "Zoek een adres, stad…",
40
43
  "share": "Deel",
41
44
  "share_links": "Links",
42
- "share_page": "Link naar deze pagina",
45
+ "share_page": "Link naar deze foto",
43
46
  "share_image": "HD afbeelding",
44
47
  "share_embed": "Embedden op uw website",
45
48
  "share_print": "Afdrukken",
@@ -72,7 +75,11 @@
72
75
  "👥 Personas opslaan",
73
76
  "🥞 Pannenkoekenhuizen localiseren",
74
77
  "🧑‍💻 Interface debuggen",
75
- "📈 Statistieken verhogen"
78
+ "📈 Statistieken verhogen",
79
+ "🤖 Semantiek aanleren",
80
+ "🎨 Interface herontwerpen",
81
+ "📅 Fotomappingparty's plannen",
82
+ "🧀 Kazen laten rijpen"
76
83
  ],
77
84
  "share_rss_title": "RSS-feed van nieuwe reeksen in het nu zichtbare kaartgebied",
78
85
  "josm_live": "Schakel JOSM automatische synchronisatie in bij het laden van afbeeldingen",
@@ -164,7 +171,10 @@
164
171
  "report_email_placeholder": "Optioneel",
165
172
  "report_submit": "Verzenden",
166
173
  "report_wait": "Rapport verzenden …",
167
- "report_success": "Het rapport werd succesvol verzonden. Het zal zo snel mogelijk behandeld worden."
174
+ "report_success": "Het rapport werd succesvol verzonden. Het zal zo snel mogelijk behandeld worden.",
175
+ "whats_panoramax": "Panoramax is de geo-commons voor foto's van gebieden.",
176
+ "contribute_id": "Bijdragen aan OpenStreetMap met de iD-editor",
177
+ "geo_uri": "Externe app"
168
178
  },
169
179
  "psv": {
170
180
  "twoFingers": "Gebruik twee vingers om te navigeren",
@@ -185,7 +185,12 @@
185
185
  "geo_uri": "外部程式",
186
186
  "contribute_id": "透過 iD 編輯器來貢獻 OpenStreetMap",
187
187
  "filter_date_6months": "6 個月",
188
- "picture_all": "全部"
188
+ "picture_all": "全部",
189
+ "metadata_exif_doc": "EXIF 標籤文件",
190
+ "metadata_exif_doc_title": "請參閱 Exiv2 文件以取得 EXIF 和 XMP 標籤定義的完整說明",
191
+ "metadata_location_coordinates": "座標 (經度, 緯度)",
192
+ "metadata_location_copy": "複製 {v}",
193
+ "metadata_location_copy_more": "更多座標複製選項"
189
194
  },
190
195
  "map": {
191
196
  "loading": "正在載入…",