Layer Management
Overview
The layer-manager.ts module manages the base layers of the p2d2 mapping application. It provides functions for creating WMS layers, toggle logic for visibility, and automatic state persistence in localStorage.
Managed Layers
Aerial Imagery (City of Cologne)
WMS Endpoint:
https://geoportal.stadt-koeln.de/wss/service/luftbilder_2024_wms/guestLayer Name: luftbilder_2024_23
Supported Projections:
- EPSG:3857 (Web Mercator)
- EPSG:25832 (UTM Zone 32N)
Z-Index: 7 (from MAP_CONFIG.Z_INDEX.LUFTBILD)
Features:
- Initially invisible (
visible: false) - Automatic projection detection
- Cross-origin configured for image loading
basemap.de
WMS Endpoint:
https://sgx.geodatenzentrum.de/wms_basemapdeLayer Name: de_basemapde_web_raster_farbe
Supported Projections:
- EPSG:3857 (Web Mercator)
Z-Index: 15 (from MAP_CONFIG.Z_INDEX.BASEMAP)
Features:
- Color variant (standard)
- Gray variant available:
de_basemapde_web_raster_grau - Transparency enabled for overlays
- Initially invisible (
visible: false)
API Reference
createLuftbildLayer(projection: string): TileLayer
Creates WMS layer for Cologne aerial imagery 2024.
Parameters:
projection(string): EPSG code ('EPSG:3857'or'EPSG:25832')
Returns:
- OpenLayers
TileLayerwith TileWMS source
Implementation:
export function createLuftbildLayer(projection: string): TileLayer {
const supportedProjections = ["EPSG:3857", "EPSG:25832"];
const useProjection = supportedProjections.includes(projection)
? projection
: "EPSG:3857";
const layer = new TileLayer({
source: new TileWMS({
url: "https://geoportal.stadt-koeln.de/wss/service/luftbilder_2024_wms/guest",
params: {
LAYERS: "luftbilder_2024_23",
FORMAT: "image/png",
TILED: true,
},
projection: useProjection,
crossOrigin: "anonymous",
}),
zIndex: MAP_CONFIG.Z_INDEX.LUFTBILD,
visible: false,
});
luftbildLayer = layer;
return layer;
}createBasemapLayer(): TileLayer
Creates WMS layer for basemap.de.
Parameters: None
Returns:
- OpenLayers
TileLayerwith TileWMS source
Implementation:
export function createBasemapLayer(): TileLayer {
const layer = new TileLayer({
source: new TileWMS({
url: "https://sgx.geodatenzentrum.de/wms_basemapde",
params: {
LAYERS: "de_basemapde_web_raster_farbe",
FORMAT: "image/png",
TRANSPARENT: "true",
TILED: true,
},
projection: "EPSG:3857",
crossOrigin: "anonymous",
}),
zIndex: MAP_CONFIG.Z_INDEX.BASEMAP,
visible: false,
});
basemapLayer = layer;
return layer;
}toggleBaseLayer(layerName: string): void
Toggles visibility of a base layer.
Parameters:
layerName(string):'luftbild'or'basemap'
Behavior:
- Independent toggle: Both layers can be active simultaneously
- Persistence in localStorage
- Button highlighting via CSS class
highlighted - Console logging for debugging
localStorage Keys:
luftbildVisible:'true'|'false'basemapVisible:'true'|'false'
Implementation:
export function toggleBaseLayer(layerName: string): void {
if (layerName === "luftbild" && luftbildLayer) {
// Toggle Luftbild independently
const newVisibility = !luftbildLayer.getVisible();
luftbildLayer.setVisible(newVisibility);
// Update only the Luftbild button
const luftbildBtn = document.querySelector(
'[data-layer-toggle="luftbild"]',
);
if (luftbildBtn) {
if (newVisibility) {
luftbildBtn.classList.add("highlighted");
} else {
luftbildBtn.classList.remove("highlighted");
}
}
} else if (layerName === "basemap" && basemapLayer) {
// Toggle basemap.de independently
const newVisibility = !basemapLayer.getVisible();
basemapLayer.setVisible(newVisibility);
// Update only the basemap button
const basemapBtn = document.querySelector('[data-layer-toggle="basemap"]');
if (basemapBtn) {
if (newVisibility) {
basemapBtn.classList.add("highlighted");
} else {
basemapBtn.classList.remove("highlighted");
}
}
}
// Persist both states separately in localStorage
try {
localStorage.setItem(
"luftbildVisible",
String(luftbildLayer ? luftbildLayer.getVisible() : false),
);
localStorage.setItem(
"basemapVisible",
String(basemapLayer ? basemapLayer.getVisible() : false),
);
} catch (error) {
console.warn("Could not persist layer states", error);
}
console.log("Layer toggle:", {
luftbild: luftbildLayer ? luftbildLayer.getVisible() : false,
basemap: basemapLayer ? basemapLayer.getVisible() : false,
});
}initLayerControls(): void
Initializes event listeners for layer toggle buttons.
Function:
- Registers click handlers on
[data-layer-toggle]buttons - Restores previous state from localStorage
- Updates button styling
HTML Structure:
<button data-layer-toggle="luftbild">Aerial Imagery</button>
<button data-layer-toggle="basemap">basemap.de</button>Implementation:
export function initLayerControls(): void {
// Add event listeners for layer toggle buttons
document.addEventListener("click", (event) => {
const target = event.target as HTMLElement;
const button = target.closest("[data-layer-toggle]");
if (!button) return;
const layerName = (button as HTMLElement).dataset.layerToggle;
if (layerName) {
toggleBaseLayer(layerName);
}
});
// Restore previous layer states from localStorage
try {
const luftbildVisible = localStorage.getItem("luftbildVisible") === "true";
const basemapVisible = localStorage.getItem("basemapVisible") === "true";
if (luftbildVisible && luftbildLayer) {
luftbildLayer.setVisible(true);
const btn = document.querySelector('[data-layer-toggle="luftbild"]');
if (btn) btn.classList.add("highlighted");
}
if (basemapVisible && basemapLayer) {
basemapLayer.setVisible(true);
const btn = document.querySelector('[data-layer-toggle="basemap"]');
if (btn) btn.classList.add("highlighted");
}
} catch (error) {
console.warn("Could not restore layer states from localStorage", error);
}
}Getter Functions
getLuftbildLayer(): TileLayer | null
Returns the current aerial imagery layer instance.
getBasemapLayer(): TileLayer | null
Returns the current basemap.de layer instance.
getLayerStates(): { luftbild: boolean; basemap: boolean }
Returns the current visibility status of both layers (for debugging).
State Management
LocalStorage Schema
| Key | Value | Description |
|---|---|---|
luftbildVisible | 'true' | 'false' | Aerial imagery layer visibility |
basemapVisible | 'true' | 'false' | basemap.de visibility |
Global Variables
luftbildLayer: TileLayer | null- Reference to aerial imagery layerbasemapLayer: TileLayer | null- Reference to basemap.de layer
Usage
Complete Setup
import {
createLuftbildLayer,
createBasemapLayer,
initLayerControls
} from './layer-management';
// Create layers
const luftbild = createLuftbildLayer('EPSG:3857');
const basemap = createBasemapLayer();
// Add to map
map.addLayer(luftbild);
map.addLayer(basemap);
// Initialize controls
initLayerControls();HTML Integration
<div class="layer-controls">
<button data-layer-toggle="luftbild" class="layer-btn">Aerial Imagery</button>
<button data-layer-toggle="basemap" class="layer-btn">basemap.de</button>
</div>CSS for Button Highlighting
.layer-btn.highlighted {
background-color: #007bff;
color: white;
}Dependencies
Imports:
ol/layer/Tile(TileLayer)ol/source/TileWMS../config/map-config(MAP_CONFIG)
Exports:
createLuftbildLayercreateBasemapLayertoggleBaseLayerinitLayerControlsgetLuftbildLayergetBasemapLayergetLayerStatesLAYER_ZINDEX(Re-export from MAP_CONFIG.Z_INDEX)
Error Handling
- localStorage errors are caught and warned
- Missing layer instances are checked before operations
- Console logging for debugging purposes
Best Practices
- Layer Creation Before Controls: Always create layers first, then initialize controls
- Projection Consistency: Create aerial imagery layer with correct projection
- State Persistence: localStorage is automatically managed
- Button Integration: HTML buttons require
data-layer-toggleattribute