|
|
|
|
@@ -1,53 +1,48 @@
|
|
|
|
|
<script setup lang="ts">
|
|
|
|
|
import { computed, ref, onMounted } from 'vue'
|
|
|
|
|
import { Line } from 'vue-chartjs'
|
|
|
|
|
import {computed, ref, onMounted} from 'vue';
|
|
|
|
|
import {Line} from 'vue-chartjs';
|
|
|
|
|
import {
|
|
|
|
|
Chart as ChartJS, CategoryScale, LinearScale, PointElement,
|
|
|
|
|
LineElement, Tooltip, Legend, Filler, type ChartOptions
|
|
|
|
|
} from 'chart.js'
|
|
|
|
|
import { METRICS, formatValue } from '../services/units'
|
|
|
|
|
import { fetchHistoricHourly } from '../services/weather'
|
|
|
|
|
import type { DataRow } from '../services/api'
|
|
|
|
|
import { api } from '../services/api'
|
|
|
|
|
} from 'chart.js';
|
|
|
|
|
import {METRICS, formatValue} from '../services/units';
|
|
|
|
|
import type {DataRow} from '../services/api';
|
|
|
|
|
import {api} from '../services/api';
|
|
|
|
|
|
|
|
|
|
ChartJS.register(CategoryScale, LinearScale, PointElement, LineElement, Tooltip, Legend, Filler)
|
|
|
|
|
ChartJS.register(CategoryScale, LinearScale, PointElement, LineElement, Tooltip, Legend, Filler);
|
|
|
|
|
|
|
|
|
|
const props = defineProps<{ metricKey: string; currentData: DataRow }>()
|
|
|
|
|
const props = defineProps<{metricKey: string; currentData: DataRow}>();
|
|
|
|
|
|
|
|
|
|
const historic = ref<DataRow[]>([])
|
|
|
|
|
const forecast = ref<DataRow[]>([])
|
|
|
|
|
const loading = ref(true)
|
|
|
|
|
const meta = computed(() => METRICS[props.metricKey])
|
|
|
|
|
const historic = ref<DataRow[]>([]);
|
|
|
|
|
const forecast = ref<DataRow[]>([]);
|
|
|
|
|
const loading = ref(true);
|
|
|
|
|
const meta = computed(() => METRICS[props.metricKey]);
|
|
|
|
|
|
|
|
|
|
onMounted(async () => {
|
|
|
|
|
const now = new Date()
|
|
|
|
|
const start = new Date(now.getTime() - 24 * 3600000).toISOString()
|
|
|
|
|
const end = new Date(now.getTime() + 48 * 3600000).toISOString()
|
|
|
|
|
const [hist, fore] = await Promise.allSettled([
|
|
|
|
|
fetchHistoricHourly(start, now.toISOString()),
|
|
|
|
|
api.hourly(now.toISOString(), end),
|
|
|
|
|
])
|
|
|
|
|
if (hist.status === 'fulfilled') historic.value = hist.value.filter(r => r[props.metricKey] != null)
|
|
|
|
|
if (fore.status === 'fulfilled') forecast.value = fore.value.filter(r => r[props.metricKey] != null)
|
|
|
|
|
loading.value = false
|
|
|
|
|
})
|
|
|
|
|
const start = new Date(Date.now() - 24 * 3600000);
|
|
|
|
|
const end = new Date(Date.now() + 48 * 3600000);
|
|
|
|
|
const hourly = await api.hourly(start, end);
|
|
|
|
|
historic.value = hourly.filter((h: any) => new Date(h.time).getTime() <= Date.now());
|
|
|
|
|
forecast.value = hourly.filter((h: any) => new Date(h.time).getTime() > Date.now());
|
|
|
|
|
loading.value = false;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const nowLabel = computed(() => {
|
|
|
|
|
const d = new Date()
|
|
|
|
|
return `${d.getHours().toString().padStart(2,'0')}:${d.getMinutes().toString().padStart(2,'0')}`
|
|
|
|
|
})
|
|
|
|
|
const d = new Date();
|
|
|
|
|
return `${d.getHours().toString().padStart(2, '0')}:${d.getMinutes().toString().padStart(2, '0')}`;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const chartData = computed(() => {
|
|
|
|
|
const color = meta.value?.color ?? '#38bdf8'
|
|
|
|
|
const histLabels = historic.value.map(r => r.time as string)
|
|
|
|
|
const foreLabels = forecast.value.map(r => r.time as string)
|
|
|
|
|
const histVals = historic.value.map(r => r[props.metricKey] as number)
|
|
|
|
|
const foreVals = forecast.value.map(r => r[props.metricKey] as number)
|
|
|
|
|
const currentVal = props.currentData[props.metricKey] as number | null
|
|
|
|
|
const color = meta.value?.color ?? '#38bdf8';
|
|
|
|
|
const histLabels = historic.value.map(r => r.time as string);
|
|
|
|
|
const foreLabels = forecast.value.map(r => r.time as string);
|
|
|
|
|
const histVals = historic.value.map(r => r[props.metricKey] as number);
|
|
|
|
|
const foreVals = forecast.value.map(r => r[props.metricKey] as number);
|
|
|
|
|
const currentVal = props.currentData[props.metricKey] as number | null;
|
|
|
|
|
|
|
|
|
|
const allLabels = [...histLabels, nowLabel.value, ...foreLabels]
|
|
|
|
|
const histData = [...histVals, currentVal, ...foreVals.map(() => null)]
|
|
|
|
|
const foreData = [...histVals.map(() => null), currentVal, ...foreVals]
|
|
|
|
|
const allLabels = [...histLabels, nowLabel.value, ...foreLabels];
|
|
|
|
|
const histData = [...histVals, currentVal, ...foreVals.map(() => null)];
|
|
|
|
|
const foreData = [...histVals.map(() => null), currentVal, ...foreVals];
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
labels: allLabels,
|
|
|
|
|
@@ -87,8 +82,8 @@ const chartData = computed(() => {
|
|
|
|
|
spanGaps: false,
|
|
|
|
|
}
|
|
|
|
|
]
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
};
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const chartOptions = computed<ChartOptions<'line'>>(() => ({
|
|
|
|
|
responsive: true,
|
|
|
|
|
@@ -109,8 +104,8 @@ const chartOptions = computed<ChartOptions<'line'>>(() => ({
|
|
|
|
|
maxTicksLimit: 12,
|
|
|
|
|
maxRotation: 0,
|
|
|
|
|
callback(val, i) {
|
|
|
|
|
const lbl = this.getLabelForValue(i)
|
|
|
|
|
return lbl?.length === 5 && lbl.endsWith(':00') ? lbl : ''
|
|
|
|
|
const lbl = this.getLabelForValue(i);
|
|
|
|
|
return lbl?.length === 5 && lbl.endsWith(':00') ? lbl : '';
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
grid: {color: 'var(--border)'},
|
|
|
|
|
@@ -132,7 +127,7 @@ const chartOptions = computed<ChartOptions<'line'>>(() => ({
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}))
|
|
|
|
|
}));
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
<style scoped lang="scss">
|
|
|
|
|
|