I’ve just retired and I’ve been trying to teach myself Vue and Python as hobby by writing a front-end (Vuetify) and back-end (DRF) to monitor our energy usage and cost. It’s been a challenge but all my CRUD functionality to maintain supplier, contract, tariff and meter reading data is working. Now I want to show the gas and net electricity use and how much the solar panels have generated in a chart. I think I’m fairly close and would be very grateful if someone could take a look at the following files and show me what I’m missing. They’re not so long so I posted all the code.
ReadingChart.vue is my component to display the chart:
<script setup lang="ts">
import { ref, onMounted,computed, onBeforeMount } from "vue";
import { getPrimary, getSecondary } from '@/utils/UpdateColors';
import { useMeterStore } from '@/stores/apps/meter';
const store = useMeterStore();
const getChartYears: any = computed(() => {
return store.years;
});
const getChartGas: any = computed(() => {
return store.gas;
});
const getChartStand_i: any = computed(() => {
return store.stand_i;
});
const getChartstand_ii: any = computed(() => {
return store.stand_ii;
});
let chart_years = ref(getChartYears);
let chart_gas = ref(getChartGas);
let chart_stand_i = ref(getChartStand_i);
let chart_stand_ii = ref(getChartstand_ii);
/*Chart*/
const chartOptions = computed(() => {
return {
grid: {
show: false,
borderColor: "transparent",
padding: { left: 0, right: 0, bottom: 0 },
},
plotOptions: {
bar: { horizontal: false, columnWidth: "35%", borderRadius: 0 },
},
colors: [getPrimary.value,getSecondary.value],
fill: { type: "solid", opacity: 1 },
chart: {
type: "bar",
height: 320,
offsetX: -15,
toolbar: { show: false },
foreColor: "#adb0bb",
fontFamily: "Poppins",
sparkline: { enabled: false },
},
dataLabels: { enabled: false },
markers: { size: 0 },
legend: { show: false },
xaxis: {
type: "category",
categories: JSON.parse(JSON.stringify(chart_years.value)),
// categories: ["2015","2018","2019","2020","2021","2022","2023","2024"],
labels: {
style: { cssClass: "grey--text lighten-2--text fill-color" },
},
},
yaxis: {
show: true,
min: 100,
max: 3500,
tickAmount: 3,
labels: {
style: {
cssClass: "grey--text lighten-2--text fill-color",
},
},
},
stroke: {
show: true,
width: 5,
lineCap: "butt",
colors: ["transparent"],
},
tooltip: { theme: "dark" },
};
});
let Chart = ref({
series: [
{ name: "gas_data", data: [] },
{ name: "stand_i_data", data: [] },
{ name: "stand_ii_data", data: [] },
],
});
const elementVisible = ref(false);
onMounted(() => {
store.fetchChartData();
const Chart = ref({
series: [
// { name: "gas_data", data: JSON.parse(JSON.stringify(chart_gas.value)) },
{ name: "gas_data", data: ["17.0","2.01","706.11","549.25","584.65","315.86","304.04",
"123.97"] },
{ name: "stand_i_data", data: JSON.parse(JSON.stringify(chart_stand_i.value)) },
{ name: "stand_ii_data", data: JSON.parse(JSON.stringify(chart_stand_ii.value))},
],
});
setTimeout(() => (elementVisible.value = true), 50);
});
</script>
<template>
<!-- ------------------------------------ -->
<!-- html -->
<!-- ------------------------------------ -->
<VCard elevation="10">
<v-card-text>
<div class="d-sm-flex align-center">
<div>
<h3 class="text-h5 title mb-1">Sales Overview</h3>
<h5 class="text-subtitle-1">Ample Admin Vs Pixel Admin</h5>
</div>
<div class="ml-auto">
<div class="d-flex align-center">
<div class="d-flex align-center px-2">
<span class="text-primary">
<span class="text-overline">
<i class="mdi mdi-brightness-1 mx-1"></i>
</span>
<span class="font-weight-regular">Ample</span>
</span>
</div>
<div class="d-flex align-center px-2">
<span class="text-secondary">
<span class="text-overline">
<i class="mdi mdi-brightness-1 mx-1"></i>
</span>
<span class="font-weight-regular">Pixel Admin</span>
</span>
</div>
</div>
</div>
</div>
<div v-show="elementVisible" class="mt-5">
<apexchart
type="bar" height="320" :options="chartOptions" :series="Chart.series"
></apexchart>
</div>
</v-card-text>
</VCard>
</template>
meter.ts is my store where I fetch the data from the database
import { defineStore } from 'pinia';
// project imports
import axios from 'axios';
const baseApiUrl = `${import.meta.env.VITE_DRF_API_URL}`;
const url = `${import.meta.env.VITE_DRF_API_URL}/api/reading/`;
export const useMeterStore = defineStore({
id: 'Meter',
state: () => ({
meter_readings: [],
chart_data: {},
years: [],
gas: [],
stand_i: [],
stand_ii: [],
}),
getters: {},
actions: {
// Fetch followers from action
async fetchMeterReadings() {
try {
const headers = get_headers();
const response = await axios.get(url, {headers}).then(request => request.data);
this.meter_readings = response.data;
} catch (error) {
// alert(error);
console.log(error);
}
},
async fetchChartData() {
try {
const headers = get_headers();
let customUrl = baseApiUrl + "/api/readingchart?year=all";
await axios.get(customUrl, {headers}).then(
request => {
this.years = request.data.data.years;
this.gas = request.data.data.gas;
this.stand_i = request.data.data.stand_i;
this.stand_ii = request.data.data.stand_ii;
}
)
} catch (error) {
// alert(error);
console.log(error);
}
},
async updateMeterReading(reading: {
id: string; consumption_date: string; stand_i: string; stand_ii: string; gas: string;
}){
try {
let token = localStorage.getItem('token');
const headers = get_headers();
await axios.put(url + reading.id + "/", reading, {headers}) .then(request => request.data);
}
catch (error) {
console.log(error);
}
}
}
});
function get_headers() {
let token = localStorage.getItem('token');
const headers = {
'Content-Type': 'application/json',
'Authorization': 'Token ' + token,
};
return headers;
}
The reason I said I thought I was close was that when the application is running and I make a change in VS Code by commenting out one of the lines of code in the Chart object series property or on the x-axis category (see code) and saving then the chart is displayed. If I run it again then the chart disappears and so I go around in circles. I cant figure it out. I guess I’m not quite there yet with Vue reactivity and I’d appreciate any help. I’m using node 20.12.2 and @vue/cli 5.0.8.