remove echarts, use canvas

This commit is contained in:
Vincent van der Wal
2026-07-19 15:25:04 +02:00
parent 6d81af8df5
commit e031716ce6
37 changed files with 1483 additions and 2510 deletions
+106
View File
@@ -0,0 +1,106 @@
/**
* Chart Data Helpers
*
* Shared color palette and data-processing helpers used by the chart pages.
* Ported from the previous ECharts utilities so the visual identity and
* calculations stay identical.
*/
// ─── Color Palette ───────────────────────────────────────────────────────────
/** Default series color palette matching the application's design system */
export const SERIES_COLORS = [
'#5470c6',
'#91cc75',
'#fac858',
'#ee6666',
'#73c0de',
'#3ba272',
'#fc8452',
'#9a60b4',
'#ea7ccc',
'#4dc9f6'
] as const;
/** Semantic colors used for specific chart elements */
export const CHART_COLORS = {
average: '#5e5e5e',
currentTimeLine: '#ef4444',
daylight: 'rgba(255, 255, 194, 0.3)',
memberLine: 'rgba(115, 192, 222, 0.45)'
} as const;
// ─── Utility: Detect column-type variables ───────────────────────────────────
/** Units that should be rendered as bar/column charts instead of lines. */
const COLUMN_UNITS = new Set(['mm', 'cm', 'inch', 'MJ/m²']);
/**
* Returns true if the given unit should be rendered as a bar chart.
*/
export function isColumnUnit(unit: string): boolean {
return COLUMN_UNITS.has(unit);
}
// ─── Data Processing Helpers ─────────────────────────────────────────────────
export interface AverageResult {
average: number[];
averageCount: number[];
}
/**
* Calculates per-timestep average and count from hourly model data.
*
* @param hourlyData - The `data.hourly` object from the API response
* @param variable - The variable prefix to filter on (e.g. 'temperature_2m')
* @param timeLength - Number of timesteps
* @returns Object containing running average and count arrays
*/
export function calculateAverage(
hourlyData: Record<string, unknown>,
variable: string,
timeLength: number
): AverageResult {
const average = new Array<number>(timeLength).fill(0);
const averageCount = new Array<number>(timeLength).fill(0);
for (const [model, values] of Object.entries(hourlyData)) {
if (model === 'time') continue;
if (!model.startsWith(variable)) continue;
for (const [index, val] of (values as number[]).entries()) {
if (val !== null && val !== undefined && isFinite(val)) {
average[index] += val;
averageCount[index]++;
}
}
}
// Finalize average values
for (let i = 0; i < timeLength; i++) {
if (averageCount[i] > 0) {
average[i] = Math.round((average[i] / averageCount[i]) * 10) / 10;
}
}
return { average, averageCount };
}
/**
* Finds the unit string for a given variable from the hourly_units map.
* Returns an empty string if the variable is not found.
*/
export function findUnit(
hourlyUnits: Record<string, string>,
hourlyData: Record<string, unknown>,
variable: string
): string {
for (const model of Object.keys(hourlyData)) {
if (model === 'time') continue;
if (model.startsWith(variable) && hourlyUnits[model]) {
return hourlyUnits[model];
}
}
return '';
}