diff --git a/packages/react-maplibre/package.json b/packages/react-maplibre/package.json index a02fb1e3..301a3ede 100644 --- a/packages/react-maplibre/package.json +++ b/packages/react-maplibre/package.json @@ -52,7 +52,7 @@ "redux-thunk": "^3.1.0", "topojson-client": "^3.1.0", "uuid": "^11.1.0", - "maplibre-gl": "^5.7.0", + "maplibre-gl": "^5.16.0", "wms-capabilities": "^0.6.0" }, "peerDependencies": { diff --git a/packages/react-maplibre/src/components/MlTerrainLayer/MlTerrainLayer.cy.tsx b/packages/react-maplibre/src/components/MlTerrainLayer/MlTerrainLayer.cy.tsx index 5bc1ed77..ebe7668d 100644 --- a/packages/react-maplibre/src/components/MlTerrainLayer/MlTerrainLayer.cy.tsx +++ b/packages/react-maplibre/src/components/MlTerrainLayer/MlTerrainLayer.cy.tsx @@ -17,7 +17,7 @@ describe('MlTerrainLayer Tests', () => { const { _map }: any = win; cy.wrap(_map).should((_map: any) => { // eslint-disable-next-line @typescript-eslint/no-unused-expressions - expect(_map?.style?.sourceCaches?.terrain).to.not.be.undefined; + expect(_map?.style?.getSource('terrain')).to.not.be.undefined; // eslint-disable-next-line @typescript-eslint/no-unused-expressions expect(_map?.style?._layers?.hills).to.not.be.undefined; }); @@ -33,7 +33,7 @@ describe('MlTerrainLayer Tests', () => { const { _map }: any = win; cy.wrap(_map).should((_map: any) => { // eslint-disable-next-line @typescript-eslint/no-unused-expressions - expect(_map?.style?.sourceCaches?.terrain).to.be.undefined; + expect(_map?.style?.getSource('terrain')).to.be.undefined; // eslint-disable-next-line @typescript-eslint/no-unused-expressions expect(_map?.style?._layers?.hills).to.be.undefined; }); diff --git a/packages/react-maplibre/src/components/MlWmsLayer/MlWmsLayer.tsx b/packages/react-maplibre/src/components/MlWmsLayer/MlWmsLayer.tsx index 5c88eee6..5ce229a5 100644 --- a/packages/react-maplibre/src/components/MlWmsLayer/MlWmsLayer.tsx +++ b/packages/react-maplibre/src/components/MlWmsLayer/MlWmsLayer.tsx @@ -13,6 +13,7 @@ const defaultProps: MlWmsLayerProps = { srs: 'EPSG:3857', width: '256', height: '256', + Transparent: 'true', styles: '', }, }; @@ -122,29 +123,16 @@ const MlWmsLayer = (props: MlWmsLayerProps) => { } }, [mapHook.map, props, tileUrl]); - useEffect(() => { - if (initializedRef.current) return; - - createLayer(); - }, [createLayer]); - useEffect(() => { if ( - !mapHook.map || - !mapHook.map?.map?.style?.sourceCaches?.[layerId.current] || - !initializedRef.current + initializedRef.current && + (mapHook?.map?.map?.getSource?.(layerId.current) as RasterSourceSpecification)?.tiles?.[0] === + tileUrl ) return; - const source = mapHook.map.map.getSource(layerId.current) as RasterSourceSpecification; - source.tiles = [tileUrl]; - - mapHook.map.map.style.sourceCaches[layerId.current].clearTiles(); - - mapHook.map.map.style.sourceCaches[layerId.current].update(mapHook.map.map.transform); - - mapHook.map.map.triggerRepaint(); - }, [mapHook.map, tileUrl]); + createLayer(); + }, [createLayer]); useEffect(() => { if (!mapHook.map || !initializedRef.current) return; diff --git a/packages/react-maplibre/src/components/MlWmsLoader/MlWmsLoader.tsx b/packages/react-maplibre/src/components/MlWmsLoader/MlWmsLoader.tsx index cf08a0cb..8b3b5ef1 100644 --- a/packages/react-maplibre/src/components/MlWmsLoader/MlWmsLoader.tsx +++ b/packages/react-maplibre/src/components/MlWmsLoader/MlWmsLoader.tsx @@ -100,6 +100,14 @@ export interface MlWmsLoaderProps { * A function to set the feature info active state */ setFeatureInfoActive?: (val: boolean | ((current: boolean) => boolean)) => void; + /** + * Callback function that is called after the featureInfoRequest has succeeded + */ + featureInfoSuccess?: (content: string, lngLat: { lng: number; lat: number }) => void; + /** + * If true, displays a marker at the feature info location + */ + featureInfoMarkerEnabled?: boolean; /** * The WMS configuration object */ @@ -121,6 +129,14 @@ export interface MlWmsLoaderProps { */ buttons?: React.JSX.Element; sortable?: boolean; + /** + * Array of layer Names (IDs) that should be visible at start. If not provided, default visibility logic applies. + */ + visibleLayersAtStart?: string[]; + /** + * If true, renders the layer list UI. If false, only the WMS layer is rendered without UI controls. + */ + showLayerList?: boolean; } export interface WmsLayer { @@ -170,8 +186,10 @@ const defaultProps = { TRANSPARENT: 'TRUE', }, featureInfoEnabled: true, + featureInfoMarkerEnabled: true, zoomToExtent: false, showDeleteButton: false, + showLayerList: true, }; /** * Loads a WMS getCapabilities xml document and adds a MlWmsLayer component for each layer that is @@ -289,6 +307,7 @@ const MlWmsLoader = (props: MlWmsLoaderProps) => { QUERY_LAYERS: layers .map((layer: LayerType) => (layer.visible && layer.queryable ? layer.Name : undefined)) .filter((n) => n), + STYLES: '', WIDTH: 100, HEIGHT: 100, srs: 'EPSG:3857', @@ -327,6 +346,7 @@ const MlWmsLoader = (props: MlWmsLoaderProps) => { .then((text) => { setFeatureInfoLngLat(ev.lngLat); setFeatureInfoContent(text); + props.featureInfoSuccess?.(text, ev.lngLat); }) .catch((error) => console.log(error)); }, @@ -383,8 +403,11 @@ const MlWmsLoader = (props: MlWmsLoaderProps) => { if (idx === 0) { _LatLonBoundingBox = layer.EX_GeographicBoundingBox || layer?.LatLonBoundingBox || []; } + const isVisible = props.visibleLayersAtStart + ? props.visibleLayersAtStart.includes(layer.Name || '') + : true; return { - visible: capabilities?.Capability?.Layer?.Layer?.length > 2 ? idx > 1 : true, + visible: isVisible, Attribution: { Title: '' }, // eslint-disable-next-line @typescript-eslint/no-unused-vars ...(({ CRS, ..._layer }) => _layer)(layer), @@ -398,8 +421,12 @@ const MlWmsLoader = (props: MlWmsLoaderProps) => { if (idx === 0) { _LatLonBoundingBox = layer.EX_GeographicBoundingBox || layer?.LatLonBoundingBox || []; } + const isVisible = + props.visibleLayersAtStart && layer.Name + ? props.visibleLayersAtStart.includes(layer.Name) + : false; return { - visible: false, + visible: isVisible, Attribution: { Title: '' }, // eslint-disable-next-line @typescript-eslint/no-unused-vars ...(({ CRS, ..._layer }) => _layer)(layer), @@ -527,57 +554,60 @@ const MlWmsLoader = (props: MlWmsLoaderProps) => { )} {wmsUrl && ( <> - {props.layerId && props.sortable && ( - {listContent} + {props.showLayerList && ( + <> + {props.sortable && {listContent}} + {!props.sortable && listContent} + + + {wmsUrl && + layers?.map?.((layer, idx) => { + return layer?.Name ? ( + {layer?.queryable && }} + > + + { + const _layers: Array = [...layers]; + _layers[idx].visible = !_layers[idx].visible; + setLayers([..._layers]); + }} + /> + + + + ) : ( + <> + ); + })} + + + + )} + {wmsUrl && layers?.length && ( + layer.visible) + .map((el) => el.Name) + .reverse() + .join(','), + }} + insertBeforeLayer={props?.insertBeforeLayer} + /> )} - {props.layerId && !props.sortable && listContent} - - - {wmsUrl && - layers?.map?.((layer, idx) => { - return layer?.Name ? ( - {layer?.queryable && }} - > - - { - const _layers: Array = [...layers]; - _layers[idx].visible = !_layers[idx].visible; - setLayers([..._layers]); - }} - /> - - - - ) : ( - <> - ); - })} - - {wmsUrl && layers?.length && ( - layer.visible) - .map((el) => el.Name) - .reverse() - .join(','), - }} - insertBeforeLayer={props?.insertBeforeLayer} - /> - )} - - {props.featureInfoEnabled && featureInfoLngLat && ( + {props.featureInfoEnabled && props.featureInfoMarkerEnabled && featureInfoLngLat && ( )} diff --git a/packages/react-maplibre/src/ui_components/LayerList/LayerListItem.tsx b/packages/react-maplibre/src/ui_components/LayerList/LayerListItem.tsx index a1380692..e92ae0d2 100644 --- a/packages/react-maplibre/src/ui_components/LayerList/LayerListItem.tsx +++ b/packages/react-maplibre/src/ui_components/LayerList/LayerListItem.tsx @@ -202,7 +202,7 @@ function LayerListItem({ return ( <> {props.sortable && props.layerId && !layerComponent?.props?.layers && ( - {listContent} + {listContent} )} {!props.sortable && !layerComponent?.props?.layers && listContent} {_layerComponent} diff --git a/packages/react-maplibre/src/ui_components/LayerList/util/SortableContainer.tsx b/packages/react-maplibre/src/ui_components/LayerList/util/SortableContainer.tsx index 007901fe..07f426c8 100644 --- a/packages/react-maplibre/src/ui_components/LayerList/util/SortableContainer.tsx +++ b/packages/react-maplibre/src/ui_components/LayerList/util/SortableContainer.tsx @@ -1,16 +1,15 @@ -import { ReactNode } from 'react'; +import { ReactNode, useRef } from 'react'; import { useSortable } from '@dnd-kit/sortable'; import { CSS } from '@dnd-kit/utilities'; +import { v4 as uuid } from 'uuid'; interface SortableContainerProps { children: ReactNode; - layerId: string; } -function SortableContainer({ children, layerId }: SortableContainerProps) { - const { attributes, listeners, setNodeRef, transform } = useSortable({ - id: layerId, - }); +function SortableContainer({ children }: SortableContainerProps) { + const idRef = useRef(uuid()); + const { attributes, listeners, setNodeRef, transform } = useSortable({ id: idRef.current }); const style = { transform: CSS.Transform.toString(transform), }; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b5e78338..0bc1d090 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -382,8 +382,8 @@ importers: specifier: ^3.0.2 version: 3.0.2 maplibre-gl: - specifier: ^5.7.0 - version: 5.7.1 + specifier: ^5.16.0 + version: 5.16.0 osm2geojson-lite: specifier: ^1.1.2 version: 1.1.2 @@ -2659,9 +2659,19 @@ packages: resolution: {integrity: sha512-IGJtuBbaGzOUgODdBRg66p8stnwj9iDXkgbYKoYcNiiQmaez5WVRfXm4b03MCDwmZyX93csbfHFWEJJYHnn5oA==} hasBin: true + '@maplibre/maplibre-gl-style-spec@24.4.1': + resolution: {integrity: sha512-UKhA4qv1h30XT768ccSv5NjNCX+dgfoq2qlLVmKejspPcSQTYD4SrVucgqegmYcKcmwf06wcNAa/kRd0NHWbUg==} + hasBin: true + + '@maplibre/mlt@1.1.2': + resolution: {integrity: sha512-SQKdJ909VGROkA6ovJgtHNs9YXV4YXUPS+VaZ50I2Mt951SLlUm2Cv34x5Xwc1HiFlsd3h2Yrs5cn7xzqBmENw==} + '@maplibre/vt-pbf@4.0.3': resolution: {integrity: sha512-YsW99BwnT+ukJRkseBcLuZHfITB4puJoxnqPVjo72rhW/TaawVYsgQHcqWLzTxqknttYoDpgyERzWSa/XrETdA==} + '@maplibre/vt-pbf@4.2.0': + resolution: {integrity: sha512-bxrk/kQUwWXZgmqYgwOCnZCMONCRi3MJMqJdza4T3E4AeR5i+VyMnaJ8iDWtWxdfEAJRtrzIOeJtxZSy5mFrFA==} + '@math.gl/core@4.1.0': resolution: {integrity: sha512-FrdHBCVG3QdrworwrUSzXIaK+/9OCRLscxI2OUy6sLOHyHgBMyfnEGs99/m3KNvs+95BsnQLWklVfpKfQzfwKA==} @@ -9032,6 +9042,10 @@ packages: mapbox-gl@3.14.0: resolution: {integrity: sha512-KYhi9ZOQL4BB0J061admPH8O5ZZhhxsyiJ6DQCOkCaps0JEB4HF3SbJwu8S0pJKaQUxNS33sSbzW8iDSSauHPQ==} + maplibre-gl@5.16.0: + resolution: {integrity: sha512-/VDY89nr4jgLJyzmhy325cG6VUI02WkZ/UfVuDbG/piXzo6ODnM+omDFIwWY8tsEsBG26DNDmNMn3Y2ikHsBiA==} + engines: {node: '>=16.14.0', npm: '>=8.1.0'} + maplibre-gl@5.7.1: resolution: {integrity: sha512-iCOQB6W/EGgQx8aU4SyfU5a5/GR2E+ELF92NMsqYfs3x+vnY+8mARmz4gor6XZHCz3tv19mnotVDRlRTMNKyGw==} engines: {node: '>=16.14.0', npm: '>=8.1.0'} @@ -9514,6 +9528,7 @@ packages: osm2geojson-lite@1.1.2: resolution: {integrity: sha512-6s1uW548fdyLTJ4Cp/hQTKvdgCl/E8nUvBMEzUXnAJPHAFHoIhwMqZ3KGdph2A1g48rsCeA6gVnkPruWGiwupw==} hasBin: true + bundledDependencies: [] ospath@1.2.2: resolution: {integrity: sha512-o6E5qJV5zkAbIDNhGSIlyOhScKXgQrSRMilfph0clDfM0nEnBOlKlH4sWDmG95BW/CvwNz0vmm7dJVtU2KlMiA==} @@ -14037,6 +14052,20 @@ snapshots: rw: 1.3.3 tinyqueue: 3.0.0 + '@maplibre/maplibre-gl-style-spec@24.4.1': + dependencies: + '@mapbox/jsonlint-lines-primitives': 2.0.2 + '@mapbox/unitbezier': 0.0.1 + json-stringify-pretty-compact: 4.0.0 + minimist: 1.2.8 + quickselect: 3.0.0 + rw: 1.3.3 + tinyqueue: 3.0.0 + + '@maplibre/mlt@1.1.2': + dependencies: + '@mapbox/point-geometry': 1.1.0 + '@maplibre/vt-pbf@4.0.3': dependencies: '@mapbox/point-geometry': 1.1.0 @@ -14047,6 +14076,16 @@ snapshots: pbf: 4.0.1 supercluster: 8.0.1 + '@maplibre/vt-pbf@4.2.0': + dependencies: + '@mapbox/point-geometry': 1.1.0 + '@mapbox/vector-tile': 2.0.4 + '@types/geojson-vt': 3.2.5 + '@types/supercluster': 7.1.3 + geojson-vt: 4.0.2 + pbf: 4.0.1 + supercluster: 8.0.1 + '@math.gl/core@4.1.0': dependencies: '@math.gl/types': 4.1.0 @@ -22937,6 +22976,32 @@ snapshots: supercluster: 8.0.1 tinyqueue: 3.0.0 + maplibre-gl@5.16.0: + dependencies: + '@mapbox/geojson-rewind': 0.5.2 + '@mapbox/jsonlint-lines-primitives': 2.0.2 + '@mapbox/point-geometry': 1.1.0 + '@mapbox/tiny-sdf': 2.0.7 + '@mapbox/unitbezier': 0.0.1 + '@mapbox/vector-tile': 2.0.4 + '@mapbox/whoots-js': 3.1.0 + '@maplibre/maplibre-gl-style-spec': 24.4.1 + '@maplibre/mlt': 1.1.2 + '@maplibre/vt-pbf': 4.2.0 + '@types/geojson': 7946.0.16 + '@types/geojson-vt': 3.2.5 + '@types/supercluster': 7.1.3 + earcut: 3.0.2 + geojson-vt: 4.0.2 + gl-matrix: 3.4.4 + kdbush: 4.0.2 + murmurhash-js: 1.0.0 + pbf: 4.0.1 + potpack: 2.1.0 + quickselect: 3.0.0 + supercluster: 8.0.1 + tinyqueue: 3.0.0 + maplibre-gl@5.7.1: dependencies: '@mapbox/geojson-rewind': 0.5.2