I am new in reactjs. Currently I'm developing an app which shows json COVID-19 api data into visualization using chartjs. I tried this from yesterday but I can't show the visual data.
Here is my code
App Component
import React, { useState, useEffect } from "react";
import axios from "axios";
import Chart from "./Chart";
const App = () => {
const [state, setState] = useState({});
const [loading, setLoading] = useState(true);
const [chart, setChart] = useState({});
useEffect(() => {
getData("italy");
setChart({
labels: ["Cases", "Deaths", "Recovered"],
datasets: [
{
label: "cases",
data: [state.cases]
},
{
label: "deaths",
data: [state.deaths]
},
{
label: "recovered",
data: [state.recovered]
}
]
});
}, []);
const getData = async country => {
try {
const res = await axios.get(
`https://corona.lmao.ninja/v2/historical/${country}`
);
setLoading(false);
setState(res.data.timeline);
} catch (error) {
console.log(error.response);
}
};
return (
<div>
{!loading
? console.log(
"cases",
state.cases,
"deaths",
state.deaths,
"recovered",
state.recovered
)
: null}
{!loading ? <Chart chart={chart} /> : "loading failed"}
</div>
);
};
export default App;
And Here is Chart Component
import React from "react";
import { Line } from "react-chartjs-2";
const Chart = ({chart}) => {
return (
<div>
<Line
data={chart}
height={300}
width={200}
options={{
maintainAspectRatio: false,
title: {
display: true,
text: "Covid-19",
fontSize: 25
},
legend: {
display: true,
position: "top"
}
}}
/>
</div>
);
};
export default Chart;
If I open browser and dev tools it look likes this
I want to visualize the data like this
Here is codeSandBox.io
Looks like data property within dataset takes only array of numbers. I have simplifies your code using class based component. It will help you get started.
https://codesandbox.io/s/react-chartjs-2-example-mzh9o
setChartData = () => {
let { data } = this.state;
let chartData = {
labels: ["Cases", "Deaths", "Recovered"],
datasets: [
{
label: "cases",
data: Object.values(data.cases)
},
{
label: "deaths",
data: Object.values(data.deaths)
},
{
label: "recovered",
data: Object.values(data.recovered)
}
]
};
this.setState({
chart: chartData
});
};
Related
I have this component Chart.js, I've managed to get the value out from console logging the Select component, which is the value in siteOptions variable, my question is how to pass the onchange value to mapStatetoProps below so the key siteSelect is filled with the value of my selected value the Select component? so I can pass the siteSelect as props to ChartLine component
const Charts = ({siteSelect}) => {
const siteOptions = [
{ value: "USTP", label: "USTP" },
{ value: "SMG", label: "SMG" },
{ value: "GCM", label: "GCM" },
{ value: "SJE", label: "SJE" },
{ value: "SBE", label: "SBE" },
{ value: "SLM", label: "SLM" },
];
const [site, setSite] = useState(siteOptions["0"].value);
const handleSiteChange = (e, site) =>{
setSite(site.value)
console.log(site.value)
}
return (
<>
<Grid.Column>
<Select
placeholder="Select Site"
options={siteOptions}
onChange{handleSiteChange}/>
</Grid.Column>
<Grid.Column width={4}>
<ChartLine site={siteSelected} />
</Grid.Column>
</>
const mapStateToProps = (state) => {
return {
siteSelect: ??????
};
};
)
export default connect (mapStateToProps) (Charts);
In Chartline component, when it received the site props value, it will fire up useEffect to dispatch a new parameter and call a new api.
This is my Chartline component
import { connect, useDispatch } from "react-redux";
import { fetchData } from "./Action";
import { useEffect } from "react";
import format from "dateformat"
import _ from "lodash";
import LoadingStatus from "../../../../templates/LoadingStatus";
import LineChart from "../../../../templates/LineChart";
const Charts = ({ chart_10, site, p_date, title = "Line Chart" }) => {
const dispatch = useDispatch();
const options = {
maintainAspectRatio: false,
responsive: true,
};
const labels = chart_10?.map((data) => data["BULAN"]);
const data = {
labels,
datasets: [
{
label: "Actual",
data: chart_10?.map((data) => data["ACTUAL"]),
borderColor: "rgb(255, 99, 132)",
backgroundColor: "rgba(255, 99, 132, 0.5)",
},
{
label: "Budget",
data: chart_10?.map((data) => data["BUDGET"]),
borderColor: "rgb(51, 131, 255)",
backgroundColor: "rgba(51, 131, 255, 0.5)",
},
],
options,
}
useEffect(() => {
dispatch(fetchData(site, p_date));
}, [dispatch, site, p_date]);
if (_.isNull(chart_10)) return <LoadingStatus />;
return (
<LineChart data={data} title={title} />
);
};
const mapStateToProps = (state) => {
return {
chart_10: state.dashboard.chart_10,
p_date: format((state.auth.menu.user.currentdate), "dd-mm-yyyy")
};
};
export default connect(mapStateToProps, { fetchData })(Charts);
I'm using a npm package called ReactDataGrid which has SelectEditor module which renders a combo box. In the editorProps, I am able to set a function which needs to be called on onChange event. This function setClientonChange needs to call another function which is nested inside a function component? How can I call it?
import React, {useState } from 'react';
import ReactDataGrid from '#inovua/reactdatagrid-community';
const columns = [
...
{ name: 'currency_id', groupBy: false, defaultFlex: 1, maxWidth: 150, textAlign: 'center', header: 'Currency', editor: SelectEditor, editable:true,
editorProps: {
dataSource: ['Dollar', 'Euro', 'Pound', 'INR'].map((element) => ({
id: element,
label: element
})),
setClientonChange(){
//have to call setCurrencyValue() here
}
}
}
];
const RoomDeposit = () => {
const [gridRef, setGridRef] = useState(null);
const setCurrencyValue = () => {
gridRef.current.setItemPropertyAt(2, 'amount', '20')
}
return (
<ReactDataGrid
onReady={setGridRef}
columns={columns}
dataSource={dataSource}
/>
);
}
export default () => <RoomDeposit />
import React, { useState } from "react";
import ReactDataGrid from "#inovua/reactdatagrid-community";
const columns = (setCurrencyValue) => [
...{
name: "currency_id",
groupBy: false,
defaultFlex: 1,
maxWidth: 150,
textAlign: "center",
header: "Currency",
editor: SelectEditor,
editable: true,
editorProps: {
dataSource: ["Dollar", "Euro", "Pound", "INR"].map((element) => ({
id: element,
label: element,
})),
setClientonChange() {
//have to call setCurrencyValue() here
setCurrencyValue();
},
},
},
];
const RoomDeposit = () => {
const [gridRef, setGridRef] = useState(null);
const setCurrencyValue = () => {
gridRef.current.setItemPropertyAt(2, "amount", "20");
};
return (
<ReactDataGrid
onReady={setGridRef}
columns={columns(setCurrencyValue)}
dataSource={dataSource}
/>
);
};
export default () => <RoomDeposit />;
Really I am not able to understand the question self.
we can execute global function from inside of function.
Function should be declarer first then execute.
But as per my understanding the answer can be look like this.
import React, {useState } from 'react';
import ReactDataGrid from '#inovua/reactdatagrid-community';
const RoomDeposit = () => {
const [gridRef, setGridRef] = useState(null);
const setCurrencyValue = () => {
gridRef.current.setItemPropertyAt(2, 'amount', '20')
}
function onDropdownChange(){
setCurrencyValue(); //You can execute from here
}
return (
<ReactDataGrid
onReady={setGridRef}
columns={columns}
dataSource={dataSource}
/>
);
}
export default () => <RoomDeposit />
I am trying to update a chart with the values I get from the API.
I don't know how to tweak this useEffect hook.
If you could advise, I would owe you a lot.
Let me show my code:
import React, { useEffect, useState } from "react";
import { useQuery, gql } from "#apollo/client";
import { Bar } from "react-chartjs-2";
const total = gql`
query GetIntell {
webs(
sort: "severity:desc",
pagination: { start: 0, limit: 10 },
filters: {site :{eq: "nist"}}
) {
data {
id
attributes {
dateAdded
severity
}
}
}
}
`
export default function Test() {
const {data }= useQuery(total)
const [chartData, setChartData] = useState({})
useEffect (() => {. <--------HERE COMES THE ERROR Line 29:5:
setChartData({
labels: data.webs.data.map((t) => t.attributes.severity),
datasets: [
{
label: "Price in USD",
data: data.webs.data.map((t) => t.attributes.id),
backgroundColor: [
"#ffbb11",
"#ecf0f1",
"#50AF95",
"#f3ba2f",
"#2a71d0"
]
}
]
}), [data]
})
console.log(data)
return (
<div className="container">
<Bar
data={chartData}
options={{
plugins: {
title: {
display: true,
text: "Cryptocurrency prices"
},
legend: {
display: true,
position: "bottom"
}
}
}}
/>
</div>
);
}
Basically I need to get the graph data, only after the const data is retrieved from graphql. I have no clue how to tweak the code to run it ok.
I've seen a lot of old code with this error so I could not find a newer topic with this error to check it.
Later Edit
This is how the data looks like
Your useEffect dependency array is in the wrong place, I think that's what is causing it.
should be:
useEffect (() => {
setChartData({
labels: data.webs.data.map((t) => t.attributes.severity),
datasets: [
{
label: "Price in USD",
data: data.webs.data.map((t) => t.attributes.id),
backgroundColor: [
"#ffbb11",
"#ecf0f1",
"#50AF95",
"#f3ba2f",
"#2a71d0"
]
}
]
})
}, [data])
Also ther is a . on the line you have the arrow on but I'm not sure id it's a copy paste typo or is it actually in your code
This is my code of dynamic graph, I am using apex chart library,
import React, { Component, useEffect, useState } from "react";
import Chart from "react-apexcharts";
import axios from "axios";
const App = () => {
useEffect(() => {
axios
.get(`https://api.thingspeak.com/channels/1285233/fields/1.json`)
.then((res) => {
console.log("RESPONSE", res.data.feeds);
setData(res.data);
})
.catch((error) => {
});
}, []);
const [data, setData] = useState({});
let series = data.feeds?.map((x) => x.entry_id);
let xaxisdata = []
for(let i = 0; i >= 200 ; i++)
{
xaxisdata.push(i)
}
console.log("SERIES", series);
const options = {
chart: {
id: "basic-bar",
},
xaxis: {
categories: xaxisdata,
},
series: [
{
name: "series-1",
data: series,
},
// {
// name: "series-2",
// data: [10, 80, 60, 75, 35, 72, 8, 42],
// },
],
};
return (
<div className="app">
<div className="row">
<div className="mixed-chart">
<div className="chartPosition">
<Chart
options={options}
series={options.series}
type="line"
width="1000"
/>
</div>
</div>
</div>
</div>
);
};
export default App;
I want to convert my graph into real time changing graph just like the CPU usage graph in task manager it get changes in different time interval. I want that one graph
The problem is quite forward, I can't see the line of the graph, and when I press any button. The time of the X-axes should change accordingly to which button is pressed I have been looking through the documentation, for quite some time, but still can't figure it out.
ChartData
import React, { useRef, useEffect, useState } from "react";
import { historyOptions } from '../chartConfig/chartConfig';
import 'chartjs-adapter-moment';
import annotationPlugin from 'chartjs-plugin-annotation';
import { Chart, registerables } from 'chart.js';
Chart.register(...registerables);
Chart.register(annotationPlugin);
const determineTimeFormat = (
timeFormat: string,
day: any,
week: any,
year: any
) => {
switch (timeFormat) {
case "24h":
return day;
case "7d":
return week;
case "1y":
return year;
default:
return day;
}
};
interface Props {
data: any
}
const ChartData: React.FC<Props> = ({ data }) => {
const chartCanvasRef = useRef<HTMLCanvasElement | null>(null);
const { day, week, year, detail } = data;
const [timeFormat, setTimeFormat] = useState("24h");
const [isRebuildingCanvas, setIsRebuildingCanvas] = useState(false);
useEffect(() => {
setIsRebuildingCanvas(true);
}, [timeFormat]);
useEffect(() => {
if (isRebuildingCanvas) {
setIsRebuildingCanvas(false);
}
}, [isRebuildingCanvas]);
useEffect(() => {
if (chartCanvasRef && chartCanvasRef.current && detail) {
const chartCanvas = chartCanvasRef.current
if (isRebuildingCanvas || !chartCanvas) {
return;
}
const chartInstance = new Chart(chartCanvasRef.current, {
type: "line",
data: {
datasets: [
{
label: `${detail.name} price`,
data: determineTimeFormat(timeFormat, day, week, year),
backgroundColor: "rgba(134,159,152, 1)",
borderColor: "rgba(174, 305, 194, 0.4",
},
],
},
Options
options: {
plugins: {
annotation: {
annotations: {
}
}
},
animations: {
tension: {
duration: 1000,
easing: 'linear',
from: 1,
to: 0,
loop: true
}
},
maintainAspectRatio: false,
responsive: true,
scales: {
x:
{
type: 'time',
},
},
}
});
return () => {
chartInstance.destroy();
}
}}, [day, isRebuildingCanvas,timeFormat, week, year, detail]);
Rest of the Component code
return (
<div className='chart__container'>
{renderPrice()}
{isRebuildingCanvas ? undefined : (
<canvas ref={chartCanvasRef} id='myChart' width={250} height={250}></canvas>
)}
<button className='time__format' onClick={() => setTimeFormat("24h")}>24h</button>
<button className='time__format' onClick={() => setTimeFormat("7d")}>7d</button>
<button className='time__format' onClick={() => setTimeFormat("1y")}>1y</button>
</div>
);
};
export default ChartData;
Looks like your isRebuildingCanvas logic might be inconsistent, or I don't just understand it.
Anyway, from the Chart.js perspective, you'd want to change the data and call chartInstance.update() when pressing the button that changes the data.
Partial example:
const canvas = useRef(null);
const [chart, setChart] = useState();
const [timeFormat, setTimeFormat] = useState("24h");
useEffect(() => {
if (chart || !canvas.current) return;
const ctx = canvas.current.getContext("2d");
if (!ctx) return;
const config = {/*...*/};
setChart(new Chart(ctx, config));
}, [chart, canvas]);
useEffect(() => {
if (!chart) return;
chart.config.data.datasets[0].data = determineTimeFormat(timeFormat, day, week, year);
chart.update();
}, [chart, timeFormat]);
And a complete, very similar example:
https://codesandbox.io/s/blissful-faraday-hzcq0