how to map time with its respective data in chart - javascript

I'm working on apexcharts. I managed to pass data in chart, but there seem to be issue with timestamps. I have two data i.e sender and receiver, each has its own timestamps. the graph's x-axis is based on the timestamps. but I don't know how to map the timestamp with its respective data. currently, the data in the graph are not showing right due to the timestamp issue. kindly help me to fix it. thanks in advance
here's my full code
const receiverData = [];
const senderData = [];
const timeData = [];
export default function GraphCard() {
const [GraphData, setGraphData] = useState([])
const showData = () => {
axios.get('http://localhost:8006/api/v2/user/transactions').then(function (res) {
var result = res.data.data;
console.log(result)
if (result.data) {
setGraphData(result.data)
for (const obj of result.data) {
if (obj.role === 'Sender') {
receiverData.push(obj.tokens)
timeData.push(obj.date)
}
if (obj.role === 'Receiver') {
senderData.push(obj.tokens)
timeData.push(obj.date)
}
}
console.log("Reciever", receiverData)
console.log("Sender", senderData)
}
else {
console.log('error')
}
})
}
const state = {
series: [{
color: '#000073',
name: 'Received',
data: receiverData.map((data) => (data))
},
{
color: '#CA9026',
name: 'Sent',
data: senderData.map((data) => (data))
}],
options: {
chart: {
height: 280,
type: 'area'
},
dataLabels: {
enabled: false
},
stroke: {
curve: 'smooth'
},
xaxis: {
type: 'datetime',
categories: timeData.map((data) =>(data))
},
yaxis: {
type: ''
},
tooltip: {
x: {
format: 'dd/MM/yy HH:mm'
},
},
},
}
useEffect(() => {
showData()
}, [])
return (
<Card >
<CardContent display='flex' sx={{ flexDirection: 'column', }} >
<Stack flexDirection='row' alignItems="center" gap={1}>
< SsidChartOutlinedIcon sx={{ color: "text.secondary" }} />
<Typography sx={{ fontSize: 15, fontWeight: 'bold' }} color="text.secondary" gutterBottom>
Recent Transactions
</Typography>
</Stack>
<div id="chart">
<ReactApexChart options={state.options} series={state.series} type="area" height={280} />
</div>
</CardContent>
</Card>
);
}

On apex chart website, they have a case that is similar to yours:
series: [{
data: [{ x: '05/06/2014', y: 54 }, { x: '05/08/2014', y: 17 } , ... , { x: '05/28/2014', y: 26 }]
}]
apexchart docs
To achieve this kind of objects, you can just do this:
const showData = () => {
axios.get('http://localhost:8006/api/v2/user/transactions').then(function (res) {
var result = res.data.data;
console.log(result)
if (result.data) {
setGraphData(result.data)
for (const obj of result.data) {
if (obj.role === 'Sender') {
receiverData.push({x: obj.date.toString(), y: obj.tokens}) //date.toString() is not necessary if your date is already a string
timeData.push(obj.date)
}
if (obj.role === 'Receiver') {
senderData.push({x: obj.date.toString(), y: obj.tokens})
timeData.push(obj.date)
}
}
console.log("Reciever", receiverData)
console.log("Sender", senderData)
}
else {
console.log('error')
}
})
}
And the rest should not need to be changed.

Related

How to hide the legend in chart.js in a react project?

I am trying to hide the legend of my chart created with Chart.js.
According to the official documentation (https://www.chartjs.org/docs/latest/configuration/legend.html), to hide the legend, the display property of the options.display object must be set to false.
I have tried to do it in the following way:
const options = {
legend: {
display: false,
}
};
But it doesn't work, my legend is still there. I even tried this other way, but unfortunately, without success.
const options = {
legend: {
display: false,
labels: {
display: false
}
}
}
};
This is my full code.
import React, { useEffect, useState } from 'react';
import { Line } from "react-chartjs-2";
import numeral from 'numeral';
const options = {
legend: {
display: false,
},
elements: {
point: {
radius: 1,
},
},
maintainAspectRatio: false,
tooltips: {
mode: "index",
intersect: false,
callbacks: {
label: function (tooltipItem, data) {
return numeral(tooltipItem.value).format("+0,000");
},
},
},
scales: {
xAxes: [
{
type: "time",
time: {
format: "DD/MM/YY",
tooltipFormat: "ll",
},
},
],
yAxes: [
{
gridLines: {
display: false,
},
ticks: {
callback: function(value, index, values) {
return numeral(value).format("0a");
},
},
},
],
},
};
const buildChartData = (data, casesType = "cases") => {
let chartData = [];
let lastDataPoint;
for(let date in data.cases) {
if (lastDataPoint) {
let newDataPoint = {
x: date,
y: data[casesType][date] - lastDataPoint
}
chartData.push(newDataPoint);
}
lastDataPoint = data[casesType][date];
}
return chartData;
};
function LineGraph({ casesType }) {
const [data, setData] = useState({});
useEffect(() => {
const fetchData = async() => {
await fetch("https://disease.sh/v3/covid-19/historical/all?lastdays=120")
.then ((response) => {
return response.json();
})
.then((data) => {
let chartData = buildChartData(data, casesType);
setData(chartData);
});
};
fetchData();
}, [casesType]);
return (
<div>
{data?.length > 0 && (
<Line
data={{
datasets: [
{
backgroundColor: "rgba(204, 16, 52, 0.5)",
borderColor: "#CC1034",
data: data
},
],
}}
options={options}
/>
)}
</div>
);
}
export default LineGraph;
Could someone help me? Thank you in advance!
PD: Maybe is useful to try to find a solution, but I get 'undefined' in the text of my legend and when I try to change the text like this, the text legend still appearing as 'Undefindex'.
const options = {
legend: {
display: true,
text: 'Hello!'
}
};
As described in the documentation you linked the namespace where the legend is configured is: options.plugins.legend, if you put it there it will work:
var options = {
type: 'line',
data: {
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
datasets: [{
label: '# of Votes',
data: [12, 19, 3, 5, 2, 3],
borderColor: 'pink'
}
]
},
options: {
plugins: {
legend: {
display: false
}
}
}
}
var ctx = document.getElementById('chartJSContainer').getContext('2d');
new Chart(ctx, options);
<body>
<canvas id="chartJSContainer" width="600" height="400"></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.5.0/chart.js"></script>
</body>
On another note, a big part of your options object is wrong, its in V2 syntax while you are using v3, please take a look at the migration guide
Reason why you get undefined as text in your legend is, is because you dont supply any label argument in your dataset.
in the newest versions this code works fine
const options = {
plugins: {
legend: {
display: false,
},
},
};
return <Doughnut data={data} options={options} />;
Import your options value inside the charts component like so:
const options = {
legend: {
display: false
}
};
<Line data={data} options={options} />

Can't change the time of the xAxes in the Chart.js

So I have ChartData Component. I am taking the data from an API, the data is being displayed through Chart. I have determine Format Logic, which it's the main thing is to determine the time of the data, I have 3 buttons, the thing that I am struggling to achieve is when let's say I wanna see the data of 7days when I press the button. I can see data is changing in the yAxes but I can't see time being changed on thexAxes, it's still set to hours, it should display the days.
ChartData
import React, { useRef, useEffect, useState } from "react";
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
return (
<div className='chart__container'>
{renderPrice()}
{isRebuildingCanvas ? undefined : (
<canvas ref={chartCanvasRef} width={250} height={250} id='myChart'></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;
I have created a similar working example without reactjs. This can be useful for you to understand. You can refer the fiddle as well. A limitation that am currently facing is if there is data more than 100 then am getting errors while updating the data, performed slicing of data upto 100 to make it working.
var coinData = {};
var fetchData = async() => {
api = "https://api.coingecko.com/api/v3";
id = "bitcoin";
var [day1, week1, year1, detail1] = await Promise.all([
fetch(api + `/coins/${id}/market_chart/?vs_currency=usd&days=1`).then(data => {
return data.json()
}),
fetch(api + `/coins/${id}/market_chart/?vs_currency=usd&days=7`).then(data => {
return data.json()
}),
fetch(api + `/coins/${id}/market_chart/?vs_currency=usd&days=365`).then(data => {
return data.json()
}),
fetch(api + `/coins/markets/?vs_currency=usd&ids=${id}`).then(data => {
return data.json()
})
]);
coinData = {
day: formatData(day1.prices).slice(0, 100),
week: formatData(week1.prices).slice(0, 100),
year: formatData(year1.prices).slice(0, 100),
detail: detail1[0]
}
}
const formatData = (data) => {
return data.map((el) => {
return {
t: el[0],
y: el[1].toFixed(2)
};
});
};
const determineTimeFormat = (timeFormat) => {
switch (timeFormat) {
case "24h":
return coinData.day;
case "7d":
return coinData.week;
case "1y":
return coinData.year;
default:
return coinData.day;
}
};
var chartInstance;
fetchData().then(() => {
/* console.log(coinData); */
var ctx = document.getElementById('chartJSContainer');
chartInstance = new Chart(ctx, {
type: "line",
labels: false,
data: {
datasets: [{
label: `${coinData.detail.name} price`,
data: determineTimeFormat('1d'),
parsing: {
yAxisKey: 'y',
xAxisKey: 't',
},
backgroundColor: "rgba(134,159,152, 1)",
borderColor: "rgba(174, 305, 194, 0.4)"
}],
},
options: {
scales: {
x: {
ticks: {
source: "data"
},
type: 'time',
time: {
unit: "day"
}
}
},
}
});
});
function setTimeFormat(format) {
Chart.instances[0].data.datasets[0].data = determineTimeFormat(format);
Chart.instances[0].update();
}
<script src="https://cdn.jsdelivr.net/npm/chart.js#3.3.1/dist/chart.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-moment#1.0.0/dist/chartjs-adapter-moment.min.js"></script>
<body>
<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><br><br>
<canvas id="chartJSContainer" width="600" height="400"></canvas>
</body>

how to resolve the problem that hovering mouse on chart will appear old data/charts?

I used react hooks useEffect for rendering a chart from chart.js to canvas. However, I found problem of old chart showing when I hover my mouse on the chart. From the sources I found online I realized the problem might be able to solve by chart.destroy(), but I just do not know where and how to use it in my case of code. I have attached a snip of my code here, hope anybody can help me out.
import React, { useEffect } from 'react';
import Chart from 'chart.js';
import { Card } from 'components/Card';
import { localDateTime, dateFilter } from 'helpers';
const red = '#644DFF';
const purple = '#F73F64';
const DailyTrafficCard = (props) => {
const { store, capacity, data, setVar} = props;
const lastSevenDays = Array(7)
.fill()
.map((_, i) => {
const localdate = localDateTime(store);
return localdate()
.subtract(i, 'day')
.format('YYYY-MM-DD[T]07:00:00[Z]');
});
useEffect(() => {
const ctx = document && document.querySelector('#daily-traffic-chart');
if (!ctx) {
return;
}
const bar = new Chart(ctx, {
type: 'bar',
data: {
labels: [],
datasets: [{
data: data[data.length-1],
barThickness: 13,
backgroundColor: (ctx) => {
const idx = ctx && ctx.dataIndex;
const val = ctx && ctx.dataset && ctx.dataset.data && ctx.dataset.data[idx];
return val < 40 ? purple : red;
}
}]
},
options: {
intersect: false,
legend: {
display: false,
},
scales: {
xAxes: [{
type: 'time',
offset: true,
time: {
unit: 'hour',
displayFormats: {
hour: 'HH',
},
},
ticks: {},
gridLines: {
display: false,
},
}],
yAxes: [{
gridLines: {
display: true,
},
ticks: {
beginAtZero: true,
min: 0,
max: capacity,
stepSize: 5
},
}],
},
}
});
}, [data,capacity]);
const handleOnChange = (event) => {
setVar(event.target.value);
}
return (
<Card
classname="DailyTrafficCard"
icon={<span><i className="icon-user"/></span>}
title={<h3>Daily Traffic Analytics</h3>}>
<div className="daily">
<div className="daily-head p-4 text-center">
<select className="py-2 px-3" onChange={handleOnChange}>
{lastSevenDays.map(date => (
<option key={date} value={date}>{dateFilter(date, 'dddd')}</option>
))}
</select>
</div>
<div className="px-8">
{data && data.length > 0 && (
<canvas width="250" id="daily-traffic-chart"></canvas>
)}
</div>
</div>
</Card>
)
}
export {
DailyTrafficCard
}

How to use axios to fetch data from servlet and then crossfilter it and display via highcharts

I am trying to display charts through highcharts with data from my servlet, but somehow it's not able to display data properly from my servlet(like its showing in console but after that I think I'm missing few steps). I am totally new to react js and this web development stuff, please help, I think its something with axios,
import React from 'react';
import SearchPanel from '../components/SearchPanel'
import { Grid } from '#material-ui/core';
import Highcharts from 'highcharts';
import HighchartsReact from 'highcharts-react-official';
import crossfilter from 'crossfilter2';
import axios from 'axios';
import App1 from '../components/App1';
export default class AnalyticsSection extends React.Component {
state = {
dataResults: [],
data : [],
};
componentDidMount() {
axios.get('http://localhost:8080/Internship_Backend/customer')
.then(response => {
console.log(response);
this.setState({ dataResults : response.data });
})
.catch(error => {
console.log(error);
});
var dataset = crossfilter(this.state.dataResults);
var bcodedim = dataset.dimension(d => d.business_code);
var bcodegrp = bcodedim.group().reduceSum(d => d.actualOpenAmount);
function prepareDataForHighcharts(groups){
var categories =[];
var data = [];
var gdata = groups.top(4);
gdata.forEach(d => {
categories.push(d.key);
data.push(d.value);
});
return{
categories : categories,
data : data
}
}
var tempObject = prepareDataForHighcharts(bcodegrp);
var options = {
chart: {
renderTo : 'container',
type : 'bar',
backgroundColor:'#1b1f38',
minWidth: 275,
height: '222px',
},
// colors: ['#FFFFFFa5 '],
title : {
text : "Total Amount by Company Code",
style:{
color: '#FFFFFFa5'
}
},
xAxis : {
type : 'category',
categories : tempObject.categories,
title: {
text: null
},
overflow : 'auto'
},
yAxis : {
min: 0,
// overflow : 'scroll'
// tickInterval: 10000,
},
tooltip: {
valueSuffix: ' dollars'
},
series : [{
// name : 'Count',
data : tempObject.data,
// data: [125, 100,85, 74, ]
}],
legend : {
enabled : false,
},
credits: {
enabled : false,
},
exporting: {
enabled : false,
},
plotOptions: {
}
}
var chart = new Highcharts.chart(options);
}
render (){
return (
<Grid container >
<Grid item xs style={{
minWidth: 275,
height: '225px',
margin: '2px 2px 10px ',
backgroundColor: "rgb(93,175,240,0.5)",
marginTop:'-10px',
marginLeft : '12px',
marginRight : '-5px'
}} >
<div id = 'container' align='center' style = {{ marginTop : '2px' }}> </div>
</Grid>
<Grid item xs style = {{
minWidth: 275,
height: '225px',
margin: '2px 2px 10px ',
backgroundColor: "rgb(93,175,240,0.5)",
marginTop:'0px',
marginLeft : '12px',
marginRight : '-5px'
}} >
<SearchPanel/>
< div align='center'>
</div>
</Grid>
</Grid>
);
}
}
the data in my servlet is in json format
I would process data further in the then callback and then store results in state.
const url = (() => {
const data = [{"pk_id":1,"acct_doc_header_id":539592086,"company_id":60,"document_number":39439082,"document_number_norm":39439082,"business_code":"pier9","create_year":"","document_line_number":0,"doctype":"RI","customer_number":218994,"customer_number_norm":218994,"fk_customer_map_id":-1,"customer_name":"pied piper","division":"","documentCreateDate":"Jul 5, 2018","documentCreateDateNorm":"Jul 5, 2018","posting_id":"","invoice_id":39439082,"invoice_id_norm":39439082,"totalOpenAmount":0.0,"totalOpenAmountNorm":0.0,"cust_payment_terms":60,"business_area":"","ship_to":"","clearingDate":"Sep 5, 2018","clearingDateNorm":"Sep 5, 2018","reason_code":"","isOpen":0,"debit_credit_indicator":"","payment_method":"","invoiceAmountDocCurrency":3925.91,"document_id":539592086,"actualOpenAmount":3925.91,"paidAmount":3925.91,"dayspast_due":2,"invoice_age":62,"disputed_amount":0.0}]
const blob = new Blob([JSON.stringify(data)], {
type: 'application/json'
})
return URL.createObjectURL(blob);
})()
const options = ({data, categories}) => ({
chart: {
type : 'bar',
backgroundColor:'#1b1f38',
minWidth: 275,
height: '222px',
},
title : {
text : "Total Amount by Company Code",
style:{
color: '#FFFFFFa5'
}
},
xAxis : {
type : 'category',
categories,
title: {
text: null
},
overflow : 'auto'
},
yAxis : {
min: 0,
},
tooltip: {
valueSuffix: ' dollars'
},
series : [{
data
}],
legend : {
enabled : false,
},
credits: {
enabled : false,
},
exporting: {
enabled : false,
},
plotOptions: {}
})
const prepareDataForHighcharts = (groups) => {
const categories = [];
const data = [];
const gdata = groups.top(4);
for(const {key, value} of gdata) {
categories.push(key);
data.push(value);
}
return {
categories,
data
}
}
const ReactHighcharts = ReactHighcharts;
const { Component, useState, useEffect } = React;
class AnalyticsSection extends Component {
constructor(props) {
super(props);
this.state = {
isLoading: true,
dataResults: [],
config: {}
}
}
componentDidMount() {
this.mounted = true;
axios.get(url)
.then(response => {
const dataResults = response.data;
if(!this.mounted) {
return;
}
const dataset = crossfilter(dataResults);
const bcodedim = dataset
.dimension(({business_code}) => business_code);
const bcodegrp = bcodedim.group()
.reduceSum(({actualOpenAmount}) => actualOpenAmount);
const obj = prepareDataForHighcharts(bcodegrp);
const config = options(obj);
this.setState(state => ({
isLoading: false,
config
}));
})
.catch(error => {
console.log(error);
});
}
componentWillUnmount() {
this.mounted = false;
}
render() {
const { isLoading, config } = this.state;
return <div>
{isLoading ? <div>Loading</div> : <ReactHighcharts config = {config}></ReactHighcharts>}
</div>
}
}
ReactDOM.render(
<AnalyticsSection />,
document.getElementById('root')
);
<script src="https://unpkg.com/react/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/babel-standalone#6/babel.min.js"></script>
<script src="https://code.highcharts.com/highcharts.js"></script>
<script src="https://unpkg.com/react-highcharts#16.0.2/bundle/ReactHighcharts.js"></script>
<script src="https://unpkg.com/crossfilter2#latest/crossfilter.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.19.2/axios.js"></script>
<div id="root"></div>

Passing dynamic data Victory-native charts

I am using victory-native chart to render a pie chart. I am confused on how to pass the data fetched from Rest API to the {data} being passed to the pie chart for it's 'y' values. Here is my code:
import React, {Component} from "react";
import { StyleSheet, View } from "react-native";
import axios from 'axios'
import { VictoryPie, VictoryGroup, VictoryTheme } from "victory-native";
import Svg from 'react-native-svg';
export default class Chart extends Component {
state= {
id: '********************',
data: []
}
componentDidMount(){
var headers = {
'Content-Type': 'application/x-www-form-urlencoded',
'Access-Control-Allow-Headers': 'x-access-token',
'x-access-token': this.state.id
}
axios.post('http://bi.servassure.net/api/SalesOverviewOEMLevel2', {
oem:'all'
},
{headers: headers}).then((res) => {
let TotalSales = res.data.data[0].TotalSales;
this.setState({
data: TotalSales
})
console.log(this.state.data);
})
.catch(err => {
console.log(err)
});
}
render() {
const myColorScale = ["#1b4f72", "#21618c", "#2e86c1","#3498db", "#76d7c4", "#d1f2eb"];
const data = [
{ x: 1, y: 6, i: 0 },
{ x: 2, y: 2, i: 1 },
{ x: 3, y: 3, i: 2 },
{ x: 4, y: 5, i: 3 },
]
return (
<View style={styles.container}>
<Svg
height={200}
width={200}
viewBox={'0 0 300 300'}
preserveAspectRatio='none'
>
<VictoryGroup width={300} theme={VictoryTheme.material}>
<VictoryPie
style={{
data: {
fill: (d) => myColorScale[d.i]
},
labels: { fill: "white", fontSize: 10, fontWeight: "bold" }
}}
radius={100}
innerRadius={60}
labelRadius={70}
data={data}
labels={(d) => `y: ${d.y}`}
/>
</VictoryGroup>
</Svg>
</View>
);
}
}
This is the consoled form of my data that I want to pass into as 'Y' values to the chart:
The static data is rendering chart perfectly, but stuck on dynamic on how to loop the values. Please help to figure out.
You need to transform your data to match your example data:
Try this:
const your_data = this.state.data.map((val, index) => {
// you can also pass an i- value, but that's up to you
return { x: index, y: val };
});
and then:
<VictoryPie
style={{
data: {
fill: (d) => myColorScale[d.x] // d.x, because i didn't specify an "i-value"
},
labels: { fill: "white", fontSize: 10, fontWeight: "bold" }
}}
radius={100}
innerRadius={60}
labelRadius={70}
data={your_data} // pass here your new data
labels={(d) => `y: ${d.y}`}
/>

Categories

Resources