Skip to content

Commit

Permalink
fix: reactivity of Pie and Bar charts
Browse files Browse the repository at this point in the history
  • Loading branch information
0xbrayo committed Jul 10, 2024
1 parent 3165b56 commit d22aa30
Show file tree
Hide file tree
Showing 5 changed files with 142 additions and 149 deletions.
23 changes: 3 additions & 20 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@
"chart.js": "^4.4.2",
"chartjs-plugin-autocolors": "^0.2.2",
"firebase": "^9.23.0",
"lodash": "^4.17.21",
"pinia": "^2.1.3",
"pinia-plugin-persistedstate": "^3.2.1",
"vue": "^3.3.4",
"vue-chartjs": "^5.3.0",
"vue-router": "^4.2.2"
},
"devDependencies": {
Expand Down
2 changes: 1 addition & 1 deletion src/components/Dashboard.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<AWLHeader />
<div>
<h1>Dashboard</h1>
<StackedBarChart id="chart" :summary="summaries" />
<StackedBarChart id="chart" :summaries="summaries" />
<PieChart id="pie" :summaries="summaries" />
</div>
</template>
Expand Down
130 changes: 69 additions & 61 deletions src/components/PieChart.vue
Original file line number Diff line number Diff line change
@@ -1,70 +1,78 @@
<template>
<div>
<Pie :data="chartData" :options="chartOptions" />
</div>
<canvas ref="canvasRef" id="myChart"></canvas>
</template>

<script lang="ts" setup>
import { Pie } from 'vue-chartjs'
import autocolors from 'chartjs-plugin-autocolors'
import { Chart as ChartJS, ArcElement, Tooltip, Title } from 'chart.js'
import type { ChartDataset } from '@/types'
import type { ScreenTimeSummary } from '@/types'
import { ref } from 'vue'
<script setup lang="ts">
import { ref, watch } from 'vue';
import type { ScreenTimeSummary } from '@/types';
import autocolors from 'chartjs-plugin-autocolors';
import { Chart as ChartJS, ArcElement,PieController, Tooltip, Title } from 'chart.js';
ChartJS.register(autocolors, ArcElement, Tooltip, Title)
ChartJS.register(autocolors, ArcElement, PieController, Tooltip, Title);
const props = defineProps({
summaries: {
type: Array as () => ScreenTimeSummary[] | null,
required: true
}
})
const chartData = ref({
labels: [] as string[],
datasets: [] as ChartDataset[]
})
const chartOptions = {
responsive: true,
title: {
display: true,
text: 'Category time'
},
plugins: {
autocolors: {
enabled: true,
mode: 'data' as const
}
}
}
const summaries = ref(props.summaries)
const uniqueCategoriesSet: Set<string> = new Set()
summaries.value?.forEach((summary) => {
for (const category in summary.categoryTotals) {
uniqueCategoriesSet.add(category)
}
})
const uniqueCategories = Array.from(uniqueCategoriesSet)
const categoryTotals: number[] = []
for (const category of uniqueCategories) {
const categoryTotal = summaries.value?.reduce((acc, summary) => {
return acc + (summary.categoryTotals[category] || 0)
}, 0)
categoryTotals.push(categoryTotal || 0)
interface Props {
summaries: ScreenTimeSummary[] | null;
}
chartData.value.labels = uniqueCategories
chartData.value.datasets = [
{
label: 'Category time',
data: categoryTotals
const props = defineProps<Props>();
const canvasRef = ref<HTMLCanvasElement | null>(null);
const getChartData = () => {
const uniqueCategoriesSet: Set<string> = new Set();
props.summaries?.forEach((summary) => {
for (const category in summary.categoryTotals) {
uniqueCategoriesSet.add(category);
}
});
const uniqueCategories = Array.from(uniqueCategoriesSet);
const categoryTotals: number[] = [];
for (const category of uniqueCategories) {
const categoryTotal = props.summaries?.reduce((acc, summary) => {
return acc + (summary.categoryTotals[category] || 0);
}, 0);
categoryTotals.push(categoryTotal || 0);
}
]
</script>
return {
labels: uniqueCategories,
datasets: [
{
label: 'Category time',
data: categoryTotals
}
]
};
};
<style scoped>
canvas {
width: 400px;
height: 400px;
}
</style>
const renderChart = () => {
const canvas = canvasRef.value;
if (!canvas) return;
const ctx = canvas.getContext('2d');
if (!ctx) return;
ChartJS.getChart(canvas)?.destroy();
new ChartJS(ctx, {
type: 'pie',
data: getChartData(),
options: {
responsive: true,
plugins: {
autocolors: {
enabled: true,
mode: 'data'
}
}
}
});
};
watch(
() => props.summaries,
() => {
console.log('summaries changed');
renderChart();
},
{ deep: true }
);
</script>
134 changes: 68 additions & 66 deletions src/components/StackedBarChart.vue
Original file line number Diff line number Diff line change
@@ -1,26 +1,71 @@
<template>
<Bar :data="chartData" :options="chartOptions" />
<canvas ref="canvasRef" id="myChart"></canvas>
</template>

<script lang="ts" setup>
import {
Chart as ChartJS,
Title,
Tooltip,
Legend,
BarElement,
CategoryScale,
LinearScale
} from 'chart.js'
import autocolors from 'chartjs-plugin-autocolors'
import { Bar } from 'vue-chartjs'
import type { ChartDataset } from '@/types'
import type { ScreenTimeSummary } from '@/types'
import { ref } from 'vue'
import { ref, watch } from 'vue';
import type { ScreenTimeSummary } from '@/types';
import autocolors from 'chartjs-plugin-autocolors';
import { Chart as ChartJS, Legend, BarElement, BarController,CategoryScale, LinearScale, Tooltip, Title } from 'chart.js';
ChartJS.register(Title, Tooltip, Legend, BarElement, CategoryScale, LinearScale, autocolors)
ChartJS.register(Title, Tooltip, Legend, BarElement,BarController, CategoryScale, LinearScale, autocolors)
const chartOptions = {
interface Props {
summaries: ScreenTimeSummary[] | null;
}
const props = defineProps<Props>();
const canvasRef = ref<HTMLCanvasElement | null>(null);
const getChartData = () => {
const uniqueDates = Array.from(new Set(props.summaries?.map((summary) => summary.date)));
const uniqueDatesSorted = uniqueDates.sort((a, b) => {
const dateA = new Date(a);
const dateB = new Date(b);
return dateA.getTime() - dateB.getTime();
});
const uniqueWeekDays = uniqueDatesSorted.map((date) => {
const dateObj = new Date(date);
return dateObj.toLocaleDateString('en-US', { weekday: 'short' });
});
const uniqueCategoriesSet: Set<string> = new Set();
props.summaries?.forEach((summary) => {
for (const category in summary.categoryTotals) {
uniqueCategoriesSet.add(category);
}
});
const uniqueCategories = Array.from(uniqueCategoriesSet);
const categoryTotals: number[] = [];
for (const category of uniqueCategories) {
const categoryTotal = props.summaries?.reduce((acc, summary) => {
return acc + (summary.categoryTotals[category] || 0);
}, 0);
categoryTotals.push(categoryTotal || 0);
}
return {
labels: uniqueWeekDays,
datasets: uniqueCategories.map((category) => {
return {
label: category,
data: props.summaries?.map((summary) => summary.categoryTotals[category] || 0)
};
})
};
};
const renderChart = () => {
const canvas = canvasRef.value;
if (!canvas) return;
const ctx = canvas.getContext('2d');
if (!ctx) return;
ChartJS.getChart(canvas)?.destroy();
new ChartJS(ctx, {
type: 'bar',
data: getChartData(),
options: {
responsive: true,
plugins: {
legend: {
Expand All @@ -36,54 +81,11 @@ const chartOptions = {
}
}
}
});
};
const chartData = ref({
labels: [] as string[],
datasets: [] as ChartDataset[]
})
const props = defineProps({
summary: {
type: Array as () => ScreenTimeSummary[] | null,
required: true
}
})
const summaries = ref(props.summary)
const uniqueDates = Array.from(new Set(summaries.value?.map((summary) => summary?.date)))
const uniqueDatesSorted = uniqueDates.sort((a, b) => {
const dateA = new Date(a)
const dateB = new Date(b)
return dateA.getTime() - dateB.getTime()
})
const uniqueWeekDays = uniqueDatesSorted.map((date) => {
const dateObj = new Date(date)
return dateObj.toLocaleDateString('en-US', { weekday: 'short' })
})
const uniqueCategoriesSet: Set<string> = new Set()
summaries.value?.forEach((summary) => {
for (const category in summary?.categoryTotals) {
uniqueCategoriesSet.add(category)
}
})
const uniqueCategories = Array.from(uniqueCategoriesSet)
chartData.value.labels = uniqueWeekDays
const categoryValues: { [key: string]: number[] } = {}
watch(() => props.summaries, () => {
renderChart();
});
uniqueCategories.forEach((category) => {
categoryValues[category] = new Array(uniqueDatesSorted.length).fill(0)
})
summaries.value?.forEach((summary) => {
for (const category in summary?.categoryTotals) {
const dateIndex = uniqueDatesSorted.indexOf(summary?.date)
categoryValues[category][dateIndex] = summary?.categoryTotals[category]
}
})
chartData.value.datasets = uniqueCategories.map((category) => {
return {
label: category,
data: categoryValues[category]
}
})
</script>
</script>

0 comments on commit d22aa30

Please sign in to comment.