Skip to content

Commit

Permalink
speedspacechart: add drawing function
Browse files Browse the repository at this point in the history
Signed-off-by: Florian Amsallem <florian.amsallem@gmail.com>
  • Loading branch information
flomonster committed Sep 27, 2024
1 parent c792bf3 commit 27042bd
Show file tree
Hide file tree
Showing 8 changed files with 235 additions and 109 deletions.
6 changes: 4 additions & 2 deletions ui-speedspacechart/src/components/const.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,11 +69,13 @@ export const LAYERS_SELECTION: Array<keyof Store['layersDisplay']> = [
// Colors

export const BLACK = chroma(0, 0, 0);
export const WHITE = chroma(255, 255, 255);
export const ERROR_30 = chroma(255, 104, 104);
export const ERROR_60 = chroma(217, 28, 28);
export const GREY_50 = chroma(121, 118, 113);
export const GREY_80 = chroma(49, 46, 43);
export const LIGHT_BLUE = chroma(33, 112, 185);
export const ERROR_60 = chroma(217, 28, 28);
export const WARNING_30 = chroma(234, 167, 43);
export const WHITE = chroma(255, 255, 255);

/**
* COLOR_DICTIONARY maps specific colors to their corresponding secondary colors used for speed limit tags.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,33 +1,100 @@
import type { DrawFunctionParams } from '../../../types/chartTypes';
import { ERROR_60, MARGINS } from '../../const';
import { clearCanvas, positionToPosX, maxPositionValue, maxSpeedValue } from '../../utils';
import { ERROR_30, ERROR_60, MARGINS, WARNING_30 } from '../../const';
import {
clearCanvas,
maxPositionValue,
maxSpeedValue,
convertMToKm,
positionToPosX,
} from '../../utils';

const { CURVE_MARGIN_TOP } = MARGINS;
const { CURVE_MARGIN_TOP, MARGIN_RIGHT, MARGIN_LEFT, MARGIN_BOTTOM, MARGIN_TOP } = MARGINS;
const GRADIENT_HEIGHT = 16;
const TRAIN_LENGTH_MARKER_HEIGHT = 8;

export const drawSpeedLimits = ({ ctx, width, height, store }: DrawFunctionParams) => {
const { mrsp, trainLength, ratioX, leftOffset } = store;
const maxSpeed = maxSpeedValue(store);

if (!mrsp) return;

clearCanvas(ctx, width, height);

ctx.save();
ctx.translate(leftOffset, 0);

const realHeight = height - MARGIN_BOTTOM - MARGIN_TOP;
const maxSpeed = maxSpeedValue(store);
const maxPosition = maxPositionValue(store);
// Add the last boundary to the boundaries array
mrsp.boundaries.push(maxPosition);

// TODO: draw speed limits
ctx.beginPath();
ctx.lineWidth = 1;
ctx.lineCap = 'round';
ctx.strokeStyle = ERROR_60.hex();

const adjustedHeight = height - CURVE_MARGIN_TOP;
const y = height - (200 / maxSpeed) * adjustedHeight;
const xStart = positionToPosX(0, maxPosition, width, ratioX);
ctx.lineTo(xStart, y);
const xEnd = positionToPosX(maxPosition, maxPosition, width, ratioX);
ctx.lineTo(xEnd, y);
ctx.stroke();
let previousBoundaryX = positionToPosX(0, maxPosition, width, ratioX);
let previousSpeedY: number | null = null;
for (let i = 0; i < mrsp.values.length; i++) {
const { speed, isTemporary } = mrsp.values[i];

const currentBoundaryX = positionToPosX(mrsp.boundaries[i], maxPosition, width, ratioX);

const speedY = realHeight - (speed / maxSpeed) * (realHeight - CURVE_MARGIN_TOP) + MARGIN_TOP;
// Draw vertical line joining 2 speed limits
if (previousSpeedY !== null) {
ctx.beginPath();
ctx.strokeStyle = ERROR_30.alpha(0.5).hex();
ctx.lineWidth = 0.5;
ctx.moveTo(previousBoundaryX, previousSpeedY);
ctx.lineTo(previousBoundaryX, speedY);
ctx.stroke();
}

const speedColor = isTemporary ? WARNING_30 : ERROR_60;

// Draw gradient
const gradient = ctx.createLinearGradient(0, speedY, 0, speedY - GRADIENT_HEIGHT);
if (isTemporary) {
gradient.addColorStop(0, speedColor.alpha(0.23).hex());
} else {
gradient.addColorStop(0, speedColor.alpha(0.15).hex());
}
gradient.addColorStop(1, speedColor.alpha(0).hex());
ctx.fillStyle = gradient;
ctx.rect(previousBoundaryX, speedY, currentBoundaryX - previousBoundaryX, -GRADIENT_HEIGHT);
ctx.fill();

// Handle train length (only if next speed is higher than current speed)
let extendedBoundaryX: number | null = null;
if (i < mrsp.values.length - 1 && mrsp.values[i + 1].speed > speed) {
extendedBoundaryX = positionToPosX(
Math.min(mrsp.boundaries[i] + convertMToKm(trainLength), maxPosition),
maxPosition,
width,
ratioX
);
}

// Draw main line
ctx.beginPath();
ctx.lineWidth = 1;
ctx.strokeStyle = speedColor.hex();
ctx.moveTo(previousBoundaryX, speedY);
ctx.lineTo(extendedBoundaryX ?? currentBoundaryX, speedY);

// Draw a small vertical line to mark the end of the train's length.
if (extendedBoundaryX !== null) {
ctx.moveTo(extendedBoundaryX, speedY - TRAIN_LENGTH_MARKER_HEIGHT / 2);
ctx.lineTo(extendedBoundaryX, speedY + TRAIN_LENGTH_MARKER_HEIGHT / 2);
}
ctx.stroke();

// Update previous values to current ones
previousBoundaryX = currentBoundaryX;
previousSpeedY = speedY;
}

ctx.restore();

// Prevent overlapping with y axis
ctx.clearRect(0, 0, MARGIN_LEFT, height);
ctx.clearRect(width - MARGIN_RIGHT, 0, MARGIN_RIGHT, height);
};
5 changes: 4 additions & 1 deletion ui-speedspacechart/src/components/utils.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import {
CURSOR_SNAP_DISTANCE,
LINEAR_LAYER_SEPARATOR_HEIGHT,
LINEAR_LAYERS_HEIGHTS,
LINEAR_LAYERS_HEIGHTS_BY_NAME,
MARGINS,
CURSOR_SNAP_DISTANCE,
type LAYERS_SELECTION,
} from './const';
import type { LayerData, Store } from '../types/chartTypes';
Expand Down Expand Up @@ -295,6 +295,9 @@ export const binarySearch = <T>(data: T[], element: number, lambda: (element: T)
return left;
};

/** Convert meters to kilometers */
export const convertMToKm = (meters: number) => meters / 1000;

/** Transform a position in km into a position on the x-axis in pixels */
export const positionToPosX = (
position: number,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ export const pathPropertiesPmpLm: PathProperties = {
191414000, 191514000, 192764000, 193014000, 193464000, 193614000, 193664000, 194564000,
195114000, 195464000, 196014000, 196464000, 197564000, 197934000, 198089000, 198303000,
198464000, 199614000, 199664000, 200014000, 200064000, 200164000, 200464000, 200514000,
200564000, 200610000,
200564000, 201649000,
],
values: [
0.0, 7.7, 4.1, 0.0, 3.3, 0.0, 8.4, 4.2, 6.3, 0.0, 9.3, 11.5, 11.3, 0.0, 11.3, 0.0, 6.5, 1.0,
Expand Down Expand Up @@ -655,7 +655,7 @@ export const pathPropertiesPmpLm: PathProperties = {
name: 'Le Mans',
},
},
position: 201544000,
position: 201649000,
},
],
};
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,6 @@ export const powerRestrictionsPmpLm: PowerRestriction[] = [
code: 'BBBB',
handled: true,
start: 180550965,
stop: 201544000,
stop: 201649000,
},
];
Loading

0 comments on commit 27042bd

Please sign in to comment.