Skip to content

Commit e1199bc

Browse files
authored
Merge pull request #1004 from terrestris/fix-coordinateinfo
Fix coordinateInfo issues
2 parents 4cd272d + 8648ac1 commit e1199bc

1 file changed

Lines changed: 96 additions & 47 deletions

File tree

src/Hooks/useCoordinateInfo/useCoordinateInfo.ts

Lines changed: 96 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,11 @@ import {
3232
} from '@terrestris/ol-util';
3333

3434
import useMap from '../useMap/useMap';
35+
import useOlListener from '../useOlListener/useOlListener';
3536

3637
export interface FeatureLayerResult {
3738
feature: OlFeature;
38-
layer: WmsLayer|WmtsLayer|WfsLayer;
39+
layer: WmsLayer | WmtsLayer | WfsLayer;
3940
featureType: string;
4041
}
4142

@@ -83,53 +84,69 @@ export const useCoordinateInfo = ({
8384

8485
const map = useMap();
8586

86-
const [clickCoordinate, setClickCoordinate] = useState<OlCoordinate | undefined>();
87+
const mapView = useMemo(() => map?.getView(), [map]);
88+
89+
const [mapCoordinate, setMapCoordinate] = useState<OlCoordinate | undefined>();
8790
const [pixelCoordinate, setPixelCoordinate] = useState<OlPixel | undefined>();
8891
const [featureResults, setFeatureResults] = useState<FeatureLayerResult[] | undefined>();
8992
const [loading, setLoading] = useState<boolean>(false);
93+
const [viewResolution, setViewResolution] = useState<number | undefined>(mapView?.getResolution());
9094

9195
const abortControllers = useRef<Map<string, AbortController>>(new Map());
9296

93-
const mapView = useMemo(() => map?.getView(), [map]);
94-
const viewResolution = useMemo(() => mapView?.getResolution(), [mapView]);
9597
const viewProjection = useMemo(() => mapView?.getProjection(), [mapView]);
9698

97-
const wmsMapLayers = useMemo(() => {
99+
useOlListener(
100+
mapView,
101+
v => v.on('change:resolution', () => {
102+
setViewResolution(v.getResolution());
103+
}),
104+
[mapView]
105+
);
106+
107+
const wmsMapLayerUids = useMemo(() => {
98108
if (_isNil(map) || _isNil(pixelCoordinate)) {
99109
return [];
100110
}
101111
return map.getAllLayers()
102112
.reverse()
103113
.filter(layerFilter)
104-
.filter(l => l.getData && l.getData(pixelCoordinate) && isWmsLayer(l)) as WmsLayer[];
114+
.filter(l => l.getData && l.getData(pixelCoordinate) && isWmsLayer(l))
115+
.map(getUid);
105116
}, [layerFilter, map, pixelCoordinate]);
106117

107-
const wmtsMapLayers = useMemo(() => {
118+
const wmtsMapLayerUids = useMemo(() => {
108119
if (_isNil(map) || _isNil(pixelCoordinate)) {
109120
return [];
110121
}
111122
return map.getAllLayers()
112123
.reverse()
113124
.filter(layerFilter)
114-
.filter(l => isWmtsLayer(l)) as WmtsLayer[];
125+
.filter(l => isWmtsLayer(l))
126+
.map(getUid);
115127
}, [layerFilter, map, pixelCoordinate]);
116128

117-
const wfsMapLayers = useMemo(() => {
129+
const wfsMapLayerUids = useMemo(() => {
118130
if (_isNil(map) || _isNil(pixelCoordinate)) {
119131
return [];
120132
}
121133
return map.getAllLayers()
122134
.reverse()
123135
.filter(layerFilter)
124-
.filter(l => isWfsLayer(l)) as WfsLayer[];
136+
.filter(l => isWfsLayer(l))
137+
.map(getUid);
125138
}, [layerFilter, map, pixelCoordinate]);
126139

127-
const orderedLayers = useMemo(() => {
140+
const orderedLayerUids = useMemo(() => {
128141
if (_isNil(map)) {
129142
return [];
130143
}
131144
const all = map.getAllLayers().reverse();
132-
const relevantLayers = [...wfsMapLayers, ...wmtsMapLayers, ...wmsMapLayers];
145+
const relevantLayers = map.getAllLayers()
146+
.filter(l => {
147+
const uid = getUid(l);
148+
return wfsMapLayerUids.includes(uid) || wmtsMapLayerUids.includes(uid) || wmsMapLayerUids.includes(uid);
149+
});
133150

134151
relevantLayers.sort((a, b) => {
135152
if (_isNil(a) || _isNil(b)) {
@@ -142,8 +159,8 @@ export const useCoordinateInfo = ({
142159
return aIndex - bIndex;
143160
});
144161

145-
return relevantLayers;
146-
}, [map, wfsMapLayers, wmtsMapLayers, wmsMapLayers]);
162+
return relevantLayers.map(getUid);
163+
}, [map, wfsMapLayerUids, wmtsMapLayerUids, wmsMapLayerUids]);
147164

148165
/**
149166
* Event handler for pointer move events on the map.
@@ -253,17 +270,21 @@ export const useCoordinateInfo = ({
253270
}
254271

255272
const results: FeatureLayerResult[] = [];
256-
const layers = useWms ? wmsMapLayers : wmtsMapLayers;
273+
const layerUids = useWms ? wmsMapLayerUids : wmtsMapLayerUids;
257274

258-
for (const layer of layers) {
275+
for (const layerId of layerUids) {
259276
try {
260-
const layerId = getUid(layer);
261277
const abortController = abortControllers.current.get(layerId);
262278

263279
if (! abortController) {
264280
continue;
265281
}
266282

283+
const layer = map.getAllLayers().find(l => getUid(l) === layerId) as WmsLayer | WmtsLayer | undefined;
284+
if (!layer) {
285+
continue;
286+
}
287+
267288
const layerSource = layer.getSource();
268289
if (!layerSource) {
269290
continue;
@@ -305,7 +326,7 @@ export const useCoordinateInfo = ({
305326
if (fetchOpts instanceof Function) {
306327
opts = fetchOpts(layer);
307328
} else {
308-
opts = fetchOpts[getUid(layer)];
329+
opts = fetchOpts[layerId];
309330
}
310331

311332
const response = await fetch(featureInfoUrl, {
@@ -338,7 +359,7 @@ export const useCoordinateInfo = ({
338359
}
339360

340361
return results;
341-
}, [map, viewResolution, viewProjection, wmsMapLayers, wmtsMapLayers,
362+
}, [map, viewResolution, viewProjection, wmsMapLayerUids, wmtsMapLayerUids,
342363
getInfoFormat, featureCount, fetchOpts, drillDown]);
343364

344365
const getResultsFromWfsLayers = useCallback(async (
@@ -350,11 +371,16 @@ export const useCoordinateInfo = ({
350371

351372
const results: FeatureLayerResult[] = [];
352373

353-
for (const layer of wfsMapLayers) {
374+
for (const layerId of wfsMapLayerUids) {
354375
if (! drillDown && results.length > 0) {
355376
break;
356377
}
357378

379+
const layer = map.getAllLayers().find(l => getUid(l) === layerId) as WfsLayer | undefined;
380+
if (!layer) {
381+
continue;
382+
}
383+
358384
const wfsLayerSource = layer.getSource();
359385
if (!wfsLayerSource) {
360386
continue;
@@ -368,7 +394,7 @@ export const useCoordinateInfo = ({
368394
}
369395

370396
return results;
371-
}, [map, viewProjection, wfsMapLayers, drillDown]);
397+
}, [map, viewProjection, wfsMapLayerUids, drillDown]);
372398

373399
/**
374400
* Event handler for map events (click, double-click, pointer rest) that retrieves the coordinate of the
@@ -393,18 +419,25 @@ export const useCoordinateInfo = ({
393419

394420
const clonedCoordinate = _cloneDeep(coordinate);
395421
const clonedPixelCoordinate = _cloneDeep(evtPixelCoordinate ?? pixel);
396-
setClickCoordinate(clonedCoordinate);
422+
setMapCoordinate(clonedCoordinate);
397423
setPixelCoordinate(clonedPixelCoordinate);
398424
}, [clickEvent, map, viewProjection, viewResolution]);
399425

426+
/**
427+
* Resets featureResults when mapCoordinate changes.
428+
*/
400429
useEffect(() => {
401-
if (!_isNil(clickCoordinate)) {
430+
if (!_isNil(mapCoordinate)) {
402431
setFeatureResults(undefined);
403432
}
404-
}, [clickCoordinate]);
433+
}, [mapCoordinate]);
405434

406435
useEffect(() => {
407-
if (_isNil(clickCoordinate) || _isNil(map) || orderedLayers?.length === 0) {
436+
if (loading) {
437+
return;
438+
}
439+
440+
if (_isNil(mapCoordinate) || _isNil(map) || orderedLayerUids?.length === 0) {
408441
return;
409442
}
410443

@@ -415,37 +448,47 @@ export const useCoordinateInfo = ({
415448
abortControllers.current.forEach(controller => controller.abort());
416449
abortControllers.current.clear();
417450

418-
orderedLayers.forEach(layer => {
419-
const layerId = getUid(layer);
451+
orderedLayerUids.forEach(uid => {
420452
const abortController = new AbortController();
421-
abortControllers. current.set(layerId, abortController);
453+
abortControllers.current.set(uid, abortController);
422454
});
423455

424456
const fetchFeatures = async () => {
425457
try {
426458
setLoading(true);
459+
setFeatureResults(undefined);
427460

428461
const promises: Promise<FeatureLayerResult[]>[] = [];
462+
const allRelevantLayerUids = [...wfsMapLayerUids, ...wmtsMapLayerUids, ...wmsMapLayerUids];
463+
464+
for (const uid of orderedLayerUids) {
465+
const layerId = allRelevantLayerUids.find(id => id === uid);
466+
const layer = map.getAllLayers().find(l => getUid(l) === layerId);
429467

430-
for (const layer of orderedLayers) {
468+
if (!layer) {
469+
continue;
470+
}
431471
if (isWmsLayer(layer)) {
432-
promises.push(getResultsFromImageLayers(clickCoordinate, true));
472+
promises.push(getResultsFromImageLayers(mapCoordinate, true));
433473
} else if (isWmtsLayer(layer)) {
434-
promises.push(getResultsFromImageLayers(clickCoordinate, false));
474+
promises.push(getResultsFromImageLayers(mapCoordinate, false));
435475
} else if (isWfsLayer(layer)) {
436-
promises.push(getResultsFromWfsLayers(clickCoordinate));
437-
}
438-
439-
if (!drillDown) {
440-
break;
476+
promises.push(getResultsFromWfsLayers(mapCoordinate));
441477
}
442478
}
443479

444-
let allResults: FeatureLayerResult[][];
445-
if (drillDown) {
446-
allResults = await Promise.all(promises);
447-
} else {
448-
const firstResult = await Promise.race(promises);
480+
let allResults: FeatureLayerResult[][] = await Promise.all(promises);
481+
allResults = await Promise.all(promises);
482+
483+
if (!drillDown) {
484+
// filter empty results, order by layer index and return the first layer found
485+
const firstResult = allResults
486+
.filter(r => r.length > 0)
487+
.sort((a, b) => {
488+
const aIdx = orderedLayerUids.indexOf(getUid(a[0].layer));
489+
const bIdx = orderedLayerUids.indexOf(getUid(b[0].layer));
490+
return aIdx - bIdx;
491+
})[0] ?? [];
449492
allResults = [firstResult];
450493
}
451494

@@ -468,10 +511,13 @@ export const useCoordinateInfo = ({
468511
});
469512

470513
}, [
471-
clickCoordinate, drillDown, featureResults, getResultsFromImageLayers, getResultsFromWfsLayers, map, orderedLayers,
472-
onError, onSuccess
514+
mapCoordinate, drillDown, featureResults, getResultsFromImageLayers, getResultsFromWfsLayers, map, orderedLayerUids,
515+
onError, onSuccess, loading, wfsMapLayerUids, wmsMapLayerUids, wmtsMapLayerUids
473516
]);
474517

518+
/**
519+
* (Re)creates map event listeners whenever relevant props change (active, drilldown, clickEvent).
520+
*/
475521
useEffect(() => {
476522
let keyMove: EventsKey | undefined;
477523
let keyRest: EventsKey | undefined;
@@ -481,11 +527,11 @@ export const useCoordinateInfo = ({
481527
keyClick = map?.on(clickEvent, handleMapEvent);
482528
}
483529

484-
if (registerOnPointerMove) {
530+
if (registerOnPointerMove && !drillDown) {
485531
keyMove = map?.on('pointermove', onPointerMove);
486532
}
487533

488-
if (registerOnPointerRest) {
534+
if (registerOnPointerRest && !drillDown) {
489535
// @ts-expect-error pointerrest is no default event
490536
keyRest = map?.on('pointerrest', handleMapEvent);
491537
}
@@ -507,7 +553,7 @@ export const useCoordinateInfo = ({
507553
};
508554
}, [
509555
active, map, onPointerMove, handleMapEvent, registerOnClick,
510-
registerOnPointerMove, registerOnPointerRest, clickEvent
556+
registerOnPointerMove, registerOnPointerRest, clickEvent, drillDown
511557
]);
512558

513559
useEffect(() => {
@@ -518,6 +564,9 @@ export const useCoordinateInfo = ({
518564
};
519565
}, [viewResolution]);
520566

567+
/**
568+
* Update mouse cursor when GFI is loading.
569+
*/
521570
useEffect(() => {
522571
if (_isNil(map)) {
523572
return;
@@ -528,7 +577,7 @@ export const useCoordinateInfo = ({
528577
// We want to propagate the state here so the variables do
529578
// not change on every render cycle.
530579
return {
531-
clickCoordinate,
580+
clickCoordinate: mapCoordinate,
532581
features: featureResults,
533582
loading,
534583
pixelCoordinate

0 commit comments

Comments
 (0)