diff --git a/front/src/applications/editor/Editor.tsx b/front/src/applications/editor/Editor.tsx index 7736ed70ca1..a2165cf4ea7 100644 --- a/front/src/applications/editor/Editor.tsx +++ b/front/src/applications/editor/Editor.tsx @@ -1,6 +1,7 @@ import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { ChevronLeft, ChevronRight } from '@osrd-project/ui-icons'; +import { skipToken } from '@reduxjs/toolkit/query'; import cx from 'classnames'; import { isNil, toInteger } from 'lodash'; import { useTranslation } from 'react-i18next'; @@ -20,7 +21,7 @@ import useSwitchTypes from 'applications/editor/tools/switchEdition/useSwitchTyp import type { switchProps } from 'applications/editor/tools/switchProps'; import type { CommonToolState } from 'applications/editor/tools/types'; import { centerMapOnObject, selectEntities } from 'applications/editor/tools/utils'; -import type { ObjectType } from 'common/api/osrdEditoastApi'; +import { osrdEditoastApi, type ObjectType } from 'common/api/osrdEditoastApi'; import useCheckUserPrivileges from 'common/authorization/hooks/useCheckUserPrivileges'; import useProtectedAction from 'common/authorization/hooks/useProtectedAction'; import { useModal } from 'common/BootstrapSNCF/ModalSNCF'; @@ -28,6 +29,7 @@ import { LoaderState } from 'common/Loaders'; import MapButtons from 'common/Map/Buttons/MapButtons'; import MapSearch from 'common/Map/Search/MapSearch'; import { MapContextProvider } from 'common/Map/useMapContext'; +import { computeBBoxViewport } from 'common/Map/WarpedMap/core/helpers'; import { useInfraActions, useInfraID, useOsrdActions } from 'common/osrdContext'; import useInfra from 'modules/infra/useInfra'; import { useMapSettings, useMapSettingsActions } from 'reducers/commonMap'; @@ -310,6 +312,20 @@ const Editor = () => { } }, [urlInfra]); + const { data: infraBbox } = osrdEditoastApi.endpoints.getInfraByInfraIdBbox.useQuery( + infraID ? { infraId: infraID } : skipToken + ); + useMemo(() => { + if (infraBbox === undefined) return; + const { min_lat, min_lon, max_lat, max_lon } = infraBbox!; + + const newViewport = computeBBoxViewport([min_lon, min_lat, max_lon, max_lat], viewport, { + padding: 64, + }); + + setViewport(newViewport); + }, [infraBbox]); + // Lifecycle events on tools: useEffect(() => { if (toolAndState.tool.onMount) toolAndState.tool.onMount(extendedContext); diff --git a/front/src/applications/operationalStudies/views/Scenario/components/ManageTrainSchedule/Itinerary/ItineraryModalMap.tsx b/front/src/applications/operationalStudies/views/Scenario/components/ManageTrainSchedule/Itinerary/ItineraryModalMap.tsx index 9496a1da1f5..2161315180e 100644 --- a/front/src/applications/operationalStudies/views/Scenario/components/ManageTrainSchedule/Itinerary/ItineraryModalMap.tsx +++ b/front/src/applications/operationalStudies/views/Scenario/components/ManageTrainSchedule/Itinerary/ItineraryModalMap.tsx @@ -1,5 +1,6 @@ import { useCallback, useEffect, useMemo, useRef, useState, type PropsWithChildren } from 'react'; +import { skipToken } from '@reduxjs/toolkit/query'; import type { Feature, Position } from 'geojson'; import { useTranslation } from 'react-i18next'; import type { MapLayerMouseEvent, MapRef } from 'react-map-gl/maplibre'; @@ -16,6 +17,7 @@ import MapButtons from 'common/Map/Buttons/MapButtons'; import PathStepMarker, { PATH_STEP_MARKER_STATE } from 'common/Map/components/PathStepMarker'; import { SnappedMarker } from 'common/Map/Layers'; import { MapContextProvider } from 'common/Map/useMapContext'; +import { computeBBoxViewport } from 'common/Map/WarpedMap/core/helpers'; import { useInfraID } from 'common/osrdContext'; import { LAYER_GROUPS_ORDER, LAYERS } from 'config/layerOrder'; import Itinerary from 'modules/simulationResult/components/SimulationResultsMap/RenderItinerary'; @@ -103,6 +105,25 @@ const ItineraryModalMap = ({ const lastRealStepIndex = pathSteps ? pathSteps.length - (lastStepHasLocation ? 1 : 2) : -1; const isNewPlacement = isMapSelectionMode; + const locatedStepsCount = useMemo( + () => pathSteps?.filter((step) => step.location !== null).length ?? 0, + [pathSteps] + ); + + const { data: infraBbox } = osrdEditoastApi.endpoints.getInfraByInfraIdBbox.useQuery( + infraID ? { infraId: infraID } : skipToken + ); + + useMemo(() => { + if (infraBbox === undefined) return; + if (locatedStepsCount >= 2) return; + const { min_lat, min_lon, max_lat, max_lon } = infraBbox!; + + const newViewport = computeBBoxViewport([min_lon, min_lat, max_lon, max_lat], viewport, { + padding: 64, + }); + updateViewport(newViewport); + }, [infraBbox, locatedStepsCount]); useEffect(() => { if (!isMapSelectionMode) { diff --git a/front/src/applications/referenceMap/Map.tsx b/front/src/applications/referenceMap/Map.tsx index 7c49aa41b48..9f7811ad467 100644 --- a/front/src/applications/referenceMap/Map.tsx +++ b/front/src/applications/referenceMap/Map.tsx @@ -1,12 +1,16 @@ import { useCallback, useMemo, useRef } from 'react'; +import { skipToken } from '@reduxjs/toolkit/query'; import type { MapLibreEvent } from 'maplibre-gl'; import type { MapRef } from 'react-map-gl/maplibre'; +import { osrdEditoastApi } from 'common/api/osrdEditoastApi'; import BaseMap from 'common/Map/BaseMap'; import MapButtons from 'common/Map/Buttons/MapButtons'; import { MapContextProvider } from 'common/Map/useMapContext'; +import { computeBBoxViewport } from 'common/Map/WarpedMap/core/helpers'; import { useInfraID } from 'common/osrdContext'; +import { useParams } from 'react-router-dom'; import { useMapSettings, useMapSettingsActions } from 'reducers/commonMap'; import type { MapSettings, Viewport } from 'reducers/commonMap/types'; import { syncReferenceMapRouterViewport, updateReferenceMapViewport } from 'reducers/referenceMap'; @@ -58,6 +62,27 @@ const Map = () => { [layersSettings.track_sections] ); + const { urlLat } = useParams(); + const skipNextInfraAutoFocusRef = useRef(urlLat !== undefined); + const { data: infraBbox } = osrdEditoastApi.endpoints.getInfraByInfraIdBbox.useQuery( + infraID ? { infraId: infraID } : skipToken + ); + useMemo(() => { + if (infraBbox === undefined) return; + if (skipNextInfraAutoFocusRef.current) { + skipNextInfraAutoFocusRef.current = false; + return; + } + + const { min_lat, min_lon, max_lat, max_lon } = infraBbox!; + + const newViewport = computeBBoxViewport([min_lon, min_lat, max_lon, max_lat], viewport, { + padding: 64, + }); + + updateViewportChange(newViewport); + }, [infraBbox]); + return (