I'm trying to display three Google Chart Gauges on a page to represent data from three temperature sensors. I have a JS function GetCurrentTemperature that returns the three temperature values in an array. I want the gauges to update at regular intervals. I've had this working fine with a single gauge, but when I try and use setInterval for the three charts, they're not updating. The code I'm using is listed below.
function drawTemperatureGauges() {
var currentTemp = GetCurrentTemperature();
var gaugeCount = currentTemp.length;
var options = {
width: 200,
height: 200,
redFrom: 65,
redTo: 80,
yellowFrom: 50,
yellowTo: 65,
minorTicks: 5,
max: 80
};
for(var i=0; i<gaugeCount; i++) {
var data = google.visualization.arrayToDataTable([
['Label', 'Value'],
['Temp', currentTemp[i] ]
]);
var divName = 'gauge'.concat(i+1).concat('_div');
var chart = new google.visualization.Gauge(document.getElementById(divName));
chart.draw(data, options);
setInterval(function() {
var cTemp = GetCurrentTemperature();
data.setValue(0, 1, cTemp[i]);
chart.draw(data, options);
}, 2000);
}
}
I assume it's because I'm using i inside the anonymous setInterval function. I've looked at posts related to closures and also ones that specify the use of let rather than var but I still can't work out what syntax I need.
Any pointers greatly appreciated
Bbz
did you try locking in a closure like this?
for(var i=0; i<gaugeCount; i++) {
drawGauge(i);
}
function drawGauge(i) {
var data = google.visualization.arrayToDataTable([
['Label', 'Value'],
['Temp', currentTemp[i] ]
]);
var divName = 'gauge'.concat(i+1).concat('_div');
var chart = new google.visualization.Gauge(document.getElementById(divName));
chart.draw(data, options);
setInterval(function() {
var cTemp = GetCurrentTemperature();
data.setValue(0, 1, cTemp[i]);
chart.draw(data, options);
}, 2000);
}
Related
I have flask app with
#app.route('/dash_data')
def dash_data():
***
return jsonify({'key' : dashDetails})
which return nice json string
{"key":[["Food",50],["Health",10],["Restaurants",2],["Sports",20],["Taxi",5]]}
My google chart script expects
[
['Food', 50],
['Health', 10],
['Restaurants', 2],
['Sports', 20],
['Taxi', 5]
]
and it has the following way to pass this data to the chart:
var testData = $.get('/dash_data');
var tm = test_data.done(function (resp){ return resp;})
var dataArray = tm.responseJSON.key
var data = google.visualization.arrayToDataTable(dataArray);
However, the console output is
Uncaught (in promise) TypeError: Cannot read property 'key' of undefined at drawChart
Where is my mistake?
The full google-chart js file:
google.charts.load("current", {packages:["corechart"]});
google.charts.setOnLoadCallback(drawChart);
function drawChart() {
var test_data = $.get('/dash_data');
var tm = test_data.done(function (resp){return resp;})
var t = tm.responseJSON.key
var data = google.visualization.arrayToDataTable(t);
var options = {
title: 'Expences 12.2020',
pieHole: 0.4,
width: 380,
height: 200
};
var chart = new google.visualization.PieChart(document.getElementById('exp_month_chart'));
chart.draw(data, options);
}
Thank you.
$.get runs asynchronously,
so you need to wait for the done callback before trying to draw the chart...
google.charts.load("current", {
packages: ["corechart"]
}).then(function () {
$.get('/dash_data').done(function (resp) {
var data = google.visualization.arrayToDataTable(resp.key);
var options = {
title: 'Expences 12.2020',
pieHole: 0.4,
width: 380,
height: 200
};
var chart = new google.visualization.PieChart(document.getElementById('exp_month_chart'));
chart.draw(data, options);
});
});
in the post above,
var t = tm.responseJSON.key
runs before
var tm = test_data.done(function (resp){return resp;})
is finished...
I am using the Google Visualization API. A chart is generated based on values from an ajax call function drawchart().
The user then inputs values in textboxes and this point is added on the chart also (function addUserPoint()). function addUserPoint2() is autogenerated and is also added onto the map. The result of adduserpoint and adduserpoint2 have a line between them.
My issue: If the user adds a new point again, the chart adds those values and the previously added points stay on the chart. I want to get rid of the results of adduserpoint and adduserpoint2 before adding a new point. How can I achieve this?
var chartData;
var options2;
function addUserPoint() {
if (chartData.getNumberOfColumns() === 2) {
chartData.addColumn('number', '');
}
var aa= $("#wbtotala").text();
var bb= $("#wbtotalb").text();
chartData.addRow([
parseFloat(bb),
null,
parseFloat(aa)
]);
myLineChart.draw(chartData, options2);
}
function addUserPoint2(){
if (chartData.getNumberOfColumns() === 2) {
chartData.addColumn('number', '');
}
myLineChart.draw(0,0, options2);
var aa2 = fweight;
var bb2= fcg;
chartData.addRow([
parseFloat(bb2),
null,
parseFloat(aa2)
]);
myLineChart.draw(chartData, options2);
}
function drawchart() {
document.getElementById('addPoint').addEventListener('click', addUserPoint, false);
document.getElementById('addPoint').addEventListener('click', addUserPoint2, false);
chartData = new google.visualization.DataTable();
chartData.addColumn('number', 'Sli');
chartData.addColumn('number', 'Weight');
for (var i = 0; i < chartdatax.length; i++) {
chartData.addRow([parseFloat(chartdatax[i]), parseFloat(chartdatay[i])]);
};
options2 = {
height: 500,
hAxis: {
title: 'AB',
gridlines: {
count: 20
}
},
vAxis: {
title: 'CD',
gridlines: {
count: 15
}
},
chartArea: {top:40, width: "70%", height: "75%"},
legend: { position: 'none' },
pointSize: 5
};
myLineChart = new google.visualization.LineChart(document.getElementById('myChart2'));
myLineChart.draw(chartData, options2);
}
Use the Below Command.Here data is the DataTable Variable.
var data = new google.visualization.DataTable();
Set chartData to an empty object in addUserPoint();
function addUserPoint() {
charData = {};
if (chartData.getNumberOfColumns() === 2) {
...
}
}
This makes sure that anytime you add a new Data, it clears the previous data and you have a fresh new dataset ;)
I'm having trouble scaling my chart correctly. My chart represents data for every hour of the day in a 24 hour format, meaning that I need the numbers 0-24 on my linechart.
I've tried adding the logScale, minValue and maxValue properties to the hAxis, but nothing is working.
As you can see on the chart, the hour axis is not spanning a fixed axis from 0-24 hours, but instead from 9-15 hours.
I also only have 3 rows in my data set, which reside on the hours 9, 14 and 15. Despite this, the lines are spanning from 9-14 as if they have values; however there is no data there, so the lines should be running along the bottom at 0 between these two points.
How can I put a fixed horizontal scale on my chart, and have individual values on my lines for each hour?
Here's my code:
google.load('visualization', '1.1', {packages: ['line']});
google.setOnLoadCallback(drawChart);
function drawChart()
{
var json = $.getJSON('my JSON data link', function(data)
{
var chartStructure = new google.visualization.DataTable();
var chartData = [];
chartStructure.addColumn('number', 'Hour');
chartStructure.addColumn('number', 'Pageviews');
chartStructure.addColumn('number', 'Unique Pageviews');
chartStructure.addColumn('number', 'Sales');
chartStructure.addColumn('number', 'Earnings in $AUD');
for (i = 0; i < data.length; i++)
{
chartData[i] = [];
chartData[i][0] = parseInt(data[i].hour);
chartData[i][1] = parseFloat(data[i].profit);
chartData[i][2] = parseFloat(data[i].profit);
chartData[i][3] = parseFloat(data[i].sales);
chartData[i][4] = parseFloat(data[i].profit);
// These chartData values are not correct because I am testing
chartStructure.addRows(chartData);
}
var options = {
hAxis: {
'minValue': 0,
'maxValue': 24
}
};
var chart = new google.charts.Line(document.getElementById('todays-total-sales'));
chart.draw(chartStructure, options);
});
}
$(window).resize(function()
{
drawChart();
});
Use viewWindow.
hAxis: {
title: 'Time',
viewWindow:{
max:1000,
min:-100
}
},
JSFiddle
UPDATE
If you are using MaterialCharts please note that the options have different syntax!
In order for you to be able to use the classic options, you need to change
chart.draw(data, options);
to
chart.draw(data, google.charts.Line.convertOptions(options));
HERE is your updated fiddle.
var options = {
title: "Posted Memes",
width: 450,
height: 300,
is3D:true,
bar: { groupWidth: "95%" },
legend: { position: "none" },
vAxis: {
title: 'No of Memes',
viewWindowMode: 'explicit',
viewWindow: {
max: 180,
min: 0,
interval: 1,
},
}
};
I'm trying to show several Google Gauge charts in separate divs on the same screen. I also need to handle the click event on those divs (consequently the charts). I tried to do that dynamically but I had some issues. But anyway, even when I tried do this statically (which worked), I still couldn't get the chart area to be clickable. What happened is that the whole div is clickable except for the chart area.
Anyway, here's my (messy - test) code:
<div id="gaugePlaceHolder" class="gaugeWrapper"></div>
<div id="gaugePlaceHolder2" class="gaugeWrapper"></div>
document.getElementsByClassName = function (cl) {
var retnode = [];
var myclass = new RegExp('\\b' + cl + '\\b');
var elem = this.getElementsByTagName('*');
for (var i = 0; i < elem.length; i++) {
var classes = elem[i].className;
if (myclass.test(classes)) retnode.push(elem[i]);
}
return retnode;
};
google.load('visualization', '1', {packages:['gauge']});
google.setOnLoadCallback(function () {
drawChart1();
drawChart2();
});
function drawChart1() {
var data = google.visualization.arrayToDataTable([
['Label', 'Value'],
['Memory', 80]
]);
var options = {
width: 400, height: 120,
redFrom: 90, redTo: 100,
yellowFrom:75, yellowTo: 90,
minorTicks: 5
};
var chart = new google.visualization.Gauge(document.getElementById('gaugePlaceHolder'));
chart.draw(data, options);
}
function drawChart2() {
var data = google.visualization.arrayToDataTable([
['Label', 'Value'],
['Another', 30]
]);
var options = {
width: 400, height: 120,
redFrom: 90, redTo: 100,
yellowFrom: 75, yellowTo: 90,
minorTicks: 5
};
var chart = new google.visualization.Gauge(document.getElementById('gaugePlaceHolder2'));
chart.draw(data, options);
}
window.onload = function () {
var elements = $('.gaugeWrapper');
console.log(elements);
elements.click(function () {
alert("clicked");
});
}
Any explanations/suggestions?
The right way to add a listener to a Gauge is using google.visualization.events.addListener method, as shown in this example.
You could also try your code on Google Playground.
This is a followup to a question I've already asked on StackOverflow. So please make sure you read that one to get the whole picture:
Multiple Instances of Google Visualizations Chart Inside Separate Divs
So in an attempt to make this whole thing dynamic, I wrote the following code:
var containers = document.getElementsByClassName('gaugeWrapper');
console.log(containers);
google.load('visualization', '1', { packages: ['gauge'] });
for(var i = 0; i < containers.length; i++) {
var id = containers[i].getAttribute('id');
var name = containers[i].getAttribute('data-name');
var value = containers[i].getAttribute('data-value');
google.setOnLoadCallback(function () { drawChart(id, name, value) });
}
function drawChart(id, name, value) {
console.log(id);
console.log(name);
console.log(value);
var data = google.visualization.arrayToDataTable([
['Label', 'Value'],
[name, value]
]);
var options = {
width: 400, height: 120,
redFrom: 90, redTo: 100,
yellowFrom: 75, yellowTo: 90,
minorTicks: 5
};
var chart = new google.visualization.Gauge(document.getElementById(id));
chart.draw(data, options);
}
This does not work. The problem is that the console outputs the data of the last div only. Which means that the function is being called 5 (containers.length) times with the same set of parameters.
UPDATE:
As per Ateszki's answer, here's my updated code:
google.load('visualization', '1', { packages: ['gauge'] });
google.setOnLoadCallback(drawChart);
function drawChart() {
var containers = document.getElementsByClassName('gaugeWrapper');
for (var i = 0; i < containers.length; i++) {
var id = containers[i].getAttribute('id');
var name = containers[i].getAttribute('data-name');
var value = containers[i].getAttribute('data-value');
var data = google.visualization.arrayToDataTable([
['Label', 'Value'],
[name, value]
]);
var options = {
width: 400, height: 120,
redFrom: 90, redTo: 100,
yellowFrom: 75, yellowTo: 90,
minorTicks: 5
};
var cont = document.getElementById(id);
console.log(cont);
var chart = new google.visualization.Gauge(cont);
chart.draw(data, options);
}
}
Unfortunately, I still couldn't get it to work, yet. Now nothing renders on the screen, although my console.log's seem to output the right things...
Any explanations/suggestions?
The function that you are binding onload is overwriting the previous one.
Maybe you can store the values in another object and load them all at once in one function.
Ok the following has solved the problem:
google.load('visualization', '1', { packages: ['gauge'] });
google.setOnLoadCallback(drawChart);
function drawChart() {
var containers = $('.gaugeWrapper');
containers.each(function (index, elem) {
var id = $(elem).attr('id');
var name = $(elem).data('name');
var value = $(elem).data('value');
var data = google.visualization.arrayToDataTable([
['Label', 'Value'],
[name, value]
]);
var options = {
width: 400, height: 120,
redFrom: 90, redTo: 100,
yellowFrom: 75, yellowTo: 90,
minorTicks: 5
};
var cont = document.getElementById(id);
var chart = new google.visualization.Gauge(cont);
chart.draw(data, options);
});
I do not know how it differs from the code in the updated section of the question except for the fact that I am now using jQuery to grab the values I'm looking for...