Javascript,Highcharts : Avoiding parallel function calls - javascript

I am developing a dashboard, where there are 5 buttons, and on click of each button, corresponding chart is displayed in the same div.
The structure of my code is as follows :
$(document).ready(function(){
$("button").click(function(){
function requestData() {
$.ajax({
url : ....,
success : function(){
.....
//Real Time Plotting of Data
chart.series[0].addPoint(eval(point), true, shift);
setTimeout(requestData, 2000);
}
});
}
chart = new Highcharts.Chart({
chart: {
renderTo: 'chart',
defaultSeriesType: 'spline'
},
....
....
});
});
});
The Problem : On every click of the button, a parallel requestData() starts, multiple parallel threads run at the same time. This leads in random addPoint and increase in memory consumed.
Also, when checked with Highcharts.Chart in the console, after every click, a undefined objects adds up.
How do I restructure the code for optimum performance ?

Refer the code below, your high chart implement can be like this
$(function () {
$(document).ready(function () {
$('#container').highcharts({
chart: {
type: 'spline',
animation: Highcharts.svg, // don't animate in old IE
marginRight: 10,
events: {
load: function () {
// set up the updating of the chart each second
var series = this.series[0];
setInterval(function () {
var x = (new Date()).getTime(), // current time
y = Math.random();
series.addPoint([x, y], true, true);
}, 1000);
}
}
},
title: {
text: 'Live random data'
},
xAxis: {
type: 'datetime',
tickPixelInterval: 150
},
yAxis: {
title: {
text: 'Value'
},
plotLines: [{
value: 0,
width: 1,
color: '#808080'
}]
},
tooltip: {
formatter: function () {
return '<b>' + this.series.name + '</b><br/>' +
Highcharts.dateFormat('%Y-%m-%d %H:%M:%S', this.x) + '<br/>' +
Highcharts.numberFormat(this.y, 2);
}
},
legend: {
enabled: false
},
exporting: {
enabled: false
},
series: [{
name: 'Random data',
data: (function () {
// generate an array of random data
var data = [],
time = (new Date()).getTime(),
i;
for (i = -19; i <= 0; i += 1) {
data.push({
x: time + i * 1000,
y: Math.random()
});
}
return data;
}())
}]
});
});
});
Basically, you do not need to make your arrangement to live plotting, high chart has this option UPDATE
Refer live fiddle
http://jsfiddle.net/anilk/3u0ng35s/
Replace below data option to your ajax call
data: (function () {
// generate an array of random data
var data = [],
time = (new Date()).getTime(),
i;
for (i = -19; i <= 0; i += 1) {
data.push({
x: time + i * 1000,
y: Math.random()
});
}
return data;
}

Related

Render chart only once with multiple events : Highcharts

So what I have is a chart in which I have events function which loads data for multiple sets.
suppose I have data of 3000 points. The first data set renders the first 1000 points and after that second data set renders 2000 points.
for which I am calling my 'events' function .
but the problem arises that after showing the first 1000 set of data. The chart starts from the begining.
I don't want that.
That's why I need a solution so that my Highchart's chart render only once and the event function loads continuously.
Here's a snip of my Highchart's js
Highcharts.chart("chartcontainer", { // make thsi chart load only once.
chart: {
type: 'line',
animation: Highcharts.svg, // don't animate in old IE
marginRight: 10,
//Load this event function as the data updates
events: {
load: function() {
var series = this.series[0],
chart = this;
setInterval(function() {
//some logic regarding the chart
//..
v = {
y: y,
x: x
};
console.log("V value", v);
series.addSeries(v, false, true);
counter++;
localcounter++;
} else
{
oldcounter=counter;
flagToreload=1;
}
}, 1000/130);
setInterval(function() {
chart.redraw(false);
}, 100);
}
}
},
time: {
useUTC: false
},
title: {
text: 'Live random data'
},
xAxis: {
type: 'Value',
gridLineWidth: 1
},
yAxis: {
title: {
text: 'Value'
},
plotLines: [{
value: 0,
width: 1,
color: '#808080'
}],
gridLineWidth: 1
},
tooltip: {
headerFormat: '<b>{series.name}</b><br/>',
pointFormat: '{point.x:%Y-%m-%d %H:%M:%S}<br/>{point.y:.2f}'
},
exporting: {
enabled: false
},
series: [{
animation: false,
name: 'Random data',
data: (function() {
// generate an array of random data
var data = [],
time = counter,
i;
for (i = -1000; i <= 0; i += 1) {
data.push([
counter,
null
]);
}
return data;
}())
}]
});
You can use:
addPoint method:
chart: {
events: {
load: function() {
var newData,
chart = this,
series = chart.series[0];
setInterval(function() {
newData = getRandomData();
newData.forEach(function(el) {
series.addPoint(el, false);
});
chart.redraw();
}, 2000);
}
}
}
Live demo: http://jsfiddle.net/BlackLabel/2a8qswhf/
API Reference: https://api.highcharts.com/class-reference/Highcharts.Series#addPoint
setData method:
chart: {
events: {
load: function() {
var newData,
chart = this,
combinedData,
series = chart.series[0];
setInterval(function() {
newData = getRandomData();
combinedData = series.userOptions.data.concat(newData);
series.setData(combinedData);
}, 2000);
}
}
}
Live demo: http://jsfiddle.net/BlackLabel/Lmsk8yw9/
API Reference: https://api.highcharts.com/class-reference/Highcharts.Series#setData

Highchart performance slow on plotting live data

I am plotting live data in Highchart's(4.2.4) Line type chart for each second data i.e. 60 points for 1 min. and requirement is to collect each second data for long duration. I am using below code to add point in series. The number of series I have is 20. And for each series I have to add point per second. The turboThreshold set for each series is also around 2000. And slicing should be done after 1000 points data.
chart.series[0].addPoint(point, false, data > 1000?shift: false, false);
I see a very low performance my browser keeps hanging and also chart is very irresponsive after some time. What can I do for better performance? I have tried below stuff:
1) Off the animation for series :
plotOptions: {
series: {
animation:false,
states: {
hover: {
lineWidthPlus: 0
}
}
}
},
2) Turn off animation and redrawing on addpoint to the chart
3) Turn off markers for series
4) Included boost.js module in application
script src="https://code.highcharts.com/modules/boost.js"
Without your actual code I can only speculate what you're doing, but my assumption is you're trying to redraw the chart every time you add a point, that would be 20 redraws per second, which is pretty excessive and will probably take more than 1 second to complete the redraws which means there will be new points added while old ones are still being drawn. Set the redraw to false on adding points and manually redraw every second or at random.
Example code:
$(function() {
var series = function(i) {
return {
name: 'Random data '+i,
data: (function() {
// generate an array of random data
var data = [],
time = (new Date()).getTime(),
i;
for (i = -19; i <= 0; i += 1) {
data.push({
x: time + i * 1000,
y: Math.random()
});
}
return data;
}())
};
};
$(document).ready(function() {
Highcharts.setOptions({
global: {
useUTC: false
}
});
$('#container').highcharts({
chart: {
type: 'line',
animation: Highcharts.svg, // don't animate in old IE
marginRight: 10,
events: {
load: function() {
var chart = this;
// set up the updating of the chart each second
setInterval(function() {
for (var i = 0; i < 20; i++) {
var series = chart.series[i];
var x = (new Date()).getTime(), // current time
y = Math.random();
series.addPoint([x, y], false, false,false);
}
chart.redraw();
}, 1000);
}
}
},
title: {
text: 'Live random data'
},
xAxis: {
type: 'datetime',
tickPixelInterval: 150
},
yAxis: {
title: {
text: 'Value'
},
plotLines: [{
value: 0,
width: 1,
color: '#808080'
}]
},
tooltip: {
formatter: function() {
return '<b>' + this.series.name + '</b><br/>' +
Highcharts.dateFormat('%Y-%m-%d %H:%M:%S', this.x) + '<br/>' +
Highcharts.numberFormat(this.y, 2);
}
},
exporting: {
enabled: true
},
plotOptions: {
series: {
marker: {
enabled: true
}
}
},
series: [series(1), series(2),series(3), series(4),series(5), series(6),series(7), series(8),series(9), series(10),series(11), series(12),series(13), series(14),series(15), series(16),series(17), series(18),series(19), series(20)]
});
});
});
Fiddle at http://jsfiddle.net/62k8sryc/1/
NOTE
Because this is JavaScript it heavily depends on browser build/version and machine specs.

How to use Highcharts to implement this dynamically shifting from right to left effect?

I'm using Highcharts to draw a graph with dynamic data.
I found this official demo.http://jsfiddle.net/vn9bk80j/
$(function () {
$(document).ready(function () {
Highcharts.setOptions({
global: {
useUTC: false
}
});
$('#container').highcharts({
chart: {
type: 'spline',
animation: Highcharts.svg, // don't animate in old IE
marginRight: 10,
events: {
load: function () {
// set up the updating of the chart each second
var series = this.series[0];
setInterval(function () {
var x = (new Date()).getTime(), // current time
y = Math.random();
series.addPoint([x, y], true, false);
}, 1000);
}
}
},
title: {
text: 'Live random data'
},
xAxis: {
type: 'datetime',
tickPixelInterval: 150
},
yAxis: {
title: {
text: 'Value'
},
plotLines: [{
value: 0,
width: 1,
color: '#808080'
}]
},
tooltip: {
formatter: function () {
return '<b>' + this.series.name + '</b><br/>' +
Highcharts.dateFormat('%Y-%m-%d %H:%M:%S', this.x) + '<br/>' +
Highcharts.numberFormat(this.y, 2);
}
},
legend: {
enabled: false
},
exporting: {
enabled: false
},
series: [{
name: 'Random data',
data: []
}]
});
});
});
<script src="https://code.highcharts.com/highcharts.js"></script>
<script src="https://code.highcharts.com/modules/exporting.js"></script>
<div id="container" style="min-width: 310px; height: 400px; margin: 0 auto"></div>
The graph window size is varing, it looks like
Howerver, I need graph window size to be fixed, data in this graph shifts from right to left as a whole from the beginning. Just like in the following pic.
How can I get the effects in picture 2 with Highcharts?
You can use null points to create empty space, and then just add pints with shift=true, see: http://jsfiddle.net/vn9bk80j/1/
function getEmptyData() {
var interval = 1000, // 1 second,
numberOfPoints = 50,
now = (new Date()).getTime(),
min = now - interval * numberOfPoints,
points = [];
while (min <= now) {
points.push([min, null]); // set null points
min += interval;
}
return points;
}
And method use case:
series: [{
name: 'Random data',
data: getEmptyData()
}]
shift=true example:
series.addPoint([x, y], true, true);

Highcharts not Drawing point on setInterval

I have data being put on an api every 30 seconds on a backend. On the frontend I am using highcharts to visualize the data and a setInterval setup to retrieve the new data every 30 seconds. My problem is that on that setInterval, the line graph disappears or does not draw to the next new dot. Does anyone now why this is?
fiddle: http://jsfiddle.net/b8tf281n/3/
code:
chart1 = {
yAxisMin: 40,
yAxisMax: 100
};
// empty objects for our data and to create chart
seriesData = [];
BPM = [];
time1 = [];
// console.log(chart1.data.series);
$(function () {
$(document).ready(function () {
Highcharts.setOptions({
global: {
useUTC: false
}
});
var url = 'http://msbandhealth.azurewebsites.net/odata/PulsesAPI/';
$.ajax({
url: url,
dataType: 'json',
context: seriesData,
success: function (data) {
// structure our data
for (var i = 0; i < data.value.length; i++) {
bpm = data.value[i].BPM;
time = data.value[i].Time;
BPM.push({
x: moment(time),
y: bpm
});
// console.log(BPM);
time1.push(time);
}
console.log((new Date).getTime());
console.log(moment(time, "DD.MM.YYYY hh:mm:ss"));
console.log(BPM);
console.log(BPM[BPM.length - 1]);
// console.log(seriesData);
// set our data series and create new chart
chart1.data.series[0].data = BPM;
chart = new Highcharts.Chart(chart1.data);
$('#container').css({
height: '400px'
});
// console.log(sortedBPM);
// console.log(time1);
}
});
// give highcharts something to render to
var container = document.getElementById("container");
chart1.data = {
chart: {
renderTo: container,
type: 'spline',
animation: Highcharts.svg, // don't animate in old IE
marginRight: 10,
events: {
load: function () {
setInterval(function () {
// find last data points
var test = BPM[BPM.length - 1];
var x = (new Date).getTime(),
y = test.y;
console.log(x);
shift = chart.series[0].data.length < 30;
chart.series[0].addPoint([x, y], true, true);
},
30000);
}
}
},
title: {
text: 'Microsoft Band: Real Time Pulse Analysis'
},
xAxis: {
type: 'datetime',
tickPixelInterval: 150,
dateTimeLabelFormats: {
},
},
yAxis: {
min: chart1.yAxisMin,
max: chart1.yAxisMax,
title: {
text: 'Heart Rate'
},
plotLines: [{
value: 0,
width: 1,
color: '#808080'
}]
},
tooltip: {
formatter: function () {
return '<b>' + this.series.name + '</b><br/>' + Highcharts.dateFormat('%H:%M:%S', this.x) + '<br/>' + Highcharts.numberFormat(this.y, 2);
}
},
legend: {
enabled: false
},
exporting: {
enabled: false
},
series: [{
name: 'Beats Per Minute',
data: []
}]
};
});
});
Your test.y is the problem. It returns undefined after one interval. Somehow BPM is changing in it's structure - changing each object from {x,y} to [0,1] - therefore I used:
y = (test.y !== undefined)? test.y : test[1];
to either get the previous structure or the new. I also set the interval to 3 seconds for you to see the difference easier. Here's the DEMO.

Adding series dynamically in highcharts

(function($){
$(function () {
$(document).ready(function() {
Highcharts.setOptions({
global: {
useUTC: false
}
});
var i=0;
var chart = new Highcharts.Chart({
chart: {
type: 'spline',
renderTo: 'container',
animation: Highcharts.svg, // don't animate in old IE
marginRight: 10,
events: {
load: function() {
// set up the updating of the chart each second
var series = this.series[0];
setInterval(function() {
var Name = new Array();
Name[0] = "Random data";
Name[1] = "Volvo";
var length=chart.series.length;
var flag=0;
var index=0;
var x = (new Date()).getTime(), // current time
y = Math.random();
for (var k=0;k<Name.length;k++) {
for(var j=0;j<chart.series.length;j++) {
if(chart.series[j].name==Name[k]) {
flag=1;
index=j;
x = (new Date()).getTime();
y = Math.random();
break;
}
}
if(flag==1) {
chart.series[index].addPoint([x, y], true, true);
flag=0;
} else {
chart.addSeries({name: '' + Name[k] + '', data: [] });
chart.series[length].addPoint([x, y+1], true);
length=length+1;
}
}
}, 1000);
}
}
},
title: {
text: 'Live random data'
},
xAxis: {
type: 'datetime',
tickPixelInterval: 150
},
yAxis: {
title: {
text: 'Value'
},
plotLines: [{
value: 0,
width: 1,
color: '#808080'
}]
},
tooltip: {
formatter: function() {
return '<b>'+ this.series.name +'</b><br/>'+
Highcharts.dateFormat('%Y-%m-%d %H:%M:%S', this.x) +'<br/>'+
Highcharts.numberFormat(this.y, 2);
}
},
legend: {
enabled: false
},
exporting: {
enabled: false
},
series: [{
name: 'Random data',
data: (function() {
// generate an array of random data
var data = [],
time = (new Date()).getTime(),
i;
for (i = -19; i <= 0; i++) {
data.push({
x: time + i * 1000,
y: Math.random()
});
}
return data;
})()
}]
});
});
});
})(jQuery);
I am able to add series and add point in charts but the series that I add after initialization, which is "volvo", is not drawing lines between its points. What might be the problem?
And is there any other way of comparing arrays and adding points without a for-loop? Because I can get millions of series at times and I don't want to be looping over arrays to check if it exists or not. So is there any efficient way of finding wheteher a list already exists, and if it does what is its index?
here is its fiddle: www.jsfiddle.net/2jYLz/
It is related with fact that you have enabled shifting in addPoint() when you add new serie. In other words, shifting remove first point and add new in the end of serie. So when you have one point it caused your scenario. So you need to disable shipfing, and when lenght of series.data achieve i.e 10 points, shifting should be enabled.

Categories