Skip to content

Commit 73c9557

Browse files
committed
save
1 parent b20fa35 commit 73c9557

File tree

6 files changed

+194
-45
lines changed

6 files changed

+194
-45
lines changed

ui-manchette-with-spacetimechart/src/__tests__/helpers.spec.ts

+41-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
1-
import { describe, it, expect } from 'vitest';
1+
import { describe, it, test, expect } from 'vitest';
22

3-
import { BASE_WAYPOINT_HEIGHT } from '../consts';
4-
import { computeWaypointsToDisplay, getScales } from '../helpers';
3+
import { BASE_WAYPOINT_HEIGHT, MAX_ZOOM_Y, MIN_ZOOM_Y } from '../consts';
4+
import {
5+
computeWaypointsToDisplay,
6+
getScales,
7+
getExtremaScales,
8+
spaceScaleToZoomValue,
9+
zoomValueToSpaceScale,
10+
} from '../helpers';
511

612
// Assuming these types from your code
713

@@ -105,3 +111,35 @@ describe('getScales', () => {
105111
expect(result[0]).not.toHaveProperty('coefficient');
106112
});
107113
});
114+
115+
describe('space scale functions', () => {
116+
const pathLength = 168056000; // mm
117+
const manchettePxHeight = 528;
118+
const heightBetweenFirstLastWaypoints = 489;
119+
120+
const { minZoomMillimetrePerPx, maxZoomMillimetrePerPx } = getExtremaScales(
121+
manchettePxHeight,
122+
heightBetweenFirstLastWaypoints,
123+
pathLength
124+
);
125+
expect(minZoomMillimetrePerPx).toBeCloseTo(343672.801);
126+
expect(maxZoomMillimetrePerPx).toBeCloseTo(946.97);
127+
128+
test('zoomValueToSpaceScale', () => {
129+
expect(
130+
zoomValueToSpaceScale(minZoomMillimetrePerPx, maxZoomMillimetrePerPx, MIN_ZOOM_Y)
131+
).toBeCloseTo(343672.801);
132+
expect(
133+
zoomValueToSpaceScale(minZoomMillimetrePerPx, maxZoomMillimetrePerPx, MAX_ZOOM_Y)
134+
).toBeCloseTo(946.97);
135+
});
136+
137+
test('spaceScaleToZoomValue', () => {
138+
expect(
139+
spaceScaleToZoomValue(minZoomMillimetrePerPx, maxZoomMillimetrePerPx, 343672.801)
140+
).toBeCloseTo(MIN_ZOOM_Y);
141+
expect(
142+
spaceScaleToZoomValue(minZoomMillimetrePerPx, maxZoomMillimetrePerPx, 946.97)
143+
).toBeCloseTo(MAX_ZOOM_Y);
144+
});
145+
});

ui-manchette-with-spacetimechart/src/consts.ts

+3-6
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,16 @@ export const BASE_WAYPOINT_HEIGHT = 32;
22
export const INITIAL_WAYPOINT_LIST_HEIGHT = 521;
33
export const INITIAL_SPACE_TIME_CHART_HEIGHT = INITIAL_WAYPOINT_LIST_HEIGHT + 40;
44

5-
export const MIN_ZOOM_MS_PER_PX = 600000;
5+
export const MIN_ZOOM_MS_PER_PX = 600_000;
66
export const MAX_ZOOM_MS_PER_PX = 625;
7-
export const DEFAULT_ZOOM_MS_PER_PX = 7500;
7+
export const DEFAULT_ZOOM_MS_PER_PX = 7_500;
88
export const MIN_ZOOM_X = 0;
99
export const MAX_ZOOM_X = 100;
1010

11-
export const MIN_ZOOM_METRE_PER_PX = 10000;
12-
export const MAX_ZOOM_METRE_PER_PX = 10;
13-
export const DEFAULT_ZOOM_METRE_PER_PX = 300;
14-
1511
export const MIN_ZOOM_Y = 1;
1612
export const MAX_ZOOM_Y = 10.5;
1713
export const ZOOM_Y_DELTA = 0.5;
14+
export const MAX_ZOOM_MANCHETTE_HEIGHT_MILLIMETER = 500_000;
1815

1916
export const FOOTER_HEIGHT = 40; // height of the manchette footer
2017
export const WAYPOINT_LINE_HEIGHT = 16;

ui-manchette-with-spacetimechart/src/helpers.ts

+50-11
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,13 @@ import { clamp } from 'lodash';
33

44
import {
55
BASE_WAYPOINT_HEIGHT,
6-
MAX_ZOOM_METRE_PER_PX,
76
MAX_ZOOM_MS_PER_PX,
87
MAX_ZOOM_X,
9-
MIN_ZOOM_METRE_PER_PX,
108
MIN_ZOOM_MS_PER_PX,
119
MIN_ZOOM_X,
10+
MAX_ZOOM_Y,
11+
MIN_ZOOM_Y,
12+
MAX_ZOOM_MANCHETTE_HEIGHT_MILLIMETER,
1213
} from './consts';
1314
import { calcTotalDistance, getHeightWithoutLastWaypoint } from './utils';
1415

@@ -90,6 +91,11 @@ export const computeWaypointsToDisplay = (
9091
});
9192
};
9293

94+
/**
95+
* 2 modes
96+
* km: { coefficient: gives a scale in metre/pixel } (isProportional true)
97+
* linear: { size: height in pixel } (each point distributed evenly along the height of manchette.)
98+
*/
9399
export const getScales = (
94100
waypoints: Waypoint[],
95101
{ height, isProportional, yZoom }: WaypointsOptions
@@ -111,11 +117,8 @@ export const getScales = (
111117
const from = waypoints.at(0)!.position;
112118
const to = waypoints.at(-1)!.position;
113119

114-
const totalDistance = calcTotalDistance(waypoints);
115-
const heightWithoutFinalWaypoint = getHeightWithoutLastWaypoint(height);
116-
117120
const scaleCoeff = isProportional
118-
? { coefficient: totalDistance / heightWithoutFinalWaypoint / yZoom }
121+
? { coefficient: zoomValueToSpaceScale(yZoom) } // TODO, last thing
119122
: { size: BASE_WAYPOINT_HEIGHT * (waypoints.length - 1) * yZoom };
120123

121124
return [
@@ -134,12 +137,48 @@ export const timeScaleToZoomValue = (timeScale: number) =>
134137
(100 * Math.log(timeScale / MIN_ZOOM_MS_PER_PX)) /
135138
Math.log(MAX_ZOOM_MS_PER_PX / MIN_ZOOM_MS_PER_PX);
136139

137-
export const zoomValueToSpaceScale = (slider: number) =>
138-
MIN_ZOOM_METRE_PER_PX * Math.pow(MAX_ZOOM_METRE_PER_PX / MIN_ZOOM_METRE_PER_PX, slider / 100);
140+
/**
141+
* min zoom is computed with manchette px height between first and last waypoint.
142+
* max zoom just the canvas drawing height (without the x-axis scale section)
143+
*/
144+
export const getExtremaScales = (
145+
drawingHeightWithoutTopPadding: number,
146+
drawingHeightWithoutBothPadding: number,
147+
pathLengthMillimeter: number
148+
) => {
149+
return {
150+
minZoomMillimetrePerPx: pathLengthMillimeter / drawingHeightWithoutBothPadding,
151+
maxZoomMillimetrePerPx: MAX_ZOOM_MANCHETTE_HEIGHT_MILLIMETER / drawingHeightWithoutTopPadding,
152+
};
153+
};
154+
155+
// export const getScaleFromRectangle = ()
139156

140-
export const spaceScaleToZoomValue = (spaceScale: number) =>
141-
(100 * Math.log(spaceScale / MIN_ZOOM_METRE_PER_PX)) /
142-
Math.log(MAX_ZOOM_METRE_PER_PX / MIN_ZOOM_METRE_PER_PX);
157+
export const zoomValueToSpaceScale = (
158+
minZoomMillimetrePerPx: number,
159+
maxZoomMillimetrePerPx: number,
160+
slider: number
161+
) => {
162+
return (
163+
minZoomMillimetrePerPx *
164+
Math.pow(
165+
maxZoomMillimetrePerPx / minZoomMillimetrePerPx,
166+
(slider - MIN_ZOOM_Y) / (MAX_ZOOM_Y - MIN_ZOOM_Y)
167+
)
168+
);
169+
};
170+
171+
export const spaceScaleToZoomValue = (
172+
minZoomMillimetrePerPx: number,
173+
maxZoomMillimetrePerPx: number,
174+
spaceScale: number
175+
) => {
176+
return (
177+
((MAX_ZOOM_Y - MIN_ZOOM_Y) * Math.log(spaceScale / minZoomMillimetrePerPx)) /
178+
Math.log(maxZoomMillimetrePerPx / minZoomMillimetrePerPx) +
179+
MIN_ZOOM_Y
180+
);
181+
};
143182

144183
/** Zoom on X axis and center on the mouse position */
145184
export const zoomX = (

ui-manchette-with-spacetimechart/src/hooks/useManchetteWithSpaceTimeChart.ts

+80-20
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import { useCallback, useEffect, useMemo, useState } from 'react';
22

3-
import type { ProjectPathTrainResult, Waypoint } from '@osrd-project/ui-manchette/dist/types';
4-
import type {
5-
SpaceScale,
6-
SpaceTimeChartProps,
7-
} from '@osrd-project/ui-spacetimechart/dist/lib/types';
3+
import {
4+
CAPTION_SIZE,
5+
type SpaceScale,
6+
type SpaceTimeChartProps,
7+
} from '@osrd-project/ui-spacetimechart';
8+
import { type Waypoint, type ProjectPathTrainResult } from '@osrd-project/ui-manchette';
89

910
import usePaths from './usePaths';
1011
import {
@@ -14,16 +15,18 @@ import {
1415
DEFAULT_ZOOM_MS_PER_PX,
1516
MAX_ZOOM_MS_PER_PX,
1617
MIN_ZOOM_MS_PER_PX,
17-
MAX_ZOOM_METRE_PER_PX,
18-
MIN_ZOOM_METRE_PER_PX,
18+
BASE_WAYPOINT_HEIGHT,
19+
FOOTER_HEIGHT,
1920
} from '../consts';
2021
import {
2122
computeWaypointsToDisplay,
2223
getScales,
2324
zoomX,
2425
zoomValueToTimeScale,
26+
zoomValueToSpaceScale,
2527
timeScaleToZoomValue,
2628
spaceScaleToZoomValue,
29+
getExtremaScales,
2730
} from '../helpers';
2831
import { getDiff } from '../utils/point';
2932
import { clamp } from 'lodash';
@@ -90,7 +93,6 @@ const useManchettesWithSpaceTimeChart = (
9093
isProportional,
9194
} = state;
9295

93-
console.log(yZoom);
9496
const paths = usePaths(projectPathTrainResult, selectedTrain);
9597

9698
const waypointsToDisplay = useMemo(
@@ -109,6 +111,36 @@ const useManchettesWithSpaceTimeChart = (
109111
[waypointsToDisplay]
110112
);
111113

114+
const canvasDrawingHeight = height - FOOTER_HEIGHT; // 521
115+
const drawingHeightWithoutTopPadding = canvasDrawingHeight - BASE_WAYPOINT_HEIGHT / 2; // 505
116+
const drawingHeightWithoutBothPadding = canvasDrawingHeight - BASE_WAYPOINT_HEIGHT; // 489
117+
118+
const computedScales = useMemo(
119+
() => getScales(simplifiedWaypoints, { height, isProportional, yZoom }),
120+
[simplifiedWaypoints, height, isProportional, yZoom]
121+
);
122+
123+
console.log('computedScales', computedScales.at(-1));
124+
const { minZoomMillimetrePerPx, maxZoomMillimetrePerPx } = getExtremaScales(
125+
drawingHeightWithoutTopPadding,
126+
drawingHeightWithoutBothPadding,
127+
computedScales.at(-1)!.to
128+
);
129+
console.log(
130+
'state',
131+
zoomValueToSpaceScale(minZoomMillimetrePerPx, maxZoomMillimetrePerPx, yZoom)
132+
);
133+
134+
// console.log(computedScales, minZoomMillimetrePerPx, maxZoomMillimetrePerPx);
135+
136+
// console.log(
137+
// '\n',
138+
// `x: zoom=${xZoom}, ${zoomValueToTimeScale(xZoom)} ms/px`,
139+
// '\n',
140+
// `y: zoom=${yZoom}, ${zoomValueToSpaceScale(minZoomMillimetrePerPx, maxZoomMillimetrePerPx, yZoom)} m/px
141+
// ${zoomValueToSpaceScale(minZoomMillimetrePerPx, maxZoomMillimetrePerPx, yZoom) * canvasDrawingHeight} m`
142+
// );
143+
112144
const handleRectangleZoom = useCallback(
113145
({
114146
scales: { chosenTimeScale, chosenSpaceScale },
@@ -121,21 +153,30 @@ const useManchettesWithSpaceTimeChart = (
121153
if (prev.zoomMode || !prev.rect) {
122154
return prev;
123155
}
124-
125156
const newTimeScale = clamp(chosenTimeScale, MAX_ZOOM_MS_PER_PX, MIN_ZOOM_MS_PER_PX);
126-
const newSpaceScale = clamp(chosenSpaceScale, MAX_ZOOM_METRE_PER_PX, MIN_ZOOM_METRE_PER_PX);
157+
const newSpaceScale = clamp(
158+
chosenSpaceScale,
159+
maxZoomMillimetrePerPx,
160+
minZoomMillimetrePerPx
161+
);
162+
console.log(2, newSpaceScale);
127163
const timeZoomValue = timeScaleToZoomValue(newTimeScale);
128-
const spaceZoomValue = spaceScaleToZoomValue(newSpaceScale);
164+
const spaceZoomValue = spaceScaleToZoomValue(
165+
minZoomMillimetrePerPx,
166+
maxZoomMillimetrePerPx,
167+
newSpaceScale
168+
);
129169

170+
// console.log(newSpaceScale, spaceZoomValue);
130171
const leftRectSide = Math.min(Number(prev.rect.timeStart), Number(prev.rect.timeEnd));
131172
const topRectSide = Math.min(prev.rect.spaceStart, prev.rect.spaceEnd);
132173
const newXOffset = (timeOrigin - leftRectSide) / newTimeScale;
133174
const newYOffset = (spaceOrigin - topRectSide) / newSpaceScale;
134175

135176
return {
136177
...prev,
137-
timeZoomValue: timeZoomValue,
138-
spaceZoomValue: spaceZoomValue,
178+
xZoom: timeZoomValue,
179+
yZoom: spaceZoomValue,
139180
xOffset: newXOffset,
140181
yOffset: newYOffset,
141182
...overrideState,
@@ -145,6 +186,21 @@ const useManchettesWithSpaceTimeChart = (
145186
[timeOrigin, spaceOrigin]
146187
);
147188

189+
useEffect(() => {
190+
if (rect && !zoomMode && spaceTimeChartRef?.current) {
191+
const { timeStart, timeEnd, spaceStart, spaceEnd } = rect;
192+
const timeRange = Math.abs(Number(timeEnd) - Number(timeStart)); // width of rect in ms
193+
const spaceRange = Math.abs(spaceEnd - spaceStart); // height of rect in metre
194+
const chosenTimeScale = timeRange / spaceTimeChartRef.current.clientWidth;
195+
const chosenSpaceScale = spaceRange / drawingHeightWithoutTopPadding;
196+
console.log(1, spaceRange, drawingHeightWithoutTopPadding, chosenSpaceScale);
197+
handleRectangleZoom({
198+
scales: { chosenTimeScale, chosenSpaceScale },
199+
overrideState: { rect: null },
200+
});
201+
}
202+
}, [state.rect, state.zoomMode, handleRectangleZoom]);
203+
148204
const zoomYIn = useCallback(() => {
149205
if (yZoom < MAX_ZOOM_Y) {
150206
const newYZoom = yZoom + ZOOM_Y_DELTA;
@@ -230,15 +286,9 @@ const useManchettesWithSpaceTimeChart = (
230286
setState((prev) => ({ ...prev, isProportional: !prev.isProportional }));
231287
}, []);
232288

233-
const computedScales = useMemo(
234-
() => getScales(simplifiedWaypoints, { height, isProportional, yZoom }),
235-
[simplifiedWaypoints, height, isProportional, yZoom]
236-
);
237-
238289
const toggleZoomMode = useCallback(() => {
239290
setState((prev) => ({ ...prev, zoomMode: !prev.zoomMode }));
240291
}, []);
241-
// console.log('computedScales', computedScales);
242292

243293
const manchetteProps = useMemo(
244294
() => ({
@@ -344,8 +394,18 @@ const useManchettesWithSpaceTimeChart = (
344394
xZoom,
345395
toggleZoomMode,
346396
zoomMode,
397+
rect,
347398
}),
348-
[manchetteProps, spaceTimeChartProps, handleScroll, handleXZoom, xZoom]
399+
[
400+
manchetteProps,
401+
spaceTimeChartProps,
402+
handleScroll,
403+
handleXZoom,
404+
xZoom,
405+
toggleMode,
406+
zoomMode,
407+
rect,
408+
]
349409
);
350410
};
351411

0 commit comments

Comments
 (0)