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

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);

Related

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.

In react hooks, how can i pass the filtered values to the chart?

I am using React with hooks to pass filtered values to a chart.
The problem is that i was no able to pass the "filterData" values to the chart:
const filterData = data.datasets[0].data.filter(value => value > Number(filterdatanumber))
Any suggestion on how can i solve this?
I have tried different solutions existing in these videos https://www.youtube.com/watch?v=cz2rG-OVXXU, or create a new variable, among others, however nothing worked.
The complete code:
import React, { useState } from 'react';
import { Bar } from 'react-chartjs-2';
export default function VerticalBar() {
const [firstNumber, setFirstNumber] = useState("");
const textChangeHandler = (i) => {
setFirstNumber(i.target.value);
console.log("target.value", i.target.value);
filterChart(Number(i.target.value));
};
const data = {
labels: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
datasets: [{
label: 'Weekly Sales',
data: [18, 12, 6, 9, 11, 3, 9],
backgroundColor: [
'rgba(255, 26, 104, 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(0, 0, 0, 0.2)'
],
borderColor: [
'rgba(255, 26, 104, 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(0, 0, 0, 1)'
],
borderWidth: 1
}]
};
const filterChart = (filterdatanumber = Number.MIN_SAFE_INTEGER) => {
const filterData = data.datasets[0].data.filter(value => value > Number(filterdatanumber))
// const filterData = data.datasets[0].data.filter(value => value > 9)
const filterLabels = [];
const filterColors = [];
let i = 0;
for (i; i < filterData.length; i++) {
const result = data.datasets[0].data.indexOf(filterData[i]);
const labelsResult = data.labels[result];
const colorssResult = data.datasets[0].backgroundColor[result];
filterLabels.push(labelsResult );
filterColors.push(colorssResult);
}
console.log("filterData", filterData)
console.log("filterLabels", filterLabels)
console.log("filterColors",filterColors)
data.datasets[0].data = filterData;
data.labels = filterLabels;
data.datasets[0].backgroundColor = filterColors;
}
filterChart();
return (
<div >
<Bar data={data} />
<input value={firstNumber} type="number" name="firstNumber" onChange={textChangeHandler} />
</div>
)
}
your code has many problems regarding how you handle state date inside the component.
If data is constant then you can move it outside the component.
The function filterData can be replaced with a state holding the filtered data and a useEffect that will be triggered when another filterdatanumber state changes.
Here is an example code with these changes.
import React, { useState, useEffect } from "react";
import { Bar } from "react-chartjs-2";
const data = {
labels: ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
datasets: [
{
label: "Weekly Sales",
data: [18, 12, 6, 9, 11, 3, 9],
backgroundColor: [
"rgba(255, 26, 104, 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(0, 0, 0, 0.2)",
],
borderColor: [
"rgba(255, 26, 104, 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(0, 0, 0, 1)",
],
borderWidth: 1,
},
],
};
export default function VerticalBar() {
const [firstNumber, setFirstNumber] = useState("");
const [filterdatanumber, setFilterdatanumber] = useState(
Number.MIN_SAFE_INTEGER
);
const [filteredData, setFilteredData] = useState(data);
const textChangeHandler = (i) => {
setFirstNumber(i.target.value);
console.log("target.value", i.target.value);
filterChart(Number(i.target.value));
};
useEffect(() => {
const newData = { ...data };
const filteredData = [];
const filterLabels = [];
const filterColors = [];
for (let i = 0; i < newData.datasets[0].data.length; i++) {
const value = newData.datasets[0].data[i]
if (value > Number(filterdatanumber)) {
const labelsResult = newData.labels[i];
const colorssResult = newData.datasets[0].backgroundColor[i];
filterLabels.push(labelsResult);
filterColors.push(colorssResult);
filteredData.push(value)
}
}
console.log("filteredData", filteredData);
console.log("filterLabels", filterLabels);
console.log("filterColors", filterColors);
newData.datasets[0].data = filteredData;
newData.labels = filterLabels;
newData.datasets[0].backgroundColor = filterColors;
setFilteredData(newData);
}, [filterdatanumber]);
return (
<div>
<Bar data={filteredData} />
<input
value={firstNumber}
type="number"
name="firstNumber"
onChange={textChangeHandler}
/>
</div>
);
}
Please remember that this code is just an example, maybe it will need some edits in order to match your needs.
Here is my final solution fully working and with a refactored 3rd approach. The values are matching the keys consistently when filtered and displayed correctly in the chart.
import React, { useState, useEffect, useCallback, useMemo } from "react";
import { Bar } from "react-chartjs-2";
export default function VerticalBar() {
const [data, setData] = useState ([
{val: 18, label: "Mon"},
{val: 1, label: "Tue"},
{val: 5, label: "Wed"},
{val: 8, label: "Thu"},
{val: 19, label: "Fri"},
{val: 5, label: "Sat"},
{val: 7, label: "Sun"}
])
const chartConfig = useMemo(() => {
return {
labels: data.map(el => el.label),
datasets: [
{
label: "Weekly Sales",
data: data.map(el => el.val),
backgroundColor: [
"rgba(255, 26, 104, 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(0, 0, 0, 0.2)",
],
borderColor: [
"rgba(255, 26, 104, 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(0, 0, 0, 1)",
],
borderWidth: 1,
},
],
};
}, [data])
const textChangeHandler = useCallback(
(event) => {
setData(prevData => {
return prevData.filter((el) => parseInt(event.target.value, 10) < el.val)
})
}, [setData]);
return (
<div>
<Bar data={chartConfig} />
<input
type="number"
name="firstNumber"
onChange={textChangeHandler}
/>
</div>
);
}

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;

How to change graph grid and axis colors in react-chartjs-2

I'm new to react and also just found react-chartjs-2 graphing npm package. So I implemented this to my react project. Now I need to change the grid lines and axis colours to white. So I tried this line of two code also in two times.But it didn't work.
defaults.global.defaultColor='rgba(255,255,255,1)'
defaults.global.defaultColor='rgba(255,255,255,1)'
How can I do that?
Thanks in advance.
You can change the axis grid color using gridLines option. Find more styling options here.
import React from "react";
import "./style.css";
import { Bar } from "react-chartjs-2";
const data = {
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
datasets: [
{
label: "# of Votes",
data: [12, 19, 13, 15, 12, 13],
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
}
]
};
const options = {
scales: {
yAxes: [
{
gridLines: {
color: "red"
}
}
],
xAxes: [
{
gridLines: {
color: "blue"
}
}
]
}
};
export default function App() {
return (
<div>
<Bar data={data} options={options} />
</div>
);
}

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