@geogirafe/lib-geoportal 1.1.0-dev.2545448597 → 1.1.0-dev.2557861681

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.
@@ -27,6 +27,9 @@ export default class GeoGirafeApi extends GirafeHTMLElement {
27
27
  private manageTooltipAttribute;
28
28
  private manageMarkersAttribute;
29
29
  private markerStringToMapMarker;
30
+ private manageMarkersFileAttribute;
31
+ private readMarkersFromFile;
32
+ private lineToMarker;
30
33
  private initialize;
31
34
  private injectConfigMetaTags;
32
35
  }
@@ -11,6 +11,21 @@ import MapCustomContextMenuComponent from '../components/context-menu/custom-con
11
11
  import SearchComponent from '../components/search/component.js';
12
12
  import SelectionWindowComponent from '../components/selectionwindow/component.js';
13
13
  import { splitTrimAndConvertToNumber } from '../tools/utils/utils.js';
14
+ const getImageSize = (url) => {
15
+ return new Promise((resolve, reject) => {
16
+ const img = new Image();
17
+ img.onload = () => {
18
+ resolve({
19
+ width: img.naturalWidth,
20
+ height: img.naturalHeight
21
+ });
22
+ };
23
+ img.onerror = () => {
24
+ reject(new Error(`Failed to load image: ${url}`));
25
+ };
26
+ img.src = url;
27
+ });
28
+ };
14
29
  export default class GeoGirafeApi extends GirafeHTMLElement {
15
30
  templateUrl = null;
16
31
  styleUrls = null;
@@ -47,7 +62,7 @@ export default class GeoGirafeApi extends GirafeHTMLElement {
47
62
  });
48
63
  }
49
64
  static get observedAttributes() {
50
- return ['center', 'zoom', 'basemap', 'basemapselector', 'crosshair', 'tooltip', 'markers', 'layers'];
65
+ return ['center', 'zoom', 'basemap', 'basemapselector', 'crosshair', 'tooltip', 'markers', 'markersfile', 'layers'];
51
66
  }
52
67
  attributeChangedCallback(name, oldValue, newValue) {
53
68
  if (this.isInitialized) {
@@ -74,6 +89,9 @@ export default class GeoGirafeApi extends GirafeHTMLElement {
74
89
  else if (name === 'markers') {
75
90
  this.manageMarkersAttribute();
76
91
  }
92
+ else if (name === 'markersfile') {
93
+ this.manageMarkersFileAttribute();
94
+ }
77
95
  else if (name === 'layers') {
78
96
  this.manageLayersAttribute();
79
97
  }
@@ -96,6 +114,7 @@ export default class GeoGirafeApi extends GirafeHTMLElement {
96
114
  this.manageCrosshairAttribute();
97
115
  this.manageTooltipAttribute();
98
116
  this.manageMarkersAttribute();
117
+ this.manageMarkersFileAttribute();
99
118
  this.manageLayersAttribute();
100
119
  this.manageSelectionboxAttribute();
101
120
  this.manageUserInteraction();
@@ -294,6 +313,82 @@ export default class GeoGirafeApi extends GirafeHTMLElement {
294
313
  return undefined;
295
314
  }
296
315
  }
316
+ manageMarkersFileAttribute() {
317
+ const markersFile = this.getAttributeFromConfig('markersfile');
318
+ if (markersFile) {
319
+ void this.readMarkersFromFile(markersFile).then((markers) => {
320
+ this.context.stateManager.state.position.markers.push(...markers);
321
+ });
322
+ }
323
+ }
324
+ async readMarkersFromFile(fileUrl) {
325
+ const response = await fetch(fileUrl);
326
+ if (!response.ok) {
327
+ console.warn(`Cannot read markers file '${fileUrl}': ${response.status} ${response.statusText}`);
328
+ return [];
329
+ }
330
+ const fileContent = await response.text();
331
+ const lines = fileContent
332
+ .split(/\r?\n/)
333
+ .map((line) => line.trim())
334
+ .filter((line) => line.length > 0);
335
+ if (lines.length < 2) {
336
+ return [];
337
+ }
338
+ const headers = lines[0].split('\t').map((header) => header.trim());
339
+ const pointIndex = headers.indexOf('point');
340
+ const iconIndex = headers.indexOf('icon');
341
+ const iconSizeIndex = headers.indexOf('iconSize');
342
+ const iconOffsetIndex = headers.indexOf('iconOffset');
343
+ if (pointIndex === -1 || iconIndex === -1) {
344
+ console.warn(`Invalid markers file '${fileUrl}': missing required 'point' or 'icon' column`);
345
+ return [];
346
+ }
347
+ const markers = [];
348
+ const legacy = fileUrl.includes('legacy');
349
+ for (const line of lines.slice(1)) {
350
+ await this.lineToMarker(line, pointIndex, iconIndex, iconSizeIndex, iconOffsetIndex, legacy).then((marker) => {
351
+ if (marker) {
352
+ markers.push(marker);
353
+ }
354
+ });
355
+ }
356
+ return markers;
357
+ }
358
+ async lineToMarker(line, pointIndex, iconIndex, iconSizeIndex, iconOffsetIndex, legacy) {
359
+ const columns = line.split('\t');
360
+ const coords = splitTrimAndConvertToNumber(columns[pointIndex]);
361
+ const imageUrl = columns[iconIndex]?.trim();
362
+ if (coords.length < 2 || !imageUrl || Number.isNaN(coords[0]) || Number.isNaN(coords[1])) {
363
+ console.warn(`Invalid marker line ': ${line}`);
364
+ return undefined;
365
+ }
366
+ // In the old WebGIS the coordinates are in the wrong order. This is to ensure compatibility with older data.
367
+ if (coords[0] < coords[1] && this.context.stateManager.state.projection === 'EPSG:2056') {
368
+ coords.reverse();
369
+ }
370
+ const size = iconSizeIndex >= 0 && columns[iconSizeIndex]?.trim()
371
+ ? splitTrimAndConvertToNumber(columns[iconSizeIndex])
372
+ : undefined;
373
+ let offset = iconOffsetIndex >= 0 && columns[iconOffsetIndex]?.trim()
374
+ ? splitTrimAndConvertToNumber(columns[iconOffsetIndex])
375
+ : undefined;
376
+ // In the old WebGIS the Offset referred to the Size of the original Image, while now it refers to the Size of the
377
+ // resized Image. This is to ensure compatibility with older data.
378
+ if (offset && size && legacy) {
379
+ await getImageSize(imageUrl).then((imageSize) => {
380
+ const scaleX = size[0] / imageSize.width;
381
+ const scaleY = size[1] / imageSize.height;
382
+ offset = [offset[0] * scaleX, offset[1] * scaleY];
383
+ });
384
+ }
385
+ return {
386
+ position: [coords[0], coords[1]],
387
+ imageUrl,
388
+ size,
389
+ offset
390
+ };
391
+ }
297
392
  async initialize() {
298
393
  await this.context.initialize();
299
394
  // Register Coordinate Reference Systems (CRS) definitions in PROJ4
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "name": "GeoGirafe PSC",
6
6
  "url": "https://doc.geomapfish.dev"
7
7
  },
8
- "version": "1.1.0-dev.2545448597",
8
+ "version": "1.1.0-dev.2557861681",
9
9
  "type": "module",
10
10
  "engines": {
11
11
  "node": ">=20.19.0"
@@ -113,6 +113,10 @@
113
113
  text-align: left;
114
114
  margin-bottom: 1rem;
115
115
  }
116
+ ul {
117
+ width: 100%;
118
+ margin: 0;
119
+ }
116
120
  </style>
117
121
 
118
122
  <script type="module" src="src/main.api.ts"></script>
@@ -292,9 +296,12 @@
292
296
 
293
297
  <!-- Multiple markers with size and/or offset -->
294
298
  <h2>Add multiple markers with size and/or offset on the map</h2>
295
- <p class="descr">Add multiple markers at the defined coordinates. You can specify size and offset. If you only
296
- specify three parameters, the third parameter can be the size if you <strong>don't</strong> include a sign
297
- (e.g. <code>24,24</code>) or the offset if you <strong>do</strong> include a sign (e.g. <code>+2,-6</code>).
299
+ <p class="descr">
300
+ Add multiple markers at the defined coordinates. <br />
301
+ You can specify size and offset.<br />
302
+ If you only specify three parameters, the third parameter can be the size if you <strong>don't</strong> include
303
+ a sign (e.g. <code>24,24</code>) or the offset if you <strong>do</strong> include a sign (e.g.
304
+ <code>+2,-6</code>).
298
305
  </p>
299
306
  <section>
300
307
  <div class="row">
@@ -305,6 +312,35 @@
305
312
  </div>
306
313
  </section>
307
314
 
315
+ <!-- Multiple markers with size and/or offset -->
316
+ <h2>Add multiple markers on the map by providing a File/URL</h2>
317
+ <p class="descr">
318
+ You can provide a URL to a TXT file containing markers.<br />
319
+ Each line represents a marker with TAB-separated values.<br />
320
+ The file must contain the column names as header.
321
+ </p>
322
+ <p class="descr">Allowed column names:</p>
323
+ <ul>
324
+ <li><strong>point</strong>: coordinates where the amrker should be added.</li>
325
+ <li><strong>icon</strong>: url to the marker image</li>
326
+ <li><strong>iconSize</strong> (optional): size if the marker should be resized</li>
327
+ <li><strong>iconOffset</strong> (optional): offset if the marker should be shifted</li>
328
+ </ul>
329
+ <p class="descr">
330
+ Other columns will be ignored.<br />
331
+ Compatibility with the format used in the old GeoMapFish API will be managed if the URL to fo file contains the
332
+ keyword <code>legacy</code>.<br />
333
+ Coordinates can be given in both way (North,East) or (East,North) only if the SRID <code>CH:2056</code> is used.
334
+ </p>
335
+ <section>
336
+ <div class="row">
337
+ <div class="left">
338
+ <geogirafe-map markersfile="api.demo.markersFile" />
339
+ </div>
340
+ <div class="right"></div>
341
+ </div>
342
+ </section>
343
+
308
344
  <!-- Layers -->
309
345
  <h2>Add a layer to the map</h2>
310
346
  <p class="descr">Add a layer to the map. The layer name must be defined in the themes.json file.</p>
@@ -409,10 +445,6 @@
409
445
  - projection: configure map projection
410
446
  - legend:
411
447
  - embeded: deactivate mouse scroll
412
- - marker: offset, size, ...
413
- - load markers from file
414
- - load data from file
415
-
416
448
  -->
417
449
  </body>
418
450
  </html>
@@ -1 +1 @@
1
- {"version":"1.1.0-dev.2545448597", "build":"2545448597", "date":"22/05/2026"}
1
+ {"version":"1.1.0-dev.2557861681", "build":"2557861681", "date":"28/05/2026"}
@@ -0,0 +1,8 @@
1
+ id point title description icon iconSize iconOffset
2
+ 1 1146337,2554168 Information Office de l'information<br />Tél: 032 000 00 00<br>Email: <a href="mailto:info@example.com">info@example.com</a><br />Internet: <a href="http://fr.wikipedia.org/wiki/La_Chaux-de-Fonds" target=new>Cliquer ici</a> api/marker-plus.png 21,25 -51,-90
3
+ 2 1146205,2554168 Ma première station Diesel pas cher api/marker2-plus.png 21,25 -51,-90
4
+ 3 1145605,2554168 Mon parking C'est celui-là le meilleur. api/marker2-plus.png 21,25 -51,-90
5
+ 4 1145542,2554168 Mon parking Ce parking est<br/>le meillleur. api/marker2-plus.png 21,25 -51,-90
6
+ 5 1145977,2554168 Ma deuxième station Sans-plomb pas cher. api/marker-plus.png 21,25 -51,-90
7
+ 6 1145631,2554175 Test marker 1. api/marker-plus.png 21,25 -51,-90
8
+ 7 1145472,2554507 Test marker 2. api/marker2-plus.png 21,25 -51,-90
@@ -0,0 +1,6 @@
1
+ id point title description icon iconSize iconOffset
2
+ 1 2611778,1266865 Popups konfigurieren <br>Popups können via der Text-Datei beliebig mit Inhalt gefüllt werden!<br/>Die anderen zwei Beispiel-Popups zeigen weitere Beispiele.<br><img src="/static/api/apihelp/img/geoportal-bs.jpg" width="300px"> api/marker-blue.png 21,25 -10.5,-25
3
+ 2 2611542,1267266 Klänge der Basler Fasnacht <br/><br/>Audio-Dateien in ein Popup einbinden:<br/><br/><audio controls><source src="/static/api/apihelp/BS_N19_Fasnacht_v1.mp3" type="audio/mp3">Your browser does not support the audio element.</audio> api/marker-green.png 21,25 -10.5,-25
4
+ 3 2613089,1267566 FILM AB! Für den GEO-Beruf <br>IFrames in ein Popup einbinden: <br/><br/><iframe width="312" height="175" src="https://www.youtube.com/embed/-Mw277Rgcyc" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe> api/parking.png 21,25 -10.5,-25
5
+ 4 2611738,1267123 Test for Offset/Size Test for Offset/Size api/marker-huge.png 24,38 -162,-512
6
+ 5 2611738,1267123 Test for Offset/Size Test for Offset/Size api/marker-huge.png 24,38 -12,-38