Skip to content

Commit

Permalink
Define the height of the diagrams based on the density of information…
Browse files Browse the repository at this point in the history
… to display
  • Loading branch information
julienrf committed Nov 13, 2023
1 parent bb3325f commit a6e63c2
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 24 deletions.
53 changes: 33 additions & 20 deletions frontend/src/diagrams/Meteogram.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,14 @@ import { inversionStyle } from '../shared';
*/
export const meteogram = (forecasts: LocationForecasts, state: State): { key: JSX.Element, view: JSX.Element } => {

const flatForecasts: Array<DetailedForecast> =
forecasts.dayForecasts.map(x => x.forecasts).reduce((x, y) => x.concat(y), []); // Alternative to flatMap
const maxBoundaryLayerDepth =
flatForecasts.reduce((x, forecast) => Math.max(x, forecast.boundaryLayer.depth), -Infinity);

// In the air diagram, show 1000 meters above the boundary layer depth, and at least 2000 meters above the ground level
const airDiagramHeightAboveGroundLevel = Math.max(2000, maxBoundaryLayerDepth + 1000 /* meters */);

const gutterHeight = 5; // px

// Our meteogram is made of five diagrams stacked on top of each other.
Expand All @@ -34,7 +42,18 @@ export const meteogram = (forecasts: LocationForecasts, state: State): { key: JS

const rainDiagramHeight = 60; // px

const airDiagramHeight = Math.min(500, diagramsAvailableHeight - highAirDiagramHeight - thermalVelocityDiagramHeight - thqDiagramHeight - rainDiagramHeight - 11 - gutterHeight * 7); // px
// Adjust the height of the air diagram depending on the available height
// Find the number of entries that will be shown in the diagram
const numberOfEntries =
// We assume that all the forecasts have similar density of information
flatForecasts[0].aboveGround
.findIndex(aboveGround => aboveGround.elevation > forecasts.elevation + airDiagramHeightAboveGroundLevel);
// The preferred height is the height where the density of information is optimal
const airDiagramPreferredHeight =
(numberOfEntries >= 0 ? numberOfEntries : flatForecasts[0].aboveGround.length) * meteogramColumnWidth;
const airDiagramAvailableHeight = diagramsAvailableHeight - highAirDiagramHeight - thermalVelocityDiagramHeight - thqDiagramHeight - rainDiagramHeight - 11 - gutterHeight * 7; // px
// If possible, use the preferred height, but if there is not enough space (e.g. on small screens), take the available height
const airDiagramHeight = Math.min(airDiagramPreferredHeight, airDiagramAvailableHeight);
const airDiagramTop = highAirDiagramTop + highAirDiagramHeight; // No gutter between high air diagram and air diagram

const rainDiagramTop = airDiagramTop + airDiagramHeight + gutterHeight * 4;
Expand Down Expand Up @@ -75,6 +94,7 @@ export const meteogram = (forecasts: LocationForecasts, state: State): { key: JS
leftKeyCtx,
rightKeyCtx,
forecasts,
flatForecasts,
thqDiagramTop,
thqDiagramHeight,
thermalVelocityDiagramTop,
Expand All @@ -83,6 +103,7 @@ export const meteogram = (forecasts: LocationForecasts, state: State): { key: JS
highAirDiagramHeight,
airDiagramTop,
airDiagramHeight,
airDiagramHeightAboveGroundLevel,
rainDiagramTop,
rainDiagramHeight,
canvasWidth,
Expand All @@ -108,6 +129,7 @@ const drawMeteogram = (
leftCtx: CanvasRenderingContext2D,
rightCtx: CanvasRenderingContext2D,
forecasts: LocationForecasts,
flatForecasts: Array<DetailedForecast>,
thqDiagramTop: number,
thqDiagramHeight: number,
thermalVelocityDiagramTop: number,
Expand All @@ -116,6 +138,7 @@ const drawMeteogram = (
highAirDiagramHeight: number,
airDiagramTop: number,
airDiagramHeight: number,
airDiagramHeightAboveGroundLevel: number,
rainDiagramTop: number,
rainDiagramHeight: number,
canvasWidth: number,
Expand All @@ -136,12 +159,6 @@ const drawMeteogram = (
rightCtx.fillStyle = 'white';
rightCtx.fillRect(0, 0, keyWidth, canvasHeight);
rightCtx.restore();

const flatForecasts: Array<DetailedForecast> =
forecasts.dayForecasts.map(x => x.forecasts).reduce((x, y) => x.concat(y), []); // Alternative to flatMap
const maxBoundaryLayerDepth =
flatForecasts.reduce((x, forecast) => Math.max(x, forecast.boundaryLayer.depth), -Infinity);
const airDiagramHeightAboveGroundLevel = Math.max(2000, maxBoundaryLayerDepth + 1000 /* meters */);

const pressureScale = new Scale([990, 1035 /* hPa */], [0, airDiagramHeight], false);
const pressureLevels = [990, 999, 1008, 1017, 1026, 1035];
Expand Down Expand Up @@ -174,14 +191,10 @@ const drawMeteogram = (
const temperatureStyle = 'black';

const columns = (drawColumn: (forecast: DetailedForecast, columnStart: number, columnEnd: number, date: Date) => void): void => {
let i = 0;
forecasts.dayForecasts.forEach(dayForecast => {
dayForecast.forecasts.forEach(forecast => {
const columnStart = i * meteogramColumnWidth;
const columnEnd = columnStart + meteogramColumnWidth;
drawColumn(forecast, columnStart, columnEnd, forecast.time);
i = i + 1;
});
flatForecasts.forEach((forecast, i) => {
const columnStart = i * meteogramColumnWidth;
const columnEnd = columnStart + meteogramColumnWidth;
drawColumn(forecast, columnStart, columnEnd, forecast.time);
});
}

Expand Down Expand Up @@ -426,8 +439,8 @@ const drawMeteogram = (
}

// Elevation levels
elevationLevels.forEach(elevation => {
const y = elevationScale.apply(elevation);
elevationLevels.forEach(elevationLevel => {
const y = elevationScale.apply(elevationLevel);
airDiagram.line([0, y], [canvasWidth, y], 'gray');
});

Expand Down Expand Up @@ -541,14 +554,14 @@ const drawMeteogram = (
);
leftAirDiagram.text('m', [keyWidth - 5, airDiagramHeight - 15], 'black', 'right', 'middle');

elevationLevels.forEach(elevation => {
const y = elevationScale.apply(elevation);
elevationLevels.forEach(elevationLevel => {
const y = elevationScale.apply(elevationLevel);
leftAirDiagram.line(
[keyWidth - 8, y],
[keyWidth, y],
'black'
);
leftAirDiagram.text(`${Math.round(elevation)}`, [keyWidth - 10, y], 'black', 'right', 'middle');
leftAirDiagram.text(`${Math.round(elevationLevel)}`, [keyWidth - 10, y], 'black', 'right', 'middle');
});

// Rain
Expand Down
6 changes: 4 additions & 2 deletions frontend/src/diagrams/Sounding.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import hooks from "../css-hooks";

// Difference between two temperatures shown on the temperature axis
const temperatureScaleStep = 10;
const windArrowSize = 30;

const temperatureScaleAndLevels = (
aboveGround: Array<AboveGround>,
Expand Down Expand Up @@ -300,7 +301,6 @@ const drawSounding = (

// --- Sounding Diagram

const windArrowSize = 30;
const windColor = `rgba(62, 0, 0, ${ windNumericValuesShown ? 0.5 : 0.3 })`;
const windCenterX =
temperatureScale.apply(
Expand Down Expand Up @@ -410,7 +410,9 @@ const drawSounding = (
const computeSoundingHeightAndMaxElevation = (zoomed: boolean, elevation: number, forecast: DetailedForecast): [number, number] => {
const maxElevation = zoomed ? (elevation + forecast.boundaryLayer.soaringLayerDepth + 2000) : 12000; // m

const preferredHeight = (maxElevation - elevation) / 5; // Arbitrary factor to make the diagram visually nice
const numberOfEntries = forecast.aboveGround.findIndex(aboveGround => aboveGround.elevation >= maxElevation)
const preferredHeight =
(numberOfEntries >= 0 ? numberOfEntries : forecast.aboveGround.length) * windArrowSize * 1.2;
const canvasHeight = Math.min(preferredHeight, diagramsAvailableHeight);
return [canvasHeight, maxElevation];
}
6 changes: 4 additions & 2 deletions frontend/src/styles/Styles.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,12 @@ export const closeButtonSize = 24;
// width of the left key shown on the diagrams
export const keyWidth = 40;
// width of the sounding diagrams
export const soundingWidth = Math.max(Math.min(600, document.documentElement.clientWidth - keyWidth), 250);
export const soundingWidth =
Math.max(Math.min(600, document.documentElement.clientWidth - keyWidth), 250);

// available height in the viewport for drawing the diagrams (sounding and meteogram)
export const diagramsAvailableHeight = document.documentElement.clientHeight - 35 /* top time selector */ - 52 /* bottom time selector */ - 58 /* text information and help */ - 5;
export const diagramsAvailableHeight =
document.documentElement.clientHeight - 35 /* top time selector */ - 52 /* bottom time selector */ - 58 /* text information and help */ - 5;

// height of the period selector shown at the top of the screen
export const periodSelectorHeight = 13 /* day height */ + 22 /* hour height */;
Expand Down

0 comments on commit a6e63c2

Please sign in to comment.