@panoramax/web-viewer 4.0.1-develop-32d1fb01 → 4.0.1-develop-2250d7d3
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/CHANGELOG.md +1 -0
- package/build/index.css.map +1 -1
- package/build/index.js +128 -37
- package/build/index.js.map +1 -1
- package/docs/reference/components/ui/CopyButton.md +1 -0
- package/docs/reference/components/ui/widgets/CopyCoordinates.md +32 -0
- package/docs/reference.md +1 -0
- package/mkdocs.yml +1 -0
- package/package.json +1 -1
- package/src/components/menus/PictureMetadata.js +12 -2
- package/src/components/styles.js +61 -0
- package/src/components/ui/ButtonGroup.css +2 -0
- package/src/components/ui/CopyButton.js +3 -1
- package/src/components/ui/TogglableGroup.js +1 -1
- package/src/components/ui/widgets/CopyCoordinates.js +75 -0
- package/src/components/ui/widgets/PictureLegendActions.js +1 -1
- package/src/components/ui/widgets/index.js +1 -0
- package/src/translations/en.json +3 -2
- package/src/translations/fr.json +3 -2
- package/src/translations/it.json +3 -1
- package/src/utils/utils.js +13 -0
- package/tests/utils/utils.test.js +136 -109
|
@@ -35,4 +35,5 @@ Component properties.
|
|
|
35
35
|
| [kind] | <code>string</code> | <code>"full"</code> | The style variation of the button (full, outline, flat, superflat, inline, superinline) |
|
|
36
36
|
| [size] | <code>string</code> | <code>"md"</code> | The size of the button (sm, md, l, xl, xxl) |
|
|
37
37
|
| [unstyled] | <code>boolean</code> | <code>false</code> | Disable all styling (for list group integration) |
|
|
38
|
+
| [title] | <code>string</code> | | Tooltip text displayed when hovering over the button |
|
|
38
39
|
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
<a name="Panoramax.components.ui.widgets.CopyCoordinates"></a>
|
|
2
|
+
|
|
3
|
+
## Panoramax.components.ui.widgets.CopyCoordinates ⇐ <code>[lit.LitElement](https://lit.dev/docs/api/LitElement/)</code>
|
|
4
|
+
**Kind**: static class of <code>Panoramax.components.ui.widgets</code>
|
|
5
|
+
**Extends**: <code>[lit.LitElement](https://lit.dev/docs/api/LitElement/)</code>
|
|
6
|
+
**Element**: pnx-copy-coordinates
|
|
7
|
+
|
|
8
|
+
* [.CopyCoordinates](#Panoramax.components.ui.widgets.CopyCoordinates) ⇐ <code>[lit.LitElement](https://lit.dev/docs/api/LitElement/)</code>
|
|
9
|
+
* [new CopyCoordinates()](#new_Panoramax.components.ui.widgets.CopyCoordinates_new)
|
|
10
|
+
* [.properties](#Panoramax.components.ui.widgets.CopyCoordinates+properties) : <code>Object</code>
|
|
11
|
+
|
|
12
|
+
<a name="new_Panoramax.components.ui.widgets.CopyCoordinates_new"></a>
|
|
13
|
+
|
|
14
|
+
### new CopyCoordinates()
|
|
15
|
+
Copy Coordinates button allows easy copy of several format of map coordinates.
|
|
16
|
+
|
|
17
|
+
**Example**
|
|
18
|
+
```html
|
|
19
|
+
<pnx-copy-coordinates gps=${[-1.7, 48.6]} _parent=${viewer} />
|
|
20
|
+
```
|
|
21
|
+
<a name="Panoramax.components.ui.widgets.CopyCoordinates+properties"></a>
|
|
22
|
+
|
|
23
|
+
### copyCoordinates.properties : <code>Object</code>
|
|
24
|
+
Component properties.
|
|
25
|
+
|
|
26
|
+
**Kind**: instance property of [<code>CopyCoordinates</code>](#Panoramax.components.ui.widgets.CopyCoordinates)
|
|
27
|
+
**Properties**
|
|
28
|
+
|
|
29
|
+
| Name | Type | Description |
|
|
30
|
+
| --- | --- | --- |
|
|
31
|
+
| gps | <code>Array.<number></code> | GPS/map coordinates, as [lon, lat] |
|
|
32
|
+
|
package/docs/reference.md
CHANGED
|
@@ -61,6 +61,7 @@ Basic UI components:
|
|
|
61
61
|
|
|
62
62
|
More complex UI components (but not menus):
|
|
63
63
|
|
|
64
|
+
- [CopyCoordinates](./reference/components/ui/widgets/CopyCoordinates.md) : a copy-to-clipboard button for coordinates, with many format options.
|
|
64
65
|
- [GeoSearch](./reference/components/ui/widgets/GeoSearch.md) : a geocoder search bar with GPS location tool.
|
|
65
66
|
- [Legend](./reference/components/ui/widgets/Legend.md) : a togglable map/picture legend.
|
|
66
67
|
- [MapFiltersButton](./reference/components/ui/widgets/MapFiltersButton.md) : a togglable map filters button & menu.
|
package/mkdocs.yml
CHANGED
|
@@ -77,6 +77,7 @@ nav:
|
|
|
77
77
|
- ShareMenu: 'reference/components/menus/ShareMenu.md'
|
|
78
78
|
- ui:
|
|
79
79
|
- widgets:
|
|
80
|
+
- CopyCoordinates: 'reference/components/ui/widgets/CopyCoordinates.md'
|
|
80
81
|
- GeoSearch: 'reference/components/ui/widgets/GeoSearch.md'
|
|
81
82
|
- Legend: 'reference/components/ui/widgets/Legend.md'
|
|
82
83
|
- MapFiltersButton: 'reference/components/ui/widgets/MapFiltersButton.md'
|
package/package.json
CHANGED
|
@@ -146,8 +146,18 @@ export default class PictureMetadata extends LitElement {
|
|
|
146
146
|
// Location tab
|
|
147
147
|
const orientation = this._meta?.properties?.["view:azimuth"] !== undefined && `${this._meta.properties["view:azimuth"]}°`;
|
|
148
148
|
const locationData = [
|
|
149
|
-
{
|
|
150
|
-
|
|
149
|
+
{
|
|
150
|
+
title: this._parent?._t.pnx.metadata_location_coordinates,
|
|
151
|
+
content: html`
|
|
152
|
+
${this._meta.gps[0]}, ${this._meta.gps[1]}
|
|
153
|
+
<pnx-copy-coordinates
|
|
154
|
+
._parent=${this._parent}
|
|
155
|
+
.gps=${this._meta.gps}
|
|
156
|
+
style="margin-left: 10px"
|
|
157
|
+
></pnx-copy-coordinates>
|
|
158
|
+
`,
|
|
159
|
+
style: "width: 100%"
|
|
160
|
+
},
|
|
151
161
|
{ title: this._parent?._t.pnx.metadata_location_orientation, content: orientation || missing() },
|
|
152
162
|
{ title: this._parent?._t.pnx.metadata_location_precision, content: getGPSPrecision(this._meta) || missing() },
|
|
153
163
|
];
|
package/src/components/styles.js
CHANGED
|
@@ -274,6 +274,67 @@ export const btn = css`
|
|
|
274
274
|
}
|
|
275
275
|
`;
|
|
276
276
|
|
|
277
|
+
// Button group
|
|
278
|
+
export const btngroup = css`
|
|
279
|
+
pnx-button-group > pnx-button {
|
|
280
|
+
display: inline-flex;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
pnx-button-group > pnx-button::part(btn) {
|
|
284
|
+
height: unset;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/* Togglable in group */
|
|
288
|
+
pnx-button-group > pnx-togglable-group > pnx-button {
|
|
289
|
+
width: 100%;
|
|
290
|
+
height: 100%;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/* Row */
|
|
294
|
+
pnx-button-group[dir="row"] > :not(:first-child):not(:last-child)::part(btn),
|
|
295
|
+
pnx-button-group[dir="row"] > :not(:first-child):not(:last-child) > ::part(btn) {
|
|
296
|
+
border-radius: 0;
|
|
297
|
+
border-left: none;
|
|
298
|
+
border-right: none;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
pnx-button-group[dir="row"] > :first-child::part(btn),
|
|
302
|
+
pnx-button-group[dir="row"] > :first-child > ::part(btn) {
|
|
303
|
+
border-top-right-radius: 0;
|
|
304
|
+
border-bottom-right-radius: 0;
|
|
305
|
+
border-right: none;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
pnx-button-group[dir="row"] > :last-child::part(btn),
|
|
309
|
+
pnx-button-group[dir="row"] > :last-child > ::part(btn) {
|
|
310
|
+
border-top-left-radius: 0;
|
|
311
|
+
border-bottom-left-radius: 0;
|
|
312
|
+
border-left: none;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
/* Column */
|
|
316
|
+
pnx-button-group[dir="column"] > :not(:first-child):not(:last-child)::part(btn),
|
|
317
|
+
pnx-button-group[dir="column"] > :not(:first-child):not(:last-child) > ::part(btn) {
|
|
318
|
+
border-radius: 0;
|
|
319
|
+
border-top: none;
|
|
320
|
+
border-bottom: none;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
pnx-button-group[dir="column"] > :first-child::part(btn),
|
|
324
|
+
pnx-button-group[dir="column"] > :first-child > ::part(btn) {
|
|
325
|
+
border-bottom-right-radius: 0;
|
|
326
|
+
border-bottom-left-radius: 0;
|
|
327
|
+
border-bottom: none;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
pnx-button-group[dir="column"] > :last-child::part(btn),
|
|
331
|
+
pnx-button-group[dir="column"] > :last-child > ::part(btn) {
|
|
332
|
+
border-top-left-radius: 0;
|
|
333
|
+
border-top-right-radius: 0;
|
|
334
|
+
border-top: none;
|
|
335
|
+
}
|
|
336
|
+
`;
|
|
337
|
+
|
|
277
338
|
// Titles
|
|
278
339
|
export const titles = css`
|
|
279
340
|
h1, h2, h3, h4, h5, h6 {
|
|
@@ -41,6 +41,7 @@ export default class CopyButton extends LitElement {
|
|
|
41
41
|
* @property {string} [kind=full] The style variation of the button (full, outline, flat, superflat, inline, superinline)
|
|
42
42
|
* @property {string} [size=md] The size of the button (sm, md, l, xl, xxl)
|
|
43
43
|
* @property {boolean} [unstyled=false] Disable all styling (for list group integration)
|
|
44
|
+
* @property {string} [title] Tooltip text displayed when hovering over the button
|
|
44
45
|
*/
|
|
45
46
|
static properties = {
|
|
46
47
|
text: {type: String},
|
|
@@ -48,6 +49,7 @@ export default class CopyButton extends LitElement {
|
|
|
48
49
|
kind: {type: String},
|
|
49
50
|
size: {type: String},
|
|
50
51
|
unstyled: {type: Boolean},
|
|
52
|
+
title: { type: String },
|
|
51
53
|
_active: {state: true, type: Boolean},
|
|
52
54
|
};
|
|
53
55
|
|
|
@@ -94,7 +96,7 @@ export default class CopyButton extends LitElement {
|
|
|
94
96
|
[`pnx-btn-${this.kind}`]: !this.unstyled,
|
|
95
97
|
[`pnx-btn-${this.size}`]: !this.unstyled,
|
|
96
98
|
};
|
|
97
|
-
return html`<button class=${classMap(classes)} part="btn">
|
|
99
|
+
return html`<button title=${this.title} class=${classMap(classes)} part="btn">
|
|
98
100
|
${this._active ?
|
|
99
101
|
html`${this._t?.pnx.copied || ""} ${fa(faCheck)}` :
|
|
100
102
|
html`<slot>${fa(faCopy)} ${this._t?.pnx.copy || ""}</slot>`
|
|
@@ -145,7 +145,7 @@ export default class TogglableGroup extends LitElement {
|
|
|
145
145
|
"pnx-padded": this.padded !== "false",
|
|
146
146
|
};
|
|
147
147
|
|
|
148
|
-
return html`<div class="container">
|
|
148
|
+
return html`<div class="container" @click=${e => e.stopPropagation()}>
|
|
149
149
|
<slot name="button" @slotchange=${this.handleButtonSlotChange}></slot>
|
|
150
150
|
<div class=${classMap(panelClasses)} part="menu">
|
|
151
151
|
<slot></slot>
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { LitElement, html, css } from "lit";
|
|
2
|
+
import { degToDms } from "../../../utils/utils";
|
|
3
|
+
import { fa } from "../../../utils/widgets";
|
|
4
|
+
import { faChevronDown } from "@fortawesome/free-solid-svg-icons/faChevronDown";
|
|
5
|
+
import { btngroup } from "../../styles";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Copy Coordinates button allows easy copy of several format of map coordinates.
|
|
9
|
+
* @class Panoramax.components.ui.widgets.CopyCoordinates
|
|
10
|
+
* @element pnx-copy-coordinates
|
|
11
|
+
* @extends [lit.LitElement](https://lit.dev/docs/api/LitElement/)
|
|
12
|
+
* @example
|
|
13
|
+
* ```html
|
|
14
|
+
* <pnx-copy-coordinates gps=${[-1.7, 48.6]} _parent=${viewer} />
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
export default class CopyCoordinates extends LitElement {
|
|
18
|
+
/** @private */
|
|
19
|
+
static styles = [btngroup, css`
|
|
20
|
+
pnx-togglable-group::part(menu) {
|
|
21
|
+
border-radius: 5px;
|
|
22
|
+
min-width: unset;
|
|
23
|
+
}
|
|
24
|
+
`];
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Component properties.
|
|
28
|
+
* @memberof Panoramax.components.ui.widgets.CopyCoordinates#
|
|
29
|
+
* @type {Object}
|
|
30
|
+
* @property {number[]} gps GPS/map coordinates, as [lon, lat]
|
|
31
|
+
*/
|
|
32
|
+
static properties = {
|
|
33
|
+
gps: {type: Array},
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
/** @private */
|
|
37
|
+
render() {
|
|
38
|
+
const dmslonval = degToDms(this.gps[0]);
|
|
39
|
+
const dmslon = dmslonval.d < 0 ? `${Math.abs(dmslonval.d)}°${dmslonval.m}'${dmslonval.s}"W` : `${dmslonval.d}°${dmslonval.m}'${dmslonval.s}"E`;
|
|
40
|
+
const dmslatval = degToDms(this.gps[1]);
|
|
41
|
+
const dmslat = dmslatval.d < 0 ? `${Math.abs(dmslatval.d)}°${dmslatval.m}'${dmslatval.s}"S` : `${dmslatval.d}°${dmslatval.m}'${dmslatval.s}"N`;
|
|
42
|
+
|
|
43
|
+
const values = {
|
|
44
|
+
ddeclatlon: `${this.gps[1].toFixed(7)}, ${this.gps[0].toFixed(7)}`,
|
|
45
|
+
ddeclonlat: `${this.gps[0].toFixed(7)}, ${this.gps[1].toFixed(7)}`,
|
|
46
|
+
ddmslonlat: `${dmslon}, ${dmslat}`,
|
|
47
|
+
ddmslatlon: `${dmslat}, ${dmslon}`,
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
return html`<pnx-button-group style="display: inline-block; vertical-align: baseline" dir="row">
|
|
51
|
+
<pnx-copy-button
|
|
52
|
+
size="sm"
|
|
53
|
+
text=${values.ddeclonlat}
|
|
54
|
+
title=${this._parent?._t.pnx.metadata_location_copy.replace("{v}", values.ddeclonlat)}
|
|
55
|
+
></pnx-copy-button>
|
|
56
|
+
|
|
57
|
+
<pnx-togglable-group padded="false" ._parent=${this._parent}>
|
|
58
|
+
<pnx-button
|
|
59
|
+
size="sm"
|
|
60
|
+
slot="button"
|
|
61
|
+
title=${this._parent?._t.pnx.metadata_location_copy_more}
|
|
62
|
+
>${fa(faChevronDown)}</pnx-button>
|
|
63
|
+
<pnx-list-group>
|
|
64
|
+
${Object.values(values).map(text => html`
|
|
65
|
+
<pnx-copy-button unstyled text=${text} ._t=${this._parent._t}>
|
|
66
|
+
${this._parent?._t.pnx.metadata_location_copy.replace("{v}", text)}
|
|
67
|
+
</pnx-copy-button>
|
|
68
|
+
`)}
|
|
69
|
+
</pnx-list-group>
|
|
70
|
+
</pnx-togglable-group>
|
|
71
|
+
</pnx-button-group>`;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
customElements.define("pnx-copy-coordinates", CopyCoordinates);
|
|
@@ -58,7 +58,7 @@ export default class PictureLegendActions extends LitElement {
|
|
|
58
58
|
|
|
59
59
|
/** @private */
|
|
60
60
|
_closeGroup() {
|
|
61
|
-
this.renderRoot.querySelector("
|
|
61
|
+
this.renderRoot.querySelector("#pic-legend-headline-menu").close();
|
|
62
62
|
}
|
|
63
63
|
|
|
64
64
|
/** @private */
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
* @module Panoramax:components:ui:widgets
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
+
export {default as CopyCoordinates} from "./CopyCoordinates";
|
|
6
7
|
export {default as GeoSearch} from "./GeoSearch";
|
|
7
8
|
export {default as Legend} from "./Legend";
|
|
8
9
|
export {default as MapFiltersButton} from "./MapFiltersButton";
|
package/src/translations/en.json
CHANGED
|
@@ -156,10 +156,11 @@
|
|
|
156
156
|
"metadata_camera_resolution": "Resolution",
|
|
157
157
|
"metadata_camera_focal_length": "Focal length",
|
|
158
158
|
"metadata_location": "Position",
|
|
159
|
-
"
|
|
160
|
-
"metadata_location_latitude": "Latitude",
|
|
159
|
+
"metadata_location_coordinates": "Coordinates (longitude, latitude)",
|
|
161
160
|
"metadata_location_orientation": "Direction",
|
|
162
161
|
"metadata_location_precision": "Positioning precision",
|
|
162
|
+
"metadata_location_copy": "Copy {v}",
|
|
163
|
+
"metadata_location_copy_more": "More coordinates copy options",
|
|
163
164
|
"metadata_quality": "Quality",
|
|
164
165
|
"metadata_quality_help": "Know more about Quality Score",
|
|
165
166
|
"metadata_quality_score": "Global score",
|
package/src/translations/fr.json
CHANGED
|
@@ -156,10 +156,11 @@
|
|
|
156
156
|
"metadata_camera_resolution": "Résolution",
|
|
157
157
|
"metadata_camera_focal_length": "Longueur focale",
|
|
158
158
|
"metadata_location": "Position",
|
|
159
|
-
"
|
|
160
|
-
"metadata_location_latitude": "Latitude",
|
|
159
|
+
"metadata_location_coordinates": "Coordonnées (longitude, latitude)",
|
|
161
160
|
"metadata_location_orientation": "Direction",
|
|
162
161
|
"metadata_location_precision": "Précision du positionnement",
|
|
162
|
+
"metadata_location_copy": "Copier {v}",
|
|
163
|
+
"metadata_location_copy_more": "Copier d'autres formats de coordonnées",
|
|
163
164
|
"metadata_quality": "Qualité",
|
|
164
165
|
"metadata_quality_help": "En savoir plus sur le score de qualité",
|
|
165
166
|
"metadata_quality_score": "Note globale",
|
package/src/translations/it.json
CHANGED
|
@@ -183,7 +183,9 @@
|
|
|
183
183
|
"contribute_id": "Contribuisci a OpenStreetMap con l’editor iD",
|
|
184
184
|
"geo_uri": "App esterna",
|
|
185
185
|
"filter_date_6months": "6 mesi",
|
|
186
|
-
"picture_all": "Tutte"
|
|
186
|
+
"picture_all": "Tutte",
|
|
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"
|
|
187
189
|
},
|
|
188
190
|
"psv": {
|
|
189
191
|
"loadError": "Impossibile caricare l’immagine panoramica",
|
package/src/utils/utils.js
CHANGED
|
@@ -211,6 +211,19 @@ export function xyzToPosition(x, y, z) {
|
|
|
211
211
|
};
|
|
212
212
|
}
|
|
213
213
|
|
|
214
|
+
/**
|
|
215
|
+
* Transforms decimal degrees into degrees/minutes/seconds format.
|
|
216
|
+
* @param {number} degrees The decimal degrees value
|
|
217
|
+
* @returns {object} Coordinate as {d,m,s} object
|
|
218
|
+
*/
|
|
219
|
+
export function degToDms(degrees) {
|
|
220
|
+
const d = degrees < 0 ? Math.ceil(degrees) : Math.floor(degrees);
|
|
221
|
+
const rm = Math.abs(degrees - d) * 60;
|
|
222
|
+
const m = Math.floor(rm);
|
|
223
|
+
const s = parseFloat(((rm - m) * 60).toFixed(3));
|
|
224
|
+
return { d, m, s };
|
|
225
|
+
}
|
|
226
|
+
|
|
214
227
|
/**
|
|
215
228
|
* Get the query string for JOSM to load current picture area
|
|
216
229
|
* @returns {string} The query string, or null if not available
|
|
@@ -8,18 +8,18 @@ jest.mock("../../src/utils/map", () => ({
|
|
|
8
8
|
|
|
9
9
|
describe("getGrade", () => {
|
|
10
10
|
it("works with null-like", () => {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
11
|
+
expect(utils.getGrade(utils.QUALITYSCORE_RES_FLAT_VALUES, null)).toBeNull();
|
|
12
|
+
expect(utils.getGrade(utils.QUALITYSCORE_RES_FLAT_VALUES, undefined)).toBeNull();
|
|
13
|
+
expect(utils.getGrade(utils.QUALITYSCORE_RES_FLAT_VALUES, "")).toBeNull();
|
|
14
|
+
});
|
|
15
15
|
|
|
16
16
|
it("works with grade values", () => {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
17
|
+
expect(utils.getGrade(utils.QUALITYSCORE_RES_FLAT_VALUES, 0)).toBe(1);
|
|
18
|
+
expect(utils.getGrade(utils.QUALITYSCORE_RES_FLAT_VALUES, 5)).toBe(1);
|
|
19
|
+
expect(utils.getGrade(utils.QUALITYSCORE_RES_FLAT_VALUES, 12)).toBe(2);
|
|
20
|
+
expect(utils.getGrade(utils.QUALITYSCORE_RES_FLAT_VALUES, 25)).toBe(3);
|
|
21
|
+
expect(utils.getGrade(utils.QUALITYSCORE_RES_FLAT_VALUES, 40)).toBe(4);
|
|
22
|
+
});
|
|
23
23
|
});
|
|
24
24
|
|
|
25
25
|
describe("getDistance", () => {
|
|
@@ -32,25 +32,25 @@ describe("getDistance", () => {
|
|
|
32
32
|
});
|
|
33
33
|
|
|
34
34
|
describe("svgToPSVLink", () => {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
35
|
+
it("works", () => {
|
|
36
|
+
const base64Svg = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnPjxjaXJjbGUgY3g9JzUnIGN5PSc1JyByPSc1JyBmaWxsPScjMDAwJy8+PC9zdmc+";
|
|
37
|
+
const fillColor = "red";
|
|
38
|
+
const result = utils.svgToPSVLink(base64Svg, fillColor);
|
|
39
|
+
|
|
40
|
+
expect(result).toBeInstanceOf(HTMLButtonElement);
|
|
41
|
+
expect(result.classList.contains("pnx-psv-tour-arrows")).toBe(true);
|
|
42
|
+
expect(result.style.color).toBe(fillColor);
|
|
43
|
+
expect(result.querySelector("svg")).not.toBeNull();
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it("works with invalid input", () => {
|
|
47
|
+
const invalidBase64Svg = "http://test.net/invalid_string";
|
|
48
|
+
const result = utils.svgToPSVLink(invalidBase64Svg, "blue");
|
|
49
|
+
|
|
50
|
+
expect(result).toBeInstanceOf(HTMLImageElement);
|
|
51
|
+
expect(result.src).toBe(invalidBase64Svg);
|
|
52
|
+
expect(result.alt).toBe("");
|
|
53
|
+
});
|
|
54
54
|
});
|
|
55
55
|
|
|
56
56
|
describe("getAzimuth", () => {
|
|
@@ -197,92 +197,119 @@ describe("xyzToPosition", () => {
|
|
|
197
197
|
});
|
|
198
198
|
});
|
|
199
199
|
|
|
200
|
+
describe("degToDms", () => {
|
|
201
|
+
it("converts positive decimal degrees to DMS correctly", () => {
|
|
202
|
+
const result = utils.degToDms(45.7896541);
|
|
203
|
+
expect(result).toEqual({ d: 45, m: 47, s: 22.755 });
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
it("converts negative decimal degrees to DMS correctly 1", () => {
|
|
207
|
+
const result = utils.degToDms(-12.751234);
|
|
208
|
+
expect(result).toEqual({ d: -12, m: 45, s: 4.442 });
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
it("converts negative decimal degrees to DMS correctly 2", () => {
|
|
212
|
+
const result = utils.degToDms(-21.007598);
|
|
213
|
+
expect(result).toEqual({ d: -21, m: 0, s: 27.353 });
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
it("converts zero degrees to DMS correctly", () => {
|
|
217
|
+
const result = utils.degToDms(0);
|
|
218
|
+
expect(result).toEqual({ d: 0, m: 0, s: 0 });
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
it("handles integer degrees correctly", () => {
|
|
222
|
+
const result = utils.degToDms(90);
|
|
223
|
+
expect(result).toEqual({ d: 90, m: 0, s: 0 });
|
|
224
|
+
});
|
|
225
|
+
});
|
|
226
|
+
|
|
200
227
|
describe("josmBboxParameters", () => {
|
|
201
228
|
it("works with null-like", () => {
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
229
|
+
expect(utils.josmBboxParameters(null)).toBeNull();
|
|
230
|
+
expect(utils.josmBboxParameters(undefined)).toBeNull();
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
it("works without azimuth", () => {
|
|
234
|
+
const meta = { gps: [2.3522, 48.8566] };
|
|
235
|
+
const result = utils.josmBboxParameters(meta);
|
|
236
|
+
expect(result).toBe("left=2.3522&right=2.3522&top=48.8566&bottom=48.8566&changeset_source=Panoramax");
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
it("works with azimuth = 0", () => {
|
|
240
|
+
const meta = { gps: [2.3522, 48.8566], properties: { "view:azimuth": 0 } };
|
|
241
|
+
const result = utils.josmBboxParameters(meta);
|
|
242
|
+
expect(result).toBe("left=2.3522&right=2.3524&top=48.8568&bottom=48.8566&changeset_source=Panoramax");
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
it("works with azimuth = 180", () => {
|
|
246
|
+
const meta = { gps: [2.3522, 48.8566], properties: { "view:azimuth": 180 } };
|
|
247
|
+
const result = utils.josmBboxParameters(meta);
|
|
248
|
+
expect(result).toBe("left=2.352&right=2.3524&top=48.8566&bottom=48.8564&changeset_source=Panoramax");
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
it("works with azimuth = 90", () => {
|
|
252
|
+
const meta = { gps: [2.3522, 48.8566], properties: { "view:azimuth": 90 } };
|
|
253
|
+
const result = utils.josmBboxParameters(meta);
|
|
254
|
+
expect(result).toBe("left=2.3522&right=2.3524&top=48.8568&bottom=48.8564&changeset_source=Panoramax");
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
it("works with azimuth = 270", () => {
|
|
258
|
+
const meta = { gps: [2.3522, 48.8566], properties: { "view:azimuth": 270 } };
|
|
259
|
+
const result = utils.josmBboxParameters(meta);
|
|
260
|
+
expect(result).toBe("left=2.352&right=2.3522&top=48.8568&bottom=48.8564&changeset_source=Panoramax");
|
|
261
|
+
});
|
|
235
262
|
});
|
|
236
263
|
|
|
237
264
|
describe("getCookie", () => {
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
265
|
+
it("should return the value of the specified cookie", () => {
|
|
266
|
+
jest.spyOn(document, "cookie", "get").mockReturnValueOnce("session=abc123");
|
|
267
|
+
expect(utils.getCookie("session")).toBe("abc123");
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
it("should return null if the cookie is not found", () => {
|
|
271
|
+
jest.spyOn(document, "cookie", "get").mockReturnValueOnce("session=abc123");
|
|
272
|
+
expect(utils.getCookie("user_id")).toBeUndefined();
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
it("should return the correct value when multiple cookies are set", () => {
|
|
276
|
+
jest.spyOn(document, "cookie", "get").mockReturnValueOnce("session=abc123; user_id=789; user_name=John");
|
|
277
|
+
expect(utils.getCookie("user_id")).toBe("789");
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
it("should return null if cookie with the specified name has no value", () => {
|
|
281
|
+
jest.spyOn(document, "cookie", "get").mockReturnValueOnce("session=; user_id=789");
|
|
282
|
+
expect(utils.getCookie("session")).toBe("");
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
it("should return the correct value when the cookie contains =", () => {
|
|
286
|
+
jest.spyOn(document, "cookie", "get").mockReturnValueOnce("custom_cookie=abc=123");
|
|
287
|
+
expect(utils.getCookie("custom_cookie")).toBe("abc=123");
|
|
288
|
+
});
|
|
262
289
|
});
|
|
263
290
|
|
|
264
291
|
describe("getUserAccount", () => {
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
292
|
+
it("should return an object with user id and name when all cookies are present", () => {
|
|
293
|
+
jest.spyOn(document, "cookie", "get").mockReturnValue("session=abc123; user_id=789; user_name=John");
|
|
294
|
+
expect(utils.getUserAccount()).toEqual({ id: "789", name: "John" });
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
it("should return null if session cookie is missing", () => {
|
|
298
|
+
jest.spyOn(document, "cookie", "get").mockReturnValue("user_id=789; user_name=John");
|
|
299
|
+
expect(utils.getUserAccount()).toBeNull();
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
it("should return null if user_id cookie is missing", () => {
|
|
303
|
+
jest.spyOn(document, "cookie", "get").mockReturnValue("session=abc123; user_name=John");
|
|
304
|
+
expect(utils.getUserAccount()).toBeNull();
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
it("should return null if user_name cookie is missing", () => {
|
|
308
|
+
jest.spyOn(document, "cookie", "get").mockReturnValue("session=abc123; user_id=789");
|
|
309
|
+
expect(utils.getUserAccount()).toBeNull();
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
it("should return null if all cookies are missing", () => {
|
|
313
|
+
expect(utils.getUserAccount()).toBeNull();
|
|
314
|
+
});
|
|
288
315
|
});
|