From 4ff5a782a98485c291255d2591bbadb1548bab6c Mon Sep 17 00:00:00 2001 From: Alexandre Damiron Date: Fri, 3 Nov 2023 16:03:45 +0100 Subject: [PATCH 1/5] front: restore miniGET sync by storing scale domain front:no use of chartXDomain front: no more sync by store front: no nice remove useless func def --- .../views/SimulationResults.tsx | 16 +++------- .../SpaceTimeChart/SpaceTimeChart.tsx | 5 +++- .../components/TimeLine/TimeLine.tsx | 29 ++++++++++++++----- front/src/reducers/osrdsimulation/actions.ts | 9 ------ front/src/reducers/osrdsimulation/index.ts | 5 ---- front/src/reducers/osrdsimulation/types.ts | 1 - 6 files changed, 30 insertions(+), 35 deletions(-) diff --git a/front/src/applications/operationalStudies/views/SimulationResults.tsx b/front/src/applications/operationalStudies/views/SimulationResults.tsx index f3132d6710a..f27863f2572 100644 --- a/front/src/applications/operationalStudies/views/SimulationResults.tsx +++ b/front/src/applications/operationalStudies/views/SimulationResults.tsx @@ -20,7 +20,6 @@ import TimeButtons from 'modules/simulationResult/components/TimeButtons'; // TIMELINE DISABLED // import TimeLine from 'modules/simulationResult/components/TimeLine/TimeLine'; import TrainDetails from 'modules/simulationResult/components/TrainDetails'; import DriverTrainSchedule from 'modules/trainschedule/components/DriverTrainSchedule/DriverTrainSchedule'; -import getScaleDomainFromValues from 'modules/simulationResult/components/ChartHelpers/getScaleDomainFromValues'; import SpaceCurvesSlopes from 'modules/simulationResult/components/SpaceCurvesSlopes'; import SpaceTimeChart from 'modules/simulationResult/components/SpaceTimeChart/SpaceTimeChart'; import SpeedSpaceChart from 'modules/simulationResult/components/SpeedSpaceChart/SpeedSpaceChart'; @@ -58,6 +57,8 @@ export default function SimulationResults({ const [initialHeightOfSpaceCurvesSlopesChart, setInitialHeightOfSpaceCurvesSlopesChart] = useState(heightOfSpaceCurvesSlopesChart); + const [chartXScaleDomain] = useState([]); + // X scale domain shared between SpeedSpace and SpaceCurvesSlopes charts. const [positionScaleDomain, setPositionScaleDomain] = useState({ initial: [], @@ -119,17 +120,6 @@ export default function SimulationResults({ } }, [extViewport]); - useEffect(() => { - if (selectedTrain) { - const positions = selectedTrain.base.speeds.map((speed) => speed.position); - const newPositionsScaleDomain = getScaleDomainFromValues(positions); - setPositionScaleDomain({ - initial: newPositionsScaleDomain, - current: newPositionsScaleDomain, - }); - } - }, [selectedTrain]); - return simulation.trains.length === 0 && !isUpdating ? (

{t('noData')}

) : ( @@ -156,6 +146,7 @@ export default function SimulationResults({ chart={chart} selectedTrainId={selectedTrain?.id || simulation.trains[0].id} trains={simulation.trains as SimulationReport[]} + onChangeXScaleDomain={setChartXScaleDomain} /> )} */} @@ -185,6 +176,7 @@ export default function SimulationResults({ dispatchUpdateSelectedTrainId={dispatchUpdateSelectedTrainId} dispatchPersistentUpdateSimulation={dispatchPersistentUpdateSimulation} setTrainResultsToFetch={setTrainResultsToFetch} + chartXScaleDomain={chartXScaleDomain} /> )} diff --git a/front/src/modules/simulationResult/components/SpaceTimeChart/SpaceTimeChart.tsx b/front/src/modules/simulationResult/components/SpaceTimeChart/SpaceTimeChart.tsx index 3dc5d3ff032..a74352ca467 100644 --- a/front/src/modules/simulationResult/components/SpaceTimeChart/SpaceTimeChart.tsx +++ b/front/src/modules/simulationResult/components/SpaceTimeChart/SpaceTimeChart.tsx @@ -56,6 +56,7 @@ export type SpaceTimeChartProps = { dispatchUpdateSelectedTrainId: DispatchUpdateSelectedTrainId; dispatchPersistentUpdateSimulation: DispatchPersistentUpdateSimulation; setTrainResultsToFetch?: (trainSchedulesIDs?: number[]) => void; + chartXScaleDomain?: number[] | Date[]; }; export default function SpaceTimeChart(props: SpaceTimeChartProps) { @@ -74,6 +75,7 @@ export default function SpaceTimeChart(props: SpaceTimeChartProps) { dispatchUpdateSelectedTrainId, dispatchPersistentUpdateSimulation, setTrainResultsToFetch = noop, + chartXScaleDomain, } = props; const [baseHeight, setBaseHeight] = useState(initialHeight); @@ -182,6 +184,7 @@ export default function SpaceTimeChart(props: SpaceTimeChartProps) { const trainsToDraw = trainSimulations.map((train) => createTrain(CHART_AXES.SPACE_TIME, train as Train) ); + drawAllTrains( allowancesSettings, chart, @@ -209,7 +212,7 @@ export default function SpaceTimeChart(props: SpaceTimeChartProps) { */ useEffect(() => { redrawChart(); - }, [resetChart, rotate, selectedTrain, trainSimulations, height]); + }, [resetChart, rotate, selectedTrain, trainSimulations, height, chartXScaleDomain]); /* add behaviour on zoom and mousemove/mouseover/wheel on the new chart each time the chart changes */ useEffect(() => { diff --git a/front/src/modules/simulationResult/components/TimeLine/TimeLine.tsx b/front/src/modules/simulationResult/components/TimeLine/TimeLine.tsx index 4052468060d..e0cbf6ba25a 100644 --- a/front/src/modules/simulationResult/components/TimeLine/TimeLine.tsx +++ b/front/src/modules/simulationResult/components/TimeLine/TimeLine.tsx @@ -34,9 +34,10 @@ type TimeLineProps = { chart: Chart; selectedTrainId: number; trains: SimulationReport[]; + onChangeXScaleDomain: (domain: Date[]) => void; }; -const TimeLine = ({ chart, selectedTrainId, trains }: TimeLineProps) => { +const TimeLine = ({ chart, selectedTrainId, trains, onChangeXScaleDomain }: TimeLineProps) => { const ref = useRef(null); const [svgState, setSvg] = useState< d3.Selection | undefined @@ -119,8 +120,8 @@ const TimeLine = ({ chart, selectedTrainId, trains }: TimeLineProps) => { const xScale = d3 .scaleTime() .domain(dataRange) - .range([dimensions.margin.left, dimensions.width - dimensions.margin.right]) - .nice(); + .range([dimensions.margin.left, dimensions.width - dimensions.margin.right]); + const axisBottomX = d3 .axisBottom(xScale) .tickFormat((date) => d3.timeFormat('%H:%M')(date as Date)); @@ -158,10 +159,20 @@ const TimeLine = ({ chart, selectedTrainId, trains }: TimeLineProps) => { // drag behaviour let dragValue = 0; - const drag = d3.drag().on('drag', (event) => { - dragValue += event.dx; - d3.select('#rectZoomTimeLine').attr('transform', `translate(${dragValue},0)`); - }); + const drag = d3 + .drag() + .on('end', () => { + const delta = xScale.invert(dragValue).getTime() - xScale.domain()[0].getTime(); + const newX0 = new Date(chartRect[0].getTime() + delta); + const newX1 = new Date(chartRect[1].getTime() + delta); + const newChart = { ...chart }; + newChart.x.domain([newX0, newX1]); + onChangeXScaleDomain(newChart.x.domain() as Date[]); + }) + .on('drag', (event) => { + dragValue += event.dx; + d3.select('#rectZoomTimeLine').attr('transform', `translate(${dragValue},0)`); + }); svg .append('rect') @@ -179,6 +190,10 @@ const TimeLine = ({ chart, selectedTrainId, trains }: TimeLineProps) => { drawChart(); }, [trains]); + useEffect(() => { + drawChart(); + }, [chart]); + useEffect(() => { if (svgState) { moveTimePosition(svgState); diff --git a/front/src/reducers/osrdsimulation/actions.ts b/front/src/reducers/osrdsimulation/actions.ts index 0e8e13c10d6..82772546a93 100644 --- a/front/src/reducers/osrdsimulation/actions.ts +++ b/front/src/reducers/osrdsimulation/actions.ts @@ -6,7 +6,6 @@ import { SimulationSnapshot, OsrdSimulationState } from './types'; // Action Types export const UPDATE_CHART = 'osrdsimu/UPDATE_CHART'; -export const UPDATE_CHARTXGEV = 'osrdsimu/UPDATE_CHARTXGEV'; export const UPDATE_HOVER_POSITION = 'osrdsimu/UPDATE_HOVER_POSITION'; export const UPDATE_IS_PLAYING = 'osrdsimu/UPDATE_IS_PLAYING'; export const UPDATE_IS_UPDATING = 'osrdsimu/UPDATE_IS_UPDATING'; @@ -26,14 +25,6 @@ export const UNDO_SIMULATION = 'osrdsimu/UNDO_SIMULATION'; export const REDO_SIMULATION = 'osrdsimu/REDO_SIMULATION'; // Functions -export function updateChartXGEV(chartXGEV: OsrdSimulationState['chartXGEV']) { - return (dispatch: Dispatch) => { - dispatch({ - type: UPDATE_CHARTXGEV, - chartXGEV, - }); - }; -} export function updateIsPlaying(isPlaying: OsrdSimulationState['isPlaying']) { return (dispatch: Dispatch) => { dispatch({ diff --git a/front/src/reducers/osrdsimulation/index.ts b/front/src/reducers/osrdsimulation/index.ts index 4479482de69..50a336f46dd 100644 --- a/front/src/reducers/osrdsimulation/index.ts +++ b/front/src/reducers/osrdsimulation/index.ts @@ -15,7 +15,6 @@ import undoableSimulation from './simulation'; import { UPDATE_CHART, - UPDATE_CHARTXGEV, UPDATE_IS_PLAYING, UPDATE_IS_UPDATING, UPDATE_ALLOWANCES_SETTINGS, @@ -33,7 +32,6 @@ import { // Reducer export const initialState: OsrdSimulationState = { chart: undefined, - chartXGEV: undefined, isPlaying: false, isUpdating: false, allowancesSettings: undefined, @@ -66,9 +64,6 @@ export default function reducer(inputState: OsrdSimulationState | undefined, act case UPDATE_CHART: draft.chart = action.chart; break; - case UPDATE_CHARTXGEV: - draft.chartXGEV = action.chartXGEV; - break; case UPDATE_IS_PLAYING: draft.isPlaying = action.isPlaying; break; diff --git a/front/src/reducers/osrdsimulation/types.ts b/front/src/reducers/osrdsimulation/types.ts index 198e6b68f04..ac34b7356e6 100644 --- a/front/src/reducers/osrdsimulation/types.ts +++ b/front/src/reducers/osrdsimulation/types.ts @@ -225,7 +225,6 @@ export type SpeedSpaceSettingsType = { [key in SpeedSpaceSettingKey]: boolean }; export interface OsrdSimulationState { redirectToGraph?: boolean; chart?: Chart; - chartXGEV?: Chart['x']; isPlaying: boolean; isUpdating: boolean; allowancesSettings?: AllowancesSettings; From 2c4493e7700084df8b9d5c2cfb167aa0e8f67d3f Mon Sep 17 00:00:00 2001 From: alexandredamiron Date: Thu, 7 Dec 2023 16:55:09 +0100 Subject: [PATCH 2/5] front:finish merge --- .../operationalStudies/views/SimulationResults.tsx | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/front/src/applications/operationalStudies/views/SimulationResults.tsx b/front/src/applications/operationalStudies/views/SimulationResults.tsx index f27863f2572..67f77a6446f 100644 --- a/front/src/applications/operationalStudies/views/SimulationResults.tsx +++ b/front/src/applications/operationalStudies/views/SimulationResults.tsx @@ -120,6 +120,17 @@ export default function SimulationResults({ } }, [extViewport]); + useEffect(() => { + if (selectedTrain) { + const positions = selectedTrain.base.speeds.map((speed) => speed.position); + const newPositionsScaleDomain = getScaleDomainFromValues(positions); + setPositionScaleDomain({ + initial: newPositionsScaleDomain, + current: newPositionsScaleDomain, + }); + } + }, [selectedTrain]); + return simulation.trains.length === 0 && !isUpdating ? (

{t('noData')}

) : ( From 312d0ff1ae4203c9a7eb7ee2105900ab12e384e8 Mon Sep 17 00:00:00 2001 From: Clara Ni Date: Mon, 22 Jan 2024 17:57:50 +0100 Subject: [PATCH 3/5] rebase and fix timeline --- .../views/SimulationResults.tsx | 20 +++-- .../SpaceTimeChart/SpaceTimeChart.tsx | 79 ++++++++++++------- .../components/SpaceTimeChart/d3Helpers.ts | 3 +- .../components/TimeLine/TimeLine.tsx | 70 ++++++++-------- front/src/modules/simulationResult/consts.ts | 5 ++ 5 files changed, 110 insertions(+), 67 deletions(-) diff --git a/front/src/applications/operationalStudies/views/SimulationResults.tsx b/front/src/applications/operationalStudies/views/SimulationResults.tsx index 67f77a6446f..8df926383c7 100644 --- a/front/src/applications/operationalStudies/views/SimulationResults.tsx +++ b/front/src/applications/operationalStudies/views/SimulationResults.tsx @@ -23,9 +23,10 @@ import DriverTrainSchedule from 'modules/trainschedule/components/DriverTrainSch import SpaceCurvesSlopes from 'modules/simulationResult/components/SpaceCurvesSlopes'; import SpaceTimeChart from 'modules/simulationResult/components/SpaceTimeChart/SpaceTimeChart'; import SpeedSpaceChart from 'modules/simulationResult/components/SpeedSpaceChart/SpeedSpaceChart'; -import type { PositionScaleDomain } from 'modules/simulationResult/consts'; +import type { PositionScaleDomain, TimeScaleDomain } from 'modules/simulationResult/consts'; import { Train } from 'reducers/osrdsimulation/types'; import { useStoreDataForSpaceTimeChart } from 'modules/simulationResult/components/SpaceTimeChart/useStoreDataForSpaceTimeChart'; +import getScaleDomainFromValues from 'modules/simulationResult/components/ChartHelpers/getScaleDomainFromValues'; const MAP_MIN_HEIGHT = 450; @@ -57,7 +58,10 @@ export default function SimulationResults({ const [initialHeightOfSpaceCurvesSlopesChart, setInitialHeightOfSpaceCurvesSlopesChart] = useState(heightOfSpaceCurvesSlopesChart); - const [chartXScaleDomain] = useState([]); + const [timeScaleDomain, setTimeScaleDomain] = useState({ + range: undefined, + source: undefined, + }); // X scale domain shared between SpeedSpace and SpaceCurvesSlopes charts. const [positionScaleDomain, setPositionScaleDomain] = useState({ @@ -152,14 +156,15 @@ export default function SimulationResults({ {/* SIMULATION: TIMELINE — TEMPORARILY DISABLED - {simulation.trains.length && chart && ( + {simulation.trains.length && ( - )} */} + )} + */} {/* SIMULATION : SPACE TIME CHART */}
@@ -187,7 +192,8 @@ export default function SimulationResults({ dispatchUpdateSelectedTrainId={dispatchUpdateSelectedTrainId} dispatchPersistentUpdateSimulation={dispatchPersistentUpdateSimulation} setTrainResultsToFetch={setTrainResultsToFetch} - chartXScaleDomain={chartXScaleDomain} + timeScaleDomain={timeScaleDomain} + setTimeScaleDomain={setTimeScaleDomain} /> )}
diff --git a/front/src/modules/simulationResult/components/SpaceTimeChart/SpaceTimeChart.tsx b/front/src/modules/simulationResult/components/SpaceTimeChart/SpaceTimeChart.tsx index a74352ca467..1012e9886a5 100644 --- a/front/src/modules/simulationResult/components/SpaceTimeChart/SpaceTimeChart.tsx +++ b/front/src/modules/simulationResult/components/SpaceTimeChart/SpaceTimeChart.tsx @@ -1,10 +1,10 @@ import { noop } from 'lodash'; -import React, { useEffect, useRef, useState, useCallback, useMemo } from 'react'; +import React, { useEffect, useRef, useState, useCallback } from 'react'; import { CgLoadbar } from 'react-icons/cg'; import { GiResize } from 'react-icons/gi'; import { Rnd } from 'react-rnd'; -import { CHART_AXES } from 'modules/simulationResult/consts'; +import { CHART_AXES, TimeScaleDomain } from 'modules/simulationResult/consts'; import { enableInteractivity, traceVerticalLine, @@ -51,12 +51,13 @@ export type SpaceTimeChartProps = { selectedProjection?: OsrdSimulationState['selectedProjection']; simulation?: SimulationSnapshot; simulationIsPlaying?: boolean; + timeScaleDomain?: TimeScaleDomain; isDisplayed?: boolean; onSetBaseHeight?: (newHeight: number) => void; dispatchUpdateSelectedTrainId: DispatchUpdateSelectedTrainId; dispatchPersistentUpdateSimulation: DispatchPersistentUpdateSimulation; setTrainResultsToFetch?: (trainSchedulesIDs?: number[]) => void; - chartXScaleDomain?: number[] | Date[]; + setTimeScaleDomain?: React.Dispatch>; }; export default function SpaceTimeChart(props: SpaceTimeChartProps) { @@ -70,12 +71,13 @@ export default function SpaceTimeChart(props: SpaceTimeChartProps) { selectedProjection, simulation, simulationIsPlaying = false, + timeScaleDomain, isDisplayed = true, onSetBaseHeight = noop, dispatchUpdateSelectedTrainId, dispatchPersistentUpdateSimulation, setTrainResultsToFetch = noop, - chartXScaleDomain, + setTimeScaleDomain, } = props; const [baseHeight, setBaseHeight] = useState(initialHeight); @@ -90,15 +92,14 @@ export default function SpaceTimeChart(props: SpaceTimeChartProps) { SimulationSnapshot['trains'] | undefined >(undefined); - const timeScaleRange: [Date, Date] = useMemo(() => { - if (chart) return (rotate ? chart.y.domain() : chart.x.domain()) as [Date, Date]; - return [new Date(), new Date()]; - }, [chart]); - /* coordinate the vertical cursors with other graphs (GEV for instance) */ const { timePosition, updateTimePosition } = useChartSynchronizer( (newTimePosition, positionValues) => { - if (dateIsInRange(newTimePosition, timeScaleRange)) { + if ( + timeScaleDomain && + timeScaleDomain.range && + dateIsInRange(newTimePosition, timeScaleDomain.range) + ) { traceVerticalLine(chart, CHART_AXES.SPACE_TIME, positionValues, newTimePosition, rotate); } }, @@ -179,15 +180,16 @@ export default function SpaceTimeChart(props: SpaceTimeChartProps) { dragShiftTrain(dragOffset); }, [dragOffset]); - const redrawChart = () => { + const redrawChart = (newResizedChart?: Chart) => { if (trainSimulations && allowancesSettings) { const trainsToDraw = trainSimulations.map((train) => createTrain(CHART_AXES.SPACE_TIME, train as Train) ); - drawAllTrains( + const newChart = newResizedChart ?? chart; + const newDrawnedChart = drawAllTrains( allowancesSettings, - chart, + newChart, CHART_ID, dispatchUpdateSelectedTrainId, height, @@ -196,11 +198,11 @@ export default function SpaceTimeChart(props: SpaceTimeChartProps) { rotate, selectedProjection, selectedTrain as Train, - setChart, setDragOffset, trainSimulations as Train[], trainsToDraw ); + setChart(newDrawnedChart); setResetChart(false); } }; @@ -212,22 +214,45 @@ export default function SpaceTimeChart(props: SpaceTimeChartProps) { */ useEffect(() => { redrawChart(); - }, [resetChart, rotate, selectedTrain, trainSimulations, height, chartXScaleDomain]); + }, [resetChart, rotate, selectedTrain, trainSimulations, height]); + + /* redraw the trains if the time scale range has changed from Timeline */ + useEffect(() => { + if (chart && timeScaleDomain && timeScaleDomain.source !== 'SpaceTimeChart') { + const currentTimeRange = timeScaleDomain.range; + if (currentTimeRange) { + const newChart = { ...chart }; + newChart.x.domain(currentTimeRange); + redrawChart(); + } + } + }, [timeScaleDomain]); /* add behaviour on zoom and mousemove/mouseover/wheel on the new chart each time the chart changes */ useEffect(() => { - if (trainSimulations && selectedTrain) { - const dataSimulation = createTrain(CHART_AXES.SPACE_TIME, selectedTrain as Train); - enableInteractivity( - chart, - dataSimulation, - CHART_AXES.SPACE_TIME, - rotate, - setChart, - simulationIsPlaying, - updateTimePosition, - timeScaleRange - ); + if (chart) { + const newTimeScaleRange = (rotate ? chart.y.domain() : chart.x.domain()) as [Date, Date]; + + if (setTimeScaleDomain) { + setTimeScaleDomain({ + range: newTimeScaleRange, + source: 'SpaceTimeChart', + }); + } + + if (trainSimulations && selectedTrain && timeScaleDomain) { + const dataSimulation = createTrain(CHART_AXES.SPACE_TIME, selectedTrain as Train); + enableInteractivity( + chart, + dataSimulation, + CHART_AXES.SPACE_TIME, + rotate, + setChart, + simulationIsPlaying, + updateTimePosition, + newTimeScaleRange + ); + } } }, [chart]); diff --git a/front/src/modules/simulationResult/components/SpaceTimeChart/d3Helpers.ts b/front/src/modules/simulationResult/components/SpaceTimeChart/d3Helpers.ts index 00663a16e13..4f4409782a1 100644 --- a/front/src/modules/simulationResult/components/SpaceTimeChart/d3Helpers.ts +++ b/front/src/modules/simulationResult/components/SpaceTimeChart/d3Helpers.ts @@ -59,7 +59,6 @@ const drawAllTrains = ( rotate: boolean, selectedProjection: OsrdSimulationState['selectedProjection'], selectedTrain: Train, - setChart: React.Dispatch>, setDragOffset: React.Dispatch>, simulationTrains: Train[], trainsToDraw: SimulationTrain[] @@ -96,7 +95,7 @@ const drawAllTrains = ( train ); }); - setChart(chartLocal); + return chartLocal; }; export { drawOPs, drawAllTrains }; diff --git a/front/src/modules/simulationResult/components/TimeLine/TimeLine.tsx b/front/src/modules/simulationResult/components/TimeLine/TimeLine.tsx index e0cbf6ba25a..495db1b6ce3 100644 --- a/front/src/modules/simulationResult/components/TimeLine/TimeLine.tsx +++ b/front/src/modules/simulationResult/components/TimeLine/TimeLine.tsx @@ -4,8 +4,8 @@ import React, { useEffect, useMemo, useRef, useState } from 'react'; import { SimulationReport } from 'common/api/osrdEditoastApi'; import { getDirection, gridX } from 'modules/simulationResult/components/ChartHelpers/ChartHelpers'; import { useChartSynchronizer } from 'modules/simulationResult/components/ChartHelpers/ChartSynchronizer'; -import { Chart } from 'reducers/osrdsimulation/types'; import { sec2datetime } from 'utils/timeManipulation'; +import { TimeScaleDomain } from 'modules/simulationResult/consts'; const drawTrain = ( train: SimulationReport, @@ -31,13 +31,18 @@ const drawTrain = ( }; type TimeLineProps = { - chart: Chart; + timeScaleDomain?: TimeScaleDomain; selectedTrainId: number; trains: SimulationReport[]; - onChangeXScaleDomain: (domain: Date[]) => void; + onChangeTimeScaleDomain: (domain: TimeScaleDomain) => void; }; -const TimeLine = ({ chart, selectedTrainId, trains, onChangeXScaleDomain }: TimeLineProps) => { +const TimeLine = ({ + timeScaleDomain, + selectedTrainId, + trains, + onChangeTimeScaleDomain, +}: TimeLineProps) => { const ref = useRef(null); const [svgState, setSvg] = useState< d3.Selection | undefined @@ -93,7 +98,6 @@ const TimeLine = ({ chart, selectedTrainId, trains, onChangeXScaleDomain }: Time if (d3.select(ref.current)) { d3.select(ref.current).select('svg').remove(); } - const chartRect = (chart.rotate ? chart.y.domain() : chart.x.domain()) as Date[]; const svg = d3 .select(ref.current) @@ -158,30 +162,34 @@ const TimeLine = ({ chart, selectedTrainId, trains, onChangeXScaleDomain }: Time trains.map((train) => drawTrain(train, selectedTrainId, xScale, svg, dimensions.height)); // drag behaviour - let dragValue = 0; - const drag = d3 - .drag() - .on('end', () => { - const delta = xScale.invert(dragValue).getTime() - xScale.domain()[0].getTime(); - const newX0 = new Date(chartRect[0].getTime() + delta); - const newX1 = new Date(chartRect[1].getTime() + delta); - const newChart = { ...chart }; - newChart.x.domain([newX0, newX1]); - onChangeXScaleDomain(newChart.x.domain() as Date[]); - }) - .on('drag', (event) => { - dragValue += event.dx; - d3.select('#rectZoomTimeLine').attr('transform', `translate(${dragValue},0)`); - }); - - svg - .append('rect') - .attr('id', 'rectZoomTimeLine') - .attr('x', xScale(chartRect[0])) - .attr('y', 1) - .attr('width', xScale(chartRect[1]) - xScale(chartRect[0])) - .attr('height', dimensions.height - 1) - .call(drag); + const currentTimeScaleRange = timeScaleDomain?.range; + if (currentTimeScaleRange) { + let dragValue = 0; + const drag = d3 + .drag() + .on('end', () => { + const delta = xScale.invert(dragValue).getTime() - xScale.domain()[0].getTime(); + const newX0 = new Date(currentTimeScaleRange[0].getTime() + delta); + const newX1 = new Date(currentTimeScaleRange[1].getTime() + delta); + onChangeTimeScaleDomain({ + range: [newX0, newX1], + source: 'Timeline', + }); + }) + .on('drag', (event) => { + dragValue += event.dx; + d3.select('#rectZoomTimeLine').attr('transform', `translate(${dragValue},0)`); + }); + + svg + .append('rect') + .attr('id', 'rectZoomTimeLine') + .attr('x', xScale(currentTimeScaleRange[0])) + .attr('y', 1) + .attr('width', xScale(currentTimeScaleRange[1]) - xScale(currentTimeScaleRange[0])) + .attr('height', dimensions.height - 1) + .call(drag); + } setSvg(svg); }; @@ -191,8 +199,8 @@ const TimeLine = ({ chart, selectedTrainId, trains, onChangeXScaleDomain }: Time }, [trains]); useEffect(() => { - drawChart(); - }, [chart]); + if (timeScaleDomain?.source !== 'Timeline') drawChart(); + }, [timeScaleDomain]); useEffect(() => { if (svgState) { diff --git a/front/src/modules/simulationResult/consts.ts b/front/src/modules/simulationResult/consts.ts index 700b3bf8e41..68d0eb49f4f 100644 --- a/front/src/modules/simulationResult/consts.ts +++ b/front/src/modules/simulationResult/consts.ts @@ -51,3 +51,8 @@ export type PositionScaleDomain = { current: number[]; source?: 'SpeedSpaceChart' | 'SpaceCurvesSlopes'; }; + +export type TimeScaleDomain = { + range?: [Date, Date]; + source?: 'SpaceTimeChart' | 'Timeline'; +}; From 3f37a370a58e10601f0355bf7eb4f60b736199bc Mon Sep 17 00:00:00 2001 From: Clara Ni Date: Tue, 23 Jan 2024 17:58:14 +0100 Subject: [PATCH 4/5] fix comments --- .../views/SimulationResults.tsx | 4 +- .../components/ChartHelpers/ChartHelpers.ts | 14 ++----- .../ChartHelpers/enableInteractivity.tsx | 8 +--- .../components/SpaceCurvesSlopes.tsx | 3 +- .../SpaceTimeChart/SpaceTimeChart.tsx | 37 +++++++++---------- .../SpeedSpaceChart/SpeedSpaceChart.tsx | 7 +--- .../components/SpeedSpaceChart/d3Helpers.ts | 10 ++--- .../components/TimeLine/TimeLine.tsx | 8 ++-- front/src/modules/simulationResult/consts.ts | 29 +++------------ front/src/modules/simulationResult/types.ts | 10 +++++ 10 files changed, 53 insertions(+), 77 deletions(-) create mode 100644 front/src/modules/simulationResult/types.ts diff --git a/front/src/applications/operationalStudies/views/SimulationResults.tsx b/front/src/applications/operationalStudies/views/SimulationResults.tsx index 8df926383c7..bc25ab1754d 100644 --- a/front/src/applications/operationalStudies/views/SimulationResults.tsx +++ b/front/src/applications/operationalStudies/views/SimulationResults.tsx @@ -23,7 +23,7 @@ import DriverTrainSchedule from 'modules/trainschedule/components/DriverTrainSch import SpaceCurvesSlopes from 'modules/simulationResult/components/SpaceCurvesSlopes'; import SpaceTimeChart from 'modules/simulationResult/components/SpaceTimeChart/SpaceTimeChart'; import SpeedSpaceChart from 'modules/simulationResult/components/SpeedSpaceChart/SpeedSpaceChart'; -import type { PositionScaleDomain, TimeScaleDomain } from 'modules/simulationResult/consts'; +import type { PositionScaleDomain, TimeScaleDomain } from 'modules/simulationResult/types'; import { Train } from 'reducers/osrdsimulation/types'; import { useStoreDataForSpaceTimeChart } from 'modules/simulationResult/components/SpaceTimeChart/useStoreDataForSpaceTimeChart'; import getScaleDomainFromValues from 'modules/simulationResult/components/ChartHelpers/getScaleDomainFromValues'; @@ -161,7 +161,7 @@ export default function SimulationResults({ timeScaleDomain={timeScaleDomain} selectedTrainId={selectedTrain?.id || simulation.trains[0].id} trains={simulation.trains as SimulationReport[]} - onChangeTimeScaleDomain={setTimeScaleDomain} + onTimeScaleDomainChange={setTimeScaleDomain} /> )} */} diff --git a/front/src/modules/simulationResult/components/ChartHelpers/ChartHelpers.ts b/front/src/modules/simulationResult/components/ChartHelpers/ChartHelpers.ts index 4eab98c72d1..bb81ed4fab7 100644 --- a/front/src/modules/simulationResult/components/ChartHelpers/ChartHelpers.ts +++ b/front/src/modules/simulationResult/components/ChartHelpers/ChartHelpers.ts @@ -17,15 +17,7 @@ import { SimulationD3Scale, PositionsSpeedTimes, } from 'reducers/osrdsimulation/types'; -import { - ChartAxes, - GRADIENT, - ListValues, - TIME, - XAxis, - Y2Axis, - YAxis, -} from 'modules/simulationResult/consts'; +import { ChartAxes, ListValues, XAxis, Y2Axis, YAxis } from 'modules/simulationResult/consts'; export function sec2d3datetime(time: number) { return d3.timeParse('%H:%M:%S')(sec2time(time)); @@ -383,9 +375,9 @@ const specificInterpolateOnTime = return positionInterpolated; }; -export const isSpaceTimeChart = (keyValues: ChartAxes) => keyValues[0] === TIME; +export const isSpaceTimeChart = (keyValues: ChartAxes) => keyValues[0] === 'time'; -export const isSpaceSlopesCurves = (keyValues: ChartAxes) => keyValues[1] === GRADIENT; +export const isSpaceSlopesCurves = (keyValues: ChartAxes) => keyValues[1] === 'gradient'; export function trainWithDepartureAndArrivalTimes(train: Train, dragOffset = 0) { const firstStop = train.base.stops[0]; diff --git a/front/src/modules/simulationResult/components/ChartHelpers/enableInteractivity.tsx b/front/src/modules/simulationResult/components/ChartHelpers/enableInteractivity.tsx index c7e3587b0ed..7d869e8ba50 100644 --- a/front/src/modules/simulationResult/components/ChartHelpers/enableInteractivity.tsx +++ b/front/src/modules/simulationResult/components/ChartHelpers/enableInteractivity.tsx @@ -12,12 +12,8 @@ import { getAxis, isSpaceTimeChart, } from 'modules/simulationResult/components/ChartHelpers/ChartHelpers'; -import { - CHART_AXES, - LIST_VALUES, - type ChartAxes, - type PositionScaleDomain, -} from 'modules/simulationResult/consts'; +import { CHART_AXES, LIST_VALUES, type ChartAxes } from 'modules/simulationResult/consts'; +import type { PositionScaleDomain } from 'modules/simulationResult/types'; import drawGuideLines from 'modules/simulationResult/components/ChartHelpers/drawGuideLines'; import type { SpaceCurvesSlopesData } from 'modules/simulationResult/components/SpaceCurvesSlopes'; import type { diff --git a/front/src/modules/simulationResult/components/SpaceCurvesSlopes.tsx b/front/src/modules/simulationResult/components/SpaceCurvesSlopes.tsx index 08c5433777a..e35a31893b2 100644 --- a/front/src/modules/simulationResult/components/SpaceCurvesSlopes.tsx +++ b/front/src/modules/simulationResult/components/SpaceCurvesSlopes.tsx @@ -3,7 +3,8 @@ import { useSelector } from 'react-redux'; import * as d3 from 'd3'; import { CgLoadbar } from 'react-icons/cg'; -import { CHART_AXES, type PositionScaleDomain } from 'modules/simulationResult/consts'; +import { CHART_AXES } from 'modules/simulationResult/consts'; +import type { PositionScaleDomain } from 'modules/simulationResult/types'; import { defineLinear, interpolateOnPosition, diff --git a/front/src/modules/simulationResult/components/SpaceTimeChart/SpaceTimeChart.tsx b/front/src/modules/simulationResult/components/SpaceTimeChart/SpaceTimeChart.tsx index 1012e9886a5..ff466662f36 100644 --- a/front/src/modules/simulationResult/components/SpaceTimeChart/SpaceTimeChart.tsx +++ b/front/src/modules/simulationResult/components/SpaceTimeChart/SpaceTimeChart.tsx @@ -4,7 +4,8 @@ import { CgLoadbar } from 'react-icons/cg'; import { GiResize } from 'react-icons/gi'; import { Rnd } from 'react-rnd'; -import { CHART_AXES, TimeScaleDomain } from 'modules/simulationResult/consts'; +import { CHART_AXES } from 'modules/simulationResult/consts'; +import type { TimeScaleDomain } from 'modules/simulationResult/types'; import { enableInteractivity, traceVerticalLine, @@ -57,7 +58,7 @@ export type SpaceTimeChartProps = { dispatchUpdateSelectedTrainId: DispatchUpdateSelectedTrainId; dispatchPersistentUpdateSimulation: DispatchPersistentUpdateSimulation; setTrainResultsToFetch?: (trainSchedulesIDs?: number[]) => void; - setTimeScaleDomain?: React.Dispatch>; + setTimeScaleDomain?: (newTimeScaleDomain: TimeScaleDomain) => void; }; export default function SpaceTimeChart(props: SpaceTimeChartProps) { @@ -180,16 +181,15 @@ export default function SpaceTimeChart(props: SpaceTimeChartProps) { dragShiftTrain(dragOffset); }, [dragOffset]); - const redrawChart = (newResizedChart?: Chart) => { + const redrawChart = () => { if (trainSimulations && allowancesSettings) { const trainsToDraw = trainSimulations.map((train) => createTrain(CHART_AXES.SPACE_TIME, train as Train) ); - const newChart = newResizedChart ?? chart; const newDrawnedChart = drawAllTrains( allowancesSettings, - newChart, + chart, CHART_ID, dispatchUpdateSelectedTrainId, height, @@ -221,8 +221,7 @@ export default function SpaceTimeChart(props: SpaceTimeChartProps) { if (chart && timeScaleDomain && timeScaleDomain.source !== 'SpaceTimeChart') { const currentTimeRange = timeScaleDomain.range; if (currentTimeRange) { - const newChart = { ...chart }; - newChart.x.domain(currentTimeRange); + chart.x.domain(currentTimeRange); redrawChart(); } } @@ -240,19 +239,17 @@ export default function SpaceTimeChart(props: SpaceTimeChartProps) { }); } - if (trainSimulations && selectedTrain && timeScaleDomain) { - const dataSimulation = createTrain(CHART_AXES.SPACE_TIME, selectedTrain as Train); - enableInteractivity( - chart, - dataSimulation, - CHART_AXES.SPACE_TIME, - rotate, - setChart, - simulationIsPlaying, - updateTimePosition, - newTimeScaleRange - ); - } + const dataSimulation = createTrain(CHART_AXES.SPACE_TIME, selectedTrain as Train); + enableInteractivity( + chart, + dataSimulation, + CHART_AXES.SPACE_TIME, + rotate, + setChart, + simulationIsPlaying, + updateTimePosition, + newTimeScaleRange + ); } }, [chart]); diff --git a/front/src/modules/simulationResult/components/SpeedSpaceChart/SpeedSpaceChart.tsx b/front/src/modules/simulationResult/components/SpeedSpaceChart/SpeedSpaceChart.tsx index a469371c993..5d422903c5c 100644 --- a/front/src/modules/simulationResult/components/SpeedSpaceChart/SpeedSpaceChart.tsx +++ b/front/src/modules/simulationResult/components/SpeedSpaceChart/SpeedSpaceChart.tsx @@ -5,11 +5,8 @@ import { GiResize } from 'react-icons/gi'; import { Rnd } from 'react-rnd'; import { LightRollingStock, SimulationReport } from 'common/api/osrdEditoastApi'; -import { - CHART_AXES, - type PositionScaleDomain, - type ChartAxes, -} from 'modules/simulationResult/consts'; +import { CHART_AXES, type ChartAxes } from 'modules/simulationResult/consts'; +import type { PositionScaleDomain } from 'modules/simulationResult/types'; import { enableInteractivity, traceVerticalLine, diff --git a/front/src/modules/simulationResult/components/SpeedSpaceChart/d3Helpers.ts b/front/src/modules/simulationResult/components/SpeedSpaceChart/d3Helpers.ts index 39d77397525..8fa9d7a9c56 100644 --- a/front/src/modules/simulationResult/components/SpeedSpaceChart/d3Helpers.ts +++ b/front/src/modules/simulationResult/components/SpeedSpaceChart/d3Helpers.ts @@ -6,7 +6,7 @@ import { createPowerRestrictionSegment, DRAWING_KEYS, } from 'applications/operationalStudies/consts'; -import { POSITION, SPEED, HEIGHT, CHART_AXES } from 'modules/simulationResult/consts'; +import { CHART_AXES } from 'modules/simulationResult/consts'; import drawArea from 'modules/simulationResult/components/ChartHelpers/drawArea'; import drawCurve from 'modules/simulationResult/components/ChartHelpers/drawCurve'; import defineChart from 'modules/simulationResult/components/ChartHelpers/defineChart'; @@ -39,19 +39,19 @@ function createChart( let scaleY2: d3.ScaleLinear = defineLinear(0, 0, 0); if (chart === undefined || resetChart) { - const maxX = d3.max(trainSimulation.speed, (speedObject) => speedObject[POSITION]) as number; + const maxX = d3.max(trainSimulation.speed, (speedObject) => speedObject.position) as number; scaleX = defineLinear(maxX + 100); - const maxY = d3.max(trainSimulation.speed, (speedObject) => speedObject[SPEED]) as number; + const maxY = d3.max(trainSimulation.speed, (speedObject) => speedObject.speed) as number; scaleY = defineLinear(maxY); const minY2 = d3.min( trainSimulation.slopesCurve, - (speedObject) => speedObject[HEIGHT] + (speedObject) => speedObject.height ) as number; const maxY2 = d3.max( trainSimulation.slopesCurve, - (speedObject) => speedObject[HEIGHT] + (speedObject) => speedObject.height ) as number; scaleY2 = chart === undefined ? defineLinear(maxY2, 0, minY2) : chart.y2; } else { diff --git a/front/src/modules/simulationResult/components/TimeLine/TimeLine.tsx b/front/src/modules/simulationResult/components/TimeLine/TimeLine.tsx index 495db1b6ce3..e956a16f058 100644 --- a/front/src/modules/simulationResult/components/TimeLine/TimeLine.tsx +++ b/front/src/modules/simulationResult/components/TimeLine/TimeLine.tsx @@ -5,7 +5,7 @@ import { SimulationReport } from 'common/api/osrdEditoastApi'; import { getDirection, gridX } from 'modules/simulationResult/components/ChartHelpers/ChartHelpers'; import { useChartSynchronizer } from 'modules/simulationResult/components/ChartHelpers/ChartSynchronizer'; import { sec2datetime } from 'utils/timeManipulation'; -import { TimeScaleDomain } from 'modules/simulationResult/consts'; +import type { TimeScaleDomain } from 'modules/simulationResult/types'; const drawTrain = ( train: SimulationReport, @@ -34,14 +34,14 @@ type TimeLineProps = { timeScaleDomain?: TimeScaleDomain; selectedTrainId: number; trains: SimulationReport[]; - onChangeTimeScaleDomain: (domain: TimeScaleDomain) => void; + onTimeScaleDomainChange: (domain: TimeScaleDomain) => void; }; const TimeLine = ({ timeScaleDomain, selectedTrainId, trains, - onChangeTimeScaleDomain, + onTimeScaleDomainChange, }: TimeLineProps) => { const ref = useRef(null); const [svgState, setSvg] = useState< @@ -171,7 +171,7 @@ const TimeLine = ({ const delta = xScale.invert(dragValue).getTime() - xScale.domain()[0].getTime(); const newX0 = new Date(currentTimeScaleRange[0].getTime() + delta); const newX1 = new Date(currentTimeScaleRange[1].getTime() + delta); - onChangeTimeScaleDomain({ + onTimeScaleDomainChange({ range: [newX0, newX1], source: 'Timeline', }); diff --git a/front/src/modules/simulationResult/consts.ts b/front/src/modules/simulationResult/consts.ts index 68d0eb49f4f..75056d92269 100644 --- a/front/src/modules/simulationResult/consts.ts +++ b/front/src/modules/simulationResult/consts.ts @@ -1,21 +1,15 @@ import { ArrayElement, ObjectFieldsTypes } from 'utils/types'; // CHARTS -export const TIME = 'time'; -export const POSITION = 'position'; -export const SPEED = 'speed'; -export const GRADIENT = 'gradient'; -export const RADIUS = 'radius'; -export const HEIGHT = 'height'; export type AxisKey = 'time' | 'position' | 'speed' | 'gradient' | 'radius' | 'height'; export const CHART_AXES = { - SPACE_TIME: [TIME, POSITION], - SPACE_SPEED: [POSITION, SPEED], - SPACE_GRADIENT: [POSITION, GRADIENT], - SPACE_RADIUS: [POSITION, RADIUS], - SPACE_HEIGHT: [POSITION, HEIGHT], + SPACE_TIME: ['time', 'position'], + SPACE_SPEED: ['position', 'speed'], + SPACE_GRADIENT: ['position', 'gradient'], + SPACE_RADIUS: ['position', 'radius'], + SPACE_HEIGHT: ['position', 'height'], } as const; export type ChartAxes = ObjectFieldsTypes; @@ -40,19 +34,8 @@ export const LIST_VALUES = { export type ListValues = ObjectFieldsTypes; export type AllListValues = ArrayElement; -// Signal Base is the Signaling system chosen for results display +// Signal Base is the Signaling system chosen for results display export const SIGNAL_BASE_DEFAULT = 'BAL3'; export const LIST_VALUES_SIGNAL_BASE = ['BAL3']; - -export type PositionScaleDomain = { - initial: number[]; - current: number[]; - source?: 'SpeedSpaceChart' | 'SpaceCurvesSlopes'; -}; - -export type TimeScaleDomain = { - range?: [Date, Date]; - source?: 'SpaceTimeChart' | 'Timeline'; -}; diff --git a/front/src/modules/simulationResult/types.ts b/front/src/modules/simulationResult/types.ts new file mode 100644 index 00000000000..860679dfa7c --- /dev/null +++ b/front/src/modules/simulationResult/types.ts @@ -0,0 +1,10 @@ +export type PositionScaleDomain = { + initial: number[]; + current: number[]; + source?: 'SpeedSpaceChart' | 'SpaceCurvesSlopes'; +}; + +export type TimeScaleDomain = { + range?: [Date, Date]; + source?: 'SpaceTimeChart' | 'Timeline'; +}; From 7baba083d785a6f805ff1b9439ade135bfffb69d Mon Sep 17 00:00:00 2001 From: Clara Ni Date: Fri, 26 Jan 2024 09:41:52 +0100 Subject: [PATCH 5/5] fix Paul's comments --- .../components/SpaceTimeChart/SpaceTimeChart.tsx | 2 +- front/src/modules/simulationResult/consts.ts | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/front/src/modules/simulationResult/components/SpaceTimeChart/SpaceTimeChart.tsx b/front/src/modules/simulationResult/components/SpaceTimeChart/SpaceTimeChart.tsx index ff466662f36..494b4c0b16b 100644 --- a/front/src/modules/simulationResult/components/SpaceTimeChart/SpaceTimeChart.tsx +++ b/front/src/modules/simulationResult/components/SpaceTimeChart/SpaceTimeChart.tsx @@ -229,7 +229,7 @@ export default function SpaceTimeChart(props: SpaceTimeChartProps) { /* add behaviour on zoom and mousemove/mouseover/wheel on the new chart each time the chart changes */ useEffect(() => { - if (chart) { + if (chart && selectedTrain) { const newTimeScaleRange = (rotate ? chart.y.domain() : chart.x.domain()) as [Date, Date]; if (setTimeScaleDomain) { diff --git a/front/src/modules/simulationResult/consts.ts b/front/src/modules/simulationResult/consts.ts index 75056d92269..ac43267b00e 100644 --- a/front/src/modules/simulationResult/consts.ts +++ b/front/src/modules/simulationResult/consts.ts @@ -2,8 +2,6 @@ import { ArrayElement, ObjectFieldsTypes } from 'utils/types'; // CHARTS -export type AxisKey = 'time' | 'position' | 'speed' | 'gradient' | 'radius' | 'height'; - export const CHART_AXES = { SPACE_TIME: ['time', 'position'], SPACE_SPEED: ['position', 'speed'],