Skip to content

Commit a05b3cf

Browse files
authored
[fix] WMS layer fixes 2 (#3149)
* [fix] WMS layer fixes and updates Signed-off-by: Ihor Dykhta <dikhta.igor@gmail.com> * wmp fixes Signed-off-by: Ihor Dykhta <dikhta.igor@gmail.com> * [fix] WMS layer fixes 2 Signed-off-by: Ihor Dykhta <dikhta.igor@gmail.com> * yarn.lock Signed-off-by: Ihor Dykhta <dikhta.igor@gmail.com> * list wms examples Signed-off-by: Ihor Dykhta <dikhta.igor@gmail.com> * fix broken import Signed-off-by: Ihor Dykhta <dikhta.igor@gmail.com> --------- Signed-off-by: Ihor Dykhta <dikhta.igor@gmail.com>
1 parent 1a47e08 commit a05b3cf

14 files changed

Lines changed: 457 additions & 131 deletions

File tree

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,7 @@
235235
"@loaders.gl/gis": "4.3.2",
236236
"@loaders.gl/schema": "4.3.2",
237237
"@loaders.gl/wkt": "4.3.2",
238+
"@loaders.gl/wms": "4.3.2",
238239
"@luma.gl/constants": "8.5.21",
239240
"@luma.gl/core": "8.5.21",
240241
"@luma.gl/experimental": "8.5.21",

src/components/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
"@kepler.gl/utils": "3.1.8",
5555
"@loaders.gl/mvt": "^4.3.2",
5656
"@loaders.gl/pmtiles": "^4.3.2",
57+
"@loaders.gl/wms": "4.3.2",
5758
"@mapbox/mapbox-sdk": "^0.15.3",
5859
"@nebula.gl/edit-modes": "1.0.2-alpha.1",
5960
"@tippyjs/react": "^4.2.0",

src/components/src/modals/export-data-modal.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,8 @@ const ExportDataModalFactory = () => {
9494
const showTiledDatasetWarning = Object.keys(datasets).some(datasetId => {
9595
return (
9696
(datasets[datasetId].type === DatasetType.VECTOR_TILE ||
97-
datasets[datasetId].type === DatasetType.RASTER_TILE) &&
97+
datasets[datasetId].type === DatasetType.RASTER_TILE ||
98+
datasets[datasetId].type === DatasetType.WMS_TILE) &&
9899
(selectedDataset === datasetId || exportAllDatasets)
99100
);
100101
});

src/components/src/modals/tilesets-modals/common.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
// SPDX-License-Identifier: MIT
22
// Copyright contributors to the kepler.gl project
33

4+
import type {WMSCapabilities} from '@loaders.gl/wms';
5+
46
import type {VectorTileMetadata} from '@kepler.gl/table';
57
import type {StacTypes} from '@kepler.gl/types';
68

@@ -11,7 +13,7 @@ export type DatasetCreationAttributes = {
1113
};
1214

1315
export type MetaResponse = {
14-
metadata?: VectorTileMetadata | StacTypes.CompleteSTACObject | null;
16+
metadata?: VectorTileMetadata | StacTypes.CompleteSTACObject | WMSCapabilities | null;
1517
dataset?: DatasetCreationAttributes | null;
1618
loading?: boolean;
1719
error?: Error | null;

src/components/src/modals/tilesets-modals/load-tileset.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,6 @@ function LoadTilesetTabFactory() {
164164
</TilesetTypeContainer>
165165
<div>
166166
<CurrentForm setResponse={setResponse} />
167-
{error && <div>{getError(error)}</div>}
168167
</div>
169168
</div>
170169
<MetaContainer>

src/components/src/modals/tilesets-modals/tileset-wms-form.tsx

Lines changed: 55 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,18 @@
33

44
import React, {useCallback, useEffect, useState} from 'react';
55
import styled from 'styled-components';
6-
import {WMSCapabilities, WMSCapabilitiesLoader} from '@loaders.gl/wms';
7-
import {load} from '@loaders.gl/core';
6+
import {WMSCapabilities} from '@loaders.gl/wms';
7+
8+
import {validateUrl} from '@kepler.gl/common-utils';
9+
import {DatasetType, REMOTE_TILE, RemoteTileFormat, WMSDatasetMetadata} from '@kepler.gl/constants';
10+
import {getWMSCapabilities, wmsCapabilitiesToDatasetMetadata} from '@kepler.gl/table';
811

9-
import {DatasetType, REMOTE_TILE, RemoteTileFormat} from '@kepler.gl/constants';
1012
import {MetaResponse} from './common';
1113
import {InputLight} from '../../common';
1214

1315
const TilesetInputContainer = styled.div`
1416
display: grid;
15-
grid-template-rows: repeat(2, 1fr);
17+
grid-template-rows: repeat(3, auto);
1618
row-gap: 18px;
1719
font-size: 12px;
1820
`;
@@ -22,18 +24,34 @@ const TilesetInputDescription = styled.div`
2224
color: ${props => props.theme.AZURE200};
2325
font-size: 11px;
2426
`;
27+
28+
const ExampleUrlsContainer = styled.div`
29+
text-align: left;
30+
color: ${props => props.theme.AZURE200};
31+
font-size: 11px;
32+
33+
.example-url {
34+
margin-top: 8px;
35+
display: block;
36+
}
37+
`;
38+
2539
type WMSTileFormProps = {
2640
setResponse: (response: MetaResponse) => void;
2741
};
2842

43+
type WMSData = {
44+
metadata: WMSCapabilities | null;
45+
layers: WMSDatasetMetadata['layers'];
46+
version: string;
47+
};
48+
2949
const TilesetWMSForm: React.FC<WMSTileFormProps> = ({setResponse}) => {
3050
const [layerName, setLayerName] = useState<string>('');
3151
const [wmsUrl, setWmsUrl] = useState<string>('');
32-
const [metadata, setMetadata] = useState<any>(null);
3352
const [loading, setLoading] = useState<boolean>(false);
3453
const [error, setError] = useState<Error | null>(null);
35-
const [availableLayers, setAvailableLayers] = useState<{name: string; title: string}[]>([]);
36-
const [wmsVersion, setWmsVersion] = useState<string>('1.3.0');
54+
const [wmsData, setWMSData] = useState<WMSData | null>(null);
3755

3856
const onLayerNameChange = useCallback(
3957
(event: React.ChangeEvent<HTMLInputElement>) => {
@@ -49,48 +67,34 @@ const TilesetWMSForm: React.FC<WMSTileFormProps> = ({setResponse}) => {
4967
const newWmsUrl = event.target.value;
5068
setWmsUrl(newWmsUrl);
5169

70+
if (!validateUrl(newWmsUrl)) {
71+
setWMSData(null);
72+
return;
73+
}
74+
5275
// Fetch WMS GetCapabilities
5376
try {
5477
setLoading(true);
5578
setError(null);
56-
const data = (await load(
57-
`${newWmsUrl}?service=WMS&request=GetCapabilities`,
58-
WMSCapabilitiesLoader
59-
)) as WMSCapabilities;
79+
80+
const data = await getWMSCapabilities(newWmsUrl);
81+
82+
const datasetMetadata = wmsCapabilitiesToDatasetMetadata(data);
6083

6184
// Extract name or title from GetCapabilities response
6285
const serviceTitle = data?.title || data?.name;
6386
if (serviceTitle && !layerName) {
6487
setLayerName(serviceTitle);
6588
}
6689

67-
// Flatten layers if they are nested
68-
const layers = data.layers.flatMap(layer => {
69-
if (layer.layers && layer.layers.length > 0) {
70-
return layer.layers;
71-
}
72-
return layer;
90+
setWMSData({
91+
metadata: data,
92+
layers: datasetMetadata.layers,
93+
version: datasetMetadata.version
7394
});
74-
75-
if (Array.isArray(layers)) {
76-
const layerOptions = layers.map((layer: any) => ({
77-
name: layer.name,
78-
title: layer.title || layer.name,
79-
boundingBox: layer.geographicBoundingBox
80-
}));
81-
setAvailableLayers(layerOptions);
82-
} else {
83-
setAvailableLayers([]);
84-
}
85-
86-
// Set WMS version
87-
const version = data.version || '1.3.0';
88-
setWmsVersion(version);
89-
90-
setMetadata(data);
9195
} catch (err) {
9296
setError(err instanceof Error ? err : new Error('Unknown error'));
93-
setMetadata(null);
97+
setWMSData(null);
9498
} finally {
9599
setLoading(false);
96100
}
@@ -108,12 +112,12 @@ const TilesetWMSForm: React.FC<WMSTileFormProps> = ({setResponse}) => {
108112
remoteTileFormat: RemoteTileFormat.WMS,
109113
tilesetDataUrl: wmsUrl,
110114
tilesetMetadataUrl: `${wmsUrl}?service=WMS&request=GetCapabilities`,
111-
layers: availableLayers,
112-
wmsVersion: wmsVersion
115+
layers: wmsData?.layers || [],
116+
wmsVersion: wmsData?.version || '1.3.0'
113117
}
114118
};
115119
setResponse({
116-
metadata,
120+
metadata: wmsData?.metadata ?? null,
117121
dataset,
118122
loading,
119123
error
@@ -126,7 +130,7 @@ const TilesetWMSForm: React.FC<WMSTileFormProps> = ({setResponse}) => {
126130
error
127131
});
128132
}
129-
}, [setResponse, layerName, wmsUrl, metadata, loading, error, availableLayers, wmsVersion]);
133+
}, [setResponse, layerName, wmsUrl, wmsData, loading, error]);
130134

131135
return (
132136
<TilesetInputContainer>
@@ -149,6 +153,18 @@ const TilesetWMSForm: React.FC<WMSTileFormProps> = ({setResponse}) => {
149153
/>
150154
<TilesetInputDescription>Provide a valid WMS service URL.</TilesetInputDescription>
151155
</div>
156+
<div>
157+
<TilesetInputDescription>For example, try a public WMS URL:</TilesetInputDescription>
158+
<ExampleUrlsContainer>
159+
<div className="example-url">• https://ows.terrestris.de/osm/service</div>
160+
<div className="example-url">
161+
• https://opengeo.ncep.noaa.gov/geoserver/conus/conus_cref_qcd/ows
162+
</div>
163+
<div className="example-url">
164+
• https://gibs.earthdata.nasa.gov/wms/epsg4326/best/wms.cgi
165+
</div>
166+
</ExampleUrlsContainer>
167+
</div>
152168
</TilesetInputContainer>
153169
);
154170
};

src/components/src/side-panel/layer-panel/layer-configurator.tsx

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1032,14 +1032,10 @@ export default function LayerConfiguratorFactory(
10321032
}) {
10331033
return (
10341034
<StyledLayerVisualConfigurator>
1035-
<LayerConfigGroup label={'layer.wms'} collapsible>
1036-
<VisConfigSlider {...layer.visConfigSettings.opacity} {...visConfiguratorProps} />
1037-
<VisConfigSwitch
1038-
label={'layerVisConfigs.transparentBackground'}
1039-
{...layer.visConfigSettings.transparent}
1040-
{...visConfiguratorProps}
1041-
property="transparent"
1042-
/>
1035+
<LayerConfigGroup label={'layer.service'}>
1036+
<PanelLabel>
1037+
<FormattedMessage id={'layer.layer'} />
1038+
</PanelLabel>
10431039
<ItemSelector
10441040
selectedItems={layer.config.visConfig.wmsLayer}
10451041
options={layerChannelConfigProps.dataset.metadata.layers}
@@ -1067,6 +1063,15 @@ export default function LayerConfiguratorFactory(
10671063
}}
10681064
/>
10691065
</LayerConfigGroup>
1066+
<LayerConfigGroup label={'layer.appearance'}>
1067+
<VisConfigSlider {...layer.visConfigSettings.opacity} {...visConfiguratorProps} />
1068+
<VisConfigSwitch
1069+
label={'layerVisConfigs.transparentBackground'}
1070+
{...layer.visConfigSettings.transparent}
1071+
{...visConfiguratorProps}
1072+
property="transparent"
1073+
/>
1074+
</LayerConfigGroup>
10701075
</StyledLayerVisualConfigurator>
10711076
);
10721077
}

src/constants/src/dataset.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,3 +66,12 @@ export type RasterTileMetadataSourceType = {
6666
*/
6767
export type RasterTileDatasetMetadata = (RasterTileLocalMetadata | RasterTileRemoteMetadata) &
6868
RasterTileMetadataSourceType;
69+
70+
export type WMSDatasetMetadata = {
71+
type: typeof REMOTE_TILE;
72+
remoteTileFormat: RemoteTileFormat.WMS;
73+
tilesetDataUrl: string;
74+
tilesetMetadataUrl: string;
75+
version: string;
76+
layers: {name: string; title: string; boundingBox: number[] | null}[];
77+
};

src/deckgl-layers/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,12 @@
3838
"@kepler.gl/constants": "3.1.8",
3939
"@kepler.gl/types": "3.1.8",
4040
"@kepler.gl/utils": "3.1.8",
41+
"@loaders.gl/wms": "4.3.2",
4142
"@luma.gl/constants": "^8.5.20",
4243
"@luma.gl/core": "^8.5.20",
4344
"@mapbox/geo-viewport": "^0.4.1",
4445
"@mapbox/vector-tile": "^1.3.1",
46+
"@math.gl/web-mercator": "^3.6.2",
4547
"@types/d3-array": "^2.8.0",
4648
"@types/geojson": "^7946.0.8",
4749
"@types/lodash": "4.17.5",

0 commit comments

Comments
 (0)