@geogirafe/lib-geoportal 1.1.0-dev.2591751450 → 1.1.0-dev.2593337676
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/api/apigeogirafeapp.js +33 -19
- package/assets/i18n/de.json +2 -0
- package/assets/i18n/en.json +2 -0
- package/assets/i18n/fr.json +2 -0
- package/assets/i18n/it.json +2 -0
- package/components/context-menu/custom-context-menu/component.d.ts +5 -1
- package/components/context-menu/custom-context-menu/component.js +39 -9
- package/components/map/component.d.ts +1 -0
- package/components/map/component.js +36 -1
- package/package.json +1 -1
- package/templates/api.html +4 -2
- package/templates/public/about.json +1 -1
- package/templates/public/api/data-mapbs.txt +2 -2
- package/templates/public/api/marker-gold.png +0 -0
- package/templates/public/config.api.json +1 -1
- package/tools/main.d.ts +1 -1
- package/tools/state/mapManager.js +4 -0
- package/tools/state/mapposition.d.ts +6 -0
- package/tools/state/mapposition.js +3 -1
- package/tools/utils/utils.d.ts +3 -2
- package/tools/utils/utils.js +4 -3
package/api/apigeogirafeapp.js
CHANGED
|
@@ -11,6 +11,7 @@ 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
|
+
import DOMPurify from 'dompurify';
|
|
14
15
|
const getImageSize = (url) => {
|
|
15
16
|
return new Promise((resolve, reject) => {
|
|
16
17
|
const img = new Image();
|
|
@@ -120,7 +121,7 @@ export default class GeoGirafeApi extends GirafeHTMLElement {
|
|
|
120
121
|
this.manageUserInteraction();
|
|
121
122
|
}
|
|
122
123
|
manageUserInteraction() {
|
|
123
|
-
//
|
|
124
|
+
// Deactivate the preview of search results
|
|
124
125
|
this.context.configManager.Config.search.objectPreview = false;
|
|
125
126
|
this.context.configManager.Config.search.layerPreview = false;
|
|
126
127
|
// Force window as selection component
|
|
@@ -145,9 +146,11 @@ export default class GeoGirafeApi extends GirafeHTMLElement {
|
|
|
145
146
|
}
|
|
146
147
|
defineAndAddComponent(customElementName, customElementType) {
|
|
147
148
|
if (!customElements.get(customElementName)) {
|
|
149
|
+
console.log(`Defining custom element: ${customElementName}`);
|
|
148
150
|
customElements.define(customElementName, customElementType);
|
|
149
151
|
}
|
|
150
152
|
const existingElement = this.shadowRoot?.querySelector(customElementName);
|
|
153
|
+
console.log('existingElement', existingElement);
|
|
151
154
|
if (!existingElement) {
|
|
152
155
|
const component = new customElementType();
|
|
153
156
|
this.shadow.appendChild(component);
|
|
@@ -246,13 +249,16 @@ export default class GeoGirafeApi extends GirafeHTMLElement {
|
|
|
246
249
|
if (tooltip) {
|
|
247
250
|
this.defineAndAddComponent('girafe-custom-context-menu', MapCustomContextMenuComponent);
|
|
248
251
|
const content = tooltip.split('|');
|
|
252
|
+
const hasTitle = content.length > 2;
|
|
249
253
|
const coords = content[0].split(',');
|
|
250
254
|
const x = Number(coords[0].trim());
|
|
251
255
|
const y = Number(coords[1].trim());
|
|
252
256
|
if (!Number.isNaN(x) && !Number.isNaN(y)) {
|
|
253
|
-
const
|
|
257
|
+
const title = hasTitle ? content[1] : undefined;
|
|
258
|
+
const text = content[hasTitle ? 2 : 1];
|
|
254
259
|
this.context.stateManager.state.position.tooltip = {
|
|
255
260
|
position: [x, y],
|
|
261
|
+
title,
|
|
256
262
|
content: text
|
|
257
263
|
};
|
|
258
264
|
}
|
|
@@ -316,6 +322,7 @@ export default class GeoGirafeApi extends GirafeHTMLElement {
|
|
|
316
322
|
manageMarkersFileAttribute() {
|
|
317
323
|
const markersFile = this.getAttributeFromConfig('markersfile');
|
|
318
324
|
if (markersFile) {
|
|
325
|
+
this.defineAndAddComponent('girafe-custom-context-menu', MapCustomContextMenuComponent);
|
|
319
326
|
void this.readMarkersFromFile(markersFile).then((markers) => {
|
|
320
327
|
this.context.stateManager.state.position.markers.push(...markers);
|
|
321
328
|
});
|
|
@@ -336,18 +343,22 @@ export default class GeoGirafeApi extends GirafeHTMLElement {
|
|
|
336
343
|
return [];
|
|
337
344
|
}
|
|
338
345
|
const headers = lines[0].split('\t').map((header) => header.trim());
|
|
339
|
-
const
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
346
|
+
const columnIndexes = {
|
|
347
|
+
pointIndex: headers.indexOf('point'),
|
|
348
|
+
titleIndex: headers.indexOf('title'),
|
|
349
|
+
descriptionIndex: headers.indexOf('description'),
|
|
350
|
+
iconIndex: headers.indexOf('icon'),
|
|
351
|
+
iconSizeIndex: headers.indexOf('iconSize'),
|
|
352
|
+
iconOffsetIndex: headers.indexOf('iconOffset')
|
|
353
|
+
};
|
|
354
|
+
if (columnIndexes.pointIndex === -1 || columnIndexes.iconIndex === -1) {
|
|
344
355
|
console.warn(`Invalid markers file '${fileUrl}': missing required 'point' or 'icon' column`);
|
|
345
356
|
return [];
|
|
346
357
|
}
|
|
347
358
|
const markers = [];
|
|
348
359
|
const legacy = fileUrl.includes('legacy');
|
|
349
360
|
for (const line of lines.slice(1)) {
|
|
350
|
-
await this.lineToMarker(line,
|
|
361
|
+
await this.lineToMarker(line, columnIndexes, legacy).then((marker) => {
|
|
351
362
|
if (marker) {
|
|
352
363
|
markers.push(marker);
|
|
353
364
|
}
|
|
@@ -355,11 +366,12 @@ export default class GeoGirafeApi extends GirafeHTMLElement {
|
|
|
355
366
|
}
|
|
356
367
|
return markers;
|
|
357
368
|
}
|
|
358
|
-
async lineToMarker(line,
|
|
369
|
+
async lineToMarker(line, columnIndexes, legacy) {
|
|
359
370
|
const columns = line.split('\t');
|
|
360
|
-
const
|
|
361
|
-
const
|
|
362
|
-
|
|
371
|
+
const getColumOrUndefined = (index) => index ? columns[index]?.trim() : undefined;
|
|
372
|
+
const coords = splitTrimAndConvertToNumber(columns[columnIndexes.pointIndex]);
|
|
373
|
+
const imageUrl = columnIndexes.iconIndex ? columns[columnIndexes.iconIndex]?.trim() : undefined;
|
|
374
|
+
if (!coords || coords.length < 2 || !imageUrl || Number.isNaN(coords[0]) || Number.isNaN(coords[1])) {
|
|
363
375
|
console.warn(`Invalid marker line ': ${line}`);
|
|
364
376
|
return undefined;
|
|
365
377
|
}
|
|
@@ -367,12 +379,8 @@ export default class GeoGirafeApi extends GirafeHTMLElement {
|
|
|
367
379
|
if (coords[0] < coords[1] && this.context.stateManager.state.projection === 'EPSG:2056') {
|
|
368
380
|
coords.reverse();
|
|
369
381
|
}
|
|
370
|
-
const size = iconSizeIndex
|
|
371
|
-
|
|
372
|
-
: undefined;
|
|
373
|
-
let offset = iconOffsetIndex >= 0 && columns[iconOffsetIndex]?.trim()
|
|
374
|
-
? splitTrimAndConvertToNumber(columns[iconOffsetIndex])
|
|
375
|
-
: undefined;
|
|
382
|
+
const size = splitTrimAndConvertToNumber(getColumOrUndefined(columnIndexes.iconSizeIndex));
|
|
383
|
+
let offset = splitTrimAndConvertToNumber(getColumOrUndefined(columnIndexes.iconOffsetIndex));
|
|
376
384
|
// In the old WebGIS the Offset referred to the Size of the original Image, while now it refers to the Size of the
|
|
377
385
|
// resized Image. This is to ensure compatibility with older data.
|
|
378
386
|
if (offset && size && legacy) {
|
|
@@ -382,11 +390,17 @@ export default class GeoGirafeApi extends GirafeHTMLElement {
|
|
|
382
390
|
offset = [offset[0] * scaleX, offset[1] * scaleY];
|
|
383
391
|
});
|
|
384
392
|
}
|
|
393
|
+
const tooltipTitle = getColumOrUndefined(columnIndexes.titleIndex);
|
|
394
|
+
const tooltipContent = getColumOrUndefined(columnIndexes.descriptionIndex);
|
|
395
|
+
const tooltip = tooltipTitle && tooltipContent ?
|
|
396
|
+
{ title: tooltipTitle, content: DOMPurify.sanitize(tooltipContent) } :
|
|
397
|
+
undefined;
|
|
385
398
|
return {
|
|
386
399
|
position: [coords[0], coords[1]],
|
|
387
400
|
imageUrl,
|
|
388
401
|
size,
|
|
389
|
-
offset
|
|
402
|
+
offset,
|
|
403
|
+
tooltip,
|
|
390
404
|
};
|
|
391
405
|
}
|
|
392
406
|
async initialize() {
|
package/assets/i18n/de.json
CHANGED
|
@@ -495,6 +495,7 @@
|
|
|
495
495
|
"Swisstopo WMTS": "Swisstopo WMTS",
|
|
496
496
|
"system": "System",
|
|
497
497
|
"Take measure": "Messen",
|
|
498
|
+
"Test for Translation": "Test für Übersetzung",
|
|
498
499
|
"Thanks for your message. If necessary, somebody will enter in contact with you as soon as possible.": "Vielen Dank für Ihre Nachricht. Falls erforderlich, wird sich so schnell wie möglich jemand mit Ihnen in Verbindung setzen.",
|
|
499
500
|
"The following link will be sent with your message. It contains your current configuration and will help us to understand your problem.": "Der folgende Link wird mit Ihrer Nachricht gesendet. Er enthält Ihre aktuelle Konfiguration und hilft uns, Ihr Problem zu verstehen.",
|
|
500
501
|
"The generated document may contain sensitive data.": "Das generierte Dokument kann sensible Daten enthalten.",
|
|
@@ -509,6 +510,7 @@
|
|
|
509
510
|
"themes-type-custom": "Benutzerdefinierte",
|
|
510
511
|
"themes-type-favorites": "Favoriten",
|
|
511
512
|
"This instance of GeoGirafe cannot be used at the moment.": "Diese Instanz von GeoGirafe kann momentan nicht verwendet werden.",
|
|
513
|
+
"This Text should be translated": "Dieser Text sollte übersetzt werden",
|
|
512
514
|
"Toggle all legends": "Alle Legenden umschalten",
|
|
513
515
|
"Toggle legend": "Legende umschalten",
|
|
514
516
|
"Tools": "Werkzeuge",
|
package/assets/i18n/en.json
CHANGED
|
@@ -498,6 +498,7 @@
|
|
|
498
498
|
"Swisstopo WMTS": "Swisstopo WMTS",
|
|
499
499
|
"system": "System",
|
|
500
500
|
"Take measure": "Take measure",
|
|
501
|
+
"Test for Translation": "Test for Translation",
|
|
501
502
|
"Thanks for your message. If necessary, somebody will enter in contact with you as soon as possible.": "Thanks for your message. If necessary, someone will get in touch with you as soon as possible.",
|
|
502
503
|
"The following link will be sent with your message. It contains your current configuration and will help us to understand your problem.": "The following link will be sent with your message. It contains your current configuration and will help us to understand your problem.",
|
|
503
504
|
"The generated document may contain sensitive data.": "The generated document may contain sensitive data.",
|
|
@@ -512,6 +513,7 @@
|
|
|
512
513
|
"themes-type-custom": "Custom Themes",
|
|
513
514
|
"themes-type-favorites": "Favorite Themes",
|
|
514
515
|
"This instance of GeoGirafe cannot be used at the moment.": "This instance of GeoGirafe cannot be used at the moment.",
|
|
516
|
+
"This Text should be translated": "This Text should be translated",
|
|
515
517
|
"Toggle all legends": "Toggle all legends",
|
|
516
518
|
"Toggle legend": "Toggle legend",
|
|
517
519
|
"Tools": "Tools",
|
package/assets/i18n/fr.json
CHANGED
|
@@ -495,6 +495,7 @@
|
|
|
495
495
|
"Swisstopo WMTS": "Swisstopo WMTS",
|
|
496
496
|
"system": "Système",
|
|
497
497
|
"Take measure": "Prendre une mesure",
|
|
498
|
+
"Test for Translation": "Test de traduction",
|
|
498
499
|
"Thanks for your message. If necessary, somebody will enter in contact with you as soon as possible.": "Merci pour votre message. Si nécessaire, quelqu'un prendra contact avec vous dès que possible.",
|
|
499
500
|
"The following link will be sent with your message. It contains your current configuration and will help us to understand your problem.": "Le lien ci-dessous sera envoyé avec votre message. Il contient votre configuration courante et nous aidera à analyser votre demande.",
|
|
500
501
|
"The generated document may contain sensitive data.": "Le document généré peut contenir des données sensibles.",
|
|
@@ -509,6 +510,7 @@
|
|
|
509
510
|
"themes-type-custom": "Personnalisés",
|
|
510
511
|
"themes-type-favorites": "Favoris",
|
|
511
512
|
"This instance of GeoGirafe cannot be used at the moment.": "Cette instance de GeoGirafe ne peut pas être utilisée pour le moment.",
|
|
513
|
+
"This Text should be translated": "Ce texte doit être traduit",
|
|
512
514
|
"Toggle all legends": "Afficher / Masquer toutes les légendes",
|
|
513
515
|
"Toggle legend": "Afficher / Masquer la légende",
|
|
514
516
|
"Tools": "Outis",
|
package/assets/i18n/it.json
CHANGED
|
@@ -495,6 +495,7 @@
|
|
|
495
495
|
"Swisstopo WMTS": "Swisstopo WMTS",
|
|
496
496
|
"system": "Sistema",
|
|
497
497
|
"Take measure": "Prendi misura",
|
|
498
|
+
"Test for Translation": "Test di traduzione",
|
|
498
499
|
"Thanks for your message. If necessary, somebody will enter in contact with you as soon as possible.": "Grazie per il tuo messaggio. Se necessario, qualcuno ti contatterà il prima possibile.",
|
|
499
500
|
"The following link will be sent with your message. It contains your current configuration and will help us to understand your problem.": "Il seguente link verrà inviato con il tuo messaggio. Contiene la tua configurazione attuale e ci aiuterà a capire il problema.",
|
|
500
501
|
"The generated document may contain sensitive data.": "Il documento generato potrebbe contenere dati sensibili.",
|
|
@@ -509,6 +510,7 @@
|
|
|
509
510
|
"themes-type-custom": "Personalizzati",
|
|
510
511
|
"themes-type-favorites": "Preferiti",
|
|
511
512
|
"This instance of GeoGirafe cannot be used at the moment.": "Questa istanza di GeoGirafe non può essere utilizzata al momento.",
|
|
513
|
+
"This Text should be translated": "Questo testo dovrebbe essere tradotto",
|
|
512
514
|
"Toggle all legends": "Attiva / Disattiva tutte le legende",
|
|
513
515
|
"Toggle legend": "Attiva / Disattiva legenda",
|
|
514
516
|
"Tools": "Strumenti",
|
|
@@ -4,7 +4,11 @@ declare class MapCustomContextMenuComponent extends GirafeHTMLElement {
|
|
|
4
4
|
protected styleUrls: string[] | null;
|
|
5
5
|
template: () => import("uhtml").Hole;
|
|
6
6
|
private get map();
|
|
7
|
-
private static
|
|
7
|
+
private static readonly contextMenuOverlayByMap;
|
|
8
|
+
private get contextMenuOverlay();
|
|
9
|
+
private set contextMenuOverlay(value);
|
|
10
|
+
get tooltipTitle(): "" | import("uhtml").Hole;
|
|
11
|
+
get tooltipContent(): "" | import("uhtml").Hole;
|
|
8
12
|
constructor();
|
|
9
13
|
render(): void;
|
|
10
14
|
closeMenu(): void;
|
|
@@ -8,7 +8,7 @@ class MapCustomContextMenuComponent extends GirafeHTMLElement {
|
|
|
8
8
|
styleUrls = null;
|
|
9
9
|
template = () => {
|
|
10
10
|
return uHtml `<style>
|
|
11
|
-
.map-info-contextmenu{--contextmenu-border-width:1px;--contextmenu-triangle-width:20px;--contextmenu-triangle-height:10px;border:var(--contextmenu-border-width) solid var(--text-color-grad1);bottom:var(--contextmenu-triangle-height);border-radius:0;position:absolute;left:0;transform:translate(-50%)}
|
|
11
|
+
.map-info-contextmenu{--contextmenu-border-width:1px;--contextmenu-triangle-width:20px;--contextmenu-triangle-height:10px;border:var(--contextmenu-border-width) solid var(--text-color-grad1);bottom:var(--contextmenu-triangle-height);border-radius:0;position:absolute;left:0;transform:translate(-50%);& .title-container{padding-bottom:.5rem;&.no-title{padding-bottom:0}& span.title{font-weight:700}}}
|
|
12
12
|
</style><style>
|
|
13
13
|
*{font-family:Arial,sans-serif}.hidden{display:none!important}.gg-rotate90{transform:rotate(90deg)}.gg-rotate180{transform:rotate(180deg)}.gg-rotate270{transform:rotate(270deg)}img{filter:var(--svg-filter)}img.legend-image{filter:var(--svg-map-filter);background:var(--svg-legend-bkg)}div{scrollbar-width:thin}a,a:visited{color:var(--link-color)}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}@keyframes spin-wait{0%{transform:rotate(0)}7%{transform:rotate(360deg)}to{transform:rotate(360deg)}}.gg-spin{animation-name:spin;animation-duration:2s;animation-timing-function:linear;animation-iteration-count:infinite}.gg-spin-wait{animation-name:spin-wait;animation-duration:10s;animation-timing-function:linear;animation-iteration-count:infinite}::-webkit-scrollbar{width:5px}::-webkit-scrollbar-thumb{background:#999}.gg-button,.gg-select,.gg-input,.gg-textarea{background-color:var(--bkg-color);color:var(--text-color);border:var(--app-standard-border);box-sizing:border-box;cursor:pointer;border-radius:3px;outline:0;margin:0;padding:0 0 0 .5rem;display:inline-block}.gg-label{background-color:var(--bkg-color);color:var(--text-color);border:none;align-items:center;margin:0;padding:0;display:flex}.gg-button,.gg-select,.gg-input,.gg-label{min-height:calc(var(--app-standard-height) / 1.5)}.gg-textarea{max-height:initial;resize:vertical;height:6rem;padding:.5rem;line-height:1.3rem}.gg-input{cursor:text}.gg-checkbox{accent-color:var(--text-color);width:1.2rem}.gg-range{accent-color:var(--text-color)}.gg-button{padding:0 .5rem}.gg-button.active{border:solid 1px var(--text-color-grad2);background-color:var(--text-color-grad2);color:var(--bkg-color)}.gg-button:disabled{color:gray;cursor:not-allowed;background-color:#d3d3d3;border:none}.gg-input:disabled,.gg-select:disabled,.gg-textarea:disabled{color:gray;cursor:not-allowed;background-color:#d3d3d3}.gg-button>img{vertical-align:middle}.gg-icon-button{color:var(--text-color);cursor:pointer;background-color:#0000;border:none;flex-direction:column;justify-content:center;align-items:center;padding:0;display:flex}.gg-icon{justify-content:center;align-items:center;display:flex}.gg-big,.gg-big-withtext{min-width:var(--app-standard-height);min-height:var(--app-standard-height);max-height:var(--app-standard-height)}.gg-big img,.gg-big-withtext img{width:calc(var(--app-standard-height) - 1.5rem);margin:0}.gg-big-withtext span{font-variant:small-caps;padding:0 1rem;font-size:.9rem}.gg-medium,.gg-medium-withtext{min-width:calc(var(--app-standard-height) / 1.2);min-height:calc(var(--app-standard-height) / 1.2);max-height:calc(var(--app-standard-height) / 1.2);flex-direction:row}.gg-medium img{width:calc(var(--app-standard-height) / 2.4);margin:0}.gg-medium-withtext img{width:calc(var(--app-standard-height) / 2.4);margin-left:.5rem}.gg-medium-withtext span{padding:0 1rem 0 .5rem;font-size:.9rem}.gg-small,.gg-small-withtext{min-width:calc(var(--app-standard-height) / 2);min-height:calc(var(--app-standard-height) / 2);max-height:calc(var(--app-standard-height) / 2);flex-direction:row}.gg-small img{width:calc(var(--app-standard-height) / 3);margin:0}.gg-small-withtext img{width:calc(var(--app-standard-height) / 3);margin-left:.5rem}.gg-small-withtext span{padding:0 .5rem 0 .3rem;font-size:.9rem}.gg-button:hover,.gg-select:hover,.gg-input:hover,.gg-textarea:hover,.gg-icon-button:hover{background-color:var(--bkg-color-grad1)}.gg-opacity{opacity:.5}.gg-opacity:hover{opacity:1;background-color:#0000}.gg-tabs{cursor:pointer;grid-auto-flow:column;padding-bottom:1rem;font-size:1rem;display:grid}.gg-tab{border:none;border-bottom:var(--app-standard-border);cursor:pointer;color:var(--text-color);background:0 0;padding:.5rem}.gg-tab.active{border-bottom:solid 1px var(--text-color)}.girafe-button-big,.girafe-button-large,.girafe-button-small,.girafe-button-tiny{color:var(--text-color);background-color:#0000;border:none;flex-direction:column;display:flex}.girafe-button-big:hover,.girafe-button-large:hover,.girafe-button-small:hover,.girafe-button-tiny:hover{background-color:var(--bkg-color-grad1);cursor:pointer}.girafe-button-big.dark,.girafe-button-large.dark,.girafe-button-small.dark,.girafe-button-tiny.dark{background-color:var(--bkg-color);filter:invert()}.girafe-button-big{width:var(--app-standard-height);height:var(--app-standard-height);align-items:center;padding:1rem}.girafe-button-big img{overflow:hidden}.girafe-button-large{flex-direction:row}.girafe-button-large img{height:2rem;margin:.3rem}.girafe-button-large span{height:2rem;margin:.3rem;line-height:2rem}.girafe-button-small{min-width:calc(var(--app-standard-height) / 2);height:calc(var(--app-standard-height) / 2);align-items:center;padding:.5rem}.girafe-button-small img{overflow:hidden}.girafe-button-small span{text-align:left;text-overflow:ellipsis;width:100%;overflow:hidden}.girafe-button-tiny{align-items:center;width:1rem;height:1rem;padding:0}.girafe-button-tiny img{overflow:hidden}.girafe-onboarding-theme{background-color:var(--bkg-color)!important;color:var(--text-color)!important}.girafe-onboarding-theme button{background-color:var(--bkg-color)!important;color:var(--text-color)!important;text-shadow:none!important}.girafe-onboarding-theme button.driver-popover-close-btn{z-index:10000}
|
|
14
14
|
</style><style>
|
|
@@ -17,21 +17,51 @@ class MapCustomContextMenuComponent extends GirafeHTMLElement {
|
|
|
17
17
|
.ol-popup{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;font-size:.9em}.ol-popup .ol-popup-content{cursor:default;padding:.25em .5em;overflow:hidden}.ol-popup.hasclosebox .ol-popup-content{margin-right:1.7em}.ol-popup .ol-popup-content:after{clear:both;content:"";height:0;font-size:0;display:block}.ol-popup .anchor{pointer-events:none;background:red;width:0;height:0;margin:-11px 22px;display:block;position:absolute}.ol-popup .anchor:after,.ol-popup .anchor:before{position:absolute}.ol-popup-right .anchor:after,.ol-popup-right .anchor:before{right:0}.ol-popup-top .anchor{top:0}.ol-popup-bottom .anchor{bottom:0}.ol-popup-right .anchor{right:0}.ol-popup-left .anchor{left:0}.ol-popup-center .anchor{left:50%;margin-left:0!important}.ol-popup-middle .anchor{top:50%;margin-top:0!important}.ol-popup-center.ol-popup-middle .anchor{display:none}.ol-popup.ol-fixed{margin:0!important;inset:.5em .5em auto auto!important;transform:none!important}.ol-popup.ol-fixed .anchor{display:none}.ol-popup.ol-fixed.anim>div{animation:none}.ol-popup .ol-fix{float:right;cursor:pointer;background:#fff;width:1em;height:.9em;margin:.2em;position:relative}.ol-popup .ol-fix:before{content:"";box-sizing:border-box;border:.1em solid #666;border-right-width:.3em;width:.8em;height:.7em;margin:.1em;display:block}.ol-popup.shadow{box-shadow:2px 2px 2px 2px #00000080}.ol-popup .closeBox{color:#fff;cursor:pointer;float:right;background-color:#003c8880;border:0;border-radius:2px;width:1.4em;height:1.4em;margin:5px 5px 0 0;padding:0;font-size:.9em;font-weight:700;display:none;position:relative}.ol-popup.hasclosebox .closeBox{display:block}.ol-popup .closeBox:hover{background-color:#003c88b3}.ol-popup .closeBox:after{content:"u00d7";text-align:center;width:100%;margin:-.5em 0;font-size:1.5em;line-height:1em;position:absolute;top:50%;left:0;right:0}.ol-popup.modifytouch{background-color:#eee}.ol-popup.modifytouch .ol-popup-content{white-space:nowrap;padding:0 .25em;font-size:.85em}.ol-popup.modifytouch .ol-popup-content a{text-decoration:none}.ol-popup.tooltips{background-color:#ffa}.ol-popup.tooltips .ol-popup-content{white-space:nowrap;padding:0 .25em;font-size:.85em}.ol-popup.default>div{background-color:#fff;border:1px solid #69f;border-radius:5px}.ol-popup.default{margin:-11px 0;transform:translateY(-22px)}.ol-popup-top.ol-popup.default{margin:11px 0;transform:none}.ol-popup-left.default{margin:-11px -22px;transform:translateY(-22px)}.ol-popup-top.ol-popup-left.default{margin:11px -22px;transform:none}.ol-popup-right.default{margin:-11px 22px;transform:translate(44px,-22px)}.ol-popup-top.ol-popup-right.default{margin:11px 22px;transform:translate(44px)}.ol-popup-middle.default{margin:0 10px;transform:none}.ol-popup-middle.ol-popup-right.default{margin:0 -10px;transform:translate(-20px)}.ol-popup.default .anchor{color:#69f}.ol-popup.default .anchor:after,.ol-popup.default .anchor:before{content:"";border:11px solid;border-color:currentColor #0000;margin:0 -11px}.ol-popup.default .anchor:after{border-width:11px;border-color:#fff #0000;margin:2px -11px}.ol-popup-top.default .anchor:before,.ol-popup-top.default .anchor:after{border-top:0;top:0}.ol-popup-bottom.default .anchor:before,.ol-popup-bottom.default .anchor:after{border-bottom:0;bottom:0}.ol-popup-middle.default .anchor:before{border-color:#0000 currentColor;margin:-11px -33px}.ol-popup-middle.default .anchor:after{border-color:#0000 #fff;margin:-11px -31px}.ol-popup-middle.ol-popup-left.default .anchor:before,.ol-popup-middle.ol-popup-left.default .anchor:after{border-left:0}.ol-popup-middle.ol-popup-right.default .anchor:before,.ol-popup-middle.ol-popup-right.default .anchor:after{border-right:0}.ol-popup.placemark{color:#c00;margin:-.65em 0;transform:translateY(-1.3em)}.ol-popup.placemark>div{width:2em;height:2em;min-width:unset;box-sizing:border-box;background-color:#fff;border:0;border-radius:50%;font-size:15px;position:relative;box-shadow:inset 0 0 0 .45em}.ol-popup.placemark .ol-popup-content{cursor:default;text-align:center;width:1em;height:1em;padding:.25em 0;line-height:1em;position:absolute;top:50%;left:50%;overflow:hidden;transform:translate(-50%,-50%)}.ol-popup.placemark .anchor{margin:0}.ol-popup.placemark .anchor:before{content:"";background:0 0;border-radius:50%;width:1em;height:.5em;margin:-.5em;box-shadow:0 1em .5em #00000080}.ol-popup.placemark .anchor:after{content:"";border:.7em solid #0000;border-top:1em solid;border-bottom:0 solid;margin:-.75em -.7em;bottom:0}.ol-popup.placemark.shield>div{border-radius:.2em}.ol-popup.placemark.shield .anchor:after{border-width:.8em 1em 0;margin:-.7em -1em}.ol-popup.placemark.blazon>div{border-radius:.2em}.ol-popup.placemark.pushpin{margin:-2.2em 0;transform:translateY(-4em)}.ol-popup.placemark.pushpin>div{border-radius:0;width:1.1em;box-shadow:inset 2em 0;background:0 0!important}.ol-popup.placemark.pushpin>div:before{content:"";pointer-events:none;border:.5em solid #0000;border-top:.3em solid;border-bottom-color:currentColor;width:1.3em;height:1.5em;position:absolute;top:50%;left:50%;transform:translate(-50%,-50%)}.ol-popup.placemark.needle{margin:-2em 0;transform:translateY(-4em)}.ol-popup.placemark.pushpin .anchor,.ol-popup.placemark.needle .anchor{margin:-1.2em}.ol-popup.placemark.pushpin .anchor:after,.ol-popup.placemark.needle .anchor:after{border-style:solid;border-width:2em .15em 0;width:.1em;margin:-.55em -.2em}.ol-popup.placemark.pushpin .anchor:before,.ol-popup.placemark.needle .anchor:before{margin:-.75em -.5em}.ol-popup.placemark.flagv{margin:-2em 1em;transform:translateY(-4em)}.ol-popup.placemark.flagv>div{box-shadow:none;background-color:#0000;border-radius:0}.ol-popup.placemark.flagv>div:before{content:"";pointer-events:none;border:1em solid #0000;border-left:2em solid;position:absolute}.ol-popup.placemark.flagv .anchor{margin:-1.4em}.ol-popup.placemark.flag{margin:-2em 1em;transform:translateY(-4em)}.ol-popup.placemark.flag>div{border-radius:0;transform-origin:0 150%!important}.ol-popup.placemark.flag .anchor{margin:-1.4em}.ol-popup.placemark.flagv .anchor:after,.ol-popup.placemark.flag .anchor:after{border-style:solid;border-width:2em .15em 0;width:.1em;margin:-.55em -1em}.ol-popup.placemark.flagv .anchor:before,.ol-popup.placemark.flag .anchor:before{margin:-.75em -1.25em}.ol-popup.placemark.flag.finish{margin:-2em 1em}.ol-popup.placemark.flag.finish>div{background-image:linear-gradient(45deg,currentColor 25%,#0000 25% 75%,currentColor 75%,currentColor),linear-gradient(45deg,currentColor 25%,#0000 25% 75%,currentColor 75%,currentColor);background-position:.5em 0,0 .5em;background-size:1em 1em;box-shadow:inset 0 0 0 .25em}.ol-popup.black .closeBox{color:#f80;background-color:#00000080;border-radius:5px}.ol-popup.black .closeBox:hover{color:#da2;background-color:#000000b3}.ol-popup.black{margin:-20px 0;transform:translateY(-40px)}.ol-popup.black>div{color:#fff;background-color:#0009;border-radius:5px}.ol-popup-top.ol-popup.black{margin:20px 0;transform:none}.ol-popup-left.black{margin:-20px -22px;transform:translateY(-40px)}.ol-popup-top.ol-popup-left.black{margin:20px -22px;transform:none}.ol-popup-right.black{margin:-20px 22px;transform:translate(44px,-40px)}.ol-popup-top.ol-popup-right.black{margin:20px 22px;transform:translate(44px)}.ol-popup-middle.black{margin:0 11px;transform:none}.ol-popup-left.ol-popup-middle.black{transform:none}.ol-popup-right.ol-popup-middle.black{margin:0 -11px;transform:translate(-22px)}.ol-popup.black .anchor{color:#0009;margin:-20px 11px}.ol-popup.black .anchor:before{content:"";border:20px solid;border-left:11px solid #0000;border-right:11px solid #0000}.ol-popup-top.black .anchor:before{border-top:0;top:0}.ol-popup-bottom.black .anchor:before{border-bottom:0;bottom:0}.ol-popup-middle.black .anchor:before{border-color:#0000 currentColor;margin:-20px -22px}.ol-popup-middle.ol-popup-left.black .anchor:before{border-left:0}.ol-popup-middle.ol-popup-right.black .anchor:before{border-right:0}.ol-popup-center.black .anchor:before{margin:0 -10px}.ol-popup.tips .closeBox{color:#fff;background-color:red;border-radius:50%;width:1.2em;height:1.2em}.ol-popup.tips .closeBox:hover{background-color:#f40}.ol-popup.tips{margin:-20px 0;transform:translateY(-40px)}.ol-popup.tips>div{color:#333;background-color:#cea;border:5px solid #ad7;border-radius:5px}.ol-popup-top.ol-popup.tips{margin:20px 0;transform:none}.ol-popup-left.tips{margin:-20px -22px;transform:translateY(-40px)}.ol-popup-top.ol-popup-left.tips{margin:20px -22px;transform:none}.ol-popup-right.tips{margin:-20px 22px;transform:translate(44px,-40px)}.ol-popup-top.ol-popup-right.tips{margin:20px 22px;transform:translate(44px)}.ol-popup-middle.tips{margin:0;transform:none}.ol-popup-left.ol-popup-middle.tips{margin:0 22px;transform:none}.ol-popup-right.ol-popup-middle.tips{margin:0 -22px;transform:translate(-44px)}.ol-popup.tips .anchor{color:#ad7;margin:-18px 22px}.ol-popup.tips .anchor:before{content:"";border:20px solid;border-left:11px solid #0000;border-right:11px solid #0000}.ol-popup-top.tips .anchor:before{border-top:0;top:0}.ol-popup-bottom.tips .anchor:before{border-bottom:0;bottom:0}.ol-popup-center.tips .anchor:before{border-width:20px 6px;margin:0 -6px}.ol-popup-left.tips .anchor:before{border-left:0;margin-left:0}.ol-popup-right.tips .anchor:before{border-right:0;margin-right:0}.ol-popup-middle.tips .anchor:before{border-width:6px 20px;border-color:#0000 currentColor;margin:-6px -41px}.ol-popup-middle.ol-popup-left.tips .anchor:before{border-left:0}.ol-popup-middle.ol-popup-right.tips .anchor:before{border-right:0}.ol-popup.warning .closeBox{color:#fff;background-color:red;border-radius:50%;font-size:.83em}.ol-popup.warning .closeBox:hover{background-color:#f40}.ol-popup.warning{color:#900;background-color:#fd0;border:4px dashed red;border-radius:3px;margin:-28px 10px;transform:translateY(-56px)}.ol-popup-top.ol-popup.warning{margin:28px 10px;transform:none}.ol-popup-left.warning{margin:-28px -22px;transform:translateY(-56px)}.ol-popup-top.ol-popup-left.warning{margin:28px -22px;transform:none}.ol-popup-right.warning{margin:-28px 22px;transform:translate(44px,-56px)}.ol-popup-top.ol-popup-right.warning{margin:28px 22px;transform:translate(44px)}.ol-popup-middle.warning{margin:0;transform:none}.ol-popup-left.ol-popup-middle.warning{margin:0 22px;transform:none}.ol-popup-right.ol-popup-middle.warning{margin:0 -22px;transform:translate(-44px)}.ol-popup.warning .anchor{margin:-33px 7px}.ol-popup.warning .anchor:before{content:"";border:30px solid red;border-left:11px solid #0000;border-right:11px solid #0000}.ol-popup-top.warning .anchor:before{border-top:0;top:0}.ol-popup-bottom.warning .anchor:before{border-bottom:0;bottom:0}.ol-popup-center.warning .anchor:before{margin:0 -21px}.ol-popup-middle.warning .anchor:before{border-width:10px 22px;border-color:#0000 red;margin:-10px -33px}.ol-popup-middle.ol-popup-left.warning .anchor:before{border-left:0}.ol-popup-middle.ol-popup-right.warning .anchor:before{border-right:0}.ol-popup .ol-popupfeature table{width:100%}.ol-popup .ol-popupfeature table td{text-overflow:ellipsis;max-width:25em;overflow:hidden}.ol-popup .ol-popupfeature table td img{max-width:100px;max-height:100px}.ol-popup .ol-popupfeature tr:nth-child(odd){background-color:#eee}.ol-popup .ol-popupfeature .ol-zoombt{color:#003c8880;background:0 0;border:0;outline:none;width:2em;height:2em;display:inline-block;position:relative}.ol-popup .ol-popupfeature .ol-zoombt:before{content:"";box-sizing:border-box;background-color:#0000;border:.17em solid;border-radius:100%;width:1em;height:1em;position:absolute;top:.3em;left:.3em}.ol-popup .ol-popupfeature .ol-zoombt:after{content:"";box-sizing:border-box;border-style:solid;border-width:.1em .3em;border-radius:.03em;position:absolute;top:1.35em;left:1.15em;transform:rotate(45deg);box-shadow:-.2em 0 0 -.04em}.ol-popup .ol-popupfeature .ol-count{float:right;margin:.25em 0}.ol-popup .ol-popupfeature .ol-prev,.ol-popup .ol-popupfeature .ol-next{vertical-align:bottom;cursor:pointer;border:.5em solid #0000;border-left-color:#003c8880;border-right:0 solid #003c8880;margin:0 .5em;display:inline-block}.ol-popup .ol-popupfeature .ol-prev{border-width:.5em .5em .5em 0}.ol-popup.tooltips.black{background-color:#0000}.ol-popup.tooltips.black>div{background-color:#00000080;padding:.2em .5em;transform:scaleY(1.3)}.ol-popup-middle.tooltips.black .anchor:before{border-width:5px 10px;margin:-5px -21px}.ol-popup-center.ol-popup-middle,.ol-popup-top.ol-popup-left.ol-fixPopup,.ol-popup-top.ol-popup-right.ol-fixPopup,.ol-popup.ol-fixPopup{margin:0}
|
|
18
18
|
</style>
|
|
19
19
|
<style>${this.customStyle}</style>
|
|
20
|
-
<div class="map-info-contextmenu"><button class="contextmenu-closer gg-icon-button gg-small" onclick="${() => this.closeMenu()}"></button><div>${this.
|
|
20
|
+
<div class="map-info-contextmenu"><div class="${this.tooltipTitle ? 'title-container' : 'title-container no-title'}"><span class="title">${this.tooltipTitle}</span> <button class="contextmenu-closer gg-icon-button gg-small" onclick="${() => this.closeMenu()}"></button></div><div>${this.tooltipContent}</div><svg class="tooltip-triangle" viewBox="0 0 20 10" preserveAspectRatio="none"><polygon points="0,0 10,10 20,0" class="triangle-fill"/><path d="M0,0 L10,10 L20,0" class="triangle-border"/></svg></div>`;
|
|
21
21
|
};
|
|
22
22
|
get map() {
|
|
23
23
|
return this.context.mapManager.getMap();
|
|
24
24
|
}
|
|
25
|
-
// We use a static property for the overlay
|
|
26
|
-
//
|
|
27
|
-
|
|
25
|
+
// We use a static property/getter for the overlay, because OpenLayer is recreating a new object each time when we do
|
|
26
|
+
// an addOverlay(). But as multiple instances of the Map (when using multiple <geogirafe-map ... /> in API context)
|
|
27
|
+
// should NOT share the same overlay, we need to create a new one for each map instance (indentified by Map's custom
|
|
28
|
+
// UUID Property).
|
|
29
|
+
static contextMenuOverlayByMap = {};
|
|
30
|
+
get contextMenuOverlay() {
|
|
31
|
+
const uuid = this.map.get('uuid');
|
|
32
|
+
return MapCustomContextMenuComponent.contextMenuOverlayByMap[uuid];
|
|
33
|
+
}
|
|
34
|
+
set contextMenuOverlay(value) {
|
|
35
|
+
const uuid = this.map.get('uuid');
|
|
36
|
+
MapCustomContextMenuComponent.contextMenuOverlayByMap[uuid] = value;
|
|
37
|
+
}
|
|
38
|
+
get tooltipTitle() {
|
|
39
|
+
const title = this.state.position.tooltip?.title;
|
|
40
|
+
if (!title) {
|
|
41
|
+
return '';
|
|
42
|
+
}
|
|
43
|
+
if (title.includes('<')) {
|
|
44
|
+
return this.htmlUnsafe(title);
|
|
45
|
+
}
|
|
46
|
+
return this.htmlUnsafe(this.context.i18nManager.getTranslation(title));
|
|
47
|
+
}
|
|
48
|
+
get tooltipContent() {
|
|
49
|
+
const content = this.state.position.tooltip?.content;
|
|
50
|
+
if (!content) {
|
|
51
|
+
return '';
|
|
52
|
+
}
|
|
53
|
+
if (content.includes('<')) {
|
|
54
|
+
return this.htmlUnsafe(content);
|
|
55
|
+
}
|
|
56
|
+
return this.htmlUnsafe(this.context.i18nManager.getTranslation(content));
|
|
57
|
+
}
|
|
28
58
|
constructor() {
|
|
29
59
|
super('custom-map-context-menu');
|
|
30
60
|
}
|
|
31
61
|
render() {
|
|
32
62
|
if (this.state.position.tooltip) {
|
|
33
63
|
super.render();
|
|
34
|
-
|
|
64
|
+
this.contextMenuOverlay.setPosition(this.state.position.tooltip.position);
|
|
35
65
|
}
|
|
36
66
|
else {
|
|
37
67
|
super.renderEmpty();
|
|
@@ -53,12 +83,12 @@ class MapCustomContextMenuComponent extends GirafeHTMLElement {
|
|
|
53
83
|
}
|
|
54
84
|
connectedCallback() {
|
|
55
85
|
super.connectedCallback();
|
|
56
|
-
if (!
|
|
57
|
-
|
|
86
|
+
if (!this.contextMenuOverlay) {
|
|
87
|
+
this.contextMenuOverlay = new Overlay({
|
|
58
88
|
element: this,
|
|
59
89
|
autoPan: { animation: { duration: 250 } }
|
|
60
90
|
});
|
|
61
|
-
this.map.addOverlay(
|
|
91
|
+
this.map.addOverlay(this.contextMenuOverlay);
|
|
62
92
|
}
|
|
63
93
|
this.registerEvents();
|
|
64
94
|
}
|
|
@@ -55,6 +55,7 @@ export default class MapComponent extends GirafeHTMLElement {
|
|
|
55
55
|
geolocationSource: VectorSource;
|
|
56
56
|
private readonly markerSource;
|
|
57
57
|
private readonly markerLayer;
|
|
58
|
+
private mapMarkerUnderCursor;
|
|
58
59
|
get projection(): import("ol/proj.js").Projection;
|
|
59
60
|
get config(): import("../../tools/main.js").GirafeConfig;
|
|
60
61
|
get onMobile(): boolean;
|
|
@@ -82,6 +82,7 @@ export default class MapComponent extends GirafeHTMLElement {
|
|
|
82
82
|
markerLayer = new VectorLayer({
|
|
83
83
|
source: this.markerSource
|
|
84
84
|
});
|
|
85
|
+
mapMarkerUnderCursor = null;
|
|
85
86
|
get projection() {
|
|
86
87
|
return this.olMap.getView().getProjection();
|
|
87
88
|
}
|
|
@@ -362,6 +363,17 @@ export default class MapComponent extends GirafeHTMLElement {
|
|
|
362
363
|
if (this.registerInteractionListener('map.select', false)) {
|
|
363
364
|
// Simple click for single feature selection
|
|
364
365
|
this.olMap.on('singleclick', (e) => {
|
|
366
|
+
if (this.mapMarkerUnderCursor) {
|
|
367
|
+
const mapMarker = this.mapMarkerUnderCursor.get('mapMarker');
|
|
368
|
+
if (mapMarker) {
|
|
369
|
+
this.state.position.tooltip = {
|
|
370
|
+
title: mapMarker.tooltip?.title,
|
|
371
|
+
content: mapMarker.tooltip?.content ?? '',
|
|
372
|
+
position: mapMarker.position
|
|
373
|
+
};
|
|
374
|
+
return;
|
|
375
|
+
}
|
|
376
|
+
}
|
|
365
377
|
if (this.canExecute('map.select')) {
|
|
366
378
|
this.onClick(e);
|
|
367
379
|
}
|
|
@@ -396,6 +408,19 @@ export default class MapComponent extends GirafeHTMLElement {
|
|
|
396
408
|
}
|
|
397
409
|
onPointerMove(e) {
|
|
398
410
|
this.state.mouseCoordinates = e.coordinate;
|
|
411
|
+
const featuresAtPixel = this.olMap.getFeaturesAtPixel(e.pixel, { layerFilter: (layer) => layer === this.markerLayer });
|
|
412
|
+
let cursor = 'default';
|
|
413
|
+
if (featuresAtPixel.length > 0) {
|
|
414
|
+
this.mapMarkerUnderCursor = featuresAtPixel[0];
|
|
415
|
+
const mapMarker = this.mapMarkerUnderCursor.get('mapMarker');
|
|
416
|
+
if (mapMarker?.tooltip) {
|
|
417
|
+
cursor = 'pointer';
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
else {
|
|
421
|
+
this.mapMarkerUnderCursor = null;
|
|
422
|
+
}
|
|
423
|
+
this.mapTarget.style.cursor = cursor;
|
|
399
424
|
}
|
|
400
425
|
onMoveEnd(_e) {
|
|
401
426
|
const view = this.olMap.getView();
|
|
@@ -1028,9 +1053,18 @@ export default class MapComponent extends GirafeHTMLElement {
|
|
|
1028
1053
|
this.markerSource.clear();
|
|
1029
1054
|
}
|
|
1030
1055
|
addMarker(mapMarker) {
|
|
1056
|
+
/*
|
|
1057
|
+
In OpenLayers we need to calculate the anchor based on the marker size and offset as it is `fraction` by default.
|
|
1058
|
+
As the offset and the size are provided in pixel, we need to calculate the fraction for each axis. So, for example,
|
|
1059
|
+
when you have size [21,25] and offset [-10.5,-25] the anchor must be [0.5, 1] to have the bottom center of the
|
|
1060
|
+
marker at the given coordinates.
|
|
1061
|
+
*/
|
|
1062
|
+
const anchor = mapMarker.offset && mapMarker.size
|
|
1063
|
+
? [Math.abs(mapMarker.offset[0] / mapMarker.size[0]), Math.abs(mapMarker.offset[1] / mapMarker.size[1])]
|
|
1064
|
+
: undefined;
|
|
1031
1065
|
const iconStyle = new Style({
|
|
1032
1066
|
image: new Icon({
|
|
1033
|
-
|
|
1067
|
+
anchor: anchor,
|
|
1034
1068
|
src: mapMarker.imageUrl,
|
|
1035
1069
|
width: mapMarker.size ? mapMarker.size[0] : undefined,
|
|
1036
1070
|
height: mapMarker.size ? mapMarker.size[1] : undefined
|
|
@@ -1040,6 +1074,7 @@ export default class MapComponent extends GirafeHTMLElement {
|
|
|
1040
1074
|
geometry: new Point(mapMarker.position)
|
|
1041
1075
|
});
|
|
1042
1076
|
marker.setStyle(iconStyle);
|
|
1077
|
+
marker.set('mapMarker', mapMarker);
|
|
1043
1078
|
this.markerSource.addFeature(marker);
|
|
1044
1079
|
}
|
|
1045
1080
|
showCrosshair(position) {
|
package/package.json
CHANGED
package/templates/api.html
CHANGED
|
@@ -260,7 +260,7 @@
|
|
|
260
260
|
|
|
261
261
|
<!-- Tooltip -->
|
|
262
262
|
<h2>Add a toolip somewhere on the map</h2>
|
|
263
|
-
<p class="descr">Add a tooltip with
|
|
263
|
+
<p class="descr">Add a tooltip with custom text and optional title at the defined coordinates.</p>
|
|
264
264
|
<section>
|
|
265
265
|
<div class="row">
|
|
266
266
|
<div class="left">
|
|
@@ -321,7 +321,9 @@
|
|
|
321
321
|
</p>
|
|
322
322
|
<p class="descr">Allowed column names:</p>
|
|
323
323
|
<ul>
|
|
324
|
-
<li><strong>point</strong>: coordinates where the
|
|
324
|
+
<li><strong>point</strong>: coordinates where the marker should be added.</li>
|
|
325
|
+
<li><strong>title</strong> (optional): the title for the popup shown when clicking on the marker.</li>
|
|
326
|
+
<li><strong>description</strong> (optional): the description (content) of the popup shown when clicking on the marker.</li>
|
|
325
327
|
<li><strong>icon</strong>: url to the marker image</li>
|
|
326
328
|
<li><strong>iconSize</strong> (optional): size if the marker should be resized</li>
|
|
327
329
|
<li><strong>iconOffset</strong> (optional): offset if the marker should be shifted</li>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":"1.1.0-dev.
|
|
1
|
+
{"version":"1.1.0-dev.2593337676", "build":"2593337676", "date":"11/06/2026"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
id point title description icon iconSize iconOffset
|
|
2
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-
|
|
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-gold.png 21,25 -10.5,-25
|
|
4
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
5
|
4 2611738,1267123 Test for Offset/Size Test for Offset/Size api/marker-huge.png 24,38 -162,-512
|
|
6
|
-
5
|
|
6
|
+
5 2611638,1267183 Test for Translation This Text should be translated api/marker-green.png 24,38 -12,-38
|
|
Binary file
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
"zoom": "11",
|
|
6
6
|
"basemap": "ArcGIS Imagery",
|
|
7
7
|
"crosshair": "1631989, 5067094",
|
|
8
|
-
"tooltip": "1631989, 5067094 | Hello from the GeoGirafe API!",
|
|
8
|
+
"tooltip": "1631989, 5067094 | GeoGirafe API | Hello from the GeoGirafe API!",
|
|
9
9
|
"layers": "OpenTopoMap",
|
|
10
10
|
"multiLayers": "GL_AbschnittsStoergrade, SW_Jugendlichenanteil, KJ_Jugendangebot",
|
|
11
11
|
"layersWithConfig": "GR_Grundwasserschutzzonen|o;0.4|f;gr_gz_kantypbez;eq;S1",
|
package/tools/main.d.ts
CHANGED
|
@@ -86,7 +86,7 @@ export type { default as IGirafePanel } from './state/igirafepanel.js';
|
|
|
86
86
|
export { isGirafePanel } from './state/igirafepanel.js';
|
|
87
87
|
export { default as LayersConfig } from './state/layersConfig.js';
|
|
88
88
|
export { default as MapManager } from './state/mapManager.js';
|
|
89
|
-
export type { MapMarker } from './state/mapposition.js';
|
|
89
|
+
export type { MapMarkerTooltip, MapMarker } from './state/mapposition.js';
|
|
90
90
|
export { default as MapPosition } from './state/mapposition.js';
|
|
91
91
|
export type { InitialSelectionQuery } from './state/objectselection.js';
|
|
92
92
|
export { default as ObjectSelection } from './state/objectselection.js';
|
|
@@ -5,6 +5,7 @@ import { defaults as defaultControls } from 'ol/control/defaults.js';
|
|
|
5
5
|
import { defaults as defaultInteractions } from 'ol/interaction/defaults.js';
|
|
6
6
|
import { DragPan } from 'ol/interaction.js';
|
|
7
7
|
import { Kinetic } from 'ol';
|
|
8
|
+
import { v4 as uuidv4 } from 'uuid';
|
|
8
9
|
/** The singleton containing the main OpenLayers map accessible from everywhere */
|
|
9
10
|
export default class MapManager extends GirafeSingleton {
|
|
10
11
|
map;
|
|
@@ -26,6 +27,9 @@ export default class MapManager extends GirafeSingleton {
|
|
|
26
27
|
interactions: interactions,
|
|
27
28
|
moveTolerance: 5
|
|
28
29
|
});
|
|
30
|
+
// Needed to identify the map instance for reusing Overlay (or not) in the context menu (see
|
|
31
|
+
// CustomContextMenu.contextMenuOverlayByMap)
|
|
32
|
+
this.map.set('uuid', uuidv4());
|
|
29
33
|
}
|
|
30
34
|
getMap() {
|
|
31
35
|
if (!this.map) {
|
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
import { Coordinate } from 'ol/coordinate.js';
|
|
2
|
+
export type MapMarkerTooltip = {
|
|
3
|
+
title: string;
|
|
4
|
+
content?: string;
|
|
5
|
+
};
|
|
2
6
|
export type MapMarker = {
|
|
3
7
|
imageUrl: string;
|
|
4
8
|
position: Coordinate;
|
|
5
9
|
size?: number[];
|
|
6
10
|
offset?: number[];
|
|
11
|
+
tooltip?: MapMarkerTooltip;
|
|
7
12
|
};
|
|
8
13
|
declare class MapPosition {
|
|
9
14
|
center: Coordinate;
|
|
@@ -12,6 +17,7 @@ declare class MapPosition {
|
|
|
12
17
|
scale?: number;
|
|
13
18
|
crosshair?: Coordinate;
|
|
14
19
|
tooltip?: {
|
|
20
|
+
title?: string;
|
|
15
21
|
content: string;
|
|
16
22
|
position?: Coordinate;
|
|
17
23
|
};
|
|
@@ -24,6 +24,7 @@ class MapPosition {
|
|
|
24
24
|
position.crosshair = this.crosshair ? [...this.crosshair] : undefined;
|
|
25
25
|
position.tooltip = this.tooltip
|
|
26
26
|
? {
|
|
27
|
+
title: this.tooltip.title,
|
|
27
28
|
content: this.tooltip.content,
|
|
28
29
|
position: this.tooltip.position ? [...this.tooltip.position] : undefined
|
|
29
30
|
}
|
|
@@ -33,7 +34,8 @@ class MapPosition {
|
|
|
33
34
|
imageUrl: marker.imageUrl,
|
|
34
35
|
position: marker.position,
|
|
35
36
|
size: marker.size,
|
|
36
|
-
offset: marker.offset
|
|
37
|
+
offset: marker.offset,
|
|
38
|
+
tooltip: marker.tooltip,
|
|
37
39
|
});
|
|
38
40
|
}
|
|
39
41
|
return position;
|
package/tools/utils/utils.d.ts
CHANGED
|
@@ -78,7 +78,8 @@ export declare const linkify: (str: string) => string;
|
|
|
78
78
|
*/
|
|
79
79
|
export declare function applyDefaultPrefixToUrl(context: IGirafeContext, metadataUrl?: string): string | undefined;
|
|
80
80
|
/**
|
|
81
|
-
* Splits a String containing Numbers into an Array of Numbers. The Separator is a comma.
|
|
81
|
+
* Splits a String containing Numbers into an Array of Numbers. The Separator is a comma. Or returns
|
|
82
|
+
* <code>undefined</code> if the input is <code>undefined</code>
|
|
82
83
|
* @param numbersAsString The String containing Numbers.
|
|
83
84
|
*/
|
|
84
|
-
export declare const splitTrimAndConvertToNumber: (numbersAsString: string) => number[];
|
|
85
|
+
export declare const splitTrimAndConvertToNumber: (numbersAsString: string | undefined) => number[] | undefined;
|
package/tools/utils/utils.js
CHANGED
|
@@ -200,12 +200,13 @@ export function applyDefaultPrefixToUrl(context, metadataUrl) {
|
|
|
200
200
|
return metadataUrl;
|
|
201
201
|
}
|
|
202
202
|
/**
|
|
203
|
-
* Splits a String containing Numbers into an Array of Numbers. The Separator is a comma.
|
|
203
|
+
* Splits a String containing Numbers into an Array of Numbers. The Separator is a comma. Or returns
|
|
204
|
+
* <code>undefined</code> if the input is <code>undefined</code>
|
|
204
205
|
* @param numbersAsString The String containing Numbers.
|
|
205
206
|
*/
|
|
206
207
|
export const splitTrimAndConvertToNumber = (numbersAsString) => {
|
|
207
|
-
return numbersAsString
|
|
208
|
+
return numbersAsString ? numbersAsString
|
|
208
209
|
.split(',')
|
|
209
210
|
.map((e) => e.trim())
|
|
210
|
-
.map(Number);
|
|
211
|
+
.map(Number) : undefined;
|
|
211
212
|
};
|