fix(map): restore subject flight and search inset

This commit is contained in:
Codex
2026-08-09 15:06:11 +03:00
parent beb84f6de6
commit 71c1528b83
5 changed files with 65 additions and 9 deletions
+22 -1
View File
@@ -375,6 +375,7 @@ export type CesiumMapRendererHandle = {
getCameraView: () => MapCameraView | null;
fitRuntimeEntities: (entityIds?: string[]) => boolean;
focusRuntimeEntity: (entityId: string) => boolean;
focusSubjectCoordinates: (longitude: number, latitude: number) => boolean;
focusCoordinates: (longitude: number, latitude: number) => boolean;
focusGridSector: (sector: GridSectorSelection) => boolean;
focusGridMajorTile: (tile: GridMajorTileSelection) => boolean;
@@ -2744,6 +2745,25 @@ export const CesiumMapRenderer = forwardRef<CesiumMapRendererHandle, {
return true;
}, [runtimeEntities]);
const focusSubjectCoordinates = useCallback((longitude: number, latitude: number) => {
const viewer = viewerRef.current;
if (!viewer || viewer.isDestroyed()
|| !Number.isFinite(longitude) || longitude < -180 || longitude > 180
|| !Number.isFinite(latitude) || latitude < -90 || latitude > 90) return false;
// Selection can make a filtered subject visible and request navigation in
// the same React tick. In that case Cesium has not rebuilt its data source
// yet, so entity lookup cannot be the only way to fly to the subject.
// Coordinates from the authorized search/runtime fact provide the same
// explicit, inspectable camera composition without clearing user filters.
const target = Cartesian3.fromDegrees(longitude, latitude, 0, viewer.scene.globe.ellipsoid);
viewer.camera.flyToBoundingSphere(new BoundingSphere(target, 1), {
duration: 0.45,
offset: new HeadingPitchRange(0, -0.9, 8_000),
});
return true;
}, []);
useImperativeHandle(ref, () => ({
startSpiralAnimation,
stopSpiralAnimation,
@@ -2754,9 +2774,10 @@ export const CesiumMapRenderer = forwardRef<CesiumMapRendererHandle, {
fitRuntimeEntities,
focusCoordinates,
focusRuntimeEntity,
focusSubjectCoordinates,
focusGridSector,
focusGridMajorTile,
}), [fitRuntimeEntities, focusCoordinates, focusGridMajorTile, focusGridSector, focusRuntimeEntity, startSpiralAnimation, stopSpiralAnimation]);
}), [fitRuntimeEntities, focusCoordinates, focusGridMajorTile, focusGridSector, focusRuntimeEntity, focusSubjectCoordinates, startSpiralAnimation, stopSpiralAnimation]);
useEffect(() => {
const stopForPageLeave = () => stopSpiralAnimation("stopped");
+24 -6
View File
@@ -332,6 +332,15 @@ function mapFactSectorScopeValue(fact: MapRuntimeFact, field: string) {
return normalizedSectorScopeValue(fact.attributes[field]) ?? MAP_SCOPE_MISSING_VALUE;
}
function mapFactPointCoordinates(fact: MapRuntimeFact | undefined): [number, number] | null {
if (fact?.geometry?.type !== "Point") return null;
const [longitude, latitude] = fact.geometry.coordinates;
return Number.isFinite(longitude) && longitude >= -180 && longitude <= 180
&& Number.isFinite(latitude) && latitude >= -90 && latitude <= 90
? [longitude, latitude]
: null;
}
function mapFactInsideGridSector(
fact: MapRuntimeFact,
selection: GridSectorSelection,
@@ -1477,10 +1486,21 @@ export const MapFixturePreview = forwardRef<MapFixturePreviewHandle, {
activateWorkspaceWindow("subject-card");
}, [activateWorkspaceWindow, dataProductBindings, selectable, subjectDetailProfiles]);
const focusSubject = useCallback((entityId: string, coordinates?: readonly [number, number]) => {
const renderer = mapRendererRef.current;
if (!renderer) return false;
if (renderer.focusRuntimeEntity(entityId)) return true;
const fallbackCoordinates = coordinates
?? mapFactPointCoordinates(selectable.find((entity) => entity.id === entityId)?.fact);
return fallbackCoordinates
? renderer.focusSubjectCoordinates(fallbackCoordinates[0], fallbackCoordinates[1])
: false;
}, [selectable]);
const handleSelectAndFocus = useCallback((entityId: string) => {
handleSelect(entityId);
mapRendererRef.current?.focusRuntimeEntity(entityId);
}, [handleSelect]);
focusSubject(entityId);
}, [focusSubject, handleSelect]);
const handleSearchResult = useCallback((result: (typeof mapSearchResults)[number]) => {
if (result.selectable) {
@@ -1494,14 +1514,12 @@ export const MapFixturePreview = forwardRef<MapFixturePreviewHandle, {
layer.id === result.bindingId ? { ...layer, visible: true } : layer
)));
}
if (!mapRendererRef.current?.focusRuntimeEntity(result.entityId)) {
mapRendererRef.current?.focusCoordinates(result.coordinates[0], result.coordinates[1]);
}
focusSubject(result.entityId, result.coordinates);
setSearchOpen(false);
setSearchQuery("");
setRemoteSearchQuery("");
setSearchActiveIndex(0);
}, [handleSelect, mapSearchResults]);
}, [focusSubject, handleSelect]);
const handleSearchKeyDown = useCallback((event: KeyboardEvent<HTMLInputElement>) => {
if (event.key === "Escape") {
-1
View File
@@ -842,7 +842,6 @@ textarea {
.catalog-map-fixture__toolbar[data-search-open] {
width: min(42rem, calc(100% - 2rem));
padding-right: 0;
}
.catalog-map-search {