This is a continuation of Part 1 of our blog series. It's advisable to read Part 1 to understand how we got to this stage.
Tutorial Outline
For reference, here's the outline of this blog series:
- Part 1: Build a finance tracker app - Setting up Strapi & implementing the app's CRUD functionalities.
- Part 2: Adding visualization with charts
- Part 3: Setting up user authentication and personalized reporting
In this, we'll learn how to visualize the financial data we dealt with in the previous part using Chart.js. We want to view our financial data using bar charts and pie charts.
Introduction to Data Visualization
Why is it important to visualize financial data?
Visualizing financial data is essential for several reasons such as:
- It provides clarity. When complex, we visually represent using charts and graphs, which makes it easier to understand than plain text.
- It helps track financial goals and monitors progress over time. They provide a clear view of budgets, income, expenses, and overall financial health.
- Visualization helps identify trends in income and spending, which can help you make informed decisions about your finances.
Overview of Chart.js
Chart.js is a flexible and easy-to-use open-source JavaScript library for creating charts and graphs. It is easy to use and provides a simple API for creating different types of charts with a few lines of code.
Chart.js offers customization options, allowing users to style charts to meet their specific requirements. It also has built-in support for animations.
Install Chart.js in the Next.js Project
To visualize our application's budget data, we'll use two charts (a bar chart and a pie chart).
-
To get started, let's install the Chart.js library using this command:
npm install chart.js
-
We'll also install the
chartjs-plugin-datalabels
plugin. This plugin allows us to display custom labels inside or outside chart elements, like pie slices. We'll be using it specifically for the pie chart.npm install chartjs-plugin-datalabels
Since we'll be using two charts, let's create two components for the charts inside our
budget
folder, located inside thedashboard
folder. We'll name them -BarChart.tsx
andPieChart.tsx
.
Prepare the Overview.tsx
Component for Receiving Chart Data
If you recall, or you can refer back to Part 1 of this series, you'll see how the Overview
component is structured. We'll need to add a few things to implement this visualization feature.
Let's modify our Overview
component to fetch the budget data from Strapi CMS and display the charts.
Here's how we'll do it:
First, we'll import the hooks we'll be using. We'll import the Axios library and then the two newly created components in our Overview.tsx component.
"use client";
import React, { useState, useEffect } from "react";
import axios from "axios";
import BarChart from "./budget/BarChart";
import PieChart from "./budget/PieChart";
-
We'll create states to store the budget and chart data types. The states will enable users to select which chart visual they want to view (bar chart or pie chart), the default being bar chart:
const [budgets, setBudgets] = useState<{ category: string; amount: number }[]>( [], ); const [chartType, setChartType] = useState<"bar" | "pie">("bar");
-
We'll implement the
useEffect
hook to take two arguments. The first argument is a function that runs as the side effect and an empty dependency array. This dependency array will only run once when the component mounts.useEffect(() => { ... }, []);
Inside the
useEffect
hook, we'll create afetchBudgets
asynchronous function to fetch the budget data from the API. Using theAxios
library, we'll send aGET
request to the budget API endpoint.The response
res
will contain thedata
property of the budget data. Then, we'll use themap
array method to iterate over each budget item and create a new array of objects containing only the category and amount properties.The
setBudgets(data)
will then update the budget state with the fetched and mapped data.
const fetchBudgets = async () => {
try {
const res = await axios.get(
"http://localhost:1337/api/budgets?populate=budget",
);
const data = res.data.data.map((budget: any) => ({
category: budget.attributes.category,
amount: budget.attributes.amount,
}));
setBudgets(data);
} catch (error) {
console.error("Error fetching budgets:", error);
}
};
fetchBudgets();
We'll call the
fetchBudgets
function after defining it within theuseEffect
hook.-
After that, we will store the budget category and amount inside variables
categories
andamounts
:const categories = budgets.map((budget) => budget.category); const amounts = budgets.map((budget) => budget.amount);
Visualize Budget Categories With Bar Chart
It's time to write the functionalities to create these charts.
We will navigate to the BarChart.tsx
component.
-
We'll first import the necessary hooks and the
chart.js
library. We'll use theauto
package to ensure all features fromchart.js
are available.import React, { useEffect, useRef } from "react"; import Chart from "chart.js/auto";
-
We'll define an interface for the props expected by the component - arrays for
categories
andamounts
.interface BarChartProps { categories: string[]; amounts: number[]; }
-
The
BarChart
component will takecategories
andamounts
as props. We will create achartRef
function to reference the canvas element, which we will soon create to represent the Chart.js instance.const BarChart: React.FC<BarChartProps> = ({ categories, amounts }) => { const chartRef = useRef<HTMLCanvasElement | null>(null);
-
Using the
useEffect
hook, we'll create the chart when the component mounts or when the categories and amounts props change:useEffect(() => { if (chartRef.current) { const chartInstance = new Chart(chartRef.current, { type: "bar", data: { labels: categories, datasets: [ { label: "Budget Amount", data: amounts, backgroundColor: [ "rgba(75, 192, 192, 0.2)", "rgba(54, 162, 235, 0.2)", "rgba(153, 102, 255, 0.2)", ], borderColor: [ "rgb(75, 192, 192)", "rgb(54, 162, 235)", "rgb(153, 102, 255)", ], borderWidth: 1, }, ], }, options: { scales: { y: { beginAtZero: true, }, }, plugins: { title: { display: true, text: "Budget data - bar chart", padding: { top: 10, bottom: 30, }, }, }, }, }); return () => { chartInstance.destroy(); }; } }, [categories, amounts]);
return ;
- In the `useEffect` function above, we added the `if (chartRef.current)` to ensure that the chart is only created if the canvas element is available.
- The `new Chart(chartRef.current, { ... })` creates a new Chart.js instance with the specified type, data, and options.
- `type: 'bar'` specifies that the chart is a bar chart.
- The `data` object contains the chart's labels (`categories`) and datasets (`amounts`), including the label, data, and bar colors.
- The `options` object is the configuration options for the chart, such as making the y-axis start at zero. The `plugins` object inside the `options has a property for setting a title for the chart.
- The `return () => { chartInstance.destroy(); }` statement cleans up the chart instance when the component unmounts or updates.
- Lastly, the `<canvas ref={chartRef} />` renders a canvas element with a `ref` to attach the Chart.js instance.
## Visualize Budget Categories With Pie Chart
For our pie chart, we want to view the percentage each budget category is taking, e.g., 20% for savings, 40% for food, etc.
We will head over to the `PieChart.tsx` component and perform the following updates.
- Similar to the `BarChart` component, we'll start by importing the necessary hooks and dependencies:
```javascript
import React, { useEffect, useRef } from 'react';
import Chart from 'chart.js/auto';
import ChartDataLabels from 'chartjs-plugin-datalabels';
-
We'll include this method from the
chartjs-plugin-datalabels
plugin:Chart.register(ChartDataLabels);
-
We'll then define the interface for the props expected by the component - arrays for
categories
andamounts
.interface PieChartProps { categories: string[]; amounts: number[]; }
-
Next, we'll define the
PieChart
component. It will takecategories
andamounts
as props. Then, we'll define thechartRef: Ref
function to reference the canvas element.const PieChart: React.FC<PieChartProps> = ({ categories, amounts }) => { const chartRef = useRef<HTMLCanvasElement | null>(null);
-
Next, we initialize the chart inside a
useEffect
hook like this:useEffect(() => { if (chartRef.current) { const totalAmount = amounts.reduce((acc, amount) => acc + amount, 0); const chartInstance = new Chart(chartRef.current, { type: "pie", data: { labels: categories, datasets: [ { label: "Budget Amount", data: amounts, backgroundColor: [ "rgba(255, 99, 132, 0.6)", "rgba(54, 162, 235, 0.6)", "rgba(255, 206, 86, 0.6)", "rgba(75, 192, 192, 0.6)", "rgba(153, 102, 255, 0.6)", "rgba(255, 159, 64, 0.6)", ], borderColor: [ "rgba(255, 99, 132, 1)", "rgba(54, 162, 235, 1)", "rgba(255, 206, 86, 1)", "rgba(75, 192, 192, 1)", "rgba(153, 102, 255, 1)", "rgba(255, 159, 64, 1)", ], borderWidth: 1, }, ], }, options: { responsive: true, maintainAspectRatio: false, plugins: { title: { display: true, text: "Budget data - pie chart", padding: { top: 10, bottom: 30, }, }, datalabels: { color: "white", formatter: (value, context) => { const percentage = ((value / totalAmount) * 100).toFixed(2); return `${percentage}%`; }, }, }, }, }); return () => { chartInstance.destroy(); }; } }, [categories, amounts]);
We initialized the
useEffect
hook and added atotalAmount
function to calculate the percentage of each category compared to other categories.Just like the bar chart, the
type: 'pie'
specifies that the chart is a pie chart.The
backgroundColor
andborderColor
arrays specify the colors for the pie chart segments.-
The
options: { responsive: true }
object makes the pie chart responsive. We added themaintainAspectRatio: false
in the options object to ensure that the chart does not maintain the default aspect ratio and can scale to the size of its container.NOTE: The default size can be quite large and take up a lot of space on your page, so you can set width and height to reduce pie chart size.
The
title
property inside theplugins
object sets the title display totrue,
which displays the chart's title.The
datalabels
object contains each category's percentage values and sets the percentage text's color to white.We returned the canvas element by wrapping the canvas element in a
div
element with specific width and height styles.
We gave the canvas element width and height attributes to set its width and height.
return (
<div style={{ marginTop: "15px", width: "700px", height: "700px" }}>
<canvas
ref={chartRef}
width="700"
height="700"
aria-label="Hello ARIA World"
role="img"
/>
</div>
);
You can adjust your chart size any way you want it to look.
Render the Pie and Bar Charts in the Overview Page
We've modified the overview page by preparing it for the charts and writing the code. Now, we need to display the charts on the overview page.
In the JSX of our Overview.tsx
component, we'll render the UI:
<main>
<div>
<section>
<h2>OVERVIEW</h2>
<div>
<button
onClick={() => setChartType("bar")}
className={`mx-2 py-2 px-3 ${chartType === "bar" ? "bg-teal-500 text-white" : "bg-gray-200 text-gray-700"} rounded-lg`}
>
Bar Chart
</button>
<button
onClick={() => setChartType("pie")}
className={`mx-2 py-2 px-3 ${chartType === "pie" ? "bg-teal-500 text-white" : "bg-gray-200 text-gray-700"} rounded-lg`}
>
Pie Chart
</button>
</div>
</section>
<section className="mt-8">
{chartType === "bar" ? (
<BarChart categories={categories} amounts={amounts} />
) : (
<PieChart categories={categories} amounts={amounts} />
)}
</section>
</div>
</main>;
We created a
div
element with two buttons. Each button has anonClick
handler that sets the chart type to either 'bar' or 'pie.'
The buttons are styled based on the currentchartType
state, representing the type we want to display.The page then conditionally renders either the
BarChart
orPieChart
component based on the current value ofchartType.
If
chartType
is'bar'
, theBarChart
component is rendered. IfchartType
is'pie'
, thePieChart
component is rendered.
Both components receivecategories
andamounts
as props to display the data.
Now our charts are ready.
Here's what our bar chart should look like:
Here's what our pie chart should look like:
If we edit a budget item from the budget page, like the category it falls under or the amount, the charts will adjust to match the new budget value.
Items and values will be dynamically added to the charts if we add more budgets via the budget page. Change the background and border colors and play around with the values.
Add Animation to the Charts
Let's add a little animation to our charts.
First, in the bar chart, we'll add the easeOutElastic
animation property.
- To do this, we'll include another property in the
options
object calledanimation
. This property will be an object with two values -duration
andeasing
.javascript animation: { duration: 6000, // Increase or decrease the duration easing: 'easeOutElastic', // Using the easing function },
We set the duration to 6000 milliseconds (6 seconds) to make the animation slower and more noticeable. When our visualization loads, the bars elasticate for 6 seconds before setting to their proper position.
In the pie chart, we'll add a bouncing animation using the easeOutBounce
property.
- We'll include the
animation
property inside theoptions
object with two values to do this.javascript animation: { duration: 6000, easing: 'easeOutBounce', },
Animation Demo
When we load our page, we'll see the bar chart's elastic animation and the pie segments' bouncing animation.
More Animations?
Check out the chart.js documentation site for a full list of other animations and transitions you can add to the charts.
We can use other charts to visualize financial data, but we will only use bar and pie charts for this article. If you're interested in exploring more visualizations with Chart.js, check out other chart types.
You can apply this concept to visualize other parts of your application. For example, you can visualize expenses for a few months to see how much you spent in a particular month compared to other months.
This is useful for making financial decisions and identifying trends.
Conclusion
In Part 2 of this tutorial series, we reviewed an overview of charts, set up Pie and Bar charts in Next.js using Chart.js and Strapi CMS, prepared them for data, added animation, and rendered them.
This project's GitHub repo has been updated to include financial data visualization.
Watch for the last part (part 3) of this blog series, where we'll add authentication and a personalized reporting feature to our finance tracker application.
Top comments (0)