diff --git a/components.d.ts b/components.d.ts index c0bb715..9493f7a 100644 --- a/components.d.ts +++ b/components.d.ts @@ -18,6 +18,7 @@ declare module 'vue' { HazardMenu: typeof import('./src/components/HazardMenu.vue')['default'] HazardSelect: typeof import('./src/components/HazardSelect.vue')['default'] HelloWorld: typeof import('./src/components/HelloWorld.vue')['default'] + LayerLegend: typeof import('./src/components/LayerLegend.vue')['default'] LayerList: typeof import('./src/components/LayerList.vue')['default'] MapComponent: typeof import('./src/components/MapComponent.vue')['default'] MapLayer: typeof import('./src/components/MapLayer.vue')['default'] diff --git a/src/App.vue b/src/App.vue index 55a39d5..5d756fa 100644 --- a/src/App.vue +++ b/src/App.vue @@ -3,10 +3,12 @@ + diff --git a/src/components/LayerLegend.vue b/src/components/LayerLegend.vue new file mode 100644 index 0000000..22bef5b --- /dev/null +++ b/src/components/LayerLegend.vue @@ -0,0 +1,191 @@ + + + + + diff --git a/src/lib/build-legend-url.js b/src/lib/build-legend-url.js new file mode 100644 index 0000000..560ee71 --- /dev/null +++ b/src/lib/build-legend-url.js @@ -0,0 +1,32 @@ +import queryString from 'query-string' + +// GeoServer - GetLegendGraphic Docs +// https://docs.geoserver.org/stable/en/user/services/wms/get_legend_graphic/index.html +export default function buildLegendUrl (layerData) { + const { url: rawUrl, layer } = layerData + + if (!rawUrl || !layer) { + return undefined + } + + // Convert WMTS URL to WMS URL for GetLegendGraphic + // Standard GeoServer structure: /gwc/service/wmts? -> /wms? + let wmsUrl = rawUrl + if (rawUrl.includes('/gwc/service/wmts')) { + wmsUrl = rawUrl.replace('/gwc/service/wmts', '/wms') + } + + // Remove trailing ? if present and add it back with params + const baseUrl = wmsUrl.endsWith('?') ? wmsUrl.slice(0, -1) : wmsUrl + + const params = queryString.stringify({ + 'request': 'GetLegendGraphic', + 'service': 'WMS', + 'version': '1.0.0', + 'format': 'image/png', + 'layer': layer, + 'legend_options': 'fontAntiAliasing:true;fontColor:0x000000;fontSize:16;labelMargin:8;dpi:90;', + }, { encode: true, sort: false }) + + return `${ baseUrl }?${ params }` +} diff --git a/src/stores/map.js b/src/stores/map.js index cb51bb3..e44a944 100644 --- a/src/stores/map.js +++ b/src/stores/map.js @@ -32,6 +32,38 @@ export const useMapStore = defineStore('map', { isLayerClickable: (state) => (layerId) => { return state.layerClickable[layerId] ?? false }, + + visibleLayersWithConfig: (state) => { + const visible = [] + const seenIds = new Set() + + for (const layerId in state.layerVisibility) { + if (state.layerVisibility[layerId] === true) { + // Skip raster layers with _raster suffix (only show base layer legends) + if (layerId.endsWith('_raster')) { + continue + } + + // Avoid duplicates + if (seenIds.has(layerId)) { + continue + } + seenIds.add(layerId) + + const layerConfig = state.layersConfig.find(config => config.id === layerId) + if (layerConfig && layerConfig.url && layerConfig.layer) { + visible.push({ + id: layerId, + url: layerConfig.url, + layer: layerConfig.layer, + name: layerConfig.name, + }) + } + } + } + + return visible + }, }, actions: { diff --git a/src/views/Home.vue b/src/views/Home.vue index cdb5fab..a4846ab 100644 --- a/src/views/Home.vue +++ b/src/views/Home.vue @@ -1,6 +1,3 @@ - -