Slow Google Charts control: Possible causes? - javascript

I have created a Google Charts linechart with a scrolling control, but the redraw performance is abysmal when I try to use the control. It literally locks up, moving fractionally when I try to scroll the horizontal scroller.
It wouldn't be the amount of data, I wouldn't think, as it is just two columns in JSON -- date and a measurement -- and only one year worth of daily data.
What am I missing? What could be causing this to be slow when I attempt to manipulate the linechart using a ChartRangeFilter?
Here is a subset of the code, just the Javascript for data loading and manipulation:
google.charts.setOnLoadCallback(drawChartRangeFilter);
function drawChartRangeFilter() {
var dashboard = new google.visualization.Dashboard(
document.getElementById('chartRangeFilter_dashboard_div'));
var control = new google.visualization.ControlWrapper({
'controlType': 'ChartRangeFilter',
'containerId': 'chartRangeFilter_control_div',
'options': {
// Filter by the date axis.
'filterColumnIndex': 0,
'ui': {
'chartType': 'LineChart',
'chartOptions': {
'chartArea': {'width': '90%'},
'hAxis': {'baselineColor': 'none'}
},
}
},
// Initial range
'state': {'range': {'start': new Date(2015, 5, 6), 'end': new Date()}}
});
var chart = new google.visualization.ChartWrapper({
'chartType': 'LineChart',
'containerId': 'chartRangeFilter_chart_div',
'options': {
// Use the same chart area width as the control for axis alignment.
'chartArea': {'height': '80%', 'width': '90%'},
'hAxis': {'slantedText': false},
//'vAxis': {'viewWindow': {'min': 0, 'max': 2000}},
'legend': {'position': 'none'}
},
// Convert the first column from 'date' to 'string'.
'view': {
'columns': [
{
'calc': function(dataTable, rowIndex) {
return dataTable.getFormattedValue(rowIndex, 0);
},
'type': 'string'
}, 1]
}
});
var data2 = $.ajax({
url: "the url",
dataType: "JSON",
async: false,
}).responseText;
var data = new google.visualization.DataTable($.parseJSON(data2));
dashboard.bind(control, chart);
dashboard.draw(data);
}

Related

Google Timeline Visualization, bars disappear if start time is not in selected range

The bars in my google timeline are disappearing when the start dates of my data are outside the range selected by my ChartRangeSlider. In other words, if I slide one of the sliders on the range slider, a bar on the edge of the active range will either show entirely or not at all.
I need partial bars to be visible for this to work. This is how I've configured the timeline and the slider in a dashboard...
// Configure range slider
var timelineRangeSlider = new google.visualization.ControlWrapper({
'controlType': 'ChartRangeFilter',
'containerId': 'timeline-filter',
'state':
{
'range':
{
'start': currentTime,
'end': fourWeek
}
},
'options':
{
'filterColumnIndex': 4,
'ui':
{
'chartType': 'ScatterChart',
'chartOptions':
{
'width': '100%',
'height': '50',
'chartArea':
{
'width': '80%', // make sure this is the same for the chart and control so the axes align right
'height': '80%'
},
'hAxis':
{
'baselineColor': 'none'
}
},
'chartView':
{
'columns': [4,6]
}
}
}
});
// Configure timeline
var timeline = new google.visualization.ChartWrapper({
'chartType': 'Timeline',
'containerId': 'timeline-chart',
'options':
{
'timeline':
{
'showBarLabels': false
},
'width': '100%',
'height': '325',
'tooltip':
{
'isHtml': true
},
'chartArea':
{
'width': '80%', // make sure this is the same for the chart and control so the axes align right
'height': '80%'
},
},
'view':
{
'columns': [0,1,2,3,4,5]
}
});
Any help is greatly appreciated. This is REALLY important for my work.
Thank you!

Google Charts API change color based on control selection

I have a google chart where I am trying to change the color based on the category control.
My chart is a histogram which should change color based on the selection in the programmaticDropdown. Part of my code is shown below:
var dashboard = new google.visualization.Dashboard(
document.getElementById('programmatic_dashboard_div'));
programmaticDropdown = new google.visualization.ControlWrapper({
'controlType': 'CategoryFilter',
'containerId': 'programmatic_control_div',
'options': {
'filterColumnLabel': 'Type',
'ui': {'allowMultiple': false},
}
});
programmaticChart = new google.visualization.ChartWrapper({
'chartType': 'Histogram',
'containerId': 'programmatic_chart_div',
'options': {
'title': 'Issues by Month',
'legend': 'none',
'height':400,
'hAxis': {
'viewWindowMode':'explicit',
'viewWindow':{
'max':13,
'min':0
}
}
},
'view': { 'columns': [0, 1] }
});
dashboard.bind(programmaticDropdown, programmaticChart);
dashboard.draw(data);
}
Also, here is a link to the google chart controls documentation that has some UI information... can anyone help?
Thanks!!!
https://developers.google.com/chart/interactive/docs/gallery/controls?hl=en#controls-gallery
Solved it!!! To do this, I had to add an event listener and function to my code. See below.
google.visualization.events.addListener(programmaticDropdown, 'statechange', changeTitle);
function changeTitle () {
var location = programmaticDropdown.getState().selectedValues[0];
if (location == "CLOSED") {
programmaticChart.setOption('colors', ['#e7711c']);
} else if (location == "OPEN") {
programmaticChart.setOption('colors', ['#ff0000']);
}
programmaticChart.draw();
}

Is it possible to create a dropdown controlwrapper from values in a row?

Is it possible to create a category filter that gets it's values from certain parts of the horizontal axis of a table. For instance in a table:
Heading 1|Heading 2|Heading 3|Heading 4|Heading 5
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
AValue 1|AValue 2|AValue 3|AValue 4|AValue 5
BValue 1|BValue 2|BValue 3|BValue 4|BValue 5
CValue 1|CValue 2|CValue 3|CValue 4|CValue 5
Instead of having a dropdown with Heading1's Values, is it possible create dropdown with only Heading3,Heading4,Heading5 as values and then the chart data displayed is only the data underneath the particular heading selected?
var CountryPicker = new google.visualization.ControlWrapper({
controlType: 'CategoryFilter',
containerId: 'control3',
options: {
filterColumnLabel: 'Location',
ui: {
labelStacking: 'vertical',
allowTyping: false,
allowMultiple: true,
caption: 'Country',
label: ''
}
}
});
EDIT:
Here is an image of the data table, I wish to be able to filter by Male, Female and Total through the dropdown.
CSV function for geochart:
function drawVisualization() {
$.get("Data_Actual_V2.csv", function(csvString) {
var arrayData = $.csv.toArrays(csvString, {onParseValue: $.csv.hooks.castToScalar});
for (var i = 1; i < arrayData[0].length; i++) {
$("select").append("<option value='" + i + "'>" + arrayData[0][i] + "</option");
}
$("#range option[value='1']").attr("selected","selected");
var data = new google.visualization.arrayToDataTable(arrayData);
var geoChart = new google.visualization.ChartWrapper({
chartType: 'GeoChart',
containerId: 'chart1',
options: {
title: 'A',
displayMode: 'regions',
width: 1000,
datalessRegionColor: 'C0C0C0',
colorAxis: {
values: [0, 12.5, 25, 37.5, 50, 62.5, 75, 87.5, 100],
colors: ['#3366FF','#33CCCC', '#00FFFF', '#CCFFFF', '#00FF00', '#FFFF99','#FFCC00','#FF9900','#FF0000'],
minValue: 0,
maxValue: 100,
}
},
view: { // Defines data to show in geoChart
columns: [0, 4]
}
});
EDIT2: I have the chart working with the single filter as first asked, but intially had more than one filter available. eg, select country, then select by method above. An example of how I did this before getting the above working is below, but how can I incorporate this with the method described in the fiddle below?
var CountryPicker = new google.visualization.ControlWrapper({
controlType: 'CategoryFilter',
containerId: 'control3',
options: {
filterColumnLabel: 'Location',
ui: {
labelStacking: 'vertical',
allowTyping: false,
allowMultiple: true,
caption: 'Country',
label: ''
}
}
});
var dashboard = new google.visualization.Dashboard(document.getElementById('dashboard'));
dashboard.bind([CountryPicker, GenderPicker, slider2],[geoChart]). // consolidated all of the bind calls
// Draw the dashboard
draw(data);

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;
}
}

How to create multi-series line chart

I am writing to seek help, in how do can I create multi-series line chart from [name] column below. Currently, I am plotting the chart using [date] and [tag] points. However, I would like to show multi-series line chart for each names. Is this plausible or does this task require manual functions to be created to link in with the API.
Please advice.
function drawVisualization() {
// Prepare the data
var data = google.visualization.arrayToDataTable([
['Name', 'Tag', 'Date'],
['ACCA', 45, 'May 14'],
['ABBA', 85, 'May 14'],
['ANNA', 100, 'May 14'],
['AMMA', 100.5, 'May 14'],
['ACCA', 99.5, 'May 15'],
['ABBA', 85.5, 'May 15'],
['ACCA', 99.6, 'May 15'],
['BACM', 94, 'May 15'],
['MMBS', 96, 'May 15']
]);
// Define category pickers for 'Name',
var countryPicker = new google.visualization.ControlWrapper({
'controlType': 'CategoryFilter',
'containerId': 'control1',
'options': {
'filterColumnLabel': 'Name',
'ui': {
'labelStacking': 'vertical',
'allowTyping': false,
'allowMultiple': false
}
}
});
var barChart = new google.visualization.ChartWrapper({
'chartType': 'LineChart',
'containerId': 'chart1',
'options': {
'width': 400,
'height': 300,
'chartArea': { top: 0, right: 0, bottom: 0 }
},
// Configure the Linechart to use columns 2 (Date) and 1 (Tag)
'view': { 'columns': [2, 1] }
});
// Define a table.
var table = new google.visualization.ChartWrapper({
'chartType': 'Table',
'containerId': 'chart2',
'options': {
'width': '300px'
}
});
new google.visualization.Dashboard(document.getElementById('dashboard')).bind([countryPicker], [barChart, table]).draw(data);
}
Edit:
Thanks.
To make this work, I would suggest removing the LineChart from your Dashboard, and using the Table's "ready" event to get the filtered data, create appropriate settings for the chart's view.columns parameter, and then drawing the chart with the filtered data:
google.visualization.events.addListener(table, 'ready', function () {
var filteredData = table.getDataTable();
// get a list of all the labels in column 0
var group = filteredData.getDistinctValues(0);
// build the columns for the view
var columns = [0];
for (var i = 0; i < group.length; i++) {
var label = group[i];
// set the columns to use in the chart's view
// calculated columns put data belonging to each country in the proper column
columns.push({
type: 'number',
label: label,
calc: (function (name) {
return function (dt, row) {
return (dt.getValue(row, 0) == name) ? dt.getValue(row, 1) : null;
}
})(label)
});
}
var view = barChart.getView() || {};
view.columns = columns;
barChart.setView(view);
barChart.setDataTable(filteredData);
barChart.draw();
});
new google.visualization.Dashboard(document.getElementById('dashboard')).bind([countryPicker], [table]).draw(data);

Categories