Skip to content

Commit

Permalink
charts: add weight property to operational points
Browse files Browse the repository at this point in the history
Signed-off-by: Theo Macron <[email protected]>
  • Loading branch information
Akctarus committed Jan 7, 2025
1 parent fed5e49 commit e4ef594
Show file tree
Hide file tree
Showing 17 changed files with 167 additions and 63 deletions.
1 change: 1 addition & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions ui-manchette-with-spacetimechart/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
"dependencies": {
"@osrd-project/ui-manchette": "0.0.1-dev",
"@osrd-project/ui-spacetimechart": "0.0.1-dev",
"@osrd-project/ui-speedspacechart": "0.0.1-dev",
"classnames": "^2.5.1",
"lodash.isequal": "^4.5.0",
"vitest": "^2.1.1"
Expand Down
10 changes: 5 additions & 5 deletions ui-manchette-with-spacetimechart/src/__tests__/helpers.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { describe, it, expect } from 'vitest';

import { BASE_WAYPOINT_HEIGHT } from '../consts';
import {
calcWaypointsToDisplay,
getDisplayedWaypoints,
calcWaypointsHeight,
getWaypointsWithPosition,
getScales,
Expand All @@ -17,9 +17,9 @@ const mockedWaypoints = [
{ position: 20, id: 'waypoint-3' },
];

describe('calcWaypointsToDisplay', () => {
describe('getDisplayedWaypoints', () => {
it('should display all points for non-proportional display', () => {
const result = calcWaypointsToDisplay(mockedWaypoints, {
const result = getDisplayedWaypoints(mockedWaypoints, {
height: 500,
isProportional: false,
yZoom: 1,
Expand All @@ -31,7 +31,7 @@ describe('calcWaypointsToDisplay', () => {
});

it('should calculate proportional display correctly', () => {
const result = calcWaypointsToDisplay(mockedWaypoints, {
const result = getDisplayedWaypoints(mockedWaypoints, {
height: 500,
isProportional: true,
yZoom: 1,
Expand All @@ -42,7 +42,7 @@ describe('calcWaypointsToDisplay', () => {
});

it('should ensure the last point is always displayed', () => {
const result = calcWaypointsToDisplay(mockedWaypoints, {
const result = getDisplayedWaypoints(mockedWaypoints, {
height: 500,
isProportional: true,
yZoom: 1,
Expand Down
22 changes: 22 additions & 0 deletions ui-manchette-with-spacetimechart/src/assets/sampleData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,132 +7,154 @@ export const SAMPLE_WAYPOINTS: Waypoint[] = [
position: 0,
name: 'Brest',
secondaryCode: 'BV',
weight: 100,
},
{
id: '2',
position: 3983000,
name: 'Le Rody',
secondaryCode: '00',
weight: 60,
},
{
id: '3',
position: 7349000,
name: 'Kerhuon',
secondaryCode: 'BV',
weight: 50,
},
{
id: '4',
position: 13882000,
name: 'La Forest',
secondaryCode: '00',
weight: 40,
},
{
id: '5',
position: 18756000,
name: 'Landerneau',
secondaryCode: 'BV',
weight: 30,
},
{
id: '6',
position: 23358000,
name: 'La Roche',
secondaryCode: '00',
weight: 35,
},
{
id: '7',
position: 33219000,
name: 'Landivisiau',
secondaryCode: '00',
weight: 70,
},
{
id: '8',
position: 40612000,
name: 'Guimiliau',
secondaryCode: '00',
weight: 40,
},
{
id: '9',
position: 44960000,
name: 'St-Thégonnec',
secondaryCode: '00',
weight: 50,
},
{
id: '10',
position: 50471000,
name: 'Pleyber-Christ',
secondaryCode: '00',
weight: 45,
},
{
id: '11',
position: 59554000,
name: 'Morlaix',
secondaryCode: 'BV',
weight: 20,
},
{
id: '12',
position: 68903000,
name: 'Plouigneau',
secondaryCode: '00',
weight: 15,
},
{
id: '13',
position: 83194000,
name: 'Plounérin',
secondaryCode: '00',
weight: 10,
},
{
id: '14',
position: 91392000,
name: 'Plouaret',
secondaryCode: '00',
weight: 0,
},
{
id: '15',
position: 102478000,
name: 'Belle-Isle-Bégard',
secondaryCode: '00',
weight: 60,
},
{
id: '16',
position: 117570000,
name: 'Guingamp',
secondaryCode: '00',
weight: 90,
},
{
id: '17',
position: 130463000,
name: 'Châtelaudren-Plouagat',
secondaryCode: 'BV',
weight: 20,
},
{
id: '18',
position: 137315000,
name: 'Plouvara-Plerneuf',
secondaryCode: '00',
weight: 40,
},
{
id: '19',
position: 141157000,
name: 'La Méaugon',
secondaryCode: '00',
weight: 45,
},
{
id: '20',
position: 147745000,
name: 'St-Brieuc',
secondaryCode: 'BV',
weight: 70,
},
{
id: '21',
position: 157361000,
name: 'Yffiniac',
secondaryCode: '00',
weight: 0,
},
{
id: '22',
position: 168056000,
name: 'Lamballe',
secondaryCode: 'BV',
weight: 100,
},
];

Expand Down
41 changes: 10 additions & 31 deletions ui-manchette-with-spacetimechart/src/helpers.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { InteractiveWaypoint, Waypoint } from '@osrd-project/ui-manchette/dist/types';
import type { OperationalPoint } from '@osrd-project/ui-spacetimechart/dist/lib/types';
import { filterVisibleElements } from '@osrd-project/ui-speedspacechart/src/components/utils';
import { clamp } from 'lodash';

import {
Expand All @@ -13,48 +14,26 @@ import { calcTotalDistance, getHeightWithoutLastWaypoint } from './utils';

type WaypointsOptions = { isProportional: boolean; yZoom: number; height: number };

export const calcWaypointsToDisplay = (
export const getDisplayedWaypoints = (
waypoints: Waypoint[],
{ height, isProportional, yZoom }: WaypointsOptions
): InteractiveWaypoint[] => {
if (!isProportional || waypoints.length === 0) {
// For non-proportional display, we always display all the waypoints:
return waypoints.map((waypoint) => ({ ...waypoint, display: true }));
}

// For proportional display, we only display waypoints that do not overlap with
// the last displayed point:
const result: InteractiveWaypoint[] = [{ ...waypoints[0], display: true }];
const totalDistance = calcTotalDistance(waypoints);
const heightWithoutFinalWaypoint = getHeightWithoutLastWaypoint(height);
let lastDisplayedWaypoint = result[0];

// We iterate through all points, and only add them if they don't collide
// with the last visible point:
for (let i = 1; i < waypoints.length; i++) {
const waypoint = waypoints[i];
const diff = waypoint.position - lastDisplayedWaypoint.position;
const display =
(diff / totalDistance) * heightWithoutFinalWaypoint * yZoom >= BASE_WAYPOINT_HEIGHT;

if (display) {
result.push({ ...waypoint, display });
lastDisplayedWaypoint = waypoint;
}
}
const minSpace = BASE_WAYPOINT_HEIGHT / yZoom;

// In the end, to make sure the last point is visible, if it's not, we swap
// it with the last visible item:
const lastItem = result[result.length - 1];
if (!lastItem.display) {
const lastVisibleItem = result.findLast((waypoint) => waypoint.display);
if (lastVisibleItem) {
lastVisibleItem.display = false;
lastItem.display = true;
}
}
const displayedWaypoints = filterVisibleElements({
elements: waypoints,
getPosition: (waypoint) => (waypoint.position / totalDistance) * heightWithoutFinalWaypoint,
getWeight: (waypoint) => waypoint.weight,
minSpace,
});

return result;
return displayedWaypoints.map((waypoint) => ({ ...waypoint, display: true }));
};

export const calcWaypointsHeight = (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import {
DEFAULT_ZOOM_MS_PER_PX,
} from '../consts';
import {
calcWaypointsToDisplay,
getDisplayedWaypoints,
getWaypointsWithPosition as getOperationalPointWithPosition,
getScales,
calcWaypointsHeight,
Expand Down Expand Up @@ -63,7 +63,7 @@ const useManchettesWithSpaceTimeChart = (
const paths = usePaths(projectPathTrainResult, selectedTrain);

const waypointsToDisplay = useMemo(
() => calcWaypointsToDisplay(waypoints, { height, isProportional, yZoom }),
() => getDisplayedWaypoints(waypoints, { height, isProportional, yZoom }),
[waypoints, height, isProportional, yZoom]
);
const waypointWithHeight = useMemo(
Expand Down
4 changes: 4 additions & 0 deletions ui-manchette/src/stories/assets/sampleData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,27 @@ export const SAMPLE_WAYPOINTS: Waypoint[] = [
name: 'South_West_station',
secondaryCode: 'BV',
position: 0,
weight: 100,
},
{
id: 'Mid_West_station',
name: 'Mid_West_station',
secondaryCode: 'BV',
position: 13000000,
weight: 30,
},
{
id: 'Mid_East_station',
name: 'Mid_East_station',
secondaryCode: 'BV',
position: 27550000,
weight: 50,
},
{
id: 'North_East_station',
name: 'North_East_station',
secondaryCode: 'BV',
position: 47050000,
weight: 100,
},
];
1 change: 1 addition & 0 deletions ui-manchette/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export type Waypoint = {
position: number; // in mm
name?: string;
secondaryCode?: string;
weight?: number;
};

export type InteractiveWaypoint = Waypoint & {
Expand Down
1 change: 1 addition & 0 deletions ui-speedspacechart/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
],
"exports": {
"./dist/theme.css": "./dist/theme.css",
"./src/components/utils": "./src/components/utils",
".": {
"types": "./dist/index.d.ts",
"default": "./dist/index.esm.js"
Expand Down
2 changes: 1 addition & 1 deletion ui-speedspacechart/src/__tests__/utils.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -374,7 +374,7 @@ describe('getSnappedStop', () => {
])('should find the correct snapped stop', (stopPositions, cursorX, expectedPos) => {
const stops = stopPositions.map((pos) => ({
position: { start: pos },
value: 'MyTestStop',
value: { name: 'MyTestStop' },
}));
const storeWithStops: Store = {
...store,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ export const drawCursor = ({ ctx, width, height, store }: DrawFunctionParams) =>
snapToStop = true;
cursorPosition = snappedStop.position.start;
reticleX = positionToPosX(cursorPosition, maxPosition, width, ratioX, leftOffset);
stopText = snappedStop.value;
stopText = snappedStop.value.name;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {
clearCanvas,
positionToPosX,
maxPositionValue,
filterStops,
getDisplayedStops,
getSnappedStop,
} from '../../utils';

Expand All @@ -24,7 +24,7 @@ export const drawSteps = ({ ctx, width, height, store }: DrawFunctionParams) =>

const maxPosition = maxPositionValue(store.speeds);

const filteredStops = filterStops(stops, ratioX, width, maxPosition);
const filteredStops = getDisplayedStops(stops, ratioX, width, maxPosition);

ctx.save();
ctx.translate(leftOffset, 0);
Expand Down Expand Up @@ -72,7 +72,7 @@ export const drawSteps = ({ ctx, width, height, store }: DrawFunctionParams) =>
ctx.restore();

// Text
const filteredTextStops = filterStops(filteredStops, ratioX, width, maxPosition, 25);
const filteredTextStops = getDisplayedStops(filteredStops, ratioX, width, maxPosition, 25);
filteredTextStops.forEach(({ position, value }) => {
if (snappedStop && position.start === snappedStop.position.start) {
return;
Expand All @@ -92,7 +92,7 @@ export const drawSteps = ({ ctx, width, height, store }: DrawFunctionParams) =>
ctx.textAlign = 'left';

// Draw the text at the origin, since the context is already transformed
ctx.fillText(value!, 0, 0);
ctx.fillText(value!.name, 0, 0);
ctx.restore();
});

Expand Down
Loading

0 comments on commit e4ef594

Please sign in to comment.