Skip to content

Commit 931e754

Browse files
authored
restore 3d state from url on app load (#295)
* restore 3d state from url on app load * factor out camera position restoration form URL into app code out of cesium library, cesium specific helper method is still with the library, just it stops making assumptions where those parameters come from * change CustomViewer props to include initial camera view as separate prop * add viewer destroyed check * improve URL refresh behavior, load state from URL only on mount in hooks * fix runtime terrain provider issues * improve HGK Terrain Provider loading and display, viewer still gets initialized too often * fix HGK, double initialization problem of 3d Viewer, fix mesh loading error * fix url updating behavior in 2d mode after 3d * force removing 3d params when updating 2D state urls
1 parent 023e565 commit 931e754

File tree

39 files changed

+1053
-624
lines changed

39 files changed

+1053
-624
lines changed

apps/geoportal/src/app/App.tsx

Lines changed: 18 additions & 213 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,9 @@
11
// Built-in Modules
2-
import { useEffect, useState } from "react";
2+
import { useState } from "react";
33

44
// 3rd party Modules
5-
65
import { Button, Modal } from "antd";
7-
import LZString from "lz-string";
86
import { ErrorBoundary } from "react-error-boundary";
9-
import { useDispatch, useSelector } from "react-redux";
10-
import { useLocation, useSearchParams } from "react-router-dom";
117
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
128
import { faSpinner } from "@fortawesome/free-solid-svg-icons";
139
// 1st party Modules
@@ -24,10 +20,7 @@ import { TweakpaneProvider } from "@carma-commons/debug";
2420
import {
2521
CarmaMapContextProvider,
2622
FeatureFlagProvider,
27-
type BackgroundLayer,
28-
type Settings,
2923
} from "@carma-apps/portals";
30-
import type { Layer } from "@carma-mapping/layers";
3124

3225
// Local Modules
3326
import AppErrorFallback from "./components/AppErrorFallback";
@@ -37,32 +30,18 @@ import MapMeasurement from "./components/map-measure/MapMeasurement";
3730
import TopNavbar from "./components/TopNavbar";
3831
import { ObliqueDataProvider } from "./oblique/components/ObliqueDataContext";
3932

40-
import type { AppDispatch } from "./store";
41-
import {
42-
getBackgroundLayer,
43-
getSelectedMapLayer,
44-
setBackgroundLayer,
45-
setLayers,
46-
setSelectedLuftbildLayer,
47-
setSelectedMapLayer,
48-
setShowFullscreenButton,
49-
setShowHamburgerMenu,
50-
setShowLocatorButton,
51-
setShowMeasurementButton,
52-
} from "./store/slices/mapping";
53-
import { getIfPopupOpend } from "./store/slices/print";
54-
55-
import {
56-
getUIAllowChanges,
57-
getUIMode,
58-
getZenMode,
59-
setUIAllowChanges,
60-
setUIShowLayerButtons,
61-
setUIShowLayerHideButtons,
62-
} from "./store/slices/ui";
33+
import { useAppConfig } from "./hooks/useAppConfig";
34+
import { useManageLayers } from "./hooks/useManageLayers";
35+
import { useSyncToken } from "./hooks/useSyncToken";
36+
import { useKeyboardShortcuts } from "./hooks/useKeyboardShortcuts";
37+
import { useCesiumSearchParams } from "./hooks/useCesiumSearchParams";
6338

6439
import { layerMap } from "./config";
65-
import { CESIUM_CONFIG } from "./config/app.config";
40+
import {
41+
CESIUM_CONFIG,
42+
CONFIG_BASE_URL,
43+
MIN_MOBILE_WIDTH,
44+
} from "./config/app.config";
6645
import { featureFlagConfig } from "./config/featureFlags";
6746
import { OBLIQUE_CONFIG, CAMERA_ID_TO_DIRECTION } from "./oblique/config";
6847

@@ -75,189 +54,15 @@ import "./index.css";
7554
if (typeof global === "undefined") {
7655
window.global = window;
7756
}
78-
79-
type View = {
80-
center: string[];
81-
zoom: string;
82-
};
83-
84-
type Config = {
85-
layers: Layer[];
86-
backgroundLayer: BackgroundLayer & { selectedLayerId: string };
87-
settings?: Settings;
88-
view?: View;
89-
};
90-
9157
function App({ published }: { published?: boolean }) {
92-
const dispatch: AppDispatch = useDispatch();
93-
const [searchParams, setSearchParams] = useSearchParams();
94-
const allowUiChanges = useSelector(getUIAllowChanges);
95-
const uiMode = useSelector(getUIMode);
96-
const zenMode = useSelector(getZenMode);
97-
const location = useLocation();
98-
const backgroundLayer = useSelector(getBackgroundLayer);
99-
const selectedMapLayer = useSelector(getSelectedMapLayer);
100-
101-
const [syncToken, setSyncToken] = useState(null);
102-
const [loadingConfig, setLoadingConfig] = useState(false);
10358
const [isModalOpen, setIsModalOpen] = useState(true);
104-
const isMobile = window.innerWidth < 600;
105-
const ifPopupPrintOpened = useSelector(getIfPopupOpend);
106-
107-
const configBaseUrl =
108-
"https://ceepr.cismet.de/config/wuppertal/_dev_geoportal/";
109-
110-
useEffect(() => {
111-
console.debug(
112-
" [GEOPORTAL|ROUTER] App Route changed to:",
113-
location.pathname
114-
);
115-
}, [location]);
116-
117-
useEffect(() => {
118-
if (searchParams.get("sync")) {
119-
setSyncToken(searchParams.get("sync"));
120-
}
121-
122-
if (searchParams.get("config")) {
123-
setLoadingConfig(true);
124-
const config = searchParams.get("config");
125-
126-
fetch(configBaseUrl + config)
127-
.then((response) => {
128-
return response.json();
129-
})
130-
.then((newConfig: Config) => {
131-
dispatch(setLayers(newConfig.layers));
132-
const selectedMapLayerId = newConfig.backgroundLayer.selectedLayerId;
133-
const selectedBackgroundLayer: BackgroundLayer = {
134-
title: layerMap[selectedMapLayerId].title,
135-
id: selectedMapLayerId,
136-
opacity: newConfig.backgroundLayer.opacity,
137-
description: layerMap[selectedMapLayerId].description,
138-
inhalt: layerMap[selectedMapLayerId].inhalt,
139-
eignung: layerMap[selectedMapLayerId].eignung,
140-
visible: newConfig.backgroundLayer.visible,
141-
layerType: "wmts",
142-
props: {
143-
name: "",
144-
url: layerMap[selectedMapLayerId].url,
145-
},
146-
layers: layerMap[selectedMapLayerId].layers,
147-
};
148-
dispatch(
149-
setBackgroundLayer({
150-
...selectedBackgroundLayer,
151-
id: newConfig.backgroundLayer.id,
152-
})
153-
);
154-
if (newConfig.backgroundLayer.id === "luftbild") {
155-
dispatch(setSelectedLuftbildLayer(selectedBackgroundLayer));
156-
} else {
157-
dispatch(setSelectedMapLayer(selectedBackgroundLayer));
158-
}
159-
searchParams.delete("config");
160-
setSearchParams(searchParams);
161-
})
162-
.finally(() => {
163-
setLoadingConfig(false);
164-
});
165-
}
166-
167-
if (searchParams.get("data")) {
168-
const data = searchParams.get("data");
169-
const newConfig: Config = JSON.parse(
170-
LZString.decompressFromEncodedURIComponent(data)
171-
);
172-
dispatch(setLayers(newConfig.layers));
173-
dispatch(setBackgroundLayer(newConfig.backgroundLayer));
174-
if (newConfig.settings) {
175-
dispatch(setUIShowLayerButtons(newConfig.settings.showLayerButtons));
176-
dispatch(setShowFullscreenButton(newConfig.settings.showFullscreen));
177-
dispatch(setShowLocatorButton(newConfig.settings.showLocator));
178-
dispatch(setShowMeasurementButton(newConfig.settings.showMeasurement));
179-
}
180-
searchParams.delete("data");
181-
setSearchParams(searchParams);
182-
}
183-
}, [searchParams]);
184-
185-
useEffect(() => {
186-
const onKeyDown = (e: KeyboardEvent) => {
187-
if (e.shiftKey) {
188-
dispatch(setUIShowLayerHideButtons(true));
189-
}
190-
191-
// if (e.key === "Escape") {
192-
// if (uiMode === "print" && !ifPopupPrintOpened) {
193-
// dispatch(setUIMode("default"));
194-
// }
195-
// dispatch(changeIfPopupOpend(false));
196-
// }
197-
};
198-
199-
const onKeyUp = (e: KeyboardEvent) => {
200-
if (allowUiChanges) {
201-
dispatch(setUIShowLayerHideButtons(false));
202-
}
203-
};
204-
205-
document.addEventListener("keydown", onKeyDown);
206-
document.addEventListener("keyup", onKeyUp);
207-
window.addEventListener("blur", onKeyUp);
208-
209-
return () => {
210-
document.removeEventListener("keydown", onKeyDown);
211-
document.removeEventListener("keyup", onKeyUp);
212-
window.removeEventListener("blur", onKeyUp);
213-
};
214-
}, [allowUiChanges]);
215-
216-
useEffect(() => {
217-
const backgroundLayerId = backgroundLayer.id;
218-
const selectedMapLayerId = selectedMapLayer.id;
219-
220-
const getId = () => {
221-
return backgroundLayerId === "luftbild"
222-
? backgroundLayerId
223-
: selectedMapLayerId;
224-
};
225-
dispatch(
226-
setBackgroundLayer({
227-
title: layerMap[getId()].title,
228-
id: backgroundLayerId,
229-
opacity: backgroundLayer.opacity,
230-
description: layerMap[getId()].description,
231-
inhalt: layerMap[getId()].inhalt,
232-
eignung: layerMap[getId()].eignung,
233-
visible: backgroundLayer.visible,
234-
layerType: "wmts",
235-
props: {
236-
name: "",
237-
url: layerMap[getId()].url,
238-
},
239-
layers: layerMap[getId()].layers,
240-
})
241-
);
59+
const isMobile = window.innerWidth < MIN_MOBILE_WIDTH;
24260

243-
dispatch(
244-
setSelectedMapLayer({
245-
title: layerMap[selectedMapLayerId].title,
246-
id: selectedMapLayerId,
247-
opacity: 1.0,
248-
description: ``,
249-
inhalt: layerMap[selectedMapLayerId].inhalt,
250-
eignung: layerMap[selectedMapLayerId].eignung,
251-
visible: selectedMapLayer.visible,
252-
layerType: "wmts",
253-
props: {
254-
name: "",
255-
url: layerMap[selectedMapLayerId].url,
256-
},
257-
layers: layerMap[selectedMapLayerId].layers,
258-
})
259-
);
260-
}, []);
61+
const isLoadingConfig = useAppConfig(CONFIG_BASE_URL, layerMap);
62+
useManageLayers(layerMap);
63+
useCesiumSearchParams();
64+
const syncToken = useSyncToken();
65+
useKeyboardShortcuts();
26166

26267
const content = (
26368
<FeatureFlagProvider config={featureFlagConfig}>
@@ -277,7 +82,7 @@ function App({ published }: { published?: boolean }) {
27782
className="flex flex-col w-full "
27883
style={{ height: "100dvh" }}
27984
>
280-
{loadingConfig && (
85+
{isLoadingConfig && (
28186
<div
28287
id="loading"
28388
className="absolute flex flex-col items-center text-white justify-center h-screen w-full bg-black/50 z-[9999999999999]"

0 commit comments

Comments
 (0)