How to update Chartjs in Reactjs? - reactjs

I am using react hooks to create chart using chartjs. With the help of socket.io, the webapp is receiving data from a nodejs server. The data gets successfully added to temp and time array, but unfortunately i am unable to update the chart everytime new data comes.
import React,{useState, useEffect} from 'react';
import logo from './logo.svg';
import './App.css';
import {Line} from 'react-chartjs-2';
import io from 'socket.io-client'
const socket = io('http://localhost:5000');
function App() {
const [chartData, setChartData] = useState({});
const [dataReact, setData] = useState({});
var temp =[];
var time = [];
const chart = ()=>{
setChartData({
labels: time,
datasets: [{
label: '# of Votes',
data: temp,
backgroundColor: [
'rgba(255, 99, 132, 0.2)',
'rgba(54, 162, 235, 0.2)',
'rgba(255, 206, 86, 0.2)',
'rgba(75, 192, 192, 0.2)',
'rgba(153, 102, 255, 0.2)',
'rgba(255, 159, 64, 0.2)'
],
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
}]
})
}
useEffect(()=>{
socket.on('data1', res => {
console.log(res);
temp.push(res.IotData.temperature);
time.push(res.MessageDate);
});
chart();
},[])
return (
<div className="App">
<Line data={chartData}/>
</div>
);
}
export default App;

In useEffect() the second parameter (i.e. the []) which is an array of properties to be observed within the scope of the stateless component. Whenever any of them are updated, the function is executed again. So add chart into the empty array.

Also don't forget to put redraw parameter in your chart:
<Line data={chartData} redraw={true}/>
This will allow the chart to update and be redrawn.

Related

How to change the Date Format in Chart.js?

I am confused about how to change my Date Format in Chart.js.
I grabbed my data from the MySQL database one of my columns is called "StartD"
[{"RECORD_NO":217,"Cost":4971,"StartD":"5/8/2022"},{"RECORD_NO":216,"Cost":1814,"StartD":"4/8/2022"},{"RECORD_NO":215,"Cost":3335,"StartD":"3/8/2022"},{"RECORD_NO":214,"Cost":1886,"StartD":"2/8/2022"},{"RECORD_NO":213,"Cost":1274,"StartD":"1/8/2022"},{"RECORD_NO":212,"Cost":2238,"StartD":"31/7/2022"},{"RECORD_NO":211,"Cost":1819,"StartD":"30/7/2022"},{"RECORD_NO":210,"Cost":1021,"StartD":"29/7/2022"},{"RECORD_NO":209,"Cost":2564,"StartD":"28/7/2022"},{"RECORD_NO":208,"Cost":4534,"StartD":"27/7/2022"},{"RECORD_NO":207,"Cost":4187,"StartD":"26/7/2022"},{"RECORD_NO":206,"Cost":2337,"StartD":"25/7/2022"},{"RECORD_NO":205,"Cost":4778,"StartD":"24/7/2022"},{"RECORD_NO":204,"Cost":3215,"StartD":"23/7/2022"},{"RECORD_NO":203,"Cost":4469,"StartD":"22/7/2022"},{"RECORD_NO":202,"Cost":1883,"StartD":"21/7/2022"},{"RECORD_NO":201,"Cost":1097,"StartD":"20/7/2022"},{"RECORD_NO":200,"Cost":2918,"StartD":"19/7/2022"},{"RECORD_NO":199,"Cost":4956,"StartD":"18/7/2022"},{"RECORD_NO":198,"Cost":1565,"StartD":"17/7/2022"},{"RECORD_NO":197,"Cost":4425,"StartD":"16/7/2022"},{"RECORD_NO":196,"Cost":2277,"StartD":"15/7/2022"},{"RECORD_NO":195,"Cost":3866,"StartD":"14/7/2022"},{"RECORD_NO":194,"Cost":1546,"StartD":"13/7/2022"},{"RECORD_NO":193,"Cost":563,"StartD":"12/7/2022"},{"RECORD_NO":192,"Cost":576,"StartD":"11/7/2022"},{"RECORD_NO":191,"Cost":731,"StartD":"10/7/2022"},{"RECORD_NO":190,"Cost":2850,"StartD":"9/7/2022"},{"RECORD_NO":189,"Cost":1154,"StartD":"8/7/2022"},{"RECORD_NO":188,"Cost":4447,"StartD":"7/7/2022"},{"RECORD_NO":187,"Cost":3476,"StartD":"6/7/2022"},{"RECORD_NO":186,"Cost":1047,"StartD":"5/7/2022"},{"RECORD_NO":185,"Cost":1049,"StartD":"4/7/2022"},{"RECORD_NO":184,"Cost":1566,"StartD":"3/7/2022"},{"RECORD_NO":183,"Cost":700,"StartD":"2/7/2022"},{"RECORD_NO":182,"Cost":4728,"StartD":"1/7/2022"},{"RECORD_NO":181,"Cost":4549,"StartD":"30/6/2022"},{"RECORD_NO":180,"Cost":1155,"StartD":"29/6/2022"},{"RECORD_NO":179,"Cost":2148,"StartD":"28/6/2022"},{"RECORD_NO":178,"Cost":4934,"StartD":"27/6/2022"},{"RECORD_NO":177,"Cost":4353,"StartD":"26/6/2022"},{"RECORD_NO":176,"Cost":2546,"StartD":"25/6/2022"},{"RECORD_NO":175,"Cost":1239,"StartD":"24/6/2022"},{"RECORD_NO":174,"Cost":1724,"StartD":"23/6/2022"},{"RECORD_NO":173,"Cost":769,"StartD":"22/6/2022"},{"RECORD_NO":172,"Cost":670,"StartD":"21/6/2022"},{"RECORD_NO":171,"Cost":4634,"StartD":"20/6/2022"},{"RECORD_NO":170,"Cost":2742,"StartD":"19/6/2022"},{"RECORD_NO":169,"Cost":4797,"StartD":"18/6/2022"},{"RECORD_NO":168,"Cost":3317,"StartD":"17/6/2022"}]
I put it into my BarChar.js file and it recognized the data.
import React, {
useState,
useEffect
} from 'react'
import {
Chart as ChartJS,
CategoryScale,
LinearScale,
BarElement,
Title,
Tooltip,
Legend,
} from 'chart.js'
import {
Bar
} from "react-chartjs-2"
// Radar, Doughnut, Polar, Pie
import axios from 'axios';
ChartJS.register(
CategoryScale, LinearScale, BarElement, Title, Tooltip, Legend
);
function BarChart() {
const [chartData, setChartData] = useState({
datasets: [],
});
const Chart = () => {
let Cost = [];
let No = [];
axios.get("http://localhost:3001/api/TranscationRecord/Cost")
.then(res => {
console.log(res);
for (const dataObj of res.data) {
Cost.push(parseInt(dataObj.Cost));
No.push(parseInt(dataObj.StartD));
}
setChartData({
labels: No,
datasets: [{
label: 'Daily Cost',
data: Cost,
backgroundColor: [
'rgba(255, 99, 132, 0.2)',
'rgba(54, 162, 235, 0.2)',
'rgba(255, 206, 86, 0.2)',
'rgba(75, 192, 192, 0.2)',
'rgba(153, 102, 255, 0.2)',
'rgba(255, 159, 64, 0.2)',
'rgba(255, 99, 132, 0.2)',
'rgba(54, 162, 235, 0.2)',
'rgba(255, 206, 86, 0.2)',
'rgba(75, 192, 192, 0.2)',
'rgba(153, 102, 255, 0.2)',
'rgba(255, 159, 64, 0.2)',
'rgba(255, 99, 132, 0.2)',
'rgba(54, 162, 235, 0.2)',
'rgba(255, 206, 86, 0.2)',
'rgba(75, 192, 192, 0.2)',
'rgba(153, 102, 255, 0.2)',
'rgba(255, 159, 64, 0.2)',
'rgba(255, 99, 132, 0.2)',
'rgba(54, 162, 235, 0.2)',
'rgba(255, 206, 86, 0.2)',
'rgba(75, 192, 192, 0.2)',
'rgba(153, 102, 255, 0.2)',
'rgba(255, 159, 64, 0.2)',
],
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)',
'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)',
'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)',
'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: {
scales: {
x: {
type: 'time',
time: {
unit: 'date',
parser: 'dd/mm/yyyy'
}
},
y: {
beginAtZero: true
}
}
}
}]
});
})
.catch(err => {
console.log(err);
})
}
useEffect(() => {
Chart();
}, []);
return ( <
div className = "App" >
<
h1 > Bar Chart < /h1> <
div >
<
Bar data = {
chartData
}
/> < /
div > <
/div>
)
}
export default BarChart;
The result
It can only present the Day but not the format of "DD/MM"
Is that a way to solve the problem?
Try displayFormats:
const chart = new Chart(ctx, {
type: 'line',
data: data,
options: {
scales: {
x: {
type: 'time',
time: {
displayFormats: {
quarter: 'MMM YYYY'
}
}
}
}
}
});
Chart.js Time Display Formats
Change your for loop like below
for (const dataObj of res.data) {
Cost.push(parseInt(dataObj.Cost));
const date = new Date(dataObj.StartD);
No.push(date->toLocaleDateString('en-us',{month:"2-digit", day:"2-digit"));
}
I just figure out the answer. Thanks for helping. I take #terinao's code for references.
Changing the code like this can solve the problem.
axios.get("http://localhost:3001/api/TranscationRecord/Cost")
.then(res => {
console.log(res);
for(const dataObj of res.data){
Cost.push(parseInt(dataObj.Cost));
const d = new Date(dataObj.StartD);
No.push(d.toLocaleDateString('en-us',{day:"2-digit",month:"2-digit" }));
}
The result be like:
(I change the colour into blue but they are the same datasets)
The bar chart
The x-axis of your bar chart is currently a category axis instead of a time axis. The reason is that options is misplaced, it should not be defined inside the dataset but follow the top level structure of the Chart.js configuration.
With react-chartjs-2, you would define options as a separate object and provide it as follows:
<Bar data={data} options={options} />
Once this is is corrected, the display format can be defined according to the Chart.js documentation here.
Please also consider that the time scale requires both, a date library and a corresponding adapter to be present.

Uncaught Error: "category" is not a registered scale

I am trying to implement React char but getting this error, I search and follow decumentation but couldn't find the solution.
import React from 'react';
import { Bar } from 'react-chartjs-2';
const BarChart = () => {
return (
<div>
<Bar data={{
labels: ['Red', 'Blue', 'Yellow', 'Green', 'Purple', 'Orange'],
datasets: [{
label: '# of Votes',
data: [12, 19, 3, 5, 2, 3],
backgroundColor: [
'rgba(255, 99, 132, 0.2)',
'rgba(54, 162, 235, 0.2)',
'rgba(255, 206, 86, 0.2)',
'rgba(75, 192, 192, 0.2)',
'rgba(153, 102, 255, 0.2)',
'rgba(255, 159, 64, 0.2)'
],
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
}]
}} />
</div>
);
};
export default BarChart;
Change your code to:
import { Bar } from 'react-chartjs-2';
import { Chart, registerables } from 'chart.js';
Chart.register(...registerables);
const BarChart = () => { ... your code ... }
As described in https://www.chartjs.org/docs/3.3.0/getting-started/integration.html#bundlers-webpack-rollup-etc you need to register all the components you're going to use.
The above code just registers everything.
Check out the link for all available components you can register.

How do I filter & update dates using react-chartjs-2

I am using React-Chartjs-2 on a project and am getting stuck on updating the filter of my chart. I am following along with the following demo, but this doesn't just the react one, but the vanilla version.https://www.youtube.com/watch?v=Gc5JF2TUG7o&t=679s # 16:32 is the update function to update the filtered dates on the chart. I am able to get the index of the date array, but my chart doesn't update. How am I able to access and update the labels and datasets value within the Line component?
import React from 'react';
import {Line} from 'react-chartjs-2'
function BarChart() {
const dates = ['2021-08-25', '2021-08-26','2021-08-27','2021-08-28', '2021-08-29', '2021-08-30','2021-08-31' ];
const datapoints =[1,2,4,9,12,15,16]
function filterData() {
const dates2 = [...dates];
console.log(dates2);
const startdate = document.getElementById('startdate');
const enddate = document.getElementById('enddate');
//get the index number in the array
const indexstartdate = dates2.indexOf(startdate.value);
const indexenddate = dates2.indexOf(enddate.value);
console.log(indexstartdate);
console.log(indexenddate);
//slice the array
const filterDate = dates2.slice(indexstartdate, indexenddate + 1);
//replace label in the chart
//HELP HERE!!!
}
return (
<div>
<div>
<Line id='myChart'
data={{
labels:dates,
datasets: [
{
label: 'Sales',
data:datapoints,
backgroundColor: [
'rgba(255, 99, 132, 0.2)',
'rgba(54, 162, 235, 0.2)',
'rgba(255, 206, 86, 0.2)',
'rgba(75, 192, 192, 0.2)',
'rgba(153, 102, 255, 0.2)',
'rgba(255, 159, 64, 0.2)'
],
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,
},
],
}}
height={400}
width={400}
options={{maintainAspectRatio:false,
scales: {
yAxes: [
{
ticks: {
beginAtZero: true,
}
}
]
},
}}
/>
</div>
<input type='date' onChange={filterData} id='startdate' />
<input type='date' onChange={filterData} id='enddate' />
</div>
)
}
export default BarChart
You need to use the React state so your component will rerender. Here is my solution, I hope it helps.
import React, { useRef, useState } from "react";
import { Line } from "react-chartjs-2";
function BarChart() {
const initialDates = [
"2021-08-25",
"2021-08-26",
"2021-08-27",
"2021-08-28",
"2021-08-29",
"2021-08-30",
"2021-08-31",
];
const initialDataPoints = [1, 2, 4, 9, 12, 15, 16];
const [dates, setDates] = useState(initialDates);
const [dataPoints, setDataPoints] = useState(initialDataPoints);
console.log(dates, dataPoints);
const inputRef1 = useRef();
const inputRef2 = useRef();
function filterData() {
const dates2 = [...dates];
const dataPoints2 = [...dataPoints];
//slice the array
let value1 = inputRef1.current.value;
let value2 = inputRef2.current.value;
const indexstartdate = dates2.indexOf(value1);
const indexenddate = dates2.indexOf(value2);
console.log(indexstartdate);
console.log(indexenddate);
//slice the array
const filterDate = dates2.slice(indexstartdate, indexenddate + 1);
const filterDataPoints = dataPoints2.slice(
indexstartdate,
indexenddate + 1
);
console.log(filterDate, filterDataPoints);
//replace label in the chart
//HELP HERE!!!
setDates(filterDate);
setDataPoints(filterDataPoints);
console.log(dates, dataPoints);
}
return (
<div>
<div>
<Line
id="myChart"
data={{
labels: dates,
datasets: [
{
label: "Sales",
data: dataPoints,
backgroundColor: [
"rgba(255, 99, 132, 0.2)",
"rgba(54, 162, 235, 0.2)",
"rgba(255, 206, 86, 0.2)",
"rgba(75, 192, 192, 0.2)",
"rgba(153, 102, 255, 0.2)",
"rgba(255, 159, 64, 0.2)",
],
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,
},
],
}}
height={400}
width={400}
options={{
maintainAspectRatio: false,
scales: {
yAxes: [
{
ticks: {
beginAtZero: true,
},
},
],
},
}}
/>
</div>
<input type="date" ref={inputRef1} />
<input type="date" ref={inputRef2} />
<button onClick={filterData}>Filter</button>
</div>
);
}
export default BarChart;

Why won't my chart.js chart render in React?

I have created this code example. I am using a React functional component, but for some reason the chart won't render. I think it is because React Hooks does not play nice with conditionals, but I don't understand why.
https://codesandbox.io/s/sparkling-darkness-e7bdj
Why doesn't the chart render?
I am using hooks because I don't want to use a class. It seems like this should work and I am getting no errors.
How can I get it to work?
I found a way to fix it.
Normally, the Chart constructor call goes in componentDidMount. The Hook equivalent is useEffect.
Working code is as follows:
import React, { useRef, useEffect } from "react";
import ReactDOM from "react-dom";
import Chart from "chart.js";
import "./styles.css";
function App() {
const chartRef = useRef(null);
useEffect(() => {
if (chartRef.current) {
const myChart = new Chart(chartRef.current, {
type: "bar",
data: {
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
datasets: [
{
label: "# of Votes",
data: [12, 19, 3, 5, 2, 3],
backgroundColor: [
"rgba(255, 99, 132, 0.2)",
"rgba(54, 162, 235, 0.2)",
"rgba(255, 206, 86, 0.2)",
"rgba(75, 192, 192, 0.2)",
"rgba(153, 102, 255, 0.2)",
"rgba(255, 159, 64, 0.2)"
],
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: {
scales: {
yAxes: [
{
ticks: {
beginAtZero: true
}
}
]
}
}
});
}
});
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<canvas ref={chartRef} />
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

Calling a helper function and passing in data to chart.js

I created a helper function to work around my chart.js.
First, on my index.html file I put the ff:
<div id="app"></div>
<canvas id="myChart" width="400" height="400"></canvas>
Next, to call chart.js, I created a helper function with the necessary data/arguments on it:
export const chartUI = (labels, data) =>{
var ctx = document.getElementById("myChart");
var myChart = new Chart(ctx, {
type: 'line',
data: {
labels: labels,
datasets: [{
label: 'RATES',
data: data,
backgroundColor: [
'rgba(255, 99, 132, 0.2)',
'rgba(54, 162, 235, 0.2)',
'rgba(255, 206, 86, 0.2)',
'rgba(75, 192, 192, 0.2)',
'rgba(153, 102, 255, 0.2)',
'rgba(255, 159, 64, 0.2)'
],
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: {
scales: {
yAxes: [{
ticks: {
beginAtZero:true
}
}]
}
}
});
};
Now on my component where I need to put my data on I called the function so it can manipulate and display the data:
import React from 'react';
const helper = require('../../../helpers/utils')
const Chart = (props) => {
return(
<div>
{props.info.map(item => {
return <p>{helper.chartUI(item.time, item.rates)}</p>
}) }
</div>
)
};
export default Chart;
When I run this code i did not see any chart on the frontend and also I got this error: Uncaught TypeError: this.ticks.map is not a function The above error occurred in the <Chart> component: TypeError: this.ticks.map is not a function
PS. Here's the the type data I am flowing from my app:
{
"rates": [
{
"time": "2018-04-13T15:45:19.5968204Z",
"asset_id_quote": "$$$",
"rate": 4000000
},
{
"time": "2018-04-13T15:45:41.7725202Z",
"asset_id_quote": "1ST",
"rate": 37714.501225721289835941919668
}
}

Resources