I am developing a web application where I want to present data in the form of a line graph. For this I am using the CanvasJS component CanvasJSChart. Everything works well except that the graph is not loaded when I try to reload a page. This is what I see when I reload the page. When I then update the code (insert a new line and save) I see this. The datetime fields are used to filter which dates and times that should be visible and they work as long as the data points are visible when I edit them. The only thing I have found that solves this is by updating the code or resizing the window.
This is the code that I use to create the options and return the chart component.
import React from 'react';
import CanvasJSReact from '@canvasjs/react-charts';
const options = {
zoomEnabled: true,
animationEnabled: true,
animationDuration: 1200,
title: {
text: "Graph to see shit"
},
toolTip: {
shared: true,
contentFormatter: function(e){
var content = " ";
for (var i = 0; i < e.entries.length; i++) {
content += e.entries[i].dataSeries.name
+ " " + "<strong>"
+ e.entries[i].dataPoint.y + "</strong>";
content += "<br/>";
}
content += e.entries[0].dataPoint.x + "<br/>";
return content
}
},
data: [
{
type: "line",
name: "Temperature",
showInLegend: true,
dataPoints: []
},
{
type: "line",
name: "Humidity",
showInLegend: true,
dataPoints: []
}]
}
export function GraphFunc(props){
options.data[0].dataPoints = props.data.tempPoints;
options.data[1].dataPoints = props.data.humPoints;
return(
<div>
< CanvasJSReact.CanvasJSChart options={options} />
</div>
)
}
This is the code that calls the API, collects datapoints, handle the date pickers and creates the chart component.
import React, { useState, useEffect } from 'react';
import axios from 'axios';
import dayjs from 'dayjs';
import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
import { DateTimePicker } from '@mui/x-date-pickers/DateTimePicker';
import { LocalizationProvider } from '@mui/x-date-pickers';
import { GraphFunc } from './GraphFunc.js'
function formatData(data, lower, upper){
var tmp = {tempPoints: [], humPoints: []};
data.forEach(element => {
var date = new Date(element.date);
if(lower != undefined && upper != undefined){
var epochTime = date.getTime();
if(upper < epochTime || epochTime < lower){
return;
}
}
tmp.tempPoints.push({y: Number(element.temp), x: date})
tmp.humPoints.push({y: Number(element.hum), x: date})
});
console.log("Nu byter jag saker")
return tmp;
}
export function Graph() {
const [data, getData] = useState('')
const [startDate, setStartValue] = useState(dayjs());
const [endDate, setEndValue] = useState(dayjs());
const [oldStart, setOldStart] = useState(dayjs());
const [oldEnd, setOldEnd] = useState(dayjs());
useEffect(() => {
getAllData(undefined, undefined);
}, []);
const getAllData = (lower, upper) => {
axios.get("/api/dhts/")
.then((res) => {
const d = formatData(res.data, lower, upper)
getData(d);
})
.catch((err) => console.log(err));
}
function handleChanges(e){
if(startDate.$d.getTime() == oldStart.$d.getTime() && endDate.$d.getTime() == oldEnd.$d.getTime()){
return
}
setOldStart(startDate);
setOldEnd(endDate);
getAllData(startDate.$d.getTime(), endDate.$d.getTime());
}
return(
<>
<GraphFunc data={data} />
<div style={{display: "flex", alignItems: "center", justifyContent: "center",}}>
<strong style={{marginBottom: 7, marginTop: 7}}>Pick dates for displaying data</strong>
</div>
<LocalizationProvider dateAdapter={AdapterDayjs}>
<div style={{display: "flex", alignItems: "center", justifyContent: "center",}}>
<DateTimePicker value={startDate} onChange={setStartValue} onClose={handleChanges} label="Start date" />
<DateTimePicker value={endDate} onChange={setEndValue} onClose={handleChanges} label="End date" />
</div>
</LocalizationProvider>
</>
)
}
I found this post which had similar issues but our programs look quite different. I do think that something is asynchronous and that causes this to not load. However, I don't have a clue what could fix it. Is anyone sitting on a quick fix for this?
Try to make the graphFunc like this, I think ur problem is in the first render.
The data is not here yet but react render the component anyways, and no re-renders to make it work again.
But when u change in code, this is actually a re-render so the DOM updated with the data
import React from 'react';
import CanvasJSReact from '@canvasjs/react-charts';
export function GraphFunc(props){
const options = {
zoomEnabled: true,
animationEnabled: true,
animationDuration: 1200,
title: {
text: "Graph to see shit"
},
toolTip: {
shared: true,
contentFormatter: function(e){
var content = " ";
for (var i = 0; i < e.entries.length; i++) {
content += e.entries[i].dataSeries.name
+ " " + "<strong>"
+ e.entries[i].dataPoint.y + "</strong>";
content += "<br/>";
}
content += e.entries[0].dataPoint.x + "<br/>";
return content
}
},
data: [
{
type: "line",
name: "Temperature",
showInLegend: true,
dataPoints: props.data?.tempPoints
},
{
type: "line",
name: "Humidity",
showInLegend: true,
dataPoints: props.data?.humPoints
}]
}
if (!props.data.humPoints || !props.data.tempPoints) return "Loading";
return(
<div>
<CanvasJSReact.CanvasJSChart options={options} />
</div>
)
}