@panoramax/web-viewer 4.4.0-develop-ce62522e → 4.4.0-develop-e873def3

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.
@@ -8,7 +8,7 @@ import PACKAGE_JSON from "../../../package.json" with { type: "json" };
8
8
  import BasicStyles from "./Basic.css" with { type: "css" };
9
9
  document.adoptedStyleSheets.push(BasicStyles);
10
10
 
11
- const __COMMIT_HASH__ = "ce62522";
11
+ const __COMMIT_HASH__ = "e873def";
12
12
 
13
13
  /**
14
14
  * Event for overlaying menu opening
@@ -1,7 +1,10 @@
1
1
  import { LitElement, css, html } from "lit";
2
+ import { svgToImg } from "../../utils/utils.js";
3
+ const SwitchBigSVG = await fetch(new URL("../../img/switch_big.svg", import.meta.url).href).then(res => res.text());
4
+ const SwitchMiniSVG = await fetch(new URL("../../img/switch_mini.svg", import.meta.url).href).then(res => res.text());
2
5
 
3
- const SwitchBig = new URL("../../img/switch_big.svg", import.meta.url).href;
4
- const SwitchMini = new URL("../../img/switch_mini.svg", import.meta.url).href;
6
+ const SwitchBig = svgToImg(SwitchBigSVG);
7
+ const SwitchMini = svgToImg(SwitchMiniSVG);
5
8
 
6
9
  /**
7
10
  * Mini layout allows to show a reduced or collapsed component in a corner of a main component.
@@ -98,7 +101,7 @@ export default class Mini extends LitElement {
98
101
  style="top: 0; right: 0"
99
102
  @click=${onExpand}
100
103
  >
101
- <img src=${SwitchBig} alt="" />
104
+ ${SwitchBig}
102
105
  ${this._parent?._t.pnx.expand}
103
106
  </pnx-button>
104
107
 
@@ -108,7 +111,7 @@ export default class Mini extends LitElement {
108
111
  style="bottom: 0; left: 0"
109
112
  @click=${() => this.collapsed = true}
110
113
  >
111
- <img src=${SwitchMini} alt="" />
114
+ ${SwitchMini}
112
115
  </pnx-button>
113
116
  `;
114
117
  }
@@ -1,8 +1,8 @@
1
1
  import { LitElement, css, html, nothing, unsafeCSS } from "lit";
2
2
  import { inRangeRandom } from "../../utils/utils.js";
3
3
 
4
- const LogoDead = new URL("../../img/logo_dead.svg", import.meta.url).href;
5
- const LoaderBg = new URL("../../img/loader_base.jpg", import.meta.url).href;
4
+ const LogoDead = await fetch(new URL("../../img/logo_dead.svg", import.meta.url).href).then(res => res.text());
5
+ const LoaderBg = await fetch(new URL("../../img/loader_base.jpg", import.meta.url).href).then(res => res.text());
6
6
 
7
7
  /**
8
8
  * Loader component display a full page covering for user waiting.
@@ -4,6 +4,7 @@ import {
4
4
  import SemanticsMapProtocol from "../../utils/SemanticsMapProtocol.js";
5
5
  import PanoraMapProtocol from "../../utils/PanoraMapProtocol.js";
6
6
  import { DISABLED_LEVEL, initIndoorEqualOnMap } from "../../utils/indoor.js";
7
+ import { svgToImg } from "../../utils/utils.js";
7
8
  import MapStyles from "./Map.css" with { type: "css" };
8
9
  document.adoptedStyleSheets.push(MapStyles);
9
10
 
@@ -19,8 +20,8 @@ maplibregl.addProtocol("panora", new PanoraMapProtocol().tile());
19
20
  // eslint-disable-next-line no-undef
20
21
  maplibregl.addProtocol("panoras", new PanoraMapProtocol().tile());
21
22
 
22
- const MarkerBaseSVG = new URL("../../img/marker.svg", import.meta.url).href;
23
- const MarkerSelectedSVG = new URL("../../img/marker_blue.svg", import.meta.url).href;
23
+ const MarkerBaseSVG = await fetch(new URL("../../img/marker.svg", import.meta.url).href).then(res => res.text());
24
+ const MarkerSelectedSVG = await fetch(new URL("../../img/marker_blue.svg", import.meta.url).href).then(res => res.text());
24
25
 
25
26
 
26
27
  /**
@@ -326,7 +327,7 @@ export default class Map extends maplibregl.Map {
326
327
  ].forEach(m => {
327
328
  const img = new Image(64, 64);
328
329
  img.onload = () => this.addImage(m.id, img);
329
- img.src = m.img;
330
+ svgToImg(m.img, img);
330
331
  });
331
332
  }
332
333
 
@@ -714,12 +715,9 @@ export default class Map extends maplibregl.Map {
714
715
  * @memberof Panoramax.components.ui.Map#
715
716
  */
716
717
  _getPictureMarker(selected = true) {
717
- const img = document.createElement("img");
718
- img.src = selected ? MarkerSelectedSVG : MarkerBaseSVG;
719
- img.alt = "";
720
718
  // eslint-disable-next-line no-undef
721
719
  return new maplibregl.Marker({
722
- element: img,
720
+ element: svgToImg(selected ? MarkerSelectedSVG : MarkerBaseSVG),
723
721
  picId: null
724
722
  })
725
723
  // Only picMarker could be draggable, don't for picMarkerPreview.
@@ -13,8 +13,8 @@ import PhotoAdapter from "../../utils/PhotoAdapter.js";
13
13
  import PhotoStyles from "./Photo.css" with { type: "css" };
14
14
  document.adoptedStyleSheets.push(PhotoStyles);
15
15
 
16
- const LogoDead = new URL("../../img/logo_dead.svg", import.meta.url).href;
17
- const LoaderImgBase = new URL("../../img/loader_base.jpg", import.meta.url).href;
16
+ const LogoDead = await fetch(new URL("../../img/logo_dead.svg", import.meta.url).href).then(res => res.text());
17
+ const LoaderImgBase = await fetch(new URL("../../img/loader_base.jpg", import.meta.url).href).then(res => res.text());
18
18
 
19
19
 
20
20
  // Default panorama (logo)
@@ -4,8 +4,8 @@ import { fa, onceParentAvailable } from "../../../utils/widgets.js";
4
4
  import { faInfoCircle } from "@fortawesome/free-solid-svg-icons";
5
5
  import { classMap } from "lit/directives/class-map.js";
6
6
  import { PanoramaxWebsiteURL } from "../../../utils/services.js";
7
-
8
- const PanoramaxImg = new URL("../../../img/panoramax.svg", import.meta.url).href;
7
+ import { svgToImg } from "../../../utils/utils.js";
8
+ const PanoramaxImg = await fetch(new URL("../../../img/panoramax.svg", import.meta.url).href).then(res => res.text());
9
9
 
10
10
  /**
11
11
  * Legend widget, handling switch between map and photo components.
@@ -137,12 +137,15 @@ export default class Legend extends LitElement {
137
137
  "pnx-legend-light": this.light,
138
138
  };
139
139
 
140
+ const logo = svgToImg(PanoramaxImg);
141
+ logo.classList.add("logo");
142
+
140
143
  return html`<div class=${classMap(classes)} part="panel">
141
144
  <div
142
145
  class="presentation"
143
146
  style=${!this.light && this.focus != "map" && this.picture ? "display: none": ""}
144
147
  >
145
- <img class="logo" src=${PanoramaxImg} alt="" />
148
+ ${logo}
146
149
 
147
150
  ${this.light ? html`
148
151
  &copy; <a
@@ -38,6 +38,13 @@
38
38
  "license": "MIT",
39
39
  "devDependencies": {
40
40
  "@eslint/js": "^9.39.4",
41
+ "@rollup/plugin-commonjs": "^29.0.2",
42
+ "@rollup/plugin-image": "^3.0.3",
43
+ "@rollup/plugin-json": "^6.1.0",
44
+ "@rollup/plugin-node-resolve": "^16.0.3",
45
+ "@rollup/plugin-replace": "^6.0.3",
46
+ "@rollup/plugin-terser": "^1.0.0",
47
+ "@rollup/plugin-url": "^8.0.2",
41
48
  "@web/dev-server": "^0.4.6",
42
49
  "@web/dev-server-rollup": "^0.6.4",
43
50
  "eslint": "^9.39.4",
@@ -50,6 +57,9 @@
50
57
  "jest-environment-jsdom": "^30.3.0",
51
58
  "jest-fixed-jsdom": "^0.0.11",
52
59
  "jsdoc-to-markdown": "^9.1.1",
60
+ "rollup": "^4.60.2",
61
+ "rollup-plugin-import-css": "^4.2.1",
62
+ "rollup-plugin-lit-css": "^6.0.1",
53
63
  "rollup-plugin-postcss": "^4.0.2",
54
64
  "whatwg-url": "^16.0.1"
55
65
  },
@@ -131,7 +141,9 @@
131
141
  "<rootDir>"
132
142
  ],
133
143
  "moduleNameMapper": {
134
- "\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/config/jest/fileMock.js",
144
+ "\\.(eot|otf|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/config/jest/fileMock.js",
145
+ "\\.(jpg|jpeg|png|gif|webp)$": "<rootDir>/config/jest/imgMock.js",
146
+ "\\.svg$": "<rootDir>/config/jest/svgMock.js",
135
147
  "\\.css$": "identity-obj-proxy"
136
148
  },
137
149
  "setupFilesAfterEnv": [
@@ -35,7 +35,7 @@
35
35
  "share_rss": "RSS sažetak sadržaja",
36
36
  "share_rss_title": "RSS sažetak sadržaja novih sekvenci u trenutno vidljivom području karte",
37
37
  "share_embed": "Ugradi na svoju web stranicu",
38
- "share_embed_docs": "Ugradi na svoju web stranicu",
38
+ "share_embed_docs": "Pročitaj više o konfiguraciji ugradnje",
39
39
  "share_print": "Ispiši",
40
40
  "panoramax": "Panoramax",
41
41
  "whats_panoramax": "Panoramax je geo-commons za slike teritorija.",
@@ -57,11 +57,95 @@
57
57
  "josm_live": "Omogući JOSM automatsku sinkronizaciju prilikom učitavanja slike",
58
58
  "loading_labels_serious": [
59
59
  "🗺️ Učitavanje podataka karte",
60
- "🖥️ API za upite"
60
+ "🖥️ API za upite",
61
+ "🖼️ Učitavanje sličica",
62
+ "🔍 Analiziranje EXIF metapodataka",
63
+ "🏘️ 3D prikaz",
64
+ "📷 Pokretanje 360°slika",
65
+ "🟠 Balansiranje boje",
66
+ "💯 Ocjena kvalitete računalstva ©",
67
+ "📡 Preuzimanje ažuriranja",
68
+ "🌍 Dohvaćanje pločica karte",
69
+ "📸 Obrada sjena"
61
70
  ],
62
71
  "show_map": "Pokaži kartu",
63
72
  "sequence_speed": "Brzina igrača",
64
73
  "minimize": "Sakrij ovu komponentu, možeš je ponovno prikazati pomoću tipke u donjem lijevom kutu",
65
- "contribute_id": "Doprinesi OpenStreetMap pomoću iD uređivača"
74
+ "contribute_id": "Doprinesi OpenStreetMap pomoću iD uređivača",
75
+ "loading_labels_fun": [
76
+ "🦌 Otkrivanje znakova prijelaza jelena",
77
+ "🚘 Pretraživanje Panoramax Car ©",
78
+ "☕ Injekcija kofeina",
79
+ "😀 Osmjeh, kartiran si!",
80
+ "🐈 Dijeljenje slika mačaka",
81
+ "😴 Smanjenje odgađanja",
82
+ "🫖 Kuhanje čaja",
83
+ "🐧 Otvaranje izvornog koda",
84
+ "🚇 Indeksiranje stanica podzemne željeznice",
85
+ "🧹 Čišćenje metapodataka",
86
+ "🚒 Slanje fotografija vatrogasne stanice",
87
+ "🚲 Ažuriranje zelenih staza",
88
+ "🚉 Prolaz na peron stanice",
89
+ "🛰️ Traženje satelita",
90
+ "👥 Pisanje persona",
91
+ "🐟 Lociranje trgovine ribom",
92
+ "🧑‍💻 Sučelje za otklanjanje pogrešaka",
93
+ "📈 Statističko povećanje",
94
+ "🤖 Učenje značenja",
95
+ "🎨 Redizajn sučelja",
96
+ "📅 Planiranje zabava foto-kartiranja",
97
+ "🧀 Dozrijevanje cheddar sira",
98
+ "🌄 Izračunavanje kornvalskog sunca",
99
+ "🌊 Mjerenje plime i oseke"
100
+ ],
101
+ "error_psv": "Photo Sphere Viewer se ne učitava ispravno",
102
+ "error_pic": "Tražena slika nije pronađena",
103
+ "error_api": "Poslužitelj slika nije dostupan",
104
+ "error_webgl": "Vaš preglednik ne podržava WebGL",
105
+ "error_api_compatibility": "Poslužitelj slika nije kompatibilan s ovom verzijom preglednika",
106
+ "filter_source_world": "Cijeli svijet",
107
+ "filter_source_local": "Ovaj server",
108
+ "filter_date": "Datum",
109
+ "filter_date_1month": "1 mjesec",
110
+ "filter_date_6months": "6 mjeseci",
111
+ "filter_user": "Korisnik",
112
+ "filter_user_mypics": "Moje slike",
113
+ "filter_picture": "Tip slike",
114
+ "filter_locked": "Filter onemogućen",
115
+ "filter_zoom_in": "Povećajte za otključavanje",
116
+ "picture_all": "Svi",
117
+ "picture_flat": "Klasično",
118
+ "picture_360": "360°",
119
+ "picture_360_long": "Panoramska slika",
120
+ "popup_details_link": "Više detalja",
121
+ "filter_qualityscore": "Ocjena kvalitete",
122
+ "filter_qualityscore_help": "Klikni da omogućiš ili onemogućiš",
123
+ "qualityscore_doc_1": "Ocjena kvalitete izračunava se za svaku sliku.",
124
+ "qualityscore_doc_2": "Rezultat je prikazan kao slovo:",
125
+ "qualityscore_doc_3": "\"A\" je najbolja ocjena, \"E\" najgora.",
126
+ "qualityscore_doc_4": "Ova se ocjena izračunava na temelju:",
127
+ "qualityscore_doc_41": "GPS preciznost",
128
+ "qualityscore_doc_42": "rezolucija slike",
129
+ "qualityscore_doc_link": "Saznajte više o ocjeni kvalitete",
130
+ "filter_gps_precision": "Preciznost lokacije",
131
+ "filter_gps_precision_lessthan": "Manje od {n} metara",
132
+ "filter_gps_precision_between": "Između {n1} i {n2} metara",
133
+ "filter_gps_precision_morethan": "Više od {n} metara",
134
+ "filter_gps_precision_help": "Saznajte više o preciznosti lokacije",
135
+ "filter_gps_precision_help_1": "Informacije o preciznosti lokacije dostupne su za svaku sliku. To odgovara GPS preciznosti tijekom snimanja slike.",
136
+ "filter_gps_precision_help_2": "Preciznost je izražena zvjezdicama:",
137
+ "filter_gps_precision_help_4": "RTK GPS imat će ocjenu \"5⭐\", akcijska kamera poput GoPro Maxa ocjenu \"3⭐\", a GPS za pametni telefon u podzemnom parkingu ocjenu \"1⭐\".",
138
+ "map_background": "Pozadina karte",
139
+ "map_background_aerial": "Zračni",
140
+ "map_background_streets": "Ulice",
141
+ "map_background_default": "Početna vrijednost",
142
+ "map_theme_default": "Klasično",
143
+ "semantics_features_default_title": "Oznaka {nb}",
144
+ "qualityscore_doc_5": "Profesionalni uređaj imat će ocjenu A, akcijska kamera od 360° ocjenu B, a pametni telefon ocjenu između C i E.",
145
+ "picture_flat_long": "Klasična slika",
146
+ "filter_gps_precision_help_3": "\"5⭐\" je vrlo precizno (<= {p5}m), \"1⭐\" je vrlo neprecizno (> {p1}m) ili nepoznato.",
147
+ "error_nopic": "Nema dostupnih slika na datoj poziciji",
148
+ "error_josm": "JOSM ne odgovara, radi li i je li udaljeno omogućeno?",
149
+ "filter_date_1year": "1 godina"
66
150
  }
67
151
  }
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  COLORS, GPS_VALUES, QUALITYSCORE_GPS_VALUES,
3
3
  QUALITYSCORE_POND_GPS, QUALITYSCORE_POND_RES, QUALITYSCORE_RES_360_VALUES,
4
- QUALITYSCORE_RES_FLAT_VALUES, QUALITYSCORE_VALUES, isNullId
4
+ QUALITYSCORE_RES_FLAT_VALUES, QUALITYSCORE_VALUES, isNullId, svgToImg,
5
5
  } from "./utils.js";
6
6
 
7
- const LoaderImg = new URL("../img/marker.svg", import.meta.url).href;
7
+ const LoaderImg = await fetch(new URL("../img/marker.svg", import.meta.url).href).then(res => res.text());
8
8
 
9
9
  export const RASTER_LAYER_ID = "pnx-aerial";
10
10
 
@@ -217,7 +217,7 @@ export const MAP_THEMES_STYLES = {
217
217
  */
218
218
  export function getThumbGif(lang) {
219
219
  const thumbGif = document.createElement("img");
220
- thumbGif.src = LoaderImg;
220
+ svgToImg(LoaderImg, thumbGif);
221
221
  thumbGif.alt = lang.loading;
222
222
  thumbGif.title = lang.loading;
223
223
  thumbGif.classList.add("pnx-map-thumb", "pnx-map-thumb-loader");
@@ -1,5 +1,4 @@
1
1
  import { COLORS, getArrow, getDistance, getSimplifiedAngle, svgToPSVLink } from "./utils.js";
2
-
3
2
  const ArrowTriangleSVG = await fetch(new URL("../img/arrow_triangle.svg", import.meta.url).href).then(res => res.text());
4
3
  const ArrowTurnSVG = await fetch(new URL("../img/arrow_turn.svg", import.meta.url).href).then(res => res.text());
5
4
  const ArrowTriangle = svgToPSVLink(ArrowTriangleSVG, "white");
@@ -2,8 +2,8 @@ import { html } from "lit";
2
2
  import { OSMURL, OSMWikiURL, PanoramaxPresetsURL, WikidataAPIURL, WikidataURL } from "./services.js";
3
3
  import { getBestLabel } from "./i18n.js";
4
4
 
5
- const logoOsm = new URL("../img/osm.svg", import.meta.url).href;
6
- const logoWd = new URL("../img/wd.svg", import.meta.url).href;
5
+ const logoOsm = await fetch(new URL("../img/osm.svg", import.meta.url).href).then(res => res.text());
6
+ const logoWd = await fetch(new URL("../img/wd.svg", import.meta.url).href).then(res => res.text());
7
7
 
8
8
 
9
9
  // List of [ Overlay ID, API filter, Maplibre Style, Sprites ]
@@ -92,6 +92,26 @@ export function getDistance(from, to) {
92
92
  return Math.sqrt(dx*dx + dy*dy);
93
93
  }
94
94
 
95
+ export function svgToImg(svg, img = null) {
96
+ if(svg.constructor.name === "HTMLImageElement") {
97
+ if(img) {
98
+ svg.width = img.width;
99
+ svg.height = img.height;
100
+ svg.onload = img.onload;
101
+ }
102
+ return svg;
103
+ }
104
+ else if(typeof svg === "string") {
105
+ if(!img) {
106
+ img = new Image();
107
+ img.alt = "";
108
+ }
109
+ if(svg.startsWith("<?xml")) { svg = URL.createObjectURL(new Blob([svg], {type: 'image/svg+xml'})); }
110
+ img.src = svg;
111
+ return img;
112
+ }
113
+ }
114
+
95
115
  /**
96
116
  * Transforms a Base64 SVG string into a DOM img element.
97
117
  * @param {string} svg The SVG as Base64 string
@@ -100,6 +120,7 @@ export function getDistance(from, to) {
100
120
  */
101
121
  export function svgToPSVLink(svg, fillColor) {
102
122
  try {
123
+ if(svg.startsWith("data:image/svg+xml,")) { svg = decodeURIComponent(svg.replace("data:image/svg+xml,", "")); }
103
124
  if(!svg.startsWith("<svg")) { throw new Error(); }
104
125
  const svgXml = (new DOMParser()).parseFromString(svg, "image/svg+xml").childNodes[0];
105
126
  const btn = document.createElement("button");
@@ -110,10 +131,7 @@ export function svgToPSVLink(svg, fillColor) {
110
131
  }
111
132
 
112
133
  catch(e) {
113
- const img = document.createElement("img");
114
- img.src = svg;
115
- img.alt = "";
116
- return img;
134
+ return svgToImg(svg);
117
135
  }
118
136
  }
119
137
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@panoramax/web-viewer",
3
- "version": "4.4.0-develop-ce62522e",
3
+ "version": "4.4.0-develop-e873def3",
4
4
  "description": "Panoramax web viewer for geolocated pictures",
5
5
  "main": "./build/index.js",
6
6
  "type": "module",
@@ -38,6 +38,13 @@
38
38
  "license": "MIT",
39
39
  "devDependencies": {
40
40
  "@eslint/js": "^9.39.4",
41
+ "@rollup/plugin-commonjs": "^29.0.2",
42
+ "@rollup/plugin-image": "^3.0.3",
43
+ "@rollup/plugin-json": "^6.1.0",
44
+ "@rollup/plugin-node-resolve": "^16.0.3",
45
+ "@rollup/plugin-replace": "^6.0.3",
46
+ "@rollup/plugin-terser": "^1.0.0",
47
+ "@rollup/plugin-url": "^8.0.2",
41
48
  "@web/dev-server": "^0.4.6",
42
49
  "@web/dev-server-rollup": "^0.6.4",
43
50
  "eslint": "^9.39.4",
@@ -50,6 +57,9 @@
50
57
  "jest-environment-jsdom": "^30.3.0",
51
58
  "jest-fixed-jsdom": "^0.0.11",
52
59
  "jsdoc-to-markdown": "^9.1.1",
60
+ "rollup": "^4.60.2",
61
+ "rollup-plugin-import-css": "^4.2.1",
62
+ "rollup-plugin-lit-css": "^6.0.1",
53
63
  "rollup-plugin-postcss": "^4.0.2",
54
64
  "whatwg-url": "^16.0.1"
55
65
  },
@@ -131,7 +141,9 @@
131
141
  "<rootDir>"
132
142
  ],
133
143
  "moduleNameMapper": {
134
- "\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/config/jest/fileMock.js",
144
+ "\\.(eot|otf|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/config/jest/fileMock.js",
145
+ "\\.(jpg|jpeg|png|gif|webp)$": "<rootDir>/config/jest/imgMock.js",
146
+ "\\.svg$": "<rootDir>/config/jest/svgMock.js",
135
147
  "\\.css$": "identity-obj-proxy"
136
148
  },
137
149
  "setupFilesAfterEnv": [