feat: implement map view for lake visualization and automate data scraping pipeline
This commit is contained in:
@@ -50,14 +50,14 @@ const LakeDetail = ({ language, lakeId }: Props) => {
|
||||
})
|
||||
.catch(err => console.error(err));
|
||||
|
||||
fetch('/data/lipno.json')
|
||||
const internalId = lakeId ? lakeId.split('|')[0] : 'VLL1';
|
||||
|
||||
fetch(`/data/${internalId}.json`)
|
||||
.then(res => res.json())
|
||||
.then(json => {
|
||||
const formattedData = json.map((item: any) => {
|
||||
const outflow = item.flow;
|
||||
const inflow = outflow + (Math.random() * 2 - 0.5);
|
||||
const volume = 301.2 + (item.level - 723) * 10;
|
||||
const fullness = (volume / 306) * 100;
|
||||
const outflow = item.flow === null || isNaN(item.flow) ? 0 : item.flow;
|
||||
const inflow = outflow; // No random inflow anymore, PVL only gives us one flow value
|
||||
|
||||
return {
|
||||
timestamp: item.timestamp,
|
||||
@@ -65,11 +65,11 @@ const LakeDetail = ({ language, lakeId }: Props) => {
|
||||
day: '2-digit', month: '2-digit', year: 'numeric',
|
||||
hour: '2-digit', minute: '2-digit'
|
||||
}),
|
||||
level: item.level,
|
||||
level: item.level === null || isNaN(item.level) ? 0 : item.level,
|
||||
outflow: outflow,
|
||||
inflow: inflow,
|
||||
volume: volume,
|
||||
fullness: fullness
|
||||
volume: 0, // PVL doesn't provide this here
|
||||
fullness: 0
|
||||
};
|
||||
});
|
||||
setData(formattedData);
|
||||
@@ -92,6 +92,17 @@ const LakeDetail = ({ language, lakeId }: Props) => {
|
||||
const latestData = data[data.length - 1] || { level: 0, inflow: 0, outflow: 0, volume: 0, fullness: 0 };
|
||||
const curveType = isSmoothed ? 'monotone' : 'linear';
|
||||
|
||||
// Find the last record that actually has flow data (often the very last record is incomplete on PVL)
|
||||
const lastValidFlowData = [...data].reverse().find(d => d.outflow > 0) || latestData;
|
||||
|
||||
const kpiData = {
|
||||
level: latestData.level,
|
||||
inflow: lastValidFlowData.inflow,
|
||||
outflow: lastValidFlowData.outflow,
|
||||
volume: lakeInfo?.volume || 0,
|
||||
fullness: lakeInfo?.capacity || 0
|
||||
};
|
||||
|
||||
return (
|
||||
<div style={{ display: 'flex', flexDirection: 'column', gap: '1.5rem', width: '100%' }}>
|
||||
<div style={{ color: 'var(--text-muted)', fontSize: '0.9rem', marginTop: '-0.5rem', display: 'flex', alignItems: 'center', gap: '0.5rem' }}>
|
||||
@@ -107,7 +118,7 @@ const LakeDetail = ({ language, lakeId }: Props) => {
|
||||
<button>{dict.all}</button>
|
||||
</div>
|
||||
|
||||
<KpiCards data={latestData} language={language} lakeName={lakeInfo ? lakeInfo.name : 'Lipno 1'} />
|
||||
<KpiCards data={kpiData} language={language} lakeName={lakeInfo ? lakeInfo.name : 'Lipno 1'} />
|
||||
|
||||
{/* CHART SECTION */}
|
||||
<div className="chart-card">
|
||||
@@ -128,15 +139,11 @@ const LakeDetail = ({ language, lakeId }: Props) => {
|
||||
</defs>
|
||||
<XAxis dataKey="date" stroke="var(--text-muted)" tick={{fill: 'var(--text-muted)', fontSize: 12}} minTickGap={50} />
|
||||
<YAxis yAxisId="left" domain={['dataMin - 0.5', 'dataMax + 0.5']} stroke="var(--text-muted)" tick={{fill: 'var(--text-muted)', fontSize: 12}} tickFormatter={(v) => v.toFixed(2)} />
|
||||
<YAxis yAxisId="right" orientation="right" domain={[0, 'auto']} stroke="var(--text-muted)" tick={{fill: 'var(--text-muted)', fontSize: 12}} />
|
||||
<YAxis yAxisId="right" orientation="right" domain={[0, (dataMax: number) => Math.max(dataMax, 1)]} stroke="var(--text-muted)" tick={{fill: 'var(--text-muted)', fontSize: 12}} />
|
||||
|
||||
<CartesianGrid strokeDasharray="3 3" stroke="rgba(255,255,255,0.05)" vertical={false} />
|
||||
<Tooltip content={<CustomTooltip language={language} />} />
|
||||
|
||||
{/* Reference Lines */}
|
||||
<ReferenceLine yAxisId="left" y={725.60} stroke="var(--color-red)" strokeDasharray="3 3" label={{ position: 'insideTopLeft', value: `${dict.maxLevel} (725.60)`, fill: 'var(--text-main)', fontSize: 12 }} />
|
||||
<ReferenceLine yAxisId="left" y={724.90} stroke="var(--color-green)" strokeDasharray="3 3" label={{ position: 'insideBottomLeft', value: `${dict.storageLevel} (724.90)`, fill: 'var(--text-main)', fontSize: 12 }} />
|
||||
|
||||
{/* Data Series */}
|
||||
<Area yAxisId="left" type={curveType} dataKey="level" stroke="var(--color-cyan)" strokeWidth={2} fillOpacity={1} fill="url(#colorLevel)" />
|
||||
<Line yAxisId="right" type={curveType} dataKey="inflow" stroke="var(--color-green)" strokeWidth={2} dot={false} />
|
||||
@@ -150,8 +157,6 @@ const LakeDetail = ({ language, lakeId }: Props) => {
|
||||
<span style={{ display: 'flex', alignItems: 'center', gap: '0.5rem' }}><div style={{ width: '12px', height: '4px', backgroundColor: 'var(--color-cyan)' }}></div> {dict.level}</span>
|
||||
<span style={{ display: 'flex', alignItems: 'center', gap: '0.5rem' }}><div style={{ width: '12px', height: '4px', backgroundColor: 'var(--color-green)' }}></div> {dict.inflow}</span>
|
||||
<span style={{ display: 'flex', alignItems: 'center', gap: '0.5rem' }}><div style={{ width: '12px', height: '4px', backgroundColor: 'var(--color-orange)' }}></div> {dict.outflow}</span>
|
||||
<span style={{ display: 'flex', alignItems: 'center', gap: '0.5rem', color: 'var(--text-muted)' }}><div style={{ width: '12px', borderTop: '2px dashed var(--color-red)' }}></div> {dict.maxLevel}</span>
|
||||
<span style={{ display: 'flex', alignItems: 'center', gap: '0.5rem', color: 'var(--text-muted)' }}><div style={{ width: '12px', borderTop: '2px dashed var(--color-green)' }}></div> {dict.storageLevel}</span>
|
||||
</div>
|
||||
|
||||
{/* Smoothed Toggle Control */}
|
||||
|
||||
Reference in New Issue
Block a user