diff --git a/packages/landing/src/components/layer.switcher.dropdown.tsx b/packages/landing/src/components/layer.switcher.dropdown.tsx index d7735e5d0..6daa00d44 100644 --- a/packages/landing/src/components/layer.switcher.dropdown.tsx +++ b/packages/landing/src/components/layer.switcher.dropdown.tsx @@ -1,3 +1,4 @@ +import { Bounds, GoogleTms, Projection } from '@basemaps/geo'; import { ChangeEventHandler, Component, ReactNode } from 'react'; import Select from 'react-select'; @@ -29,7 +30,10 @@ export interface Option { export interface LayerSwitcherDropdownState { layers?: Map; + /** Should the map be zoomed to the extent of the layer when the layer is changed */ zoomToExtent: boolean; + /** Should the drop down be limited to the approximate extent of the map */ + filterToExtent: boolean; currentLayer: string; } @@ -40,7 +44,7 @@ export class LayerSwitcherDropdown extends Component = (e) => { - const target = e.target as HTMLInputElement; - this.setState({ zoomToExtent: target.checked }); + onZoomExtentChange: ChangeEventHandler = (e) => { + gaEvent(GaEvent.Ui, 'layer-list:zoomToExtent:' + e.target.checked); + this.setState({ zoomToExtent: e.target.checked }); }; + onFilterExtentChange: ChangeEventHandler = (e) => { + gaEvent(GaEvent.Ui, 'layer-list:filterToExtent:' + e.target.checked); + this.setState({ filterToExtent: e.target.checked }); + }; + + renderTotal(total: number, hidden: number): ReactNode | null { + if (total === 0) return null; + if (hidden > 0) { + return ( + + ); + } + return

{total}

; + } + override render(): ReactNode { const ret = this.makeOptions(); return (
-
Layers
+
Layers {this.renderTotal(ret.total, ret.hidden)}
+ +
- +
); } - makeOptions(): { options: GroupedOptions[]; current: Option | null } { - if (this.state.layers == null || this.state.layers.size === 0) return { options: [], current: null }; + makeOptions(): { options: GroupedOptions[]; current: Option | null; hidden: number; total: number } { + let hidden = 0; + let total = 0; + if (this.state.layers == null || this.state.layers.size === 0) return { options: [], current: null, hidden, total }; const categories: CategoryMap = new Map(); const currentLayer = this.state.currentLayer; + const filterToExtent = this.state.filterToExtent; + + const location = Config.map.location; + const loc3857 = Projection.get(GoogleTms).fromWgs84([location.lon, location.lat]); + const tileSize = GoogleTms.tileSize * GoogleTms.pixelScale(Math.floor(location.zoom)); // width of 1 tile + // Assume the current bounds are 3x3 tiles, todo would be more correct to use the map's bounding box but we dont have access to it here + const bounds = new Bounds(loc3857[0], loc3857[1], 1, 1).scaleFromCenter(3 * tileSize, 3 * tileSize); + let current: Option | null = null; for (const layer of this.state.layers.values()) { if (ignoredLayers.has(layer.id)) continue; if (!layer.projections.has(Config.map.tileMatrix.projection.code)) continue; + total++; + // Always show the current layer + if (layer.id !== currentLayer) { + // Limit all other layers to the extent if requested + if (filterToExtent && !doesLayerIntersect(bounds, layer)) { + hidden++; + continue; + } + } + const layerId = layer.category ?? 'Unknown'; const layerCategory = categories.get(layerId) ?? { label: layerId, options: [] }; const opt = { value: layer.id, label: layer.name.replace(` ${layer.category}`, '') }; @@ -168,6 +223,30 @@ export class LayerSwitcherDropdown extends Component