@geogirafe/lib-geoportal 1.1.0-dev.2631714424 → 1.1.0-dev.2636580374

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 @@ class MenuButtonComponent extends GirafeHTMLElement {
8
8
  return uHtml `<style>
9
9
  .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}button,input,select,textarea{font:inherit}.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-grad1);background-color:var(--bkg-color-grad2)}.gg-button:disabled{background-color:var(--bkg-color-grad1);color:var(--text-color-grad2);cursor:not-allowed;border:none}.gg-button:disabled img{filter:opacity(.6)}.gg-input:disabled,.gg-select:disabled,.gg-textarea:disabled{background-color:var(--bkg-color-grad1);color:var(--text-color-grad2);cursor:not-allowed}.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:not(:disabled),.gg-select:hover:not(:disabled),.gg-input:hover:not(:disabled),.gg-textarea:hover:not(:disabled),.gg-icon-button:hover:not(:disabled){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}
10
10
  </style><style>
11
- .container{position:relative}.menu-content{border:var(--app-standard-border);background:var(--bkg-color);z-index:1000;box-shadow:var(--bx-shdw);border-width:2px;border-radius:4px;margin-right:.2rem;font-size:0;display:flex;position:absolute}.open-bottom{flex-direction:column;width:fit-content;height:max-content;top:100%;left:0}.open-bottom-left{flex-direction:row;width:fit-content;height:max-content;top:100%;right:0}.open-up{flex-direction:column;width:fit-content;height:max-content;bottom:100%;right:0}.open-up-right{flex-direction:column;width:fit-content;height:max-content;bottom:100%;left:0}.open-left{flex-direction:row;width:max-content;height:fit-content;top:0;right:100%}
11
+ .container{position:relative}.menu-content{border:var(--app-standard-border);background:var(--bkg-color);z-index:1000;box-shadow:var(--bx-shdw);border-width:2px;border-radius:4px;margin-right:.2rem;display:flex;position:absolute}.open-bottom{flex-direction:column;width:fit-content;height:max-content;top:100%;left:0}.open-bottom-left{flex-direction:row;width:fit-content;height:max-content;top:100%;right:0}.open-up{flex-direction:column;width:fit-content;height:max-content;bottom:100%;right:0}.open-up-right{flex-direction:column;width:fit-content;height:max-content;bottom:100%;left:0}.open-left{flex-direction:row;width:max-content;height:fit-content;top:0;right:100%}
12
12
  </style>
13
13
  <style>${this.customStyle}</style>
14
14
  <div class="container"><slot name="menu-button" onclick="${() => this.toggleMenu()}" onkeydown="${(e) => this.simulateClick(e)}"></slot><div class="${this.getClass()}"><slot name="menu-content"></slot></div></div>
@@ -6,7 +6,6 @@
6
6
  .menu-content {
7
7
  position: absolute;
8
8
  display: flex;
9
- font-size: 0;
10
9
  border: var(--app-standard-border);
11
10
  background: var(--bkg-color);
12
11
  border-radius: 4px;
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "name": "GeoGirafe PSC",
6
6
  "url": "https://doc.geogirafe.org"
7
7
  },
8
- "version": "1.1.0-dev.2631714424",
8
+ "version": "1.1.0-dev.2636580374",
9
9
  "type": "module",
10
10
  "engines": {
11
11
  "node": ">=20.19.0"
@@ -1 +1 @@
1
- {"version":"1.1.0-dev.2631714424", "build":"2631714424", "date":"26/06/2026"}
1
+ {"version":"1.1.0-dev.2636580374", "build":"2636580374", "date":"29/06/2026"}
@@ -1,3 +1,5 @@
1
+ import { Extent } from 'ol/extent.js';
2
+ import Feature from 'ol/Feature.js';
1
3
  export declare function formatCoordinates(coords: number[], locale: string): string[];
2
4
  /**
3
5
  * Will check if given coords can be mapped to a max extent
@@ -9,3 +11,7 @@ export declare function formatCoordinates(coords: number[], locale: string): str
9
11
  export declare function parseCoordinates(coords: number[], extent: number[] | undefined, srid: string): number[];
10
12
  export declare function decimalToDMS(coordinate: number[]): string[];
11
13
  export declare function printCoordinate(coordinate: [number, number], format: 'dms' | 'decimal', precision: number): string[];
14
+ /**
15
+ * Returns a bbox around the geometry that is x percent larger than the geometry.
16
+ */
17
+ export declare function createBufferedExtentFromFeature(feature: Feature, percentageBuffer?: number): Extent | undefined;
@@ -1,4 +1,5 @@
1
1
  // SPDX-License-Identifier: Apache-2.0
2
+ import { buffer, getHeight, getWidth } from 'ol/extent.js';
2
3
  import { fromLonLat } from 'ol/proj.js';
3
4
  export function formatCoordinates(coords, locale) {
4
5
  const east = (Math.round(coords[0] * 100) / 100).toLocaleString(locale, { minimumFractionDigits: 2 });
@@ -69,3 +70,16 @@ export function printCoordinate(coordinate, format, precision) {
69
70
  }
70
71
  return coordString;
71
72
  }
73
+ /**
74
+ * Returns a bbox around the geometry that is x percent larger than the geometry.
75
+ */
76
+ export function createBufferedExtentFromFeature(feature, percentageBuffer = 50) {
77
+ const geom = feature.getGeometry();
78
+ if (geom) {
79
+ const extent = geom.getExtent();
80
+ // We create a buffer around the extent from a specified percentage of the width/height
81
+ const bufferValue = Math.max((getWidth(extent) * percentageBuffer) / 100, (getHeight(extent) * percentageBuffer) / 100);
82
+ return buffer(extent, bufferValue);
83
+ }
84
+ return undefined;
85
+ }
package/tools/main.d.ts CHANGED
@@ -31,7 +31,7 @@ export { default as FeedbackManager } from './feedback/feedbackmanager.js';
31
31
  export { BaseFilterCondition } from './filter/basefilter.js';
32
32
  export { KNOWN_FUNCTIONALITIES } from './functionalities.js';
33
33
  export { default as GeoConsts } from './geoconsts.js';
34
- export { formatCoordinates, parseCoordinates, decimalToDMS, printCoordinate } from './geometrytools.js';
34
+ export { formatCoordinates, parseCoordinates, decimalToDMS, printCoordinate, createBufferedExtentFromFeature } from './geometrytools.js';
35
35
  export type { TranslationsDict } from './i18n/i18nmanager.js';
36
36
  export { default as I18nManager } from './i18n/i18nmanager.js';
37
37
  export { default as LayerManager } from './layers/layermanager.js';
package/tools/main.js CHANGED
@@ -26,7 +26,7 @@ export { default as FeedbackManager } from './feedback/feedbackmanager.js';
26
26
  export { BaseFilterCondition } from './filter/basefilter.js';
27
27
  export { KNOWN_FUNCTIONALITIES } from './functionalities.js';
28
28
  export { default as GeoConsts } from './geoconsts.js';
29
- export { formatCoordinates, parseCoordinates, decimalToDMS, printCoordinate } from './geometrytools.js';
29
+ export { formatCoordinates, parseCoordinates, decimalToDMS, printCoordinate, createBufferedExtentFromFeature } from './geometrytools.js';
30
30
  export { default as I18nManager } from './i18n/i18nmanager.js';
31
31
  export { default as LayerManager } from './layers/layermanager.js';
32
32
  export { default as SimpleMaskLayer } from './layers/simplemasklayer.js';
@@ -1,6 +1,6 @@
1
1
  import { GeoJSON } from 'ol/format.js';
2
2
  import GirafeSingleton from '../../base/GirafeSingleton.js';
3
- import { buffer, getHeight, getWidth } from 'ol/extent.js';
3
+ import { createBufferedExtentFromFeature } from '../geometrytools.js';
4
4
  // The default provider is a container for search results that do not result from a provider search (e.g. map re-centering)
5
5
  export const SEARCH_PROVIDER_DEFAULT = 'default';
6
6
  // The default search group contains search results that do not belong to a specific category
@@ -72,14 +72,7 @@ class AbstractSearchClient extends GirafeSingleton {
72
72
  * Returns a bbox around the geometry that is 50% larger than the geometry.
73
73
  */
74
74
  getZoomToBbox(feature) {
75
- const geom = feature.getGeometry();
76
- if (geom) {
77
- const extent = geom.getExtent();
78
- // We create a buffer around the extent from 50% of the width/height
79
- const bufferValue = Math.max((getWidth(extent) * 50) / 100, (getHeight(extent) * 50) / 100);
80
- return buffer(extent, bufferValue);
81
- }
82
- return undefined;
75
+ return createBufferedExtentFromFeature(feature);
83
76
  }
84
77
  }
85
78
  export default AbstractSearchClient;
@@ -10,6 +10,8 @@ export type SearchProviderConfig = {
10
10
  declare class SearchManager extends GirafeSingleton {
11
11
  private readonly clients;
12
12
  private abortController;
13
+ private defaultSrid;
14
+ private defaultMaxExtent?;
13
15
  readonly minSearchTermLength = 3;
14
16
  constructor(context: IGirafeContext);
15
17
  initializeSingleton(): void;
@@ -27,7 +29,8 @@ declare class SearchManager extends GirafeSingleton {
27
29
  * using different separators such as `;`, `/`, `,`, or whitespace.
28
30
  */
29
31
  detectCoordinatesInTerm(term: string): [number, number] | null;
30
- private parseCoordinate;
32
+ private parseCoordinateFromString;
33
+ private isCoordinatePairValid;
31
34
  getZoomToBbox(feature: Feature): Extent | undefined;
32
35
  }
33
36
  export default SearchManager;
@@ -4,11 +4,14 @@ import GeoAdminChSearchClient from './geoadminchsearchclient.js';
4
4
  import GmfSearchClient from './gmfsearchclient.js';
5
5
  import GirafeSingleton from '../../base/GirafeSingleton.js';
6
6
  import Feature from 'ol/Feature.js';
7
- import { parseCoordinates } from '../geometrytools.js';
7
+ import { createBufferedExtentFromFeature, parseCoordinates } from '../geometrytools.js';
8
+ import { transform, transformExtent } from 'ol/proj.js';
8
9
  import { Point } from 'ol/geom.js';
9
10
  class SearchManager extends GirafeSingleton {
10
11
  clients = new Map();
11
12
  abortController = new AbortController();
13
+ defaultSrid;
14
+ defaultMaxExtent;
12
15
  minSearchTermLength = 3;
13
16
  constructor(context) {
14
17
  super(context);
@@ -18,6 +21,8 @@ class SearchManager extends GirafeSingleton {
18
21
  for (const providerConfig of this.context.configManager.Config.search.providers ?? []) {
19
22
  this.createClient(providerConfig);
20
23
  }
24
+ this.defaultSrid = this.context.configManager.getDefaultConfigValue('map.srid');
25
+ this.defaultMaxExtent = this.context.configManager.Config.map.maxExtent?.split(',').map(Number);
21
26
  }
22
27
  createClient(providerConfig) {
23
28
  switch (providerConfig.type) {
@@ -60,16 +65,25 @@ class SearchManager extends GirafeSingleton {
60
65
  return searchResults;
61
66
  }
62
67
  createCoordinateSearchResult(coordinates) {
63
- const [coord1, coord2] = coordinates;
64
68
  const currentSrid = this.context.mapManager.getMap().getView().getProjection().getCode();
65
- const maxExtent = this.context.configManager.Config.map.maxExtent?.split(',').map(Number);
66
- const [eastCoord, northCoord] = parseCoordinates([coord1, coord2], maxExtent, currentSrid);
67
- if (!eastCoord || !northCoord) {
69
+ let parsedCoordinates;
70
+ // Checks if the coordinates are within the default SRID max extent or geographic
71
+ parsedCoordinates = parseCoordinates(coordinates, this.defaultMaxExtent, this.defaultSrid);
72
+ if (this.isCoordinatePairValid(parsedCoordinates) && this.defaultSrid !== currentSrid) {
73
+ parsedCoordinates = transform(parsedCoordinates, this.defaultSrid, currentSrid);
74
+ parsedCoordinates = parsedCoordinates.map((number) => Math.round(number * 100) / 100);
75
+ }
76
+ // Try to parse the coordinates in the current map projection
77
+ if (!this.isCoordinatePairValid(parsedCoordinates) && this.defaultMaxExtent) {
78
+ const currentMaxExtent = transformExtent(this.defaultMaxExtent, this.defaultSrid, currentSrid);
79
+ parsedCoordinates = parseCoordinates(coordinates, currentMaxExtent, currentSrid);
80
+ }
81
+ if (!this.isCoordinatePairValid(parsedCoordinates)) {
68
82
  return null;
69
83
  }
70
84
  const resultFeature = new Feature({
71
- geometry: new Point([eastCoord, northCoord]),
72
- label: `${coord1} ${coord2}`
85
+ geometry: new Point(parsedCoordinates),
86
+ label: `${parsedCoordinates[0]} ${parsedCoordinates[1]}`
73
87
  });
74
88
  // Return this result grouped by the default provider and as part of the `recenter_map` group
75
89
  return { [SEARCH_PROVIDER_DEFAULT]: { [SEARCH_GROUP_RECENTER_MAP]: [resultFeature] } };
@@ -105,26 +119,31 @@ class SearchManager extends GirafeSingleton {
105
119
  if (parts.length !== 2) {
106
120
  return null;
107
121
  }
108
- const first = this.parseCoordinate(parts[0]);
109
- const second = this.parseCoordinate(parts[1]);
122
+ const first = this.parseCoordinateFromString(parts[0]);
123
+ const second = this.parseCoordinateFromString(parts[1]);
110
124
  return first === null || second === null ? null : [first, second];
111
125
  }
112
- parseCoordinate(value) {
126
+ parseCoordinateFromString(value) {
113
127
  const normalized = value
114
128
  // Remove coordinate prefix and thousand separator
115
129
  .replace(/[NESW']/g, '')
116
- // Relace decimal separator
130
+ // Replace decimal separator
117
131
  .replace(',', '.')
118
132
  .trim();
119
133
  const number = Number(normalized);
120
134
  return Number.isFinite(number) ? number : null;
121
135
  }
136
+ isCoordinatePairValid(coordinates) {
137
+ return !!coordinates && coordinates.length === 2 && coordinates.every((coordinate) => Number.isFinite(coordinate));
138
+ }
122
139
  getZoomToBbox(feature) {
123
140
  const provider = feature.get('provider');
124
141
  if (this.clients.has(provider)) {
125
142
  return this.clients.get(provider)?.getZoomToBbox(feature);
126
143
  }
127
- return undefined;
144
+ else {
145
+ return createBufferedExtentFromFeature(feature);
146
+ }
128
147
  }
129
148
  }
130
149
  export default SearchManager;