diff --git a/ui-manchette-with-spacetimechart/src/hooks/useManchetteWithSpaceTimeChart.ts b/ui-manchette-with-spacetimechart/src/hooks/useManchetteWithSpaceTimeChart.ts index c5f0d52a0..00c33b636 100644 --- a/ui-manchette-with-spacetimechart/src/hooks/useManchetteWithSpaceTimeChart.ts +++ b/ui-manchette-with-spacetimechart/src/hooks/useManchetteWithSpaceTimeChart.ts @@ -26,6 +26,13 @@ type State = { /** only update after a zoom. used to update back the view scroll value */ scrollTo: number | null; panning: { initialOffset: { x: number; y: number } } | null; + zoomMode: boolean; + rect: { + timeStart: Date; + timeEnd: Date; + spaceStart: number; // mm + spaceEnd: number; // mm + } | null; isProportional: boolean; waypointsChart: Waypoint[]; scales: SpaceScale[]; @@ -47,12 +54,15 @@ const useManchettesWithSpaceTimeChart = ( yOffset: 0, scrollTo: null, panning: null, + zoomMode: false, + rect: null, isProportional: true, waypointsChart: [], scales: [], }); - const { xZoom, yZoom, xOffset, yOffset, scrollTo, panning, isProportional } = state; + const { xZoom, yZoom, xOffset, yOffset, scrollTo, panning, zoomMode, rect, isProportional } = + state; const paths = usePaths(projectPathTrainResult, selectedTrain); @@ -189,19 +199,39 @@ const useManchettesWithSpaceTimeChart = ( handleXZoom(xZoom + delta, position.x); } }, - onPan: (payload: { - initialPosition: { x: number; y: number }; - position: { x: number; y: number }; - isPanning: boolean; - }) => { + onPan: (payload: Parameters>[0]) => { const diff = getDiff(payload.initialPosition, payload.position); - const newState = { ...state }; + setState((prev) => { + if (!payload.isPanning) { + return { + ...prev, + panning: null, + zoomMode: false, + }; + } + + if (state.zoomMode) { + const newRect = { + timeStart: new Date(payload.initialData.time), + timeEnd: new Date(payload.data.time), + spaceStart: payload.initialData.position, + spaceEnd: payload.data.position, + }; + + return { + ...prev, + rect: newRect, + }; + } - if (!payload.isPanning) { - newState.panning = null; - } else if (!panning) { - newState.panning = { initialOffset: { x: xOffset, y: yOffset } }; - } else { + if (!panning) { + return { + ...prev, + panning: { initialOffset: { x: xOffset, y: yOffset } }, + }; + } + + const newState = { ...prev }; const { initialOffset } = panning; newState.xOffset = initialOffset.x + diff.x; @@ -215,8 +245,8 @@ const useManchettesWithSpaceTimeChart = ( newState.yOffset = newYPos; manchetteWithSpaceTimeChartContainer.current.scrollTop = newYPos; } - } - setState(newState); + return newState; + }); }, }), [ diff --git a/ui-manchette-with-spacetimechart/src/stories/rectangle-zoom.stories.tsx b/ui-manchette-with-spacetimechart/src/stories/rectangle-zoom.stories.tsx new file mode 100644 index 000000000..d1a6de710 --- /dev/null +++ b/ui-manchette-with-spacetimechart/src/stories/rectangle-zoom.stories.tsx @@ -0,0 +1,83 @@ +import React, { useRef } from 'react'; + +import Manchette, { type ProjectPathTrainResult, type Waypoint } from '@osrd-project/ui-manchette'; +import { PathLayer, SpaceTimeChart, RectangleZoom } from '@osrd-project/ui-spacetimechart'; +import type { Meta } from '@storybook/react'; + +import '@osrd-project/ui-core/dist/theme.css'; +import '@osrd-project/ui-manchette/dist/theme.css'; +import '@osrd-project/ui-manchette-with-spacetimechart/dist/theme.css'; + +import { SAMPLE_WAYPOINTS, SAMPLE_PATHS_DATA } from '../assets/sampleData'; +import useManchettesWithSpaceTimeChart from '../hooks/useManchetteWithSpaceTimeChart'; + +type ManchetteWithSpaceTimeWrapperProps = { + waypoints: Waypoint[]; + projectPathTrainResult: ProjectPathTrainResult[]; + selectedTrain: number; +}; + +const DEFAULT_HEIGHT = 561; + +const ManchetteWithSpaceTimeWrapper = ({ + waypoints, + projectPathTrainResult, + selectedTrain, +}: ManchetteWithSpaceTimeWrapperProps) => { + const manchetteWithSpaceTimeChartRef = useRef(null); + + const { manchetteProps, spaceTimeChartProps, handleScroll } = useManchettesWithSpaceTimeChart( + waypoints, + projectPathTrainResult, + manchetteWithSpaceTimeChartRef, + selectedTrain + ); + + return ( +
+
+
+ +
+ +p.departureTime))} + {...spaceTimeChartProps} + > + {spaceTimeChartProps.paths.map((path) => ( + + ))} + + +
+
+
+ ); +}; + +const meta: Meta = { + title: 'Manchette with SpaceTimeChart/Zoom rectangle', + component: ManchetteWithSpaceTimeWrapper, +}; + +export default meta; + +export const Default = { + args: { + waypoints: SAMPLE_WAYPOINTS, + projectPathTrainResult: SAMPLE_PATHS_DATA, + selectedTrain: 1, + }, +}; diff --git a/ui-spacetimechart/src/components/RectangleZoom.tsx b/ui-spacetimechart/src/components/RectangleZoom.tsx new file mode 100644 index 000000000..7fbe06d51 --- /dev/null +++ b/ui-spacetimechart/src/components/RectangleZoom.tsx @@ -0,0 +1,29 @@ +import React from 'react'; + +import { DottedBorderRect } from './DottedBorderRect'; + +export type CanvasRectProps = { + rect: { + timeStart: Date; + timeEnd: Date; + spaceStart: number; // mm + spaceEnd: number; // mm + }; +}; + +export const RectangleZoom = ({ rect }: CanvasRectProps) => { + if (!rect) { + return null; + } + return ( + + ); +}; diff --git a/ui-spacetimechart/src/index.ts b/ui-spacetimechart/src/index.ts index ab79245f3..90784d123 100644 --- a/ui-spacetimechart/src/index.ts +++ b/ui-spacetimechart/src/index.ts @@ -9,3 +9,4 @@ export * from './components/ConflictTooltip'; export * from './components/OccupancyBlockLayer'; export * from './components/WorkScheduleLayer'; export * from './components/PatternRect'; +export * from './components/RectangleZoom';