Adding condition in ComponentDidMount to display chart data - javascript

I've added a condition in componentDidMount to showcase data for either 1 or 2 datasets based on the pros recieved. However, I'm getting an error in the if condition. Here is BarChart component. Inside it, I've already imported Chart from 'chart.js'.
class BarChart1 extends Component {
constructor(props) {
super(props);
}
chartRef = React.createRef();
componentDidMount() {
const myChartRef = this.chartRef.current.getContext("2d");
let dataCheck = null;
if(this.props.data2){
let dataCheck = {
labels: this.props.labels,
datasets: [
{
label: this.props.label1,
backgroundColor: 'rgba(26,179,148,0.5)',
borderColor: "rgba(26,179,148,0.7)",
data: this.props.data1
}, {
label: this.props.label2,
backgroundColor: 'rgba(220, 220, 220, 0.5)',
pointBorderColor: "#fff",
data: this.props.data2
}
]
}
}
else {
let dataCheck = {
labels: this.props.labels,
datasets: [
{
label: this.props.label1,
backgroundColor: 'rgba(26,179,148,0.5)',
borderColor: "rgba(26,179,148,0.7)",
data: this.props.data1
}
]
}
}
new Chart(myChartRef, {
type: 'bar',
data: {dataCheck},
options: {
responsive: true,
maintainAspectRatio: false,
legend: {
display: true,
},
scales: {
yAxes: [{
ticks: {
beginAtZero: true
},
gridLines: {
display: false
}
}],
xAxes: [{
gridlines: {
display: false
},
ticks: {
fontSize: 9
}
}]
}
},
plugins: [{
beforeInit: function(chart) {
chart.data.labels.forEach(function(e, i, a) {
if (/\n/.test(e)) {
a[i] = e.split(/\n/);
}
});
}
}]
})
}
render() {
return <canvas ref={this.chartRef} />
}
}
I've edited my question. I'm now getting a blank chart without the error.

There are two errors in your code.
Your have to end the variable declaration with ; instead of ,
You have to declare datacheck outside the if else block unless you want it undefined
componentDidMount() {
...
let dataCheck;
if(this.props.data2){
dataCheck = {
...
}
}
else {
dataCheck = {
...
}
}
}

Related

react-chartjs-2 Radar Component

My Radar component hasnt ticks:{stepSize} property. Max is 5 and min is 1 but radar go up to 2. And I want it to jump one by one. more space between the triangles
i
nterface LineProps {
options: ChartOptions<"radar">;
data: ChartData<"radar">;
}
interface PropsComponent {
labels: string[];
data: number[];
}
interface PropsComponent {
labels: string[];
data: number[];
}
const Component = ({ labels, data }: PropsComponent) => {
const Props: LineProps = {
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
position: "top",
},
},
scales: {
ticks: {
beginAtZero: true,
max: 9,
min: 1,
},
},
},
data: {
datasets: [
{
label: "Datos",
data: data,
borderColor: "red",
backgroundColor: "red",
},
],
labels: labels,
},
};
labels = [criterion1,criterion2,criterion3]
values = [1,2,5]

react-chartjs-2 get visible values after pan/zoom with chartjs-plugin-zoom

Is there any way to get the visible values on a chart after zooming or panning, using react-chartjs-2? I found a solution without the react version, but I'm not sure how to reference the "chart object" in react. I tried the solution as is, but it doesn't display the visible values, but rather keeps increasing the height of my charts (stretches downwards).
So what would the react solution look like?
Here's my attempt with the linked solution
options:
const chartStyle = {
options: {
animation: false,
maintainAspectRatio: true,
responsive: true,
plugins: {
zoom: {
zoom: {
wheel: {
enabled: true,
modifierKey: "shift",
},
pinch: {
enabled: true,
},
enabled: true,
drag: true,
mode: "x",
onZoomComplete: getVisibleValues,
},
pan: {
enabled: true,
mode: "x",
speed: 2,
onPanComplete: getVisibleValues,
},
mode: "xy",
},
legend: {
display: false,
},
},
scales: {
y: {
type: "linear",
display: "true",
position: "left",
grid: {
drawBorder: true,
color: "#000000",
},
ticks: {
beginAtZero: true,
color: "#000000",
},
},
x: {
max: 9,
grid: {
drawBorder: true,
color: "#00000",
},
ticks: {
beginAtZero: false,
color: "#000000",
},
},
},
},
};
function getVisibleValues({ chart }) {
let x = chart.scales["x-axis-0"];
document.getElementById("vv").innerText = JSON.stringify(
chart.data.datasets[0].data.slice(x.minIndex, x.maxIndex + 1)
);
}
export default chartStyle;
Here's my attempt at accessing the chart instance with useRef(), but ref.scales is undefined:
const SingleChart = ({ chosenDevice, variable }) => {
const [chartData, setChartData] = useState({
labels: [],
datasets: [
{
label: variable,
data: [],
fill: false,
backgroundColor: "rgb(0,0,0)",
borderColor: "rgba(0,0,0, 0.8)",
color: "rgb(0,0,0)",
pointRadius: 4,
yAxisID: "y",
},
],
});
const [apiData, setApiData] = useState({});
const processEnv = process.env;
// USEREF ATTEMPT
const ref = useRef();
console.log(ref.scales);
let x = ref.scales["x"];
console.log("min index", x.minIndex);
console.log("max index", x.maxIndex);
useEffect(() => {
ChartComp.register(zoomPlugin);
var chartDataUrl = processEnv.REACT_APP_CHART_API + chosenDevice;
async function updatePPK() {
if (chosenDevice !== "") {
const dataResponse = await fetch(chartDataUrl);
var dataBody = await dataResponse.json();
for (var key in dataBody) {
dataBody[key].PV_POWER =
dataBody[key].PV_CURR * dataBody[key].PV_CURR;
}
setApiData(dataBody);
}
}
updatePPK();
}, [chosenDevice]);
useEffect(() => {
var chartLabels = [];
var chartValues = [];
console.log(apiData);
console.log("keys", Object.keys(apiData) !== 0);
if (Object.keys(apiData).length !== 0) {
for (var key in apiData) {
if (variable == "GEN_ON") {
chartValues.push(apiData[key][variable] == "ON" ? 1 : 0);
} else {
chartValues.push(apiData[key][variable]); // for every element in the passed in chartData object from hookMqtt, add the variable the graph requests (this.variable) to an array of data to be displayed
}
chartLabels.push(apiData[key]["TIME_COMMITED"].substring(11, 19));
}
setChartData({
labels: chartLabels,
datasets: [
{
label: variable,
data: chartValues,
fill: false,
backgroundColor: "rgb(0,0,0)",
borderColor: "rgba(0,0,0, 0.8)",
color: "rgb(0,0,0)",
pointRadius: 4,
yAxisID: "y",
},
],
});
console.log(chartData);
}
}, [chosenDevice, apiData]);
return (
<div>
<Line
ref={ref}
data={chartData}
options={variable != "GEN_ON" ? chartStyles.options : genStyle.options}
width={20}
height={10}
/>
</div>
);
};
SingleChart.propTypes = {
chartData: PropTypes.any,
chosenDevice: PropTypes.any,
setDate: PropTypes.any,
variable: PropTypes.any,
state: PropTypes.any,
};
export default SingleChart;

Chartjs in Vue integrate parsed Json Data

i have amateur problems with building a Chart with Chart.js in Vue.js. Chart.js works, I can already see a Chart and am able log the data (with console.log) in the command line.
chart-data.js
type: 'line',
data: {
labels: ['Afghanistan', 'Somalia', 'Nigeria'],
datasets: [
{ // one line graph
label: 'Number of Moons',
data: [300, 75, 468],
backgroundColor: [
'rgba(54,73,93,.5)', // Blue
],
borderColor: [
'#36495d',
],
borderWidth: 3
},
{ // another line graph
label: 'Planet Mass (x1,000 km)',
data: [4.8, 12.1, 12.7, 6.7, 139.8, 116.4, 50.7, 49.2],
backgroundColor: [
'rgba(71, 183,132,.5)', // Green
],
borderColor: [
'#47b784',
],
borderWidth: 3
}
]
},
options: {
responsive: true,
lineTension: 1,
scales: {
yAxes: [{
ticks: {
beginAtZero: true,
padding: 25,
}
}]
}
}
}
export default planetChartData;
The parsing already works, but im struggling with getting my arrays (labelNation, numOfNationals) into the variable planetChartData.
json-parse.js
const file = fs.readFileSync('./data.json', 'utf8')
const test = JSON.parse(file)
let nationality = [];
for (let i = 0; i < test.length; i++) {
nationality.push(test[i].nationality)
}
const labelNation = Array.from(new Set(nationality));
let numOfNationals = [];
for (let i = 0; i < labelNation.length; i++) {
numOfNationals.push(nationality.filter(nat => nat === labelNation[i]).length)
}
vue.js
(in the script tag)
const Chart = require('chart.js');
import planetChartData from './chart-data.js';
export default {
name: 'App',
components: {
},
data() {
return {
planetChartData: planetChartData,
}
},
mounted() {
this.createChart('planet-chart', this.planetChartData);
},
methods: {
createChart(chartId, chartData) {
const ctx = document.getElementById(chartId);
const myChart = new Chart(ctx, {
type: chartData.type,
data: chartData.data,
options: chartData.options,
});
}
}
}
Thanks a lot for your help!
can you try this:
const Chart = require('chart.js');
import planetChartData from './chart-data.js';
export default {
name: 'App',
components: {
},
data() {
return {
planetChartData: planetChartData,
}
},
mounted() { // vvv use spread operator here below
this.createChart('planet-chart', ...this.planetChartData);
},
methods: {
createChart(chartId, chartData) {
const ctx = document.getElementById(chartId);
const myChart = new Chart(ctx, {
type: chartData.type,
data: chartData.data,
options: chartData.options,
});
}
}
}
and your chart-data.js should look like this for a decent export:
i am initializing a const for declaration of planetChartData
const planetChartData = {
type: "line",
data: {
labels: ["Afghanistan", "Somalia", "Nigeria"],
datasets: [
{
// one line graph
label: "Number of Moons",
data: [300, 75, 468],
backgroundColor: [
"rgba(54,73,93,.5)" // Blue
],
borderColor: ["#36495d"],
borderWidth: 3
},
{
// another line graph
label: "Planet Mass (x1,000 km)",
data: [4.8, 12.1, 12.7, 6.7, 139.8, 116.4, 50.7, 49.2],
backgroundColor: [
"rgba(71, 183,132,.5)" // Green
],
borderColor: ["#47b784"],
borderWidth: 3
}
]
},
options: {
responsive: true,
lineTension: 1,
scales: {
yAxes: [
{
ticks: {
beginAtZero: true,
padding: 25
}
}
]
}
}
};
export default planetChartData;

Variable is losing all of its data upon a React re-render

I have a React project that utilizes Chart JS to plot charts based on data.
I have a drop down list selector to select which dataset to draw from. However, after I switch to another dataset and then switch back to the initial rendered dataset, it does not appear to work anymore. Here is my code:
import React from 'react';
import { Line } from 'react-chartjs-2';
import { chartData } from './Search.js';
import { xLabels } from './Search.js';
import { allEpsData } from './Search.js';
let chartDataSeason = [];
let xLabelsSeason = [];
export class Graph extends React.Component {
constructor(props) {
super(props);
this.state = {
selectValue: '',
seasonSelected: false,
chartIt: {
labels: xLabels,
datasets: [
{
label: 'Rating',
data: chartData,
fill: false,
borderColor: '#00B4CC',
},
],
},
chartItSeason: {
labels: xLabelsSeason,
datasets: [
{
label: 'Rating',
data: chartDataSeason,
fill: false,
borderColor: '#00B4CC',
},
],
},
};
this.handleChange = this.handleChange.bind(this);
}
handleChange(e) {
if (e.target.value === 'All Seasons') {
this.setState({
seasonSelected: false,
chartIt: {
labels: xLabels,
datasets: [
{
label: 'Rating',
data: chartData,
fill: false,
borderColor: '#00B4CC',
},
],
},
});
console.log(chartData);
} else {
chartDataSeason = [];
xLabelsSeason = [];
let seasonNum = e.target.value.slice(6);
for (let i = 0; i < allEpsData[seasonNum - 1].length; i++) {
chartDataSeason.push(allEpsData[seasonNum - 1][i].imdbRating);
xLabelsSeason.push(
`s${seasonNum}e${allEpsData[seasonNum - 1][i].Episode} "${
allEpsData[seasonNum - 1][i].Title
}"`
);
}
this.setState({
selectValue: e.target.value,
seasonSelected: true,
chartItSeason: {
labels: xLabelsSeason,
datasets: [
{
label: 'Rating',
data: chartDataSeason,
fill: false,
borderColor: '#00B4CC',
},
],
},
});
}
// console.log(chartDataSeason)
}
render() {
let seasons = [];
for (let i = 0; i < allEpsData.length; i++) {
seasons.push(i);
}
if (this.state.seasonSelected === false) {
return (
<div>
<select // selector
className="select"
value={this.state.selectValue}
onChange={this.handleChange}
>
<option>All Seasons</option>
{seasons.map((el) => {
return <option key={el}>season {el + 1}</option>;
})}
</select>
<div className="line-container">
<Line
data={this.state.chartIt}
width={600}
height={400}
options={{
maintainAspectRatio: false,
scales: {
xAxes: [
{
ticks: {
display: true, //this will remove only the label
},
gridLines: {
show: false,
display: false,
},
},
],
yAxes: [
{
gridLines: {
show: false,
drawBorder: false,
},
},
],
},
animation: {
duration: 200,
easing: 'easeInOutQuart',
},
tooltips: {
enabled: true,
},
}}
/>
</div>
<div className="seasons-graph-container"></div>
</div>
);
} else {
return (
<div>
<select
className="select"
value={this.state.selectValue}
onChange={this.handleChange}
>
<option>All Seasons</option>
{seasons.map((el) => {
return <option key={el}>season {el + 1}</option>;
})}
</select>
<div className="line-container">
<Line
data={this.state.chartItSeason}
width={600}
height={400}
options={{
maintainAspectRatio: false,
scales: {
xAxes: [
{
ticks: {
display: false, //this will remove only the label
},
gridLines: {
show: false,
display: false,
},
},
],
yAxes: [
{
gridLines: {
show: false,
drawBorder: false,
},
},
],
},
animation: {
duration: 200,
easing: 'easeInOutQuart',
},
tooltips: {
enabled: true,
},
}}
/>
</div>
<div className="seasons-graph-container"></div>
</div>
);
}
}
}
the problem lies with chartData, it is not getting re-rendered correctly -- all the data associated with it has been replaced with the data of the last menu item. However oddly enough, xLabels does get rendered properly. Nothing is changing the value of chartData or xLabels but only xLabels gets correctly updated. Is there anything that I'm missing here? Apologies in advance for the spaghetti code, I am still learning React!

ChartJS makes unwanted horizontal line on Safari

I'm currently working with ChartJS.
It works fine on Firefox and Chrome.
On Safari there is horizontal lines which appear. (here there is one good on orange and two others unwanted )
I have a lot of datapoint (2 lines of 1600 data point). I don't know if it could be a cause.
My code is here.
In some other part, I update time uni and time min.
_displayChart: function(label1, label2){
var timeFormat = 'DD/MM/YYYY HH:mm';
var ctx = document.getElementById(this.heading).getContext('2d');
const data = {
// Labels should be Date objects
//labels:this._stats[1],
datasets: [{
fill: false,
label: label1,
data: this._stats[2],
borderColor: '#fe8b36',
pointRadius: 0,
backgroundColor: [
'#fe8b36'
]
},{
label: label2,
fill: false,
data: this._stats[3],
borderWidth: 1,
pointRadius: 0,
borderColor: 'rgba(99, 100, 200, 1)',
backgroundColor: [
'rgba(99, 100, 200, 0.2)'
]
}]
}
const options = {
type: 'line',
data: data,
options: {
responsive: false,
fill: false,
responsive: true,
maintainAspectRatio:!this._isMobile(),
max: this.max,
hover: {
// Overrides the global setting
mode: 'index'
},
annotation: {
drawTime: 'beforeDatasetsDraw',
events: ['click'],
annotations: []
},
legend: {
labels: {
filter: function(legendItem, chartData) {
if(legendItem.datasetIndex == 2 || legendItem.datasetIndex == 3 ){
return false;
}
return true;
}
}
},
tooltips: {
mode:'index',
intersect : false,
callbacks: {
title: function(tooltipItems, data) {
return tooltipItems[0].xLabel.format(timeFormat);
},
label: function(tooltipItems, data) {
return tooltipItems.yLabel+'%';
}
}
},
scales: {
xAxes: [{
type: 'time',
display: true,
time:{
unit:'day',
min:moment(Date.now()-this.monthTs),
max:this._stats[1][this._stats[1].length]
}
}],
yAxes: [{
ticks: {
beginAtZero: true,
},
display: true
}]
}
}
}
this._chart = new Chart(ctx, options);
},
When I'm applying this, I have no problem:
this._chart.options.scales.xAxes[0].time.unit = 'month';
this._chart.options.scales.xAxes[0].time.stepSize = 1;
this._chart.options.scales.xAxes[0].time.min = this._stats[1][0];
this._chart.options.scales.xAxes[0].time.max = this._stats[1][this._stats[1].length-1];
Thanks

Categories