Adding data to dynamic chart from ajax - javascript

I am trying to use a dynamic chart with my arduino web page. sensor values are updated to the page using ajax. But I can not update the chart with sensor values. sensor values are in variable "data_val".once I call that variable in chart function it wont work. the problem is the value on variable data_val does not go to the chart's y value. but when i assign a numerical value to variable y it shows that assigned value.
I am not familiar with java-script and ajax. so can anyone help me to solve this.
var data_val = 0;
function GetArduinoInputs() {
nocache = "&nocache=" + Math.random() * 1000000;
var request = new XMLHttpRequest();
request.onreadystatechange = function() {
if (this.readyState == 4) {
if (this.status == 200) {
if (this.responseXML != null) {
document.getElementById("input3").innerHTML =
this.responseXML.getElementsByTagName('analog')[0].childNodes[0].nodeValue;
data_val = this.responseXML.getElementsByTagName('analog')[0].childNodes[0].nodeValue;
document.getElementById("demo").innerHTML = data_val;
}
}
}
}
request.open("GET", "ajax_inputs_one" + nocache, true);
request.send(null);
setTimeout('GetArduinoInputs()', 1000);
}
function gr() {
Highcharts.setOptions({
global: {
useUTC: false
}
});
Highcharts.chart('container', {
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 y = data_val;
var x = (new Date()).getTime(); // current time
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,
});
}
return data;
}())
}]
});
}
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
<script src="https://code.highcharts.com/highcharts.js"></script>
<script src="https://code.highcharts.com/modules/exporting.js"></script>
<body onLoad="gr();GetArduinoInputs()">
<p>Motor Speed: <span id="input3">...</span> Hz</p>
<p id="demo"></p>
<div id="container" style="min-width: 310px; height: 400px; margin: 0 auto"></div>
</body>

You need to fix your AJAX call to actually get the data. I added a failure else-block to randomly assign a value for updating.
I also changed a few variable and class names.
var currentSpeed = 0, // Current speed
dataFetchRate = 1000, // Rate of data request
refreshRate = dataFetchRate; // Rate of adding the current speed to the chart
/**
* Returns a random integer between min (inclusive) and max (inclusive)
* Using Math.round() will give you a non-uniform distribution!
*/
function getRandomInt(min, max) {
if (max === undefined) { max = min; min = 0; }
return Math.floor(Math.random() * (max - min + 1)) + min;
}
function GetArduinoInputs() {
var nocache = "&nocache=" + getRandomInt(1000000);
var request = new XMLHttpRequest();
var requestUrl = 'ajax_inputs_one' + nocache;
request.onreadystatechange = function() {
if (this.readyState == 4) {
if (this.status == 200) {
if (this.responseXML != null) {
var rawData = this.responseXML.getElementsByTagName('analog')[0]
.childNodes[0].nodeValue;
currentSpeed = parseInt(rawData, 10);
}
} else {
currentSpeed = getRandomInt(144); // If error, get a random number from 0 - 144
}
document.getElementById('current-speed').innerHTML = currentSpeed;
}
}
request.open('GET', requestUrl, true);
request.send(null);
setTimeout(GetArduinoInputs, dataFetchRate);
}
function gr() {
Highcharts.setOptions({
global: {
useUTC: false
}
});
Highcharts.chart('container', {
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 y = currentSpeed;
var x = (new Date()).getTime(); // current time
series.addPoint([x, y], true, true);
}, refreshRate);
}
}
},
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,
});
}
return data;
}())
}]
});
}
#container {
min-width: 310px;
height: 400px;
margin: 0 auto;
}
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
<script src="https://code.highcharts.com/highcharts.js"></script>
<script src="https://code.highcharts.com/modules/exporting.js"></script>
<body onLoad="gr();GetArduinoInputs()">
<p>Motor Speed: <span id="current-speed">...</span> Hz</p>
<div id="container"></div>
</body>

Related

Change Highchart graph amplitude through slider

Complete beginner here.
From Spline updating each second, I wanna change amplitude of graph (it means, the range of random generated number) via slider. How to implement it?
I am able to change variables, but variable y that stands for amplitude is inside a function, and none of my solutions worked unfortunately.
Here is the code
<html>
<head>
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
<script src="https://code.highcharts.com/highcharts.js"></script>
<script src="https://code.highcharts.com/modules/exporting.js"></script>
</head>
<body>
<div id="container" style="min-width: 310px; height: 400px; margin: 0 auto"></div>
<script>
$(document).ready(function () {
Highcharts.setOptions({
global: {
useUTC: false
}
});
Highcharts.chart('container', {
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;
}())
}]
});
});
</script>
</body>
How to add slider, that can control value of variable y in load?
Thanks in advance.
Refer to this live demo: http://jsfiddle.net/kkulig/4y120nbo/
I placed the reference to the HTML slider in 'higher' scope than load function. I use rangeForm.value to manipulate the amplitude of generated numbers:
// 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() * rangeForm.value;
series.addPoint([x, y], true, true);
}, 1000);

How to get total of highcharts multiple series

With the Highcharts value-in-legend plugin http://www.highcharts.com/plugin-registry/single/10/Value-In-Legend, I have been able to kind of implement a sort of multiple series total, but I do not understand how to get a total for a clicked y-axis point.
For example when I click, one day I will get the 3 separate series numbers, but I would like to get a total somehow as well, but I only know the y points on load and the visible y-points on redraw. I think the difficulty is getting the total of the 3 series points versus getting the individual point's value.
$(function() {
// Start the standard Highcharts setup
var seriesOptions = [],
yAxisOptions = [],
seriesCounter = 0,
names = ['MSFT', 'AAPL', 'GOOG'],
colors = Highcharts.getOptions().colors;
$.each(names, function(i, name) {
$.getJSON('http://www.highcharts.com/samples/data/jsonp.php?filename=' + name.toLowerCase() + '-c.json&callback=?', function(data) {
seriesOptions[i] = {
name: name,
data: data
};
// As we're loading the data asynchronously, we don't know what order it will arrive. So
// we keep a counter and create the chart when all the data is loaded.
seriesCounter++;
if(seriesCounter == names.length) {
createChart();
}
});
});
// create the chart when all data is loaded
function createChart() {
$('#container').highcharts('StockChart', {
chart: {
events: {
load: function(event) {
console.log('load');
var total = 0;
for(var i = 0, len = this.series[0].yData.length; i < len; i++) {
total += this.series[0].yData[i];
}
totalText_posts = this.renderer.text('Total: ' + total, this.plotLeft, this.plotTop - 35).attr({
zIndex: 5
}).add()
},
redraw: function(chart) {
console.log('redraw');
console.log(totalText_posts);
var total = 0;
for(var i = 0, len = this.series[0].yData.length; i < len; i++) {
if(this.series[0].points[i] && this.series[0].points[i].visible) total += this.series[0].yData[i];
}
totalText_posts.element.innerHTML = 'Total: ' + total;
}
}
},
rangeSelector: {
selected: 4
},
yAxis: {
labels: {
formatter: function() {
return(this.value > 0 ? '+' : '') + this.value + '%';
}
},
plotLines: [{
value: 0,
width: 2,
color: 'silver'
}]
},
legend: {
enabled: true,
floating: true,
align: 'left',
verticalAlign: 'top',
y: 35,
labelFormat: '<span style="color:{color}">{name}</span>: <b>{point.y:.2f} USD</b> ({point.change:.2f}%)<br/>',
borderWidth: 0
},
plotOptions: {
series: {
compare: 'percent',
cursor: 'pointer',
point: {
events: {
click: function () {
alert('Category: ' + this.category + ', value: ' + this.y);
}
}
}
}
},
series: seriesOptions
});
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="http://code.highcharts.com/stock/highstock.src.js"></script>
<script src="http://code.highcharts.com/stock/modules/exporting.js"></script>
<script src="https://rawgithub.com/highslide-software/value-in-legend/master/value-in-legend.js"></script>
<div id="container" style="height: 400px; min-width: 500px"></div>
I was able to find out a way to put the total result as a title in a multi series by reading the source code for the Highcharts value-in-legend plugin https://rawgithub.com/highslide-software/value-in-legend/master/value-in-legend.js.
$(function () {
var seriesOptions_likes = [],
seriesCounter_likes = 0,
names_likes = ['MSFT', 'AAPL', 'GOOG'],
totalText_likes = 0;
/**
* Create the chart when all data is loaded
* #returns {undefined}
*/
function createLikesChart() {
Highcharts.stockChart('container_likes', {
chart: {
},
rangeSelector: {
selected: 4
},
title: {
text: 'Total Results: '
},
yAxis: {
labels: {
formatter: function () {
return (this.value > 0 ? ' + ' : '') + this.value + '%';
}
},
plotLines: [{
value: 0,
width: 2,
color: 'silver'
}]
},
plotOptions: {
series: {
compare: 'percent',
showInNavigator: true
}
},
tooltip: {
pointFormat: '<span style="color:{series.color}">{series.name}</span>: <b>{point.y}</b> ({point.change}%)<br/>',
valueDecimals: 2,
split: true
},
series: seriesOptions_likes,
legend: {
enabled: true,
floating: true,
align: 'left',
verticalAlign: 'top',
y: 65,
borderWidth: 0
},
});
}
$.each(names_likes, function (i, name) {
$.getJSON('https://www.highcharts.com/samples/data/jsonp.php?filename=' + name.toLowerCase() + '-c.json&callback=?', function (data) {
seriesOptions_likes[i] = {
name: name,
data: data
};
// As we're loading the data asynchronously, we don't know what order it will arrive. So
// we keep a counter and create the chart when all the data is loaded.
seriesCounter_likes += 1;
if (seriesCounter_likes === names_likes.length) {
createLikesChart();
}
});
});
});
(function (H) {
H.Series.prototype.point = {}; // The active point
H.Chart.prototype.callbacks.push(function (chart) {
$(chart.container).bind('mousemove', function () {
var legendOptions = chart.legend.options,
hoverPoints = chart.hoverPoints,
total = 0;
if (!hoverPoints && chart.hoverPoint) {
hoverPoints = [chart.hoverPoint];
}
if (hoverPoints) {
var total = 0,
ctr = 0;
H.each(hoverPoints, function (point) {
point.series.point = point;
total += point.y;
});
H.each(chart.legend.allItems, function (item) {
item.legendItem.attr({
text: legendOptions.labelFormat ?
H.format(legendOptions.labelFormat, item) :
legendOptions.labelFormatter.call(item)
});
});
chart.legend.render();
chart.title.update({ text: 'Total Results: ' + total.toFixed(2) });
}
});
});
// Hide the tooltip but allow the crosshair
H.Tooltip.prototype.defaultFormatter = function () { return false; };
}(Highcharts));
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://code.highcharts.com/stock/highstock.js"></script>
<script src="https://code.highcharts.com/stock/modules/exporting.js"></script>
<div id="container_likes" style="height: 400px; min-width: 600px"></div>

add markers for specific values in streaming multi line in highcharts

Here I'm working on Highcharts time series chart with live streaming data, based on the sample jsfiddle. In the fiddle there shows 4 lines named as input1, input2, input3, & input 4 and it is updated with live random data but in my actual project the input values are updated via MQTT. Here I am adding points to chart with series[i].addPoint() method.I want to add some markers or symbols along with line if the value exceed a particular limit.
$(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;
var length = series.length;
setInterval(function() {
var x = (new Date()).getTime(), // current time
a0 = Math.random();
a1 = Math.random();
a2 = Math.random();
series[0].addPoint([x, Math.random()], true, true);
for (var i = 1; i < length; i++) {
series[i].addPoint([x, Math.random()], false, true);
}
}, 1000);
}
}
},
title: {
text: 'Live random data'
},
legend: {
enabled: true
},
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: false
},
series: [{
name: 'input1',
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;
}())
}, {
name: 'input2',
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;
}())
}, {
name: 'input3',
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;
}())
}, {
name: 'input4',
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;
}())
}]
});
});
});
Use setState() method and utilize the tooltip. Then you can style the tooltip or the circle that encloses a point in focus with the API for the tooltip and have the styles or the tooltip symbol/html change according to the value on the chart with conditional statements.
See this answer: Highcharts - manually trigger hover event on a point

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.

Categories