fallback and 404
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
<script lang="ts">
|
||||
import { fade } from 'svelte/transition';
|
||||
|
||||
import { storedVariablePrefs } from '$lib/stores/settings';
|
||||
|
||||
import { formatZoned, getRelativeDayLabel } from '$lib/utils/date';
|
||||
|
||||
import { ChartContainer, ChartToolbar } from '$lib/components/charts';
|
||||
@@ -68,6 +70,12 @@
|
||||
{ label: 'All', apply: () => resetZoom() }
|
||||
];
|
||||
|
||||
// Soft band drawn on every chart marking the currently selected day
|
||||
let selectedDayHighlight = $derived.by(() => {
|
||||
const start = dayStartSec(selectedDay);
|
||||
return start == null ? undefined : { start, end: start + SECONDS_PER_DAY };
|
||||
});
|
||||
|
||||
// ─── Series Building ────────────────────────────────────────────────────────
|
||||
|
||||
let tempUnit = $derived(getTempUnit(units));
|
||||
@@ -90,17 +98,14 @@
|
||||
if (!data) return [];
|
||||
|
||||
const { hourly } = data;
|
||||
// Variables the user disabled in the sidebar are left out entirely
|
||||
const on = (key: string): boolean => $storedVariablePrefs.charts?.[key] ?? true;
|
||||
const defs: ChartDef[] = [];
|
||||
|
||||
const tempChart: ChartDef = {
|
||||
title: 'Temperature & Cloud Cover',
|
||||
unit: tempUnit,
|
||||
// Hidden inverted right axis (0-250) so cloud cover hangs from the top,
|
||||
// occupying at most the upper 40% of the plot
|
||||
yMinRight: 0,
|
||||
yMaxRight: 250,
|
||||
invertRight: true,
|
||||
series: [
|
||||
{
|
||||
if (on('temperature') || on('cloud_cover')) {
|
||||
const series: ChartSeries[] = [];
|
||||
if (on('cloud_cover')) {
|
||||
series.push({
|
||||
name: 'Cloud Cover',
|
||||
type: 'line',
|
||||
color: 'rgb(150, 150, 150)',
|
||||
@@ -110,8 +115,10 @@
|
||||
fillOpacity: 0.25,
|
||||
axis: 'right',
|
||||
format: (v) => `${v.toFixed(0)}%`
|
||||
},
|
||||
{
|
||||
});
|
||||
}
|
||||
if (on('temperature')) {
|
||||
series.push({
|
||||
name: 'Temperature',
|
||||
type: 'line',
|
||||
color: '#ef6c00',
|
||||
@@ -120,26 +127,35 @@
|
||||
fill: true,
|
||||
fillOpacity: 0.2,
|
||||
format: (v) => `${v.toFixed(1)} ${tempUnit}`
|
||||
}
|
||||
]
|
||||
};
|
||||
});
|
||||
}
|
||||
defs.push({
|
||||
title: [on('temperature') && 'Temperature', on('cloud_cover') && 'Cloud Cover']
|
||||
.filter(Boolean)
|
||||
.join(' & '),
|
||||
unit: tempUnit,
|
||||
// Hidden inverted right axis (0-250) so cloud cover hangs from the top,
|
||||
// occupying at most the upper 40% of the plot
|
||||
yMinRight: 0,
|
||||
yMaxRight: 250,
|
||||
invertRight: true,
|
||||
series
|
||||
});
|
||||
}
|
||||
|
||||
const precipChart: ChartDef = {
|
||||
title: 'Precipitation & Probability',
|
||||
unit: precipUnit,
|
||||
unitRight: '%',
|
||||
yMin: 0,
|
||||
yMinRight: 0,
|
||||
yMaxRight: 100,
|
||||
series: [
|
||||
{
|
||||
if (on('precipitation') || on('precipitation_probability')) {
|
||||
const series: ChartSeries[] = [];
|
||||
if (on('precipitation')) {
|
||||
series.push({
|
||||
name: 'Precipitation',
|
||||
type: 'bar',
|
||||
color: 'rgba(30, 136, 229, 0.8)',
|
||||
data: hourly.precipitation,
|
||||
format: (v) => `${v.toFixed(1)} ${precipUnit}`
|
||||
},
|
||||
{
|
||||
});
|
||||
}
|
||||
if (on('precipitation_probability')) {
|
||||
series.push({
|
||||
name: 'Precip. Probability',
|
||||
type: 'line',
|
||||
color: '#5c6bc0',
|
||||
@@ -148,20 +164,28 @@
|
||||
dashed: true,
|
||||
axis: 'right',
|
||||
format: (v) => `${v.toFixed(0)}%`
|
||||
}
|
||||
]
|
||||
};
|
||||
});
|
||||
}
|
||||
defs.push({
|
||||
title: [
|
||||
on('precipitation') && 'Precipitation',
|
||||
on('precipitation_probability') && 'Probability'
|
||||
]
|
||||
.filter(Boolean)
|
||||
.join(' & '),
|
||||
unit: precipUnit,
|
||||
unitRight: on('precipitation_probability') ? '%' : undefined,
|
||||
yMin: 0,
|
||||
yMinRight: 0,
|
||||
yMaxRight: 100,
|
||||
series
|
||||
});
|
||||
}
|
||||
|
||||
const windChart: ChartDef = {
|
||||
title: 'Wind Speed & Humidity',
|
||||
unit: windUnit,
|
||||
unitRight: '%',
|
||||
yMin: 0,
|
||||
yMinRight: 0,
|
||||
yMaxRight: 100,
|
||||
showCredit: true,
|
||||
series: [
|
||||
{
|
||||
if (on('wind') || on('humidity')) {
|
||||
const series: ChartSeries[] = [];
|
||||
if (on('wind')) {
|
||||
series.push({
|
||||
name: 'Wind Speed',
|
||||
type: 'line',
|
||||
color: '#26a69a',
|
||||
@@ -174,8 +198,10 @@
|
||||
const dirLabel = dir != null && !isNaN(dir) ? ` (${getWindDirectionLabel(dir)})` : '';
|
||||
return `${v.toFixed(0)} ${windUnit}${dirLabel}`;
|
||||
}
|
||||
},
|
||||
{
|
||||
});
|
||||
}
|
||||
if (on('humidity')) {
|
||||
series.push({
|
||||
name: 'Humidity',
|
||||
type: 'line',
|
||||
color: '#8d6e63',
|
||||
@@ -184,11 +210,24 @@
|
||||
dashed: true,
|
||||
axis: 'right',
|
||||
format: (v) => `${v.toFixed(0)}%`
|
||||
}
|
||||
]
|
||||
};
|
||||
});
|
||||
}
|
||||
defs.push({
|
||||
title: [on('wind') && 'Wind Speed', on('humidity') && 'Humidity']
|
||||
.filter(Boolean)
|
||||
.join(' & '),
|
||||
unit: windUnit,
|
||||
unitRight: on('humidity') ? '%' : undefined,
|
||||
yMin: 0,
|
||||
yMinRight: 0,
|
||||
yMaxRight: 100,
|
||||
series
|
||||
});
|
||||
}
|
||||
|
||||
return [tempChart, precipChart, windChart];
|
||||
if (defs.length > 0) defs[defs.length - 1].showCredit = true;
|
||||
|
||||
return defs;
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -230,30 +269,39 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ChartContainer {loading} chartCount={3} chartHeight={300}>
|
||||
{#each chartDefs as def, i (def.title)}
|
||||
<CanvasChart
|
||||
bind:this={chartComponents[i]}
|
||||
timestamps={timestampsSec}
|
||||
timezone={data.timezone}
|
||||
series={def.series}
|
||||
bands={data.daylightBands}
|
||||
unit={def.unit}
|
||||
unitRight={def.unitRight}
|
||||
yMin={def.yMin}
|
||||
yMinRight={def.yMinRight}
|
||||
yMaxRight={def.yMaxRight}
|
||||
invertRight={def.invertRight}
|
||||
title={def.title}
|
||||
showCredit={def.showCredit}
|
||||
showLegend
|
||||
height={300}
|
||||
group={CHART_GROUP}
|
||||
/>
|
||||
{/each}
|
||||
</ChartContainer>
|
||||
{#if chartDefs.length > 0}
|
||||
<ChartContainer {loading} chartCount={chartDefs.length} chartHeight={300}>
|
||||
{#each chartDefs as def, i (def.title)}
|
||||
<CanvasChart
|
||||
bind:this={chartComponents[i]}
|
||||
timestamps={timestampsSec}
|
||||
timezone={data.timezone}
|
||||
series={def.series}
|
||||
bands={data.daylightBands}
|
||||
highlight={selectedDayHighlight}
|
||||
unit={def.unit}
|
||||
unitRight={def.unitRight}
|
||||
yMin={def.yMin}
|
||||
yMinRight={def.yMinRight}
|
||||
yMaxRight={def.yMaxRight}
|
||||
invertRight={def.invertRight}
|
||||
title={def.title}
|
||||
showCredit={def.showCredit}
|
||||
showLegend
|
||||
height={300}
|
||||
group={CHART_GROUP}
|
||||
/>
|
||||
{/each}
|
||||
</ChartContainer>
|
||||
|
||||
<div class="mt-6 md:mt-10">
|
||||
<ChartToolbar charts={liveCharts} fileName="week-forecast" />
|
||||
</div>
|
||||
<div class="mt-6 md:mt-10">
|
||||
<ChartToolbar charts={liveCharts} fileName="week-forecast" />
|
||||
</div>
|
||||
{:else}
|
||||
<div
|
||||
class="rounded-xl border border-dashed border-border px-4 py-10 text-center text-sm text-muted-foreground"
|
||||
>
|
||||
All chart variables are hidden — enable some under “Variables”.
|
||||
</div>
|
||||
{/if}
|
||||
</section>
|
||||
|
||||
Reference in New Issue
Block a user