is not a function within the class - javascript

I am working on a small class to handle Google Chart and for some odd reason I keep getting
googleChart.js:86 Uncaught TypeError: this.swapChart is not a function
On the page I have a button with id "btnSwitch", click on which triggers a switch of the chart from chart view to the table view and vice-versa. This is defined within this.addChartSwitchListener() and called within this.init_chart()
I can call this.swapChart() within init method so I have to assume that issue is with:
_button.addEventListener('click', this.switchChart, false);
Here is my code below:
google.load('visualization', '1.0', {'packages': ['charteditor', 'controls']});
//google.setOnLoadCallback(drawDashboard);
var GChart = GChart || (function () {
var _graphType;
var _minTime;
var _maxTime;
var _hAxisTitle;
var _vAxisTitle;
var _tableData;
var _data;
var _dashboard;
var _lineChart;
var _button;
var _showChart;
return {
init: function (tableData, graphType, minTime, maxTime, hAxisTitle, vAxisTitle) {
// google charts
//_google = google;
_tableData = tableData;
// load chart params
_graphType = graphType;
_minTime = minTime;
_maxTime = maxTime;
_hAxisTitle = hAxisTitle;
_vAxisTitle = vAxisTitle;
// some other initialising
this.build_googlechart();
},
build_googlechart: function ()
{
this.init_chart();
// also tried this - with the same result.
// google.load('visualization', '1.0', {'packages':['corechart'], 'callback': this.drawChart});
},
init_chart: function ()
{
// var data = new google.visualization.DataTable();
_data = new google.visualization.DataTable(_tableData);
// Create a dashboard.
_dashboard = new google.visualization.Dashboard(document.getElementById('dashboard_div'));
if (_graphType === 'LineChart') {
this.lineChart();
} else {
this.columnChart();
}
this.addChartSwitchListener();
},
addChartSwitchListener: function ()
{
_button = document.getElementById('btnSwitch');
_button.addEventListener('click', this.switchChart, false);
_showChart = "Chart";
// Wait for the chart to finish drawing before calling the getImageURI() method.
google.visualization.events.addListener(_lineChart, 'ready', function () {
if (_showChart !== 'Table') {
$('.save_chart').show();
$('.save_chart').removeClass('disabled');
$('.save_chart').attr('href', _lineChart.getChart().getImageURI());
$('#filter_div').show();
} else {
$('.save_chart').hide();
$('#filter_div').hide();
}
});
},
swapChart: function ()
{
var chart = "Table";
if (_showChart === "Chart") {
chart = _graphType;
}
_lineChart.setChartType(chart);
_lineChart.setOptions(this.getOptions(_showChart));
_lineChart.draw();
},
switchChart: function ()
{
_showChart = _button.value;
this.swapChart();
_showChart = (_showChart === 'Table') ? 'Chart' : 'Table';
_button.value = _showChart;
},
getOptions: function (chartType)
{
var options;
switch (chartType) {
case 'Chart':
options = {
backgroundColor: {
fill: 'transparent'
},
legend: 'right',
pointSize: 5,
crosshair: {
trigger: 'both'
},
hAxis: {
},
vAxis: {
}
};
break;
case 'Table':
options = {
showRowNumber: true,
width: '100%',
height: '100%'
};
break;
default:
options = {};
}
return options;
},
lineChart: function ()
{
var lineChartRangeFilter = new google.visualization.ControlWrapper({
'controlType': 'ChartRangeFilter',
'containerId': 'filter_div',
'options': {
filterColumnIndex: 0,
ui: {
chartType: 'LineChart',
chartOptions: {
backgroundColor: {fill: 'transparent'},
height: '50',
chartArea: {
width: '90%'
}
}
}
}
});
// Create a pie chart, passing some options
_lineChart = new google.visualization.ChartWrapper({
'chartType': "LineChart",
'containerId': 'chart_div',
'options': {
backgroundColor: {fill: 'transparent'},
'legend': 'right',
'pointSize': 5,
crosshair: {trigger: 'both'}, // Display crosshairs on focus and selection.
hAxis: {
title: _hAxisTitle,
viewWindow: {
min: _minTime,
max: _maxTime
},
},
vAxis: {
title: _vAxisTitle
}
}
});
// Establish dependencies, declaring that 'filter' drives 'pieChart',
// so that the pie chart will only display entries that are let through
// given the chosen slider range.
_dashboard.bind(lineChartRangeFilter, _lineChart);
// Draw the dashboard.
_dashboard.draw(_data);
},
columnChart: function () {
_lineChart = new google.visualization.ChartWrapper({
'chartType': "ColumnChart",
'containerId': 'chart_div',
'dataTable': _data,
'options': {backgroundColor: {fill: 'transparent'},
'legend': 'right',
'pointSize': 5,
crosshair: {trigger: 'both'}, // Display crosshairs on focus and selection.
hAxis: {
title: _hAxisTitle,
},
vAxis: {
title: _vAxisTitle,
}
}
});
_lineChart.draw();
}
};
}());

This is because you pass a reference to that method to addEventListener, which will later be called with the window object as context, and not your this object.
To overrule this behaviour, you can use several solutions, but here is one with bind():
_button.addEventListener('click', this.switchChart.bind(this), false);

Related

Continuous Axis Google Chart Loaded with CSV?

I've managed to implement a continuous axis google chart on my page and got it formatted the way I want it. Now my requirements have changed and I'm trying to load this chart from a CSV as opposed to hard coded and randomly generated data.
I've confused myself and gotten in over my head on how to convert my working chart into pulling from a CSV. I'm going to post a few things here,
One of my other charts that utilizes a CSV, this is what I was trying to recreate
My working continuous axis chart running off hard coded data
My current state of the chart now that I've tried to implement the change.
Here is #1:
function drawPieVisualization() {
$.get("Thornton.M2.csv", function(csvString) {
// transform the CSV string into a 2-dimensional array
var arrayData = $.csv.toArrays(csvString, {onParseValue: $.csv.hooks.castToScalar}, {onParseValue: $.csv.hooks.castToScalar});
// this new DataTable object holds all the data
var data = new google.visualization.arrayToDataTable(arrayData);
// CAPACITY - En-route ATFM delay - YY - CHART
var pieMain = new google.visualization.ChartWrapper({
chartType: 'BarChart',
containerId: 'pieMain',
dataTable: data,
options:{
title: 'Bar Chart Test',
'vAxis': { title: "Bar Chart Test" },
'width': 1100,
'height': 540,
'backgroundColor': 'Ivory',
'color':'Black',
'hAxis': {
title: "Date",
gridlines: { count: 3, color: '#CCC' },
format: 'dd-MMM-yyyy'
},
title: 'Bar Chart Test',
titleTextStyle : {color: 'Black', fontSize: 16},
}
});
pieMain.draw();
});
}
google.setOnLoadCallback(drawPieVisualization)
changeRange = function() {
pieMain.sort({column: 0, desc: false});
pieMain.draw();
};
changeRangeBack = function() {
pieMain.sort({column: 0, desc: true});
pieMain.draw();
};
Here is #2:
function drawVisualization() {
var data = new google.visualization.DataTable();
data.addColumn('date', 'Date');
data.addColumn('number', 'Value');
// add 100 rows of pseudo-random-walk data
for (var i = 0, val = 50; i < 100; i++) {
val += ~~(Math.random() * 5) * Math.pow(-1, ~~(Math.random() * 2));
if (val < 0) {
val += 5;
}
if (val > 100) {
val -= 5;
}
data.addRow([new Date(2014, 0, i + 1), val]);
}
var chart = new google.visualization.ChartWrapper({
chartType: 'ComboChart',
containerId: 'slider_chart_div',
options: {
'title': 'Average Ratings',
'vAxis': { title: "Average Rating" },
'backgroundColor': 'Ivory',
'color':'Black',
width: 1100,
height: 400,
// omit width, since we set this in CSS
chartArea: {
width: '75%' // this should be the same as the ChartRangeFilter
}
}
});
var control = new google.visualization.ControlWrapper({
controlType: 'ChartRangeFilter',
containerId: 'control_div',
options: {
filterColumnIndex: 0,
ui: {
chartOptions: {
'backgroundColor': 'Ivory',
'color':'Black',
width: 1100,
height: 50,
// omit width, since we set this in CSS
chartArea: {
width: '75%' // this should be the same as the ChartRangeFilter
}
}
}
}
});
var dashboard = new google.visualization.Dashboard(document.querySelector('#dashboard_div'));
dashboard.bind([control], [chart]);
dashboard.draw(data);
function zoomLastDay () {
var range = data.getColumnRange(0);
control.setState({
range: {
start: new Date(range.max.getFullYear(), range.max.getMonth(), range.max.getDate() - 1),
end: range.max
}
});
control.draw();
}
function zoomLastWeek () {
var range = data.getColumnRange(0);
control.setState({
range: {
start: new Date(range.max.getFullYear(), range.max.getMonth(), range.max.getDate() - 7),
end: range.max
}
});
control.draw();
}
function zoomLastMonth () {
// zoom here sets the month back 1, which can have odd effects when the last month has more days than the previous month
// eg: if the last day is March 31, then zooming last month will give a range of March 3 - March 31, as this sets the start date to February 31, which doesn't exist
// you can tweak this to make it function differently if you want
var range = data.getColumnRange(0);
control.setState({
range: {
start: new Date(range.max.getFullYear(), range.max.getMonth() - 1, range.max.getDate()),
end: range.max
}
});
control.draw();
}
var runOnce = google.visualization.events.addListener(dashboard, 'ready', function () {
google.visualization.events.removeListener(runOnce);
if (document.addEventListener) {
document.querySelector('#lastDay').addEventListener('click', zoomLastDay);
document.querySelector('#lastWeek').addEventListener('click', zoomLastWeek);
document.querySelector('#lastMonth').addEventListener('click', zoomLastMonth);
}
else if (document.attachEvent) {
document.querySelector('#lastDay').attachEvent('onclick', zoomLastDay);
document.querySelector('#lastWeek').attachEvent('onclick', zoomLastWeek);
document.querySelector('#lastMonth').attachEvent('onclick', zoomLastMonth);
}
else {
document.querySelector('#lastDay').onclick = zoomLastDay;
document.querySelector('#lastWeek').onclick = zoomLastWeek;
document.querySelector('#lastMonth').onclick = zoomLastMonth;
}
});
}
And Here is #3:
function drawVisualization() {
$.get("Source7Days.csv", function(csvString) {
// transform the CSV string into a 2-dimensional array
var arrayData = $.csv.toArrays(csvString, {onParseValue: $.csv.hooks.castToScalar}, {onParseValue: $.csv.hooks.castToScalar});
// this new DataTable object holds all the data
var data = new google.visualization.arrayToDataTable(arrayData);
var chart = new google.visualization.ChartWrapper({
chartType: 'ComboChart',
containerId: 'slider_chart_div',
dataTable: data,
options: {
'title': 'Average Ratings',
'vAxis': { title: "Average Rating" },
'backgroundColor': 'Ivory',
'color':'Black',
width: 1100,
height: 400,
// omit width, since we set this in CSS
chartArea: {
width: '75%' // this should be the same as the ChartRangeFilter
}
}
});
var control = new google.visualization.ControlWrapper({
controlType: 'ChartRangeFilter',
containerId: 'control_div',
options: {
filterColumnIndex: 0,
ui: {
chartOptions: {
'backgroundColor': 'Ivory',
'color':'Black',
width: 1100,
height: 50,
// omit width, since we set this in CSS
chartArea: {
width: '75%' // this should be the same as the ChartRangeFilter
}
}
}
}
});
var dashboard = new google.visualization.Dashboard(document.querySelector('#dashboard_div'));
dashboard.bind([control], [chart]);
dashboard.draw(data);
function zoomLastDay () {
var range = data.getColumnRange(0);
control.setState({
range: {
start: new Date(range.max.getFullYear(), range.max.getMonth(), range.max.getDate() - 1),
end: range.max
}
});
control.draw();
}
function zoomLastWeek () {
var range = data.getColumnRange(0);
control.setState({
range: {
start: new Date(range.max.getFullYear(), range.max.getMonth(), range.max.getDate() - 7),
end: range.max
}
});
control.draw();
}
function zoomLastMonth () {
// zoom here sets the month back 1, which can have odd effects when the last month has more days than the previous month
// eg: if the last day is March 31, then zooming last month will give a range of March 3 - March 31, as this sets the start date to February 31, which doesn't exist
// you can tweak this to make it function differently if you want
var range = data.getColumnRange(0);
control.setState({
range: {
start: new Date(range.max.getFullYear(), range.max.getMonth() - 1, range.max.getDate()),
end: range.max
}
});
control.draw();
}
var runOnce = google.visualization.events.addListener(dashboard, 'ready', function () {
google.visualization.events.removeListener(runOnce);
if (document.addEventListener) {
document.querySelector('#lastDay').addEventListener('click', zoomLastDay);
document.querySelector('#lastWeek').addEventListener('click', zoomLastWeek);
document.querySelector('#lastMonth').addEventListener('click', zoomLastMonth);
}
else if (document.attachEvent) {
document.querySelector('#lastDay').attachEvent('onclick', zoomLastDay);
document.querySelector('#lastWeek').attachEvent('onclick', zoomLastWeek);
document.querySelector('#lastMonth').attachEvent('onclick', zoomLastMonth);
}
else {
document.querySelector('#lastDay').onclick = zoomLastDay;
document.querySelector('#lastWeek').onclick = zoomLastWeek;
document.querySelector('#lastMonth').onclick = zoomLastMonth;
}
});
}
)}
And here is a sample of the CSV Data I'm utilizing
Time,Value
2017/05/22 00:05:00,6710.4305066168
2017/05/22 00:10:00,6667.5043776631
2017/05/22 00:15:00,6615.6655550003
2017/05/22 00:20:00,6554.988194257
2017/05/22 00:25:00,6532.4164219201
2017/05/22 00:30:00,6520.8965539932
The bottom part 'runOnce' in both #2 and #3 are to change the slider control on the chart from 1 day - 1 week - or 1 month of range on the chart, for clarification.
My chart is currently giving me the errors:
One or more participants failed to draw(). (Two of these)
And
The filter cannot operate on a column of type string. Column type must
be one of: number, date, datetime or timeofday. Column role must be
domain, and correlate to a continuous axis.
the second error message reveals that arrayToDataTable
creates the first column as --> type: 'string'
instead of --> type: 'date'
use a DataView to convert the string to a date
you can create calculated columns in a data view using method --> setColumns
use view in place of data when drawing the dashboard
see following snippet...
$.get("Source7Days.csv", function(csvString) {
var arrayData = $.csv.toArrays(csvString, {onParseValue: $.csv.hooks.castToScalar}, {onParseValue: $.csv.hooks.castToScalar});
// this is a static method, "new" keyword should not be used here
var data = google.visualization.arrayToDataTable(arrayData);
// create view
var view = new google.visualization.DataView(data);
view.setColumns([
// first column is calculated
{
calc: function (dt, row) {
// convert string to date
return new Date(dt.getValue(row, 0));
},
label: data.getColumnLabel(0),
type: 'date'
},
// just use index # for second column
1
]);
var chart = new google.visualization.ChartWrapper({
chartType: 'ComboChart',
containerId: 'slider_chart_div',
options: {
title: 'Average Ratings',
vAxis: { title: 'Average Rating' },
backgroundColor: 'Ivory',
color: 'Black',
width: 1100,
height: 400,
chartArea: {
width: '75%'
}
}
});
var control = new google.visualization.ControlWrapper({
controlType: 'ChartRangeFilter',
containerId: 'control_div',
options: {
filterColumnIndex: 0,
ui: {
chartOptions: {
backgroundColor: 'Ivory',
color: 'Black',
width: 1100,
height: 50,
chartArea: {
width: '75%'
}
}
}
}
});
var dashboard = new google.visualization.Dashboard(document.querySelector('#dashboard_div'));
dashboard.bind([control], [chart]);
// use data view
dashboard.draw(view);
...

Memory leak in google line charts

I have been doing lot research on this memory leak in Google charts library. Didnt found any thing thats helping my situation. Not sure whats the updates on this one so far. I saw google chart dev team is trying to fix it and release a new updates.
I'm using line chart and the data is coming from websockets. which is constantly updating.
Thanks in advance
P.S below is the code I use to getting data from websockets. when the socket is connected the drawChart function is called every second. Meaning the whole line chart is redrawn
function drawVisualization() {
var data = new google.visualization.DataTable();
data.addColumn('string', 'data');
data.addColumn('number', 'date');
var data_test = new google.visualization.DataTable();
data_test.addColumn('string', 'data test');
data_test.addColumn('number', 'date test');
for(var i=0; i<valueArr.length; i+=2) {
if (i>=120) {
data.removeRow(0);
valueArr.splice(0, 2);
timeArr.splice(0, 2);
}
data.addRow([timeArr[i], valueArr[i]]);
}
for(var i=1; i<valueArr.length; i+=2) {
if (i>=120) {
data_test.removeRow(0);
valueArr.splice(0, 2);
timeArr.splice(0, 2);
}
data_test.addRow([timeArr[i], valueArr[i]]);
}
//console.log(valueArr);
// use a DataView to 0-out all the values in the data set for the initial draw
var view = new google.visualization.DataView(data);
var view_test = new google.visualization.DataView(data_test);
// Create and draw the plot
var chart = new google.visualization.LineChart(document.getElementById('visualization'));
var chart_test = new google.visualization.LineChart(document.getElementById('visualization_test'));
var options = {
title:" ",
width: 960,
height: 460,
bar: { groupWidth: "40%" },
legend: { position: "bottom" },
animation: {"startup": true},
curveType: 'function',
lineWidth: 3,
backgroundColor: '#f9f9f9',
colors: ['red'],
tooltip: {
textStyle: {
color: 'red',
italic: true
},
showColorCode: true
},
animation: {
startup: true,
easing: 'inAndOut',
//duration: 500
},
vAxis: {
title: '',
gridlines: {
count: 8,
color: '#999'
}
/*minValue: 1.3,
maxValue: 1.4*/
},
hAxis: {
title: 'Time Stamp'
},
};
//stay in sockets
var runOnce = google.visualization.events.addListener(chart, 'ready', function () {
google.visualization.events.removeListener(runOnce);
chart.draw(data, options);
chart_test.draw(data, options);
});
chart.draw(view, options);
chart_test.draw(view_test, options);
}
function init() {
try {
socket = new WebSocket(portal);
//console.log('WebSocket status '+socket.readyState);
socket.onopen = function(msg) {
//console.log("Welcome - status "+this.readyState);
};
socket.onmessage = function(msg) {
parseData(msg);
drawVisualization();
};
socket.onclose = function(msg) {
console.log("Disconnected - status "+this.readyState);
};
}
catch(ex){
console.log(ex);
}
}
beginning with drawing only one chart, you might setup similar to following snippet...
this should draw the same chart with new data, only after the previous draw has finished...
function init() {
var getData = true;
var chart = new google.visualization.LineChart(document.getElementById('visualization'));
google.visualization.events.addListener(chart, 'ready', function () {
getData = true;
});
var options = {
title:" ",
width: 960,
height: 460,
bar: { groupWidth: "40%" },
legend: { position: "bottom" },
animation: {"startup": true},
curveType: 'function',
lineWidth: 3,
backgroundColor: '#f9f9f9',
colors: ['red'],
tooltip: {
textStyle: {
color: 'red',
italic: true
},
showColorCode: true
},
animation: {
startup: true,
easing: 'inAndOut',
//duration: 500
},
vAxis: {
title: '',
gridlines: {
count: 8,
color: '#999'
}
/*minValue: 1.3,
maxValue: 1.4*/
},
hAxis: {
title: 'Time Stamp'
},
};
// if you want data from previous draws, declare here...
var data = new google.visualization.DataTable();
data.addColumn('string', 'Time');
data.addColumn('number', 'Value');
// or see below...
// msg = object with arrays from parseData
function drawVisualization(msg) {
// if you ** don't ** want data from previous draws, declare here instead...
var data = new google.visualization.DataTable();
data.addColumn('string', 'Time');
data.addColumn('number', 'Value');
// ---<
for (var i = 0; i < msg.valueArr.length; i++) {
data.addRow([msg.timeArr[i], msg.valueArr[i]]);
}
chart.draw(data, options);
}
function parseData(msg) {
//... declare timeArr & valueArr locally here
return {
timeArr: timeArr,
valueArr: valueArr
};
}
function startData() {
try {
socket = new WebSocket(portal);
//console.log('WebSocket status '+socket.readyState);
socket.onopen = function(msg) {
//console.log("Welcome - status "+this.readyState);
};
socket.onmessage = function(msg) {
if (getData) {
getData = false;
// pass object with arrays from parseData
drawVisualization(parseData(msg));
}
};
socket.onclose = function(msg) {
//console.log("Disconnected - status "+this.readyState);
};
}
catch(ex){
console.log(ex);
}
}
startData();
}

Event click from google chart blocks pop-ups when I try to open a new window

An event click from a Google chart blocks pop-ups when I try to open a new window.
This is how I draw the chart:
printChart: function() {
var self = this;
google.load('visualization', '1', {
'packages': ['corechart'],
"callback": function() {
try {
showLoading('widget');
var data = google.visualization.arrayToDataTable([]);
data.addColumn('string', 'Classification');
data.addColumn('number', $.t('columnVisits'));
data.addColumn('number', $.t('columnContacted'));
data.addColumn('number', $.t('columnUnattended'));
data.addColumn('number', '');
data.addColumn({ type: 'string', role: 'annotation' });
//We add all the elements to the graph
var dataClassified = self.getClassifiedFromConfig();
_.each(dataClassified, function(element) {
var inactive = (element.Inactive <= 0 && element.Visits <= 0 && element.ActivitiesPhoneCalls <= 0) ? 1 : element.Inactive,
assigned = element.Assigned > 0 ? element.Assigned : 1;
data.addRow([
{
v: element.IdClassification.toString(),
f: element.Classification
},
element.Visits/assigned,
element.ActivitiesPhoneCalls/assigned,
inactive/assigned,
0, //empty column for placing the Cycle as an annotation at the end of the stacked bars.
element.Cycle + ' ' + $.t('days')
]);
});
var options = {
isStacked: true,
hAxis: {
format: '#%',
minValue: 0,
maxValue: 1,
textStyle: {
color: '#404040',
fontName: 'Roboto',
fontSize: 14
}
},
vAxis: {
textStyle: {
color: '#404040',
fontName: 'Roboto',
fontSize: responsiveFontSize
}
},
bar: {
groupWidth: '75%'
},
annotations: {
alwaysOutside: true,
stemColor: 'none', // eliminate the tick for the annotation
textStyle: {
fontName: 'Roboto',
fontSize: 14,
bold: false,
italic: false,
color: '#404040'
}
},
series: {
3: {
visibleInLegend: false
}
},
legend: {
position: 'top'
},
tooltip: {
trigger: 'none'
},
height: responsiveHeight,
width: '100%',
colors: ['#85ac1f', '#fccd3d', '#eaeaea'],
enableInteractivity: true
};
var chart = new google.visualization.BarChart(document.getElementById('portfolio-coverage-chart'));
google.visualization.events.addListener(chart, 'onmouseover', function(e){
self.mouseOverHandler(chart, data);
});
google.visualization.events.addListener(chart, 'select', function(e){
self.selectHandler(chart, data);
});
/*$('.portfolio-coverage-chart').on('click', function() {
self.selectHandler(chart, data);
});*/
chart.draw(data, options);
} catch (e) {
console.log("error printChart " + e);
} finally {
hideLoading('widget');
}
}
});
},
When the user clicks in a bar of my Google chart I call this event:
google.visualization.events.addListener(chart, 'select', function(e){
self.selectHandler(chart, data);
});
The "selectHandler" function:
selectHandler: function(chart, data) {
var self = this;
var id = 5;
var customView = "";
var elementClick = chart.getSelection();
if (elementClick.length > 0){
var row = elementClick[0].row,
column = elementClick[0].column;
if (column === 1) {
id = 5;
customView = "customview.visitcompanies";
} else if (column === 2) {
id = 6;
customView = "customview.contactcompanies";
} else if (column === 3) {
id = 7;
customView = "customview.unattendedcompanies";
} else {
return;
}
//nulls out the selection so we can select it again
chart.setSelection();
var idClassification = parseInt(data.getValue(row, 0));
var params = self.setParams(idClassification);
doDrilldown(id, customView, "companies", params);
}
}
And then, the "doDrillDown" method try to open a new window applying the window.open function:
// open entity page
var newTab = window.open(url, '_blank');
if (newTab) {
newTab.focus();
} else {
alert('Please allow popups for this website');
}
But the pop-ups of my website get blocked before opening a new window.
If instead of the event handler from google I call an on click event works as expected (the problem here is that the data from "chart.getSelection();" is not update, and I get the selection done before the last one):
$('.portfolio-coverage-chart').on('click', function() {
self.selectHandler(chart, data);
});
Why is this happening?

Google chart api explorer vs. selecthandler

I have problem with using Google.charts api... i have chart drawing function like this:
function columnDraw(sectionname) {
var data = google.visualization.arrayToDataTable(array);
var view = new google.visualization.DataView(data);
var options = {
title: "Activity of users",
bar: {groupWidth: "100%"},
legend: {position: "top"},
height: 300,
// explorer: {
//maxZoomOut:0
//maxZoomIn: 50,
// keepInBounds: true,
// axis: 'horizontal'
// },
hAxis: {
title: 'Amount of activity',
minValue : 0,
format: '0'
},
vAxis: {
title: 'Amount of users',
minValue : 0,
format: '0'
}
};
var chart = new google.visualization.ColumnChart(document.getElementById(sectionname));
function selectHandler() {
var selectedItem = chart.getSelection()[0];
if (selectedItem) {
document.getElementById("input0").value = data.getValue(selectedItem.row, 0);
}
}
google.visualization.events.addListener(chart, 'select', selectHandler);
chart.draw(view, options);
}
I want to choose parts of chartcolumn by cklicing on them, but i have a problem with zooming. This code works but once I uncomment the explorer part, selectHandler function wont work properly. Can anyone tell me whats wrong with it?
You're missing a ","
maxZoomOut:0,

Google visualisation errors

I have google vis datatable and dashboard (control filters, string control, datatable, charts). All element is bind.
So I get from database JSON and send to gViz api to draw table, chart and control.
When I use contols to filter some data and if there is no data for that string then I get error from google visualisation like this:
One or more participants failed to draw()×
Table has no rows.×
and similar messages. So in my app this is so ugly so is there any way to not showing it?
So if there is no data to not show the error...
I try with CSS option:
#google-visualization-errors-all-3 {
display:none;
}
but its not good solution for me.
Is there any other way, maybe in google visualusation api for dashboard?
UPDATE:
var slider;
var ajdi = '';
function drawVisualization() {
var cssClassNames = {
'headerRow': 'zaglavlje',
'tableRow': 'red',
'oddTableRow': 'red1',
'selectedTableRow': 'orange-background large-font',
'hoverTableRow': 'prekoreda',
'headerCell': 'gold-border',
'tableCell': 'cell',
'rowNumberCell': 'underline-blue-font'
};
var json = $.ajax({
url: 'getzadaci.php', // make this url point to the data file
dataType: 'json',
async: false
}).responseText;
// Create our data table out of JSON data loaded from server.
var data = new google.visualization.DataTable(json);
//dodajemo kolonu sa kontrolama
// Define a category picker control for the Gender column
var categoryPicker = new google.visualization.ControlWrapper({
'controlType': 'CategoryFilter',
'containerId': 'control1',
'options': {
'filterColumnLabel': 'Status',
'ui': {
'labelStacking': 'vertical',
'allowTyping': false,
'allowMultiple': true,
'caption': 'Status'
}
}
});
var categoryPicker1 = new google.visualization.ControlWrapper({
'controlType': 'CategoryFilter',
'containerId': 'control2',
'options': {
'filterColumnIndex': 8,
'ui': {
'labelStacking': 'horizontal',
'allowTyping': false,
'allowMultiple': true,
'caption': 'Parcela'
}
}
});
var categoryPicker2 = new google.visualization.ControlWrapper({
'controlType': 'CategoryFilter',
'containerId': 'control4',
'options': {
'filterColumnIndex': 2,
'ui': {
'labelStacking': 'horizontal',
'allowTyping': false,
'allowMultiple': true,
'caption': 'Vrsta zadatka'
}
}
});
var stringFilter1 = new google.visualization.ControlWrapper({
'controlType': 'StringFilter',
'containerId': 'control3',
'options': {
'matchType': 'any',
'filterColumnIndex': 1,
'ui': {'labelStacking': 'vertical'}
}
});
var slider = new google.visualization.ControlWrapper({
'controlType': 'DateRangeFilter',
'containerId': 'control5',
'options': {
'filterColumnLabel': 'Pocetak',
'ui': {'labelStacking': 'vertical'}
}
});
// Define a Pie chart
// Define a table
var table = new google.visualization.ChartWrapper({
'chartType': 'Table',
'containerId': 'chart2',
'cssClassNames': 'cssClassNames',
'view': { 'columns': [1,2,12,5,6,8,11] },
'options': {
cssClassNames: cssClassNames,
allowHtml: true
}
});
var timeline = new google.visualization.ChartWrapper({
chartType: 'Timeline',
containerId: 'chart5',
options: {
height: '350',
timeline: { colorByRowLabel: true,
backgroundColor: '#ffd' },
//timeline.barLabelStyle: {color: '#000', fontName: 'Arial', fontSize: '13px'},
//backgroundColor: '#fff',
colors: ['#55c2a2', '#89d168', '#d3eb87','#8ec63e', '#FFF0BA','#FF542E', '#CFD6DE', '#ADC1D6', '#7297BA']
//timeline: { rowLabelStyle: {fontName: 'Helvetica', fontSize: 24, color: '#603913' },
// barLabelStyle: { fontName: 'Garamond', fontSize: 14 } }
},
view: {
// as an example, use columns "Naziv", "Vrsta", "Pocetak", and "Zavrsetak" for the timeline
columns: [8, 2, 5, 6]
},
});
var formatter_short = new google.visualization.DateFormat({formatType: 'short'});
formatter_short.format(data, 5);
formatter_short.format(data, 6);
new google.visualization.events.addListener(table, 'ready', function () {
google.visualization.events.addListener(table.getChart(), 'select', function () {
var selection = table.getChart().getSelection();
// iterate over all selected rows
for (var i = 0; i < selection.length; i++) {
//$("#edit").removeClass("edit btn btn-success")
//$('#edit').addClass('edit btn btn-success');
ajdi = table.getDataTable().getValue(selection[i].row,0);
$("#vrednostid").val(table.getDataTable().getValue(selection[i].row,0));
$("#naziv1").val(table.getDataTable().getValue(selection[i].row,1));
$("#vrsta_rada1").val(table.getDataTable().getValue(selection[i].row,2));
$("#status1").val(table.getDataTable().getValue(selection[i].row,3));
$("#opis1").val(table.getDataTable().getValue(selection[i].row,4));
$("#usluzno1").val(table.getDataTable().getValue(selection[i].row,9));
var p = new Date(table.getDataTable().getValue(selection[i].row,5));
$("#dp31").datepicker("setDate", p);
var z = new Date(table.getDataTable().getValue(selection[i].row,6));
$("#dp41").datepicker("setDate", z);
//$("#parcele1").val(table.getDataTable().getValue(selection[i].row,8));
//$("#parcele1").select2("val", ["3","19"]);
var id = table.getDataTable().getValue(selection[i].row,10);
var naziv = table.getDataTable().getValue(selection[i].row,8);
var idArr = (id.lastIndexOf(',') == (id.length - 1) ? id.substr(0, id.length - 1) : id).split(', ');
var nazivArr = (naziv.lastIndexOf(',') == (naziv.length - 1) ? naziv.substr(0, naziv.length - 1) : naziv).split(', ');
var objHold = [];
for(var j=0,length=idArr.length;j<length;j++)
{
if(idArr[j] && nazivArr[j]) // make sure both arrays have a value
objHold.push({id: idArr[j], naziv: nazivArr[j]});
}
$("#parcele1").select2("data", objHold);
}
});
});
// Create a dashboard
new google.visualization.Dashboard(document.getElementById('dashboard')).
// Establish bindings, declaring the both the slider and the category
// picker will drive both charts.
bind([categoryPicker, categoryPicker1, categoryPicker2, slider, stringFilter1], [table, timeline]).
// Draw the entire dashboard.
draw(data, {'allowHtml':true, 'cssClassNames': 'cssClassNames'}); }
//table.draw(data, {'allowHtml':true, 'cssClassNames': cssClassNames}); }
function dashboardReady() {
// The dashboard is ready to accept interaction. Configure the buttons to
// programmatically affect the dashboard when clicked.
// Change the slider selected range when clicked.
document.getElementById('rangeButton').onclick = function() {
slider.setState({'lowValue': 2, 'highValue': 5});
slider.draw();
};
// Change the pie chart rendering options when clicked.
document.getElementById('optionsButton').onclick = function() {
piechart.setOption('is3D', true);
piechart.draw();
};
}
google.setOnLoadCallback(drawVisualization);// JavaScript Document
This is my code, so the important part is .ajac function, so how I can here integrate if row>0 to show charts ???
I had the same problem using the Google Charts API. To get around it I simply had to check the number of rows that made it through the filters. If it's >= 1, draw the chart. else do whatever you need to; don't draw the chart, display error, etc.
I've seen a solution to your code in someone else's fork of a GitHub project I've done a bit of work on. Since I didn't write this I'll link to it in this repository:
leonardean/angular-google-charts
Here's to code in case this link breaks:
google.visualization.events.addListener(chartWrapper, 'error', function (err) {
google.visualization.errors.removeError(err.id);
});
If you click the link above it will show you the lines I'm refering to highlighted. Basically, the author of this code is passing an event listener to the google charts api that listens for the error event, and then in the error handler removes the error. Not exactly a best practice, but I believe this would still log to console. If it doesn't you can just log the error to console yourself from the handler, but it does get rid of the ugly red box.
This function will get rid of all google chart error messages. Call it in a script tag after your DOM and charts have loaded.
// Gets rid of all Google's error messages
function removeGoogleErrors() {
var id_root = "google-visualization-errors-all-";
var index = 1;
while (document.getElementById(id_root + index.toString()) != null) {
document.getElementById(id_root + index.toString()).style.display = 'none';
index += 2;
}
}

Categories