Skip to content

Commit 43636e8

Browse files
authored
feat: introduce background layer chooser (#2385)
* feat: introduce background layer chooser * fix: apply suggestions * fix: small fixes
1 parent 4789196 commit 43636e8

6 files changed

Lines changed: 158 additions & 2 deletions

File tree

src/bootstrap.tsx

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,11 @@ import LanguageDetector from 'i18next-browser-languagedetector';
3131

3232
import Keycloak from 'keycloak-js';
3333

34+
import { Collection } from 'ol';
3435
import {
3536
defaults as OlControlDefaults
3637
} from 'ol/control';
38+
import BaseLayer from 'ol/layer/Base';
3739
import OlLayerGroup from 'ol/layer/Group';
3840
import OlLayerTile from 'ol/layer/Tile';
3941
import OlMap from 'ol/Map';
@@ -88,6 +90,10 @@ import {
8890
import {
8991
setAppInfo
9092
} from './store/appInfo';
93+
import {
94+
setAllowEmptyBackground as setBackgroundLayerChooserAllowEmptyBackground,
95+
setVisible as setBackgroundLayerChooserVisible
96+
} from './store/backgroundLayerChooser';
9197
import {
9298
setDescription
9399
} from './store/description';
@@ -324,6 +330,11 @@ export const setApplicationToStore = async (application?: Application) => {
324330
// eslint-disable-next-line camelcase
325331
user_menu: (config) => {
326332
store.dispatch(setUserMenuVisible(config?.visible ?? true));
333+
},
334+
// eslint-disable-next-line camelcase
335+
background_layer_chooser: (config) => {
336+
store.dispatch(setBackgroundLayerChooserVisible(config?.visible ?? false));
337+
store.dispatch(setBackgroundLayerChooserAllowEmptyBackground(config?.allowEmptyBackground ?? false));
327338
}
328339
};
329340

@@ -469,6 +480,8 @@ const setupSHOGunMap = async (application: Application) => {
469480

470481
const interactions = await parser.parseMapInteractions(application);
471482

483+
layers = await addBackgroundLayers(application, layers);
484+
472485
return new OlMap({
473486
view,
474487
layers,
@@ -479,6 +492,67 @@ const setupSHOGunMap = async (application: Application) => {
479492
});
480493
};
481494

495+
const addBackgroundLayers = async (application: Application, layers: OlLayerGroup | undefined): Promise< Collection<BaseLayer> | undefined> => {
496+
const blcLayers = application.toolConfig?.find(config => config.name === 'background_layer_chooser')?.config.layers;
497+
const initiallySelectedLayerId = application.toolConfig?.find(config => config.name === 'background_layer_chooser')?.config.initiallySelectedLayer;
498+
const backgroundMapLayers = [];
499+
500+
if (blcLayers){
501+
let initiallySelectedLayerPresent = false;
502+
503+
for (const layer of blcLayers) {
504+
try {
505+
if (!layer.layerId) {
506+
continue;
507+
}
508+
509+
const existingLayer = layers?.getLayersArray().find(item => item.get('shogunId')=== layer.layerId);
510+
let olLayer;
511+
if (existingLayer) {
512+
olLayer = existingLayer;
513+
} else {
514+
const l = await client?.layer().findOne(layer.layerId);
515+
if (!l) {
516+
continue;
517+
}
518+
olLayer = await parser.parseLayer(l);
519+
}
520+
521+
if (!olLayer || olLayer instanceof OlLayerGroup) {
522+
continue;
523+
}
524+
olLayer.set('isBackgroundLayer', true);
525+
olLayer.setVisible(false);
526+
527+
if (layer.title) {
528+
olLayer.set('name', layer.title);
529+
}
530+
531+
if (layer.layerId === initiallySelectedLayerId) {
532+
olLayer.setVisible(true);
533+
initiallySelectedLayerPresent = true;
534+
}
535+
if (!existingLayer) {
536+
backgroundMapLayers.push(olLayer);
537+
}
538+
}
539+
catch (error){
540+
Logger.error(`Layer ${layer.layerId} could not be loaded successfully: `, error);
541+
}
542+
}
543+
544+
// Fallback for when no initiallySelectedLayerId is set. Choose first layer as default.
545+
if (!initiallySelectedLayerPresent && backgroundMapLayers.length >= 1) {
546+
backgroundMapLayers[0].setVisible(true);
547+
}
548+
549+
for (const backgroundLayerMap of backgroundMapLayers) {
550+
layers?.getLayers().insertAt(0, backgroundLayerMap);
551+
}
552+
return layers?.getLayers();
553+
}
554+
};
555+
482556
// TODO Make default/fallback app configurable?
483557
const setupDefaultMap = () => {
484558
const osmLayer = new OlLayerTile({
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
.map {
2+
.bg-layer-chooser {
3+
bottom: 95px;
4+
width: 99%;
5+
right: 10px;
6+
7+
.layer-cards {
8+
overflow: auto;
9+
width: calc(100% - 170px);
10+
}
11+
}
12+
}

src/components/BasicMapComponent/index.tsx

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,26 @@ import {
1010

1111
import { MapUtil } from '@terrestris/ol-util/dist/MapUtil/MapUtil';
1212

13+
import {
14+
BackgroundLayerChooser
15+
} from '@terrestris/react-geo/dist/BackgroundLayerChooser/BackgroundLayerChooser';
16+
1317
import {
1418
MapComponent,
1519
MapComponentProps
1620
} from '@terrestris/react-geo/dist/Map/MapComponent/MapComponent';
1721
import { useMap } from '@terrestris/react-util/dist/Hooks/useMap/useMap';
1822

23+
import useAppSelector from '../../hooks/useAppSelector';
24+
1925
import usePlugins from '../../hooks/usePlugins';
2026

2127
import {
2228
isMapIntegration
2329
} from '../../plugin';
2430

31+
import './index.less';
32+
2533
export const BasicMapComponent: React.FC<Partial<MapComponentProps>> = ({
2634
...restProps
2735
}): JSX.Element => {
@@ -33,6 +41,9 @@ export const BasicMapComponent: React.FC<Partial<MapComponentProps>> = ({
3341
i18n
3442
} = useTranslation();
3543

44+
const blcVisible = useAppSelector(state => state.backgroundLayerChooser.visible);
45+
const allowEmptyBackground = useAppSelector(state => state.backgroundLayerChooser.allowEmptyBackground);
46+
3647
/**
3748
* Updates external layer group name when language changes.
3849
*/
@@ -80,6 +91,12 @@ export const BasicMapComponent: React.FC<Partial<MapComponentProps>> = ({
8091
map={map}
8192
{...restProps}
8293
>
94+
{blcVisible &&
95+
<BackgroundLayerChooser
96+
layers={map.getAllLayers().filter(l => l.get('isBackgroundLayer') === true).reverse()}
97+
allowEmptyBackground = {allowEmptyBackground}
98+
/>
99+
}
83100
{
84101
pluginComponents
85102
}

src/components/ToolMenu/LayerTree/index.tsx

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -251,8 +251,16 @@ export const LayerTree: React.FC<LayerTreeProps> = ({
251251
if (layer instanceof OlLayerGroup) {
252252
return true;
253253
}
254-
255-
return !(layer instanceof OlVectorLayer) || !_isNil(layer.get('shogunId'));
254+
if (layer instanceof OlVectorLayer) {
255+
return false;
256+
}
257+
if (_isNil(layer.get('shogunId'))) {
258+
return false;
259+
}
260+
if (layer.get('isBackgroundLayer')) {
261+
return false;
262+
}
263+
return true;
256264
};
257265

258266
const treeNodeTitleRenderer = (layer: OlBaseLayer) => {
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import {
2+
createSlice,
3+
PayloadAction
4+
} from '@reduxjs/toolkit';
5+
6+
export type LayerConfig = {
7+
layerId: number;
8+
title?: string;
9+
};
10+
11+
export type BackgroundLayerChooserConfig = {
12+
visible?: boolean;
13+
layers?: LayerConfig[];
14+
initiallySelectedLayer?: number | undefined;
15+
allowEmptyBackground?: boolean;
16+
};
17+
18+
const initialState: BackgroundLayerChooserConfig = {
19+
visible: false,
20+
layers: [],
21+
initiallySelectedLayer: undefined,
22+
allowEmptyBackground: false
23+
};
24+
25+
export const slice = createSlice({
26+
name: 'backgroundLayerChooser',
27+
initialState,
28+
reducers: {
29+
setVisible: (state, action: PayloadAction<boolean>) => {
30+
state.visible = action.payload;
31+
},
32+
setAllowEmptyBackground: (state, action: PayloadAction<boolean>) => {
33+
state.allowEmptyBackground = action.payload;
34+
}
35+
}
36+
});
37+
38+
export const {
39+
setVisible,
40+
setAllowEmptyBackground
41+
} = slice.actions;
42+
43+
export default slice.reducer;

src/store/store.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99

1010
import addLayerModal from './addLayerModal';
1111
import appInfo from './appInfo';
12+
import backgroundLayerChooser from './backgroundLayerChooser';
1213
import description from './description';
1314
import editFeature from './editFeature';
1415
import editFeatureDrawerOpen from './editFeatureDrawerOpen';
@@ -37,6 +38,7 @@ export const createReducer = (asyncReducers?: AsyncReducer) => {
3738
return combineReducers({
3839
addLayerModal,
3940
appInfo,
41+
backgroundLayerChooser,
4042
description,
4143
editFeature,
4244
editFeatureDrawerOpen,

0 commit comments

Comments
 (0)