I have been struggling to update a Bar Graph dynamically whenever there is a change in the data object. Despite using reactive() and ref(), I am unable to achieve the desired functionality as the graph only updates upon page refresh.
Below is my chart component:
<script setup lang="ts">
import { Bar } from "vue-chartjs"
import {
Chart as ChartJS,
Title,
Tooltip,
Legend,
BarElement,
CategoryScale,
LinearScale,
} from "chart.js"
ChartJS.register(Title, Tooltip, Legend, BarElement, CategoryScale, LinearScale)
const props = defineProps<{ userHours: {} }>()
const chartData = ref({
labels: Object.keys(props.userHours),
datasets: [
{
label: "Worker Hours per Employee",
data: [...Object.values(props.userHours)] as number[],
maxBarThickness: 32,
backgroundColor: "#ffb53c",
},
],
})
const chartOptions = ref({
responsive: true,
maintainAspectRatio: true,
scales: {
x: {
grid: {
color: "black",
},
ticks: {
color: "#eee",
},
},
y: {
grid: {
color: "black",
},
ticks: {
color: "#eee",
},
},
},
legend: {
labels: {
fontColor: "#eee",
},
},
})
const chartStyles = computed(() => {
return {
width: "100%",
height: "20ch",
}
})
</script>
<template>
<Bar
id="workhr-chart"
:options="chartOptions"
:data="chartData"
:style="chartStyles"
>
</Bar>
</template>
Here is the main page (parent) code snippet:
<script setup lang="ts">
import { User, Subtask } from ".prisma/client"
import { optionalMemberExpression } from "@babel/types"
const memberHours = reactive(initHours())
function initHours(): { [key: string]: number } {
const hoursByMember: { [key: string]: number } = {}
const tasks = project.value!.tasks.filter(
task => task.status === 0 || task.status === 1,
)
for (const task of tasks) {
for (const member of projectMembers) {
if (task.assignees.includes(member)) {
if (hoursByMember.hasOwnProperty(member.name)) {
hoursByMember[member.name] += task.workerHours
} else {
hoursByMember[member.name] = task.workerHours
}
}
}
}
return hoursByMember
}
function updateHours(uid: number, status: boolean) {
let task = project.value!.tasks.find(task => task.uid === uid)
let foundSubtask: Subtask | undefined
if (!task) {
// Check if the uid is a subtask
for (const t of project.value!.tasks) {
foundSubtask = t.subtasks.find(subtask => subtask.uid === uid)
if (foundSubtask) {
task = t
break
}
}
}
if (!task) {
return
}
const assignees = new Set(task.assignees.map(member => member.name))
for (const memberName of Object.keys(memberHours)) {
if (assignees.has(memberName)) {
if (status) {
memberHours[memberName] -= foundSubtask
? foundSubtask.workerHours
: task.workerHours
} else {
memberHours[memberName] += foundSubtask
? foundSubtask.workerHours
: task.workerHours
}
}
}
console.log(memberHours)
}
</script>
<template>
<TaskSwitcher :tasks="project!.tasks" @update="updateHours" />
<ProjectChart :user-hours="memberHours" />
</template>
Any guidance on making my chart interactive would be greatly appreciated. I've been grappling with this issue for days without success.
Thank you!