@geogirafe/lib-geoportal 1.1.0-dev.2273215791 → 1.1.0-dev.2312792329
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/components/basemap/component.d.ts +1 -0
- package/components/basemap/component.js +14 -0
- package/components/map/tools/vectortilesmanager.d.ts +7 -1
- package/components/map/tools/vectortilesmanager.js +16 -3
- package/models/basemaps/basemapswisstopovectortiles.js +1 -1
- package/models/gmf.d.ts +5 -3
- package/models/layers/layervectortiles.d.ts +3 -2
- package/models/layers/layervectortiles.js +5 -4
- package/models/main.d.ts +1 -1
- package/package.json +2 -1
- package/templates/public/about.json +1 -1
- package/templates/vite.config.js +1 -1
- package/tools/functionalities.d.ts +11 -0
- package/tools/functionalities.js +11 -0
- package/tools/main.d.ts +1 -0
- package/tools/main.js +1 -0
- package/tools/state/state.d.ts +3 -0
- package/tools/state/state.js +2 -0
- package/tools/themes/themeshelper.d.ts +1 -1
- package/tools/themes/themeshelper.js +24 -10
- package/tools/themes/themeshelper.spec.js +52 -0
- package/tools/themes/themesmanager.d.ts +3 -0
- package/tools/themes/themesmanager.js +34 -21
|
@@ -6,6 +6,7 @@ declare class BasemapComponent extends GirafeHTMLElement {
|
|
|
6
6
|
changeBasemap(basemap: Basemap): void;
|
|
7
7
|
isBasemapActive(basemap: Basemap): boolean;
|
|
8
8
|
determineClassnames(basemap: Basemap): "basemap-container active-basemap" | "basemap-container";
|
|
9
|
+
findBasemapByName(name: string): Basemap | undefined;
|
|
9
10
|
changeBasemapOpacity(basemap: Basemap, e: PointerEvent): void;
|
|
10
11
|
toggleVisibility(visible: boolean): void;
|
|
11
12
|
registerEvents(): void;
|
|
@@ -48,6 +48,9 @@ class BasemapComponent extends GirafeHTMLElement {
|
|
|
48
48
|
determineClassnames(basemap) {
|
|
49
49
|
return this.isBasemapActive(basemap) ? 'basemap-container active-basemap' : 'basemap-container';
|
|
50
50
|
}
|
|
51
|
+
findBasemapByName(name) {
|
|
52
|
+
return Object.values(this.state.basemaps).find((basemap) => basemap.name == name);
|
|
53
|
+
}
|
|
51
54
|
changeBasemapOpacity(basemap, e) {
|
|
52
55
|
e.stopPropagation();
|
|
53
56
|
if (basemap.opacityDisabled) {
|
|
@@ -77,6 +80,17 @@ class BasemapComponent extends GirafeHTMLElement {
|
|
|
77
80
|
}
|
|
78
81
|
});
|
|
79
82
|
this.subscribe('interface.basemapComponentVisible', (_oldValue, newValue) => this.toggleVisibility(newValue));
|
|
83
|
+
this.subscribe('functionalities.default_basemap', (_oldValue, newValue) => {
|
|
84
|
+
for (const defaultBasemapName of newValue) {
|
|
85
|
+
const defaultBasemap = this.findBasemapByName(defaultBasemapName == 'blank' ? 'Empty' : defaultBasemapName);
|
|
86
|
+
if (defaultBasemap) {
|
|
87
|
+
this.changeBasemap(defaultBasemap);
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
console.warn(`BasemapComponent: Could not find Basemap '${defaultBasemapName}' to set by Functionality 'functionalities.default_basemap'`);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
});
|
|
80
94
|
}
|
|
81
95
|
connectedCallback() {
|
|
82
96
|
super.connectedCallback();
|
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
import { Map } from 'ol';
|
|
2
2
|
import olVectorTileLayer from 'ol/layer/VectorTile.js';
|
|
3
3
|
import LayerVectorTiles from '../../../models/layers/layervectortiles.js';
|
|
4
|
+
import LayerGroup from 'ol/layer/Group.js';
|
|
4
5
|
declare class VectorTilesManager {
|
|
5
6
|
map: Map;
|
|
6
|
-
basemapLayers: olVectorTileLayer[];
|
|
7
|
+
basemapLayers: (olVectorTileLayer | LayerGroup)[];
|
|
7
8
|
constructor(map: Map);
|
|
8
9
|
removeAllBasemapLayers(): void;
|
|
10
|
+
/**
|
|
11
|
+
* Adds a vectortiles basemap based on its layerName. If no layerName is provided,
|
|
12
|
+
* will use apply from ol-mapbox-style to create all layers.
|
|
13
|
+
* @param basemap
|
|
14
|
+
*/
|
|
9
15
|
addBasemapLayer(basemap: LayerVectorTiles): void;
|
|
10
16
|
}
|
|
11
17
|
export default VectorTilesManager;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import olVectorTileLayer from 'ol/layer/VectorTile.js';
|
|
2
|
-
import { applyStyle } from 'ol-mapbox-style';
|
|
2
|
+
import apply, { applyStyle } from 'ol-mapbox-style';
|
|
3
|
+
import LayerGroup from 'ol/layer/Group.js';
|
|
3
4
|
class VectorTilesManager {
|
|
4
5
|
map;
|
|
5
6
|
basemapLayers = [];
|
|
@@ -12,9 +13,21 @@ class VectorTilesManager {
|
|
|
12
13
|
});
|
|
13
14
|
this.basemapLayers = [];
|
|
14
15
|
}
|
|
16
|
+
/**
|
|
17
|
+
* Adds a vectortiles basemap based on its layerName. If no layerName is provided,
|
|
18
|
+
* will use apply from ol-mapbox-style to create all layers.
|
|
19
|
+
* @param basemap
|
|
20
|
+
*/
|
|
15
21
|
addBasemapLayer(basemap) {
|
|
16
|
-
|
|
17
|
-
|
|
22
|
+
let olayer;
|
|
23
|
+
if (basemap.layerName) {
|
|
24
|
+
olayer = new olVectorTileLayer({ declutter: true });
|
|
25
|
+
applyStyle(olayer, basemap.style, basemap.layerName);
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
olayer = new LayerGroup();
|
|
29
|
+
apply(olayer, basemap.style);
|
|
30
|
+
}
|
|
18
31
|
this.basemapLayers.push(olayer);
|
|
19
32
|
// For basemap, set a minimal number (arbitrary defined to less than -5000)
|
|
20
33
|
olayer.setZIndex(-5000 - basemap.order);
|
|
@@ -16,7 +16,7 @@ export default class BasemapSwisstopoVectorTiles extends Basemap {
|
|
|
16
16
|
name: 'Swisstopo Vector-Tiles',
|
|
17
17
|
metadata: { ...basemapMetadata }
|
|
18
18
|
});
|
|
19
|
-
const vectorTilesLayer = new LayerVectorTiles(LayerConsts.LayerSwisstopoVectorTilesId, 'Swisstopo Vector-Tiles', 0, 'https://vectortiles.geo.admin.ch/styles/ch.swisstopo.
|
|
19
|
+
const vectorTilesLayer = new LayerVectorTiles(LayerConsts.LayerSwisstopoVectorTilesId, 'Swisstopo Vector-Tiles', 0, 'https://vectortiles.geo.admin.ch/styles/ch.swisstopo.lightbasemap.vt/style.json', { projection: 'EPSG:3857' });
|
|
20
20
|
this.layersList.push(vectorTilesLayer);
|
|
21
21
|
}
|
|
22
22
|
}
|
package/models/gmf.d.ts
CHANGED
|
@@ -57,13 +57,15 @@ export interface GMFTreeItem {
|
|
|
57
57
|
time?: ITimeOptions;
|
|
58
58
|
public?: boolean;
|
|
59
59
|
}
|
|
60
|
+
export type GMFThemeFunctionality = string | string[] | number | number[] | boolean | boolean[];
|
|
61
|
+
export interface GMFThemeFunctionalities {
|
|
62
|
+
[key: string]: GMFThemeFunctionality;
|
|
63
|
+
}
|
|
60
64
|
export interface GMFTheme {
|
|
61
65
|
id: number;
|
|
62
66
|
name: string;
|
|
63
67
|
icon: string;
|
|
64
|
-
functionalities:
|
|
65
|
-
[key: string]: string;
|
|
66
|
-
};
|
|
68
|
+
functionalities: GMFThemeFunctionalities;
|
|
67
69
|
metadata: GMFMetadata;
|
|
68
70
|
children: GMFTreeItem[];
|
|
69
71
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import Layer from './layer.js';
|
|
2
2
|
type LayerVectorTilesOptions = {
|
|
3
3
|
projection?: string;
|
|
4
|
+
layerName?: string;
|
|
4
5
|
isDefaultChecked?: boolean;
|
|
5
6
|
disclaimer?: string;
|
|
6
7
|
metadataUrl?: string;
|
|
@@ -16,9 +17,9 @@ declare class LayerVectorTiles extends Layer {
|
|
|
16
17
|
* For example, any method doing <this.xxx = value> is forbidden here, because the modification be known from the proxy
|
|
17
18
|
*/
|
|
18
19
|
style: string;
|
|
19
|
-
|
|
20
|
+
layerName?: string;
|
|
20
21
|
projection?: string;
|
|
21
|
-
constructor(id: number, name: string, order: number, style: string,
|
|
22
|
+
constructor(id: number, name: string, order: number, style: string, options?: LayerVectorTilesOptions);
|
|
22
23
|
clone(): LayerVectorTiles;
|
|
23
24
|
}
|
|
24
25
|
export default LayerVectorTiles;
|
|
@@ -8,24 +8,25 @@ class LayerVectorTiles extends Layer {
|
|
|
8
8
|
* For example, any method doing <this.xxx = value> is forbidden here, because the modification be known from the proxy
|
|
9
9
|
*/
|
|
10
10
|
style;
|
|
11
|
-
|
|
11
|
+
layerName;
|
|
12
12
|
projection;
|
|
13
|
-
constructor(id, name, order, style,
|
|
13
|
+
constructor(id, name, order, style, options) {
|
|
14
14
|
super(id, name, order, options);
|
|
15
15
|
this.style = style;
|
|
16
|
-
this.
|
|
16
|
+
this.layerName = options?.layerName;
|
|
17
17
|
this.projection = options?.projection;
|
|
18
18
|
}
|
|
19
19
|
clone() {
|
|
20
20
|
const options = {
|
|
21
21
|
projection: this.projection,
|
|
22
|
+
layerName: this.layerName,
|
|
22
23
|
isDefaultChecked: this.isDefaultChecked,
|
|
23
24
|
metadataUrl: this.metadataUrl,
|
|
24
25
|
disclaimer: this.disclaimer,
|
|
25
26
|
opacity: this.opacity,
|
|
26
27
|
restricted: this.restricted
|
|
27
28
|
};
|
|
28
|
-
const clonedObject = new LayerVectorTiles(this.id, this.name, this.order, this.style,
|
|
29
|
+
const clonedObject = new LayerVectorTiles(this.id, this.name, this.order, this.style, options);
|
|
29
30
|
clonedObject.activeState = this.activeState;
|
|
30
31
|
return clonedObject;
|
|
31
32
|
}
|
package/models/main.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ export { default as BasemapEmpty } from './basemaps/basemapempty.js';
|
|
|
3
3
|
export { default as BasemapOsm } from './basemaps/basemaposm.js';
|
|
4
4
|
export { default as BasemapSwisstopoVectorTiles } from './basemaps/basemapswisstopovectortiles.js';
|
|
5
5
|
export { default as CustomTheme } from './customtheme.js';
|
|
6
|
-
export type { GMFMetadata, GMFChildLayer, GMFTreeItem, GMFTheme, GMFGroup, GMFBackgroundLayer, GMFServerOgc, GMFServerOgcAttributes, GMFServerOgcObjectAttributes, GMFServerOgcColumnAttributes } from './gmf.js';
|
|
6
|
+
export type { GMFMetadata, GMFChildLayer, GMFTreeItem, GMFThemeFunctionality, GMFThemeFunctionalities, GMFTheme, GMFGroup, GMFBackgroundLayer, GMFServerOgc, GMFServerOgcAttributes, GMFServerOgcObjectAttributes, GMFServerOgcColumnAttributes } from './gmf.js';
|
|
7
7
|
export { default as BaseLayer } from './layers/baselayer.js';
|
|
8
8
|
export type { GroupLayerOptions } from './layers/grouplayer.js';
|
|
9
9
|
export { default as GroupLayer } from './layers/grouplayer.js';
|
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.
|
|
8
|
+
"version": "1.1.0-dev.2312792329",
|
|
9
9
|
"type": "module",
|
|
10
10
|
"engines": {
|
|
11
11
|
"node": ">=20.19.0"
|
|
@@ -150,6 +150,7 @@
|
|
|
150
150
|
"build-apk": "docker run -v ./dist:/geogirafe/dist -v ./buildtools:/geogirafe/buildtools geogirafe/cordova-builder bash -c \"cp /geogirafe/buildtools/cordova/apk-build.sh . && chmod u+x apk-build.sh && ./apk-build.sh\"",
|
|
151
151
|
"build-apk-win": "docker run -v %cd%/dist:/geogirafe/dist -v %cd%/buildtools:/geogirafe/buildtools geogirafe/cordova-builder bash -c \"cp /geogirafe/buildtools/cordova/apk-build.sh . && chmod u+x apk-build.sh && ./apk-build.sh\"",
|
|
152
152
|
"test": "vitest --run --coverage",
|
|
153
|
+
"test-without-coverage": "vitest --run",
|
|
153
154
|
"test-watch": "vitest",
|
|
154
155
|
"configure-demo": "bash -C './buildtools/configure-demo.sh'",
|
|
155
156
|
"configure-demo-win": "buildtools\\configure-demo.cmd",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":"1.1.0-dev.
|
|
1
|
+
{"version":"1.1.0-dev.2312792329", "build":"2312792329", "date":"08/02/2026"}
|
package/templates/vite.config.js
CHANGED
|
@@ -22,7 +22,7 @@ function customDnsLookup(hostname, arg1, arg2) {
|
|
|
22
22
|
const callback = typeof arg1 === 'function' ? arg1 : arg2;
|
|
23
23
|
const options = typeof arg1 === 'function' ? undefined : arg1;
|
|
24
24
|
if (hostname === 'app.localhost') {
|
|
25
|
-
callback(null, '
|
|
25
|
+
callback(null, '0.0.0.0', 4); // use '0.0.0.0' for being accessible from other devices on the network
|
|
26
26
|
} else {
|
|
27
27
|
originalDnsLookup(hostname, options, callback);
|
|
28
28
|
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Known Functionalities which are allowed in <code>GMFTheme.functionalities</code> and are published to
|
|
3
|
+
* <code>State.functionalities</code>. Subscribe a Handler to get notified when a Theme which such a Functionality is
|
|
4
|
+
* selected by the User (e.g., Change the Basemap):
|
|
5
|
+
* <code>
|
|
6
|
+
* GirafeHTMLElement.subscribe('functionalities.default_basemap', (oldValue: string[], newValue: string[]) => {
|
|
7
|
+
* ...
|
|
8
|
+
* });
|
|
9
|
+
* </code>
|
|
10
|
+
*/
|
|
11
|
+
export declare const KNOWN_FUNCTIONALITIES: string[];
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Known Functionalities which are allowed in <code>GMFTheme.functionalities</code> and are published to
|
|
3
|
+
* <code>State.functionalities</code>. Subscribe a Handler to get notified when a Theme which such a Functionality is
|
|
4
|
+
* selected by the User (e.g., Change the Basemap):
|
|
5
|
+
* <code>
|
|
6
|
+
* GirafeHTMLElement.subscribe('functionalities.default_basemap', (oldValue: string[], newValue: string[]) => {
|
|
7
|
+
* ...
|
|
8
|
+
* });
|
|
9
|
+
* </code>
|
|
10
|
+
*/
|
|
11
|
+
export const KNOWN_FUNCTIONALITIES = ['default_basemap'];
|
package/tools/main.d.ts
CHANGED
|
@@ -17,6 +17,7 @@ export { default as CsvManager } from './export/csvmanager.js';
|
|
|
17
17
|
export { download } from './export/download.js';
|
|
18
18
|
export type { GridDataById, GridData, FeatureToGridDataOptions } from './featuretogriddatabyid.js';
|
|
19
19
|
export { default as FeatureToGridDataById } from './featuretogriddatabyid.js';
|
|
20
|
+
export { KNOWN_FUNCTIONALITIES } from './functionalities.js';
|
|
20
21
|
export { default as GeoConsts } from './geoconsts.js';
|
|
21
22
|
export { formatCoordinates, parseCoordinates, decimalToDMS, printCoordinate } from './geometrytools.js';
|
|
22
23
|
export type { TranslationsDict } from './i18n/i18nmanager.js';
|
package/tools/main.js
CHANGED
|
@@ -15,6 +15,7 @@ export { default as ErrorManager } from './error/errormanager.js';
|
|
|
15
15
|
export { default as CsvManager } from './export/csvmanager.js';
|
|
16
16
|
export { download } from './export/download.js';
|
|
17
17
|
export { default as FeatureToGridDataById } from './featuretogriddatabyid.js';
|
|
18
|
+
export { KNOWN_FUNCTIONALITIES } from './functionalities.js';
|
|
18
19
|
export { default as GeoConsts } from './geoconsts.js';
|
|
19
20
|
export { formatCoordinates, parseCoordinates, decimalToDMS, printCoordinate } from './geometrytools.js';
|
|
20
21
|
export { default as I18nManager } from './i18n/i18nmanager.js';
|
package/tools/state/state.d.ts
CHANGED
|
@@ -11,8 +11,10 @@ import type CustomTheme from '../../models/customtheme.js';
|
|
|
11
11
|
import ObjectSelection from './objectselection.js';
|
|
12
12
|
import type Theme from '../../models/theme.js';
|
|
13
13
|
import GraphicalInterface from './graphicalInterface.js';
|
|
14
|
+
import { GMFThemeFunctionalities, GMFThemeFunctionality } from '../../models/gmf.js';
|
|
14
15
|
export type ThemesConfig = {
|
|
15
16
|
_allThemes: Record<number, ThemeLayer>;
|
|
17
|
+
_allFunctionalities: Record<number, GMFThemeFunctionalities>;
|
|
16
18
|
isLoaded: boolean;
|
|
17
19
|
lastSelectedTheme: ThemeLayer | CustomTheme | null;
|
|
18
20
|
};
|
|
@@ -85,6 +87,7 @@ export default class State {
|
|
|
85
87
|
* For example, any method doing <this.xxx = value> is forbidden here, because the modification be known from the proxy
|
|
86
88
|
*/
|
|
87
89
|
themes: ThemesConfig;
|
|
90
|
+
functionalities: Record<string, GMFThemeFunctionality>;
|
|
88
91
|
basemaps: Record<number, Basemap>;
|
|
89
92
|
ogcServers: Record<string, ServerOgc>;
|
|
90
93
|
activeBasemaps: Basemap[];
|
package/tools/state/state.js
CHANGED
|
@@ -22,9 +22,11 @@ export default class State {
|
|
|
22
22
|
// Dictionary where the key is the id of the theme
|
|
23
23
|
themes = {
|
|
24
24
|
_allThemes: {},
|
|
25
|
+
_allFunctionalities: {},
|
|
25
26
|
isLoaded: false,
|
|
26
27
|
lastSelectedTheme: null
|
|
27
28
|
};
|
|
29
|
+
functionalities = {};
|
|
28
30
|
// All basemaps from themes.json
|
|
29
31
|
// Dictionary where the key is the id of the basemap
|
|
30
32
|
basemaps = {};
|
|
@@ -7,7 +7,7 @@ export default class ThemesHelper extends GirafeSingleton {
|
|
|
7
7
|
initializeSingleton(): void;
|
|
8
8
|
private get state();
|
|
9
9
|
findBaseLayerById(layerId: number): BaseLayer;
|
|
10
|
-
private
|
|
10
|
+
private findBaseLayerRecursiveById;
|
|
11
11
|
findThemeByName(themename: string): ThemeLayer | null;
|
|
12
12
|
findGroupByName(groupname: string): GroupLayer | null;
|
|
13
13
|
findLayerByName(layername: string): Layer | null;
|
|
@@ -6,6 +6,7 @@ import LayerWms from '../../models/layers/layerwms.js';
|
|
|
6
6
|
import ThemeLayer from '../../models/layers/themelayer.js';
|
|
7
7
|
import { isTimeAwareLayer } from '../../models/layers/timeawarelayer.js';
|
|
8
8
|
import WfsFilter, { isWfsOperator } from '../wfs/wfsfilter.js';
|
|
9
|
+
import { KNOWN_FUNCTIONALITIES } from '../functionalities.js';
|
|
9
10
|
export default class ThemesHelper extends GirafeSingleton {
|
|
10
11
|
initializeSingleton() {
|
|
11
12
|
this.context.stateManager.subscribe('themes.lastSelectedTheme', (_oldTheme, newTheme) => this.onSelectedThemeChanged(newTheme));
|
|
@@ -18,20 +19,20 @@ export default class ThemesHelper extends GirafeSingleton {
|
|
|
18
19
|
if (theme.id === layerId) {
|
|
19
20
|
return theme;
|
|
20
21
|
}
|
|
21
|
-
const child = this.
|
|
22
|
+
const child = this.findBaseLayerRecursiveById(theme.children, layerId);
|
|
22
23
|
if (child) {
|
|
23
24
|
return child;
|
|
24
25
|
}
|
|
25
26
|
}
|
|
26
27
|
throw new Error(`No BaseLayer with ID ${layerId} could be found.`);
|
|
27
28
|
}
|
|
28
|
-
|
|
29
|
+
findBaseLayerRecursiveById(layers, layerId) {
|
|
29
30
|
for (const layer of layers) {
|
|
30
31
|
if (layer.id === layerId) {
|
|
31
32
|
return layer;
|
|
32
33
|
}
|
|
33
34
|
if (layer instanceof GroupLayer || layer instanceof ThemeLayer) {
|
|
34
|
-
const child = this.
|
|
35
|
+
const child = this.findBaseLayerRecursiveById(layer.children, layerId);
|
|
35
36
|
if (child) {
|
|
36
37
|
return child;
|
|
37
38
|
}
|
|
@@ -107,24 +108,37 @@ export default class ThemesHelper extends GirafeSingleton {
|
|
|
107
108
|
}
|
|
108
109
|
onThemeChanged(theme) {
|
|
109
110
|
// Create a clone of the theme object to use it in the treeview.
|
|
110
|
-
// This is essential, otherwise all changes done in the layers
|
|
111
|
-
// (For example when expanding legend, expanding a group, or activating the layer)
|
|
112
|
-
// Will also be done in the default layer configuration that has been loaded from themes.json
|
|
113
|
-
// And when a theme
|
|
111
|
+
// This is essential, otherwise all changes are done in the layers
|
|
112
|
+
// (For example, when expanding legend, expanding a group, or activating the layer).
|
|
113
|
+
// Will also be done in the default layer configuration that has been loaded from themes.json,
|
|
114
|
+
// And when a theme is selected aging from the themes-selector
|
|
114
115
|
// The default configuration will have been overwritten.
|
|
115
116
|
const clonedTheme = theme.clone();
|
|
117
|
+
const themeAlreadyInLayersList = this.state.layers.layersList.find((l) => l.id == clonedTheme.id);
|
|
118
|
+
if (themeAlreadyInLayersList) {
|
|
119
|
+
console.info(`The theme ${clonedTheme.name} is already present in the treeview.`);
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
116
122
|
if (this.context.configManager.Config.themes.selectionMode === 'replace') {
|
|
117
123
|
// Mode is <replace>
|
|
118
124
|
this.emptyLayerTree();
|
|
119
125
|
this.state.layers.layersList.push(clonedTheme);
|
|
120
126
|
}
|
|
121
|
-
else
|
|
127
|
+
else {
|
|
122
128
|
// Mode is <add>
|
|
123
129
|
clonedTheme.order = this.getInitialOrderForNewTheme();
|
|
124
130
|
this.state.layers.layersList.push(clonedTheme);
|
|
125
131
|
}
|
|
126
|
-
|
|
127
|
-
|
|
132
|
+
const themeFunctionalities = this.state.themes._allFunctionalities[theme.id];
|
|
133
|
+
if (themeFunctionalities) {
|
|
134
|
+
Object.keys(themeFunctionalities).forEach((functionality) => {
|
|
135
|
+
if (KNOWN_FUNCTIONALITIES.includes(functionality)) {
|
|
136
|
+
this.state.functionalities[functionality] = themeFunctionalities[functionality];
|
|
137
|
+
}
|
|
138
|
+
else {
|
|
139
|
+
console.warn(`Unknown functionality '${functionality}' found on Theme '${theme.name}'.`);
|
|
140
|
+
}
|
|
141
|
+
});
|
|
128
142
|
}
|
|
129
143
|
}
|
|
130
144
|
getMinimalClonedThemeForLayer(layer) {
|
|
@@ -167,3 +167,55 @@ describe('ThemesHelper.getInitialOrderForNewTheme', () => {
|
|
|
167
167
|
expect(themesHelper.getInitialOrderForNewTheme()).toEqual(103);
|
|
168
168
|
});
|
|
169
169
|
});
|
|
170
|
+
describe('ThemesHelper.onSelectedThemeChanged', () => {
|
|
171
|
+
let stateManager;
|
|
172
|
+
const callbacks = [];
|
|
173
|
+
beforeEach(() => {
|
|
174
|
+
stateManager = context.stateManager;
|
|
175
|
+
for (const callback of callbacks) {
|
|
176
|
+
stateManager.unsubscribe(callback);
|
|
177
|
+
callbacks.splice(callbacks.indexOf(callback), 1);
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
it('should trigger change in functionalities if functionality is known', () => {
|
|
181
|
+
stateManager.state.themes._allFunctionalities = {
|
|
182
|
+
42: {
|
|
183
|
+
default_basemap: ['blank']
|
|
184
|
+
}
|
|
185
|
+
};
|
|
186
|
+
let subscriptionCalled = false;
|
|
187
|
+
callbacks.push(stateManager.subscribe('functionalities.default_basemap', () => {
|
|
188
|
+
subscriptionCalled = true;
|
|
189
|
+
}));
|
|
190
|
+
stateManager.state.themes.lastSelectedTheme = new ThemeLayer(42, 'lastSelectedTheme', 101);
|
|
191
|
+
expect(subscriptionCalled).toBeTruthy();
|
|
192
|
+
});
|
|
193
|
+
it('should NOT trigger change in functionalities if functionality is not known', () => {
|
|
194
|
+
stateManager.state.themes._allFunctionalities = {
|
|
195
|
+
42: {
|
|
196
|
+
unknown_functionality: 'Lorem Ipsum Dolor Sit Amet'
|
|
197
|
+
}
|
|
198
|
+
};
|
|
199
|
+
let subscriptionCalled = false;
|
|
200
|
+
callbacks.push(stateManager.subscribe('functionalities.unknown_functionality', (_oldValue, newValue) => {
|
|
201
|
+
console.log(newValue);
|
|
202
|
+
subscriptionCalled = true;
|
|
203
|
+
}));
|
|
204
|
+
stateManager.state.themes.lastSelectedTheme = new ThemeLayer(42, 'lastSelectedTheme', 101);
|
|
205
|
+
expect(subscriptionCalled).toBeFalsy();
|
|
206
|
+
});
|
|
207
|
+
it('should trigger change in functionalities.default_basemap with expected params', () => {
|
|
208
|
+
stateManager.state.themes._allFunctionalities = {
|
|
209
|
+
42: {
|
|
210
|
+
default_basemap: ['blank']
|
|
211
|
+
}
|
|
212
|
+
};
|
|
213
|
+
let paramsCalledWith = undefined;
|
|
214
|
+
callbacks.push(stateManager.subscribe('functionalities.default_basemap', (_oldVal, newVal) => {
|
|
215
|
+
paramsCalledWith = newVal;
|
|
216
|
+
}));
|
|
217
|
+
stateManager.state.themes.lastSelectedTheme = new ThemeLayer(42, 'lastSelectedTheme', 101);
|
|
218
|
+
expect(paramsCalledWith).not.toBeUndefined();
|
|
219
|
+
expect(paramsCalledWith).toEqual(['blank']);
|
|
220
|
+
});
|
|
221
|
+
});
|
|
@@ -22,6 +22,9 @@ declare class ThemesManager extends GirafeSingleton {
|
|
|
22
22
|
*/
|
|
23
23
|
private preloadWfsServer;
|
|
24
24
|
private prepareBasemaps;
|
|
25
|
+
private addBasemapsFromConfig;
|
|
26
|
+
private applyOpacityToBasemaps;
|
|
27
|
+
private applyOpacityToBasemap;
|
|
25
28
|
private prepareThemes;
|
|
26
29
|
private calculateMetadataUrl;
|
|
27
30
|
/**
|
|
@@ -96,7 +96,9 @@ class ThemesManager extends GirafeSingleton {
|
|
|
96
96
|
const content = await response.json();
|
|
97
97
|
this.state.ogcServers = this.prepareOgcServers(content['ogcServers']);
|
|
98
98
|
this.state.basemaps = this.prepareBasemaps(content['background_layers']);
|
|
99
|
-
|
|
99
|
+
const themesAndFunctionalities = this.prepareThemes(content['themes']);
|
|
100
|
+
this.state.themes._allThemes = themesAndFunctionalities.themes;
|
|
101
|
+
this.state.themes._allFunctionalities = themesAndFunctionalities.themesFunctionalities;
|
|
100
102
|
this.context.customThemesManager.loadCustomThemes();
|
|
101
103
|
this.state.themes.isLoaded = true;
|
|
102
104
|
if (this.context.configManager.Config.themes.showErrorsOnStart) {
|
|
@@ -170,7 +172,12 @@ class ThemesManager extends GirafeSingleton {
|
|
|
170
172
|
const basemapSwisstopoVectorTiles = new BasemapSwisstopoVectorTiles();
|
|
171
173
|
basemaps[basemapSwisstopoVectorTiles.id] = basemapSwisstopoVectorTiles;
|
|
172
174
|
}
|
|
173
|
-
|
|
175
|
+
this.addBasemapsFromConfig(basemapJson, basemaps);
|
|
176
|
+
this.applyOpacityToBasemaps(basemaps);
|
|
177
|
+
return basemaps;
|
|
178
|
+
}
|
|
179
|
+
addBasemapsFromConfig(basemapsJson, basemaps) {
|
|
180
|
+
basemapsJson.forEach((elem) => {
|
|
174
181
|
// Create basemap
|
|
175
182
|
const basemap = new Basemap(elem);
|
|
176
183
|
basemaps[basemap.id] = basemap;
|
|
@@ -193,34 +200,39 @@ class ThemesManager extends GirafeSingleton {
|
|
|
193
200
|
}
|
|
194
201
|
}
|
|
195
202
|
});
|
|
196
|
-
|
|
203
|
+
}
|
|
204
|
+
applyOpacityToBasemaps(basemaps) {
|
|
197
205
|
for (const basemap of Object.values(basemaps)) {
|
|
198
206
|
if (this.context.configManager.Config.basemaps.opacityBasemaps.includes(basemap.name)) {
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
207
|
+
this.applyOpacityToBasemap(basemap);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
applyOpacityToBasemap(basemap) {
|
|
212
|
+
// If it is the default Basemap the Opacity should NOT be 0 as otherwise the User would end up seeing nothing
|
|
213
|
+
const isDefaultBasemap = this.context.configManager.Config.basemaps.defaultBasemap == basemap.name;
|
|
214
|
+
basemap.opacity = isDefaultBasemap ? OPACITY_FOR_DEFAULT_BASEMAP : DEFAULT_OPACITY;
|
|
215
|
+
for (const basemapLayer of basemap.layersList) {
|
|
216
|
+
if (basemapLayer instanceof LayerVectorTiles) {
|
|
217
|
+
// Vector tiles layers are not supported as opacitybasemap, because the tiles cannot reprojected on the fly
|
|
218
|
+
// And displaying a basemap from some SRID with an VT from another SRID won't work
|
|
219
|
+
// So for the moment we do not allow VT configured as opacitybasemaps
|
|
220
|
+
// (But the opposite will still work : a VT basemap with a WMTS opacitybasemap)
|
|
221
|
+
}
|
|
222
|
+
else if (basemapLayer instanceof Layer) {
|
|
223
|
+
basemapLayer.opacity = basemap.opacity;
|
|
213
224
|
}
|
|
214
225
|
}
|
|
215
|
-
return basemaps;
|
|
216
226
|
}
|
|
217
227
|
prepareThemes(themesJson) {
|
|
218
228
|
const themes = {};
|
|
219
229
|
const order = { value: 0 };
|
|
230
|
+
const themesFunctionalities = {};
|
|
220
231
|
themesJson.forEach((themeJson, index) => {
|
|
221
232
|
if (!themeJson.icon.startsWith('http') && this.context.configManager.Config.themes.imagesUrlPrefix) {
|
|
222
233
|
themeJson.icon = this.context.configManager.Config.themes.imagesUrlPrefix + themeJson.icon;
|
|
223
234
|
}
|
|
235
|
+
themesFunctionalities[themeJson.id] = themeJson['functionalities'];
|
|
224
236
|
const theme = new ThemeLayer(themeJson['id'], themeJson['name'], index, themeJson['icon'], themeJson['metadata']);
|
|
225
237
|
themeJson.children.forEach((layerJson) => {
|
|
226
238
|
const layer = this.prepareThemeLayer(layerJson, null, order);
|
|
@@ -231,7 +243,7 @@ class ThemesManager extends GirafeSingleton {
|
|
|
231
243
|
});
|
|
232
244
|
themes[index] = theme;
|
|
233
245
|
});
|
|
234
|
-
return themes;
|
|
246
|
+
return { themes, themesFunctionalities };
|
|
235
247
|
}
|
|
236
248
|
calculateMetadataUrl(metadataUrl) {
|
|
237
249
|
if (!metadataUrl) {
|
|
@@ -359,12 +371,13 @@ class ThemesManager extends GirafeSingleton {
|
|
|
359
371
|
projection: 'EPSG:3857',
|
|
360
372
|
isDefaultChecked: elem.metadata?.isChecked,
|
|
361
373
|
disclaimer: elem.metadata?.disclaimer,
|
|
362
|
-
metadata: elem.metadata
|
|
374
|
+
metadata: elem.metadata,
|
|
375
|
+
layerName: elem.metadata.layerName
|
|
363
376
|
};
|
|
364
377
|
if (options.metadata?.metadataUrl) {
|
|
365
378
|
options.metadata.metadataUrl = this.calculateMetadataUrl(options.metadata.metadataUrl);
|
|
366
379
|
}
|
|
367
|
-
return new LayerVectorTiles(elem.id, elem.name, order.value, elem.style,
|
|
380
|
+
return new LayerVectorTiles(elem.id, elem.name, order.value, elem.style, options);
|
|
368
381
|
}
|
|
369
382
|
return null;
|
|
370
383
|
}
|