I'm trying to create multiple Google Charts recursively with the code below. I'm using AJAX to get the chart data and to store in the array histogramData.
With this code I can create the multiple i_histogram charts, but apparently, on each loop interaction, the previous chart is overwritten by the last one.
HTML code:
<div id="histogramCharts"></div>
Javascript code:
var histogramChartElement = document.getElementById('histogramCharts');
// remove histogram chart element children
while (histogramChartElement.hasChildNodes()) {
histogramChartElement.removeChild(histogramChartElement.childNodes[0]);
}
for (var i = 0; i < histogramLabels.length; i++) {
var label = histogramLabels[i];
var node = document.createElement('div');
node.setAttribute('id', i + '_histogram');
histogramChartElement.appendChild(node);
var dataTable = new google.visualization.DataTable();
dataTable.addColumn('string', 'A');
dataTable.addColumn('number', 'B');
dataTable.addRows(histogramData[i]);
google.charts.setOnLoadCallback(function () {
var options = {
title: histogramLabels[i],
legend: {position: 'none'},
histogram: {bucketSize: 0.1}
};
var histogramChart = new google.visualization.Histogram(node);
histogramChart.draw(dataTable, options);
});
}
I got this result:
<div id="histogramCharts">
<div id="0_histogram"></div>
<div id="1_histogram"></div>
<div id="2_histogram">
<div style="position: relative;">....</div>
</div>
</div>
first, setOnLoadCallback should only be called once per page load,
once it fires, you can draw as many charts as needed...
you can also depend on the callback to know when the page is ready,
instead of --> $(document).ready -- or something similar...
as such, recommend loading google first, before anything else,
then use ajax to get the data, then draw the charts...
try similar setup as follows, placing the callback in the load statement...
google.charts.load('current', {
callback: getData,
packages:['corechart']
});
function getData() {
$.ajax({
url: '...',
}).done(drawCharts);
}
function drawCharts(data) {
// use data to build histogramData
var histogramChartElement = document.getElementById('histogramCharts');
// remove histogram chart element children
while (histogramChartElement.hasChildNodes()) {
histogramChartElement.removeChild(histogramChartElement.childNodes[0]);
}
for (var i = 0; i < histogramLabels.length; i++) {
var label = histogramLabels[i];
var node = document.createElement('div');
node.setAttribute('id', i + '_histogram');
histogramChartElement.appendChild(node);
var dataTable = new google.visualization.DataTable();
dataTable.addColumn('string', 'A');
dataTable.addColumn('number', 'B');
dataTable.addRows(histogramData[i]);
var options = {
title: histogramLabels[i],
legend: {position: 'none'},
histogram: {bucketSize: 0.1}
};
var histogramChart = new google.visualization.Histogram(node);
histogramChart.draw(dataTable, options);
}
}
Related
I am trying to abstract some of my JavaScript code by adding functions as objects of properties. The ultimate goal is a dynamic way to render data using Google charts. Below is my charts object which right now works when I call it on the page. This is assuming a separate config and util object which have some other methods:
app.charts = {
init: function(){
// Load the Visualization API and the piechart package, wait until loaded
google.load('visualization', '1.0', {'packages':['corechart']});
google.setOnLoadCallback(this.createChart);
},
createChart: function(){
// draw charts to their id
chartData = app.utils.getAjax(s.urls.dashUrl, function(data){
// Convert to a table
var jsonDataTable = new google.visualization.DataTable(data);
// Select html element and draw the chart
var chartJson = new google.visualization.BarChart(document.getElementById('json'));
chartJson.draw(jsonDataTable);
this.dataTable();
});
},
dataTable: function(){
console.log("whatever");
}
};
What i would like to do is abstract the var chartJson = new google.visualization.BarChart(document.getElementById('json')); line so that I can give an option and switch to different charts instead of hard coding every chart I want (and thus make it so I can let the user choose chart type.
Whenever I try and write another method, I get a google.visualization is undefined error. I don't see why though because I don't call anything until after the google load callback in init.
To start simple I tried to take have the dataTable: function return a new new google.visualization.DataTable(data); and I received ReferenceError: dataTable is not defined.
I am not sure what is going on that these values can't be found or used, any help appreciated.
I've just just writing some code thinking you meant one thing but I'm not sure it is now reading follow up comments... I'm posting it anyway just FYI:
app.charts = {
init: function(){
// Load the Visualization API and the piechart package, wait until loaded
google.load('visualization', '1.0', {'packages':['corechart']});
google.setOnLoadCallback(this.createChart);
},
createChart: function(){
// draw charts to their id
chartData = app.utils.getAjax(s.urls.dashUrl, function(data){
// Convert to a table
var jsonDataTable = new google.visualization.DataTable(data);
// Select html element and draw the chart
var input = document.getElementById('user-input').value;
this.chartType(input);
this.dataTable();
});
},
dataTable: function(){
console.log("whatever");
},
chartType: function(input){
switch(input)
{
case 'whatever':
var chartJson = new google.visualization.BarChart(document.getElementById('json'));
chartJson.draw(jsonDataTable);
break;
case 'whatever2':
// etc
break;
}
}
};
HTML
<select id="user-input">
<option value="whatever">whataver</option>
<option value="whatever2">whataver2</option>
</select>
I am trying to draw Doughnut Chart using chartjs
I am getting proper json response from my localhost
my code is :
$(document).on('click', '#plotGraph', function(event) {
event.preventDefault();
alert("hello");
$.getJSON("PlotExpenseGraph", function(data1) {
alert("hiiiii");
console.log(data1);
console.log(data1.expenseList[0].param);
var pieData;
$.each(data1.expenseList, function(position, expenseList) {
console.log(expenseList.param);
console.log(expenseList.totalCount);
console.log(expenseList.totalValue);
pieData = {
value: expenseList.totalValue,
color: "#F7464A",
highlight: "#FF5A5E",
label: expenseList.param
}
});
var ctx = $("#myChart").get(0).getContext("2d");
var myNewChart = new Chart(ctx);
new Chart(ctx).Doughnut(pieData);
});
});
<script src="//cdnjs.cloudflare.com/ajax/libs/Chart.js/1.0.1/Chart.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
Plot graph
<canvas id="myChart" width="500" height="300"></canvas>
My console data is
param: "Advertising"
totalCount: 2
totalValue: 754
Advertising
Advertising
2
754
My code is not plotting any figure and also it is not giving any error on console.
What scanges should I make to work above code properly.
ChartJS expects an array of objects as parameter to the Doughnut() method. You on the other hand just create the objects and thereby overwrite the last object.
Instead you should declare pieData to be an array and add entries inside the each() callback like this:
$(document).on('click', '#plotGraph', function (event) {
event.preventDefault();
$.getJSON("PlotExpenseGraph", function (data1) {
// prepare parameter to ChartJS
var pieData = [];
$.each(data1.expenseList, function (position, expenseList) {
// add respective entry
pieData.push({
value : expenseList.totalValue,
color : "#F7464A",
highlight : "#FF5A5E",
label : expenseList.param
});
});
// paint
var ctx = $("#myChart").get(0).getContext("2d");
var myNewChart = new Chart(ctx);
new Chart(ctx).Doughnut(pieData);
});
});
I'm trying to get multiple chats on the same page, each one using a different spreadsheet url for its data source.
The code below works ok, but I really want to have multiple urls for different data ranges and show a different chart each time.
When I tried this originally, it only ever showed the last chart I tried to draw.
I’ve reworked the script (which still works) to move closer to a situation where I’ve got multiple sets of data for the multiple charts and their locations. It’s not quite there though. This was based on the following post:
How to add two Google charts on the one page?
I think I need to pass the multiple sets of data as attributes of the handleQueryResponse function but I don’t know how to do that.
I was trying to get it to work for just one set of data first, and if that works ok, add multiple sets of data into it.
<script type="text/javascript" src="https://www.google.com/jsapi"></script>
<script type="text/javascript">
(function() { // Begin scoping function
// vars Global to my code, invisible outside the scoping function
// Set chart options
// I'll be using multiple options for different charts, options1, options2 etc.
var options1 = {'title':'Light & Temperature data - Last 24 Hours',
'width':750,
'height':400,
'curveType': 'function',
'backgroundColor':'ffe599',
"hAxes":[{"title":"Time"}],
"vAxes":[{"title":"Temp in °C -- Light Levels"}]};
//I think I will need containerID1, containerID2 etc. one for each chart
var containerID = 'chart_div1';
//same for chartType1, chartType2
var chartType = 'LINECHART';
// Load the Visualization API and the core chart package.
google.load('visualization', '1.0', {'packages':['corechart']});
// Set a callback to run when the Google Visualization API is loaded.
google.setOnLoadCallback(drawChart);
// Callback that creates and populates a data table,
// instantiates the chart, passes in the data and
// draws it.
function drawChart() {
//I'm going to have multiple urls and each one will be the source for a seperate chart
var query1 = new google.visualization.Query(
'https://docs.google.com/spreadsheet/ccc?key=0ArGuv......&transpose=0&headers=1&range=L1%3AN500&gid=1');
query1.send(handleQueryResponse);
}
// how do I get containerID1, containerID2, chartType1, ChartType2 Options1, Options2 etc. into this function?
function handleQueryResponse(response) {
if (response.isError()) {
alert('Error in query: ' + response.getMessage() + ' ' + response.getDetailedMessage());
return;
}
var data = response.getDataTable();
var containerDiv = document.getElementById(containerID);
var chart = false;
// Instantiate and draw the chart, based on some the chartType and passing in the options.
if (chartType.toUpperCase() == 'BARCHART') {
chart = new google.visualization.BarChart(containerDiv);
}
else if (chartType.toUpperCase() == 'COLUMNCHART') {
chart = new google.visualization.ColumnChart(containerDiv);
}
else if (chartType.toUpperCase() == 'PIECHART') {
chart = new google.visualization.PieChart(containerDiv);
}
else if (chartType.toUpperCase() == 'LINECHART'){
chart = new google.visualization.LineChart(containerDiv);
}
if (chart == false) {
return false;
}
chart.draw(data, options1);
}
})(); // End scoping function
</script>
<!--Divs that will hold the charts - Only chart_div1 is in effect at the moment -->
<div id="chart_div1"></div>
<div id="chart_div2"></div>
You need two response handlers and two queries if you are querying two different data sources:
function drawChart() {
var query1 = new google.visualization.Query(url1);
query1.send(handleQueryResponse1);
var query2 = new google.visualization.Query(url2);
query2.send(handleQueryResponse2);
}
This way my histogram works fine,when I load it like during page load.
$(document).ready()
{
x = new Array(10);
for (var i = 0; i < 10; i++) {
x[i] = new Array(2);
x[i][0]="txt";
x[i][1]=100;
}
loadChart2(x);
}
Google column chart code: (adopted from Google charting api)
function loadChart2 (histValues)
{
console.log('histValues:'+histValues);
google.load("visualization", "1", {packages:["corechart"]});
google.setOnLoadCallback(drawChart);
function drawChart() {
var data = google.visualization.arrayToDataTable(histValues);
var options = {
hAxis: {title: 'Score', titleTextStyle: {color: 'red'}}
};
var chart = new google.visualization.ColumnChart(document.getElementById('chart_div'));
chart.draw(data, options);
}
};
My problem:
But when I call loadChart2() from inside my angularJS controller, entire screen becomes white and no error is shown in browser console.
$http({method: 'GET', url: urlGetHistogramData, timeout: maxTime})
.success(function (data) {
x=new Array(data.score_hist.length);
var i=0;
$.each(data.score_hist, function(){
x[i] = new Array(2);
x[i][0]=this.interval_start;
x[i][1]=this.count;
i++;
});
loadChart2(x);
});
Debugging info:
I can see in console that interval_start and count values are printed, so service is returning values fine
Also, I can see histValues expectantly printed on console from loadChart() function.
Here is a related question, in case you want more in-depth details
How to create a historgram from json
As soon as I put loadChart2() function in any AngularJS onClick or any function, I get total white screen with no error in console. It seems, none has any comment on my problem, I will keep this page updated with my findings on this.
Edit
I am pursuing a solution to this problem, I asked a question related to this issue
https://stackoverflow.com/questions/16816782/how-set-charts-data-in-google-chart-tool-directive-module-from-a-dynamically-po
The key is to manual bootstraping your Angular module after the Google charting library load:
http://jsfiddle.net/nCFd6/22/
App
var app = angular.module('app', []);
Directive
app.directive('chart', function() {
return {
restrict: 'E',
replace: true,
scope: {
data: '=data'
},
template: '<div class="chart"></div>',
link: function(scope, element, attrs) {
var chart = new google.visualization.LineChart(element[0]);
var options = {};
scope.$watch('data', function(v) {
var data = google.visualization.arrayToDataTable(v);
chart.draw(data, options);
});
}
};
});
Controller
app.controller('ChartController', function($scope) {
$scope.scoreHistory = [];
$scope.loadDataFromServer = function() {
var x = [
['interval', 'count']
];
var scoreHistory = [
{
intervalStart: 12,
count: 20
},
{
intervalStart: 100,
count: 200
},
{
intervalStart: 200,
count: 50
},
{
intervalStart: 250,
count: 150
}
];
angular.forEach(scoreHistory, function(record, key) {
x.push([
record.intervalStart,
record.count
]);
});
$scope.scoreHistory = x;
};
});
Vodoo
google.setOnLoadCallback(function() {
angular.bootstrap(document, ['app']);
});
google.load('visualization', '1', {packages: ['corechart']});
View
<div ng-controller="ChartController">
<button ng-click="loadDataFromServer()">load data</button>
<chart data="scoreHistory"></chart>
</div>
As you can see in this example, I've made a chart directive so you can reuse it.
Here's an alternative that provides some flexibility in the event that you have already defined a module created at the root of the document (the <html> tag) and you have some controllers and directives already set up.
In application.js
var app = angular.module("chartApp", []);
app.controller("ChartCtrl", function($scope) {
$scope.buildTable = function() {
var dataTable = new google.visualization.DataTable();
dataTable.addColumn('string', 'Name');
dataTable.addColumn('string', 'Address');
var options = {showRowNumber: true};
var table = new google.visualization.Table(angular.element("div#chart")[0]);
var rows = [...]; //Table data here
dataTable.addRows(rows);
table.draw(dataTable, options);
}
//Other existing controllers and directives
In your index.html
<div id="container" ng-controller="ChartCtrl">
<div id="chart">Loading...</div>
</div>
<script type="text/javascript" src="angular.js"></script>
<script type="text/javascript" src="application.js"></script>
<script type="text/javascript" src="google/charts/api"></script>
<script type="text/javascript">
google.setOnLoadCallback(function() {
angular.element("div#container" ).scope( ).buildTable();
});
google.load('visualization', '1', {packages:['table']});
</script>
With this approach, it takes away the complexity of communicating between angular modules if the Google Charts component is just a feature of a much bigger application that you already have going.
I'm still making my way through the learning process of AngularJS too. This (https://stackoverflow.com/a/15012542/2406758) blew my mind today and I think I'll make a lot more progress in the coming weeks.
It's an excellent companion to the AngularJS tutorials and explains Services, Controllers and Directives, in a way that I haven't found anywhere else. There are some good Directive examples too, to help with understanding what he's explaining.
I'm not entirely sure this will turn out to be the answer to your problem, but it's a good place to start.
I expect you'll end up with something like
<div id='chart' chart-view>
.directive( 'chartView', function ( ) {
return {
scope: true,
link: function ( scope, element, attrs ) {
x = new Array(10);
for (var i = 0; i < 10; i++) {
x[i] = new Array(2);
x[i][0]="txt";
x[i][1]=100;
}
loadChart2(x);
}
};
});
You can try below URL:
AngularJs Google Chart Tools directive
http://bouil.github.io/angular-google-chart/
I am having a problem with the Google annotated timeline. I have this function (shown below) that is called in the jQuery ready function:
//creates an annotated timeline
function graphAnnotatedTimeLine(url) {
jQuery.get(url, function(returned_data) {
//parse returned_data ...
//build data table
var dataTable = new google.visualization.DataTable();
dataTable.addColumn('datetime', columnHeadings[0]);
dataTable.addColumn('number', columnHeadings[1]);
//populate table
for(var i = 0; i < rawData.length; i++) {
var parsedData = data[i].split(",");
dataTable.addRow([new Date(parsedData[0]), parseFloat(parsedData[1])]);
}
//draw graph
var options = {displayAnnotations: false,
allowRedraw: true,
legendPosition: 'newRow',
displayZoomButtons: false,
wmode: 'transparent'};
var chart = new google.visualization.AnnotatedTimeLine(document.getElementById('chart-div'));
chart.draw(dataTable, options);
});
}
Called in the ready function as:
$.ready(function() {
//generate url string
google.setOnLoadCallback(graphAnnotatedTimeline(url));
self.setInterval('updateGraph', 60000);
//more stuff
});
So in the ready I call it to draw the first set of data and then set an update function to be called every minute. All the update function does is basically the same as the ready function does: build a url string and call the graph function with that url. The problem I'm having is that the graph it doesn't display on startup. Once the update gets called once though, it displays fine after that. Is there anyone that can give me some insite as to why this is happening?
This is because your jquery ready function is called before the google visualization script is loaded. google.setOnLoadCallback must be called like this...
<script type="text/javascript" src='http://www.google.com/jsapi?autoload={"modules":[{"name":"visualization","version":"1","packages":["annotatedtimeline"]}]}'></script>
<script type="text/javascript">
google.setOnLoadCallback(graphAnnotatedTimeline(url));
</script>