I'm trying to build reactjs application. In this application I want to use chartjs to show line chart by subscribing the Server sent events(SSE).
I want to update line chart when there is new message from SSE. For that I've developed below code but the chart is not updating when there is new message. I'm printing the new message values in console and I can see those messages. But my chart is not updating on real-time bases.
for e.g if there is new message from SSE, the chart needs to be updated.
when I minimize my browser and maximize by browser that chart is updating with pulled messages values.
Once client connect to my server where SSE emit.
Please find screenshots here
Here is the code
let xAxis =[];
let yAxis=[];
class LineChartComponent extends Component
{
constructor(props) {
super(props);
this.state ={
data: []
}
this.eventSource = new EventSource('http://mydomainname:8090/kafka-messages');
}
componentWillMount() {
this.eventSource.onmessage = (e) => this.updateChart(JSON.parse(e.data));
}
updateChart(message){
let trgTS =message.TrgTS;
let value =parseFloat(100.0*message.Attributes[0].V/message.Attributes[1].V).toFixed(2);
xAxis.push(trgTS);
yAxis.push(value)
console.log(trgTS,value); // I can see the new messages values in console
this.setState(Object.assign({}, {
data: {
labels: xAxis,
datasets:[
{
label:'cycle time',
data: yAxis ,
fill: false,
borderColor: "#3cba9f"
}
]
}
}));
}
render()
{
return(
<div>
<Line data = {this.state.data} options = {{ maintainAspectRatio: false }} />
</div>
)
}
}
Related
I'm using ng2-charts render a simple pie chart in my component like so:
<canvas baseChart [data]="chartData" [colors]="chartColors" [options]="{ tooltips: { enabled: false } }"
chartType="pie"></canvas>
In my component class I have this chart directive which is supposed to be populated with chart object. But if I call this.chart.update() after assigning new value to chartData I get an undefined error.
export class TransactionDetailComponent implements OnInit {
#ViewChild(BaseChartDirective) chart: BaseChartDirective;
chartData: number[] = [];
generateChartData() {
//make an api call
this.chartData = [ //new data ];
}
Calling the generateChartData() method works fine the first time but chart does not get updated on subsequent calls. What am I doing wrong here?
I am using Chart.js 3.5 and Vue 3.
I was successfully able to draw a chart, and I am trying to trigger a data change, inside a Vue method. Unfortunately, I encounter the following issue: "Uncaught TypeError: Cannot set property 'fullSize' of undefined".
Edit2: Added a missed }. Code should now be runnable
MyChart.vue:
<template>
<canvas id="chartEl" width="400" height="400" ref="chartEl"></canvas>
<button #click="addData">Update Chart</button>
</template>
<script>
import Chart from 'chart.js/auto';
export default {
name: "Raw",
data() {
return {
chart: null
}
},
methods: {
createChart() {
this.chart= new Chart(this.$refs["chartEl"], {
type: 'doughnut',
data: {
labels: ['VueJs', 'EmberJs', 'ReactJs', 'AngularJs'],
datasets: [
{
backgroundColor: [
'#41B883',
'#E46651',
'#00D8FF',
'#DD1B16'
],
data: [100, 20, 80, 20]
}
]
},
options: {
plugins: {}
}
})
},
addData() {
const data = this.chart.data;
if (data.datasets.length > 0) {
data.labels.push('data #' + (data.labels.length + 1));
for (var index = 0; index < data.datasets.length; ++index) {
data.datasets[index].data.push(123);
}
// Edit2: added missed }
this.chart.update(); } // this line seems to cause the error}
}
},
mounted () {
this.createChart()
},
}
</script>
Edit1: Adding the following to the options makes the chart update successfully, but the error is still present and the animation does not work. The chart flickers and displays the final (updated) state. Other animations, such as hiding/showing arcs do not seem to be afected
options: {
responsive: true,
}
Edit3: Adding "maintainAspectRatio:false" option seems to again stop chart from updating (the above mentioned error is still present)
By walking through the debugger, the following function from 'chart.esm.js' seems to be called successfully a few times, and then error out on last call:
beforeUpdate(chart, _args, options) {
const title = map.get(chart); // this returns null, which will cause the next call to error with the above mentioned exception.
layouts.configure(chart, title, options);
title.options = options;
},
//////////////////////
configure(chart, item, options) {
item.fullSize = options.fullSize;
item.position = options.position;
item.weight = options.weight;
},
This may be a stale post but I just spent several hours wrestling with what seems like the same problem. Perhaps this will help you and/or future people with this issue:
Before assigning the Chart object as an attribute of your Vue component, call Object.seal(...) on it.
Eg:
const chartObj = new Chart(...);
Object.seal(chartObj);
this.chart = chartObj;
This is what worked for me. Vue aggressively mutates attributes of objects under its purview to add reactivity, and as near as I can tell, this prevents the internals of Chart from recognising those objects to retrieve their configurations from its internal mapping when needed. Object.seal prevents this by barring the object from having any new attributes added to it. I'm counting on Chart having added all the attributes it needs at init time - if I notice any weird behaviour from this I'll update this post.
1 year later, Alan's answer helps me too, but my code failed when calling chart.destroy().
So I searched and found what seems to be the "vue way" of handling it: markRaw, here is an example using options API:
import { markRaw } from 'vue'
// ...
export default {
// ...
beforeUnmount () {
if (this.chart) {
this.chart.destroy()
}
},
methods: {
createChart() {
const chart = new Chart(this.$refs["chartEl"], {
// ... your chart data and options
})
this.chart = markRaw(chart)
},
addData() {
// ... your update
this.chart.update()
},
},
}
I am calling some data in via an api for an ionic app I'm making. The data is being called asynchronously and I need to assign the data to different variables for use in a chart that gets presented to the user. I'm struggling to assign the data to a variable that I can then access from the function which creates the chart (I'm using chart.js). Initially I've been trying to grab a list of dates from the data for use as the X axis scale, just to get things working.
Been trying quite a few things and failing. I initially thought it was because my variable was block scoped, but now I think its an async issue. Been reading about promises for hours, but although I understand the concept I can't see away to apply it to my current code (presuming the issue is async! I'm a noob on a self teaching mission here).
So this the code which handles pulling in the data from the api
async getData() {
const loading = await this.loadingController.create({
message: 'Loading'
});
await loading.present();
this.api.getData()
.subscribe(res => {
console.log(res);
this.data1 = res[0];
loading.dismiss();
console.log(this.data1);
const datelabel = this.data1.result[1].date;
}, err => {
console.log(err);
loading.dismiss();
});
}
And this is the code which creates the chart
useAnotherOneWithWebpack() {
var ctx = (<any>document.getElementById('canvas-linechart')).getContext('2d');
console.log('GotData', this.datelabel); //just to see what data I've got here if any in the console
var chart = new Chart(ctx, {
// The type of chart we want to create
type: 'line',
// The data for our dataset
data: {
labels: this.datelabel,
datasets: [{
data: [86,114,106],
label: "Africa",
borderColor: "#3e95cd",
fill: false
}, {
data: [282,350,411],
label: "Asia",
borderColor: "#8e5ea2",
fill: false
}, {
data: [168,170,178],
label: "Europe",
borderColor: "#3cba9f",
fill: false
}
]
},
options: {
title: {
display: true,
text: 'World population per region (in millions)'
}
}
});
}
So I'm calling the datalabel variable against labels, but its displaying as undefined on the axis and in the console. I'm expecting to see three months (which are saved as strings in the variable). Tried all sorts now and its driving me a bit mad. I'm not even sure its an async issue, but from what I've done so far it feels like the issue.
Any help really appreciated!!
Not sure when/where you're calling the useAnotherOneWithWebpack() method but one issue from your code is that you're assigning some values to the local constant datelabel but not to the property from the component:
// The following line just creates a local const available only in that scope
const datelabel = this.data1.result[1].date;
Instead, you should be initializing the component's property:
this.datelabel = this.data1.result[1].date;
Keeping that in mind, please try the following:
async getData() {
const loading = await this.loadingController.create({
message: 'Loading'
});
await loading.present();
this.api.getData().subscribe(
res => {
// This line will be executed when getData finishes with a success response
console.log('Inside of the subscribe - success');
console.log(res);
this.data1 = res[0];
this.datelabel = this.data1.result[1].date;
// Now that the data is ready, you can build the chart
this.useAnotherOneWithWebpack();
loading.dismiss();
},
err => {
// This line will be executed when getData finishes with an error response
console.log('Inside of the subscribe - error');
console.log(err);
loading.dismiss();
});
// This line will be executed without waiting for the getData async method to be finished
console.log('Outside of the subscribe');
}
I am building an app using Vue.js + Chartjs. I am having a problem where I make a http call to a service to get data, parse it, and pass it into my Chartjs component. However, I keep getting the error Cannot read property '_meta' of undefined
Here are the relevant parts of my component:
<template>
<Chartjs :data="chartData" />
</template>
export default {
data () {
return {
chartData: false
}
},
created () {
this.getData()
},
methods: {
getData() {
const opts = {
url: 'some_url',
method: 'get'
}
request.callRoute(opts).then(results => {
this.chartData = results.data
}).catch(err => {
console.log(err)
})
}
},
components: {
Chartjs
}
}
Note - the chart renders fine if I hard code the chartData field with data that comes back from my request. However, it does NOT work if I make a http request first for my data.
Does anyone know what might be happening?
Thanks in advance!
Vue will render the component with the initial chartData (which is a boolean). You should use a v-if or other logic and render Chartjs component when you have the response. For example you can show a loading message/animation while the chartData is false.
We want to show loading icon when the data loads and chart is made in highcharts.
Below is pseudo code:
// service call
// data is pushed in data set
// and that data is used in highcharts.
$('Chart_name').highcharts({
});
Render chart without data, then show loading screen, fetch data, hide loading screen.
Example:
// Options without data
const options = {
series: [{
data: [],
type: 'column'
}]
}
// Redner chart
const chart = Highcharts.chart('container', options)
// Simulate fetch request timeout, get data after some delay
setTimeout(() => {
const data = [1,2,3]
chart.hideLoading()
chart.series[0].setData(data)
}, 2000)
// Show loading screen
chart.showLoading()
Live example:
https://jsfiddle.net/hLj1advd/