Related
I am making a custom legend for a Google Charts ColumnChart. I would like it to have the same behavior as the native legend. The native legend has behavior on click and mouseover. When a legend key is clicked, the column of values is selected. I can do this in my custom legend by calling
myChartWrapper.getChart().setSelection([{column: 4}]);
When a legend key is moused over, the column of values gets an outline. I would like to trigger that same outline when mousing over the key in my custom legend.
Is there a way to set that focussed column similar to setting the selection?
I thought I might be able to do it by calling events.trigger(), but I can't get anything to happen at all with that. For example, these don't seem to do anything.
// did nothing:
google.visualization.events.trigger(myChartWrapper, 'select', [{column: 4}]);
// did nothing:
google.visualization.events.trigger(myChartWrapper.getChart(), 'onmouseover', [{column: 4}]);
attempt to cause focus appearance via event trigger
google.charts.load('current', {
callback: function () {
var dataTable = new google.visualization.DataTable({
cols: [
{label: 'Month', type: 'string'},
{label: 'Amount', type: 'number'}
],
rows: [
{c:[{v: 'April'}, {v: 279899811.34}]},
{c:[{v: 'May'}, {v: 205855811}]},
{c:[{v: 'June'}, {v: 10009811}]},
{c:[{v: 'July'}, {v: 79979811}]},
{c:[{v: 'August'}, {v: 175789911}]},
{c:[{v: 'September'}, {v: 99899811}]},
{c:[{v: 'October'}, {v: 149899811}]},
{c:[{v: 'November'}, {v: 80899811}]},
{c:[{v: 'December'}, {v: 60899811}]},
{c:[{v: 'January'}, {v: 225899811}]},
{c:[{v: 'February'}, {v: 148899811}]},
{c:[{v: 'March'}, {v: 150899811}]}
]
});
var chartWrapper = new google.visualization.ChartWrapper({
chartType: 'ColumnChart',
containerId: 'chart_div',
dataTable: dataTable,
options: {
legend: {
position: 'bottom'
},
vAxis: {
format: 'short'
}
}
});
google.visualization.events.addOneTimeListener(chartWrapper, 'ready', function () {
// mouseover for custom div
document.getElementById('hover_div').addEventListener('mouseover', function () {
// trigger onmouseover for chart, pass props
google.visualization.events.trigger(chartWrapper.getChart(), 'onmouseover', {
'column': 1,
'row': null,
'test': 'over'
});
}, false);
// mouseout
document.getElementById('hover_div').addEventListener('mouseout', function () {
google.visualization.events.trigger(chartWrapper.getChart(), 'onmouseout', {
'column': 1,
'row': null,
'test': 'out'
});
}, false);
// chart event listeners
google.visualization.events.addListener(chartWrapper.getChart(), 'onmouseover', function (props) {
document.getElementById('msg_div').innerHTML = JSON.stringify(props);
});
google.visualization.events.addListener(chartWrapper.getChart(), 'onmouseout', function (props) {
document.getElementById('msg_div').innerHTML = JSON.stringify(props);
});
});
chartWrapper.draw();
},
packages:['controls', 'corechart']
});
#hover_div {
background-color: magenta;
border: 1px solid lime;
color: cyan;
height: 200px;
text-align: center;
width: 200px;
}
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="chart_div"></div>
<div id="hover_div">HOVER THIS DIV</div>
<div id="msg_div"></div>
Here's a hacky way to highlight bars in a bar chart. It's not a proper solution because it doesn't trigger the chart's native highlight. Instead, it's a way to create your own highlight by manipulating the stroke of the rects with jQuery. I approximated the highlight by setting the stroke to be 2px and grey. The actual highlight appears to be a blur effect with svg. To enhance the highlighting, I applied a slight transparency to the rects themselves.
On mouseover, I get the set of rects for all the bars, and then the subset for the particular column. It turned out to be tricky to get the right set of rects on mouseover, because the user might have selected a bar. When you select a bar with the mouse (i.e., click on it), the rect for it moves around, so you have to select the rects anew each time you mouseover. Plus selecting adds another rect for the white outline, which needs to be filtered out.
For the custom legend, I used colors from the Google Charts palette, which you get here.
I didn't add the part that would trigger a selection on clicking the legend. For that, I will follow this method.
The solution also only works with bar charts. You'd have to do something else with line charts, or other types. So the value of this solution may be limited.
google.charts.load('current', {packages: ['corechart']});
google.charts.setOnLoadCallback(draw_chart);
function draw_chart() {
// Create DataTable object from DataTable constructor or arrayToDatable()
var data = new google.visualization.DataTable({"rows":[{"c":[{"v":"Sacramento"},{"v":97},{"v":79},{"v":67},{"v":100}]},{"c":[{"v":"Montpelier"},{"v":96},{"v":74},{"v":32},{"v":96}]},{"c":[{"v":"Juneau"},{"v":24},{"v":44},{"v":54},{"v":64}]},{"c":[{"v":"Montgomery"},{"v":26},{"v":69},{"v":51},{"v":56}]},{"c":[{"v":"Little Rock"},{"v":87},{"v":69},{"v":78},{"v":41}]}],"cols":[{"type":"string","id":"cities","label":"cities"},{"type":"number","id":"A","label":"A"},{"type":"number","id":"B","label":"B"},{"type":"number","id":"C","label":"C"},{"type":"number","id":"D","label":"D"}]});
// Add formatters, if any
// Create ChartWrapper
var my_chart = new google.visualization.ChartWrapper({
"containerId": "chart_id",
"dataTable": data,
"chartType": "ColumnChart",
"options": {"bar": {"groupWidth": 67}, "chartArea": {"width": 440, "top": 20, "height": 295, "left": 60}, "height": 375, "width": 500, "fontSize": 12, "legend": "none"}
});
var bar_rect_set;
var num_rows = 5;
var num_cols = 4;
var num_series = num_rows * num_cols;
var parent_g;
function get_bar_rect_set() {
// get all the rects in the parent except for the white outline rects
// on selected bars, if any.
bar_rect_set = parent_g.find('rect[fill!="#ffffff"]');
}
google.visualization.events.addOneTimeListener(my_chart, 'ready', function () {
// Get an initial collection of the bar rects, along with their parent.
// Hereafter, get the bar rects with the method above.
// get all rects three layers down, including gridlines and axis
var g_set_1 = $("svg g g g rect");
// slice out the gridlines at the beginning and the axis line at the end
bar_rect_set = g_set_1.slice(g_set_1.length - num_series - 1, g_set_1.length - 1);
parent_g = $(bar_rect_set[0]).parent();
});
my_chart.draw();
function highlight_bars(series_num) {
if (series_num > num_cols - 1) {
return false;
}
get_bar_rect_set();
var start_index = series_num * num_rows;
var end_index = start_index + num_rows;
var series_g_set = bar_rect_set.slice(start_index, end_index)
var styles = {'stroke-width': "1.5px", "stroke": "#AAAAAA", "opacity": .8};
series_g_set.css(styles);
}
function remove_highlight() {
var styles = {'stroke-width': "0", "opacity": 1};
bar_rect_set.css(styles);
}
$("#legend tr").each(function(index, row) {
$(row).mouseover(function() {
highlight_bars(index);
}).mouseout(function() {
remove_highlight();
});
});
}
.color_bar {
width:24px;
height:12px;
margin-right:5px;
vertical-align:middle;
}
#legend td {
font-size:12;
height:19px;
font-family:"Arial";
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<script src="https://www.gstatic.com/charts/loader.js"></script>
<table id="legend">
<tr>
<td><div class='color_bar' style="background-color:#3366cc"></div></td>
<td>A</td>
</tr>
<tr>
<td><div class='color_bar' style="background-color:#dc3912"></div></td>
<td>B</td>
</tr>
<tr>
<td><div class='color_bar' style="background-color:#ff9900"></div></td>
<td>C</td>
</tr>
<tr>
<td><div class='color_bar' style="background-color:#109618"></div></td>
<td>D</td>
</tr>
</table>
<div id="chart_id" ></div>
I'm writing a Google Chart. It has stacked columns. On top of that I want to draw 2 lines, which indicate min and max allowed value.
The only solution I came up with, was modifying the first example of ComboCharts. My result looks like this:
Which isn't sufficient. The graph is variable, so if there's only 1 Quartal shown, the line will solely be a dot. My Questions are:
Is there a way to draw the line further, so it hits the left and right boundary of the Graph?
Can I draw markup lines into the graph, without pretending it's another datapoint?
You can fiddle with a ComboChart here if you want.
You can't get the lines to go edge-to-edge with a discrete (string-based) x-axis. If you switch to a continuous (number, date, datetime, timeofday) axis, then you can add one row before your real data and one row after that contain the goal lines (and nulls for the other data series):
function drawChart() {
var data = new google.visualization.DataTable();
data.addColumn('number', 'Quarter');
data.addColumn('number', 'Value 1');
data.addColumn('number', 'Value 2');
data.addColumn('number', 'Value 3');
data.addColumn('number', 'Goal 1');
data.addColumn('number', 'Goal 2');
data.addRows([
[0, null, null, null, 10, 14],
[1, 5, 4, 7, null, null],
[2, 6, 9, 6, null, null],
[3, 2, 6, 4, null, null],
[4, 3, 6, 4, null, null],
[5, null, null, null, 10, 14]
]);
var chart = new google.visualization.ComboChart(document.querySelector('#chart_div'));
chart.draw(data, {
height: 400,
width: 600,
isStacked: true,
legend: {
position: 'top'
},
seriesType: 'bars',
interpolateNulls: true,
series: {
3: {
type: 'line'
},
4: {
type: 'line'
}
},
hAxis: {
format: 'Q#',
ticks: [1, 2, 3, 4],
viewWindow: {
min: 0.5,
max: 4.5
}
},
chartArea: {
left: '10%',
width: '80%'
}
});
}
google.load('visualization', '1', {packages:['corechart'], callback: drawChart});
See working example: http://jsfiddle.net/asgallant/W67qU/
Here is some explanation of what is going on (edit on Nov 24, 2022 by Jorr.it):
At the top and bottom of the DataTable there are extra rows added with the goals only. With the hAxis.viewWindow option the two new goal dots are just cut off the chart, but resulting in a full line over the whole width of the chart. Finally option "interpolateNulls" needs to be set to connect the two invisible dots "over" the null values in the bar rows.
Maybe a bit late but I faced the same issue. I was trying to set max and min lines into a line chart with a lot of data points in the serie and I wanted to avoid adding new series with a lot of repeated points so I used overlays ( https://developers.google.com/chart/interactive/docs/overlays#javascript2 ).
Here are an example, It's just a draft in which I'm working now but maybe can help:
<html>
<head>
<script
type="text/javascript"
src="https://www.gstatic.com/charts/loader.js"
></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.0/jquery.min.js"></script>
<style>
#container {
position: relative;
width: 900px;
height: 500px;
}
.min-bar {
height: 1px;
background-color: red;
position: absolute;
left: 0;
right: 0;
}
</style>
<script type="text/javascript">
$(function() {
$.get(
"https://firebasestorage.googleapis.com/v0/b/manasav-pricetracker.appspot.com/o/products%2F-L6O-CtBKZAc2NTCFq7Z.data?alt=media&token=60e06bb6-59b7-41a9-8fd0-f82f4ddc75f2",
function(data) {
google.charts.load("current", { packages: ["corechart"] });
google.charts.setOnLoadCallback(drawChart);
var downloadedData = JSON.parse("[" + data);
function drawChart() {
var dataTable = [["Time", "New"]];
let min = Number.MAX_VALUE;
let rowMin;
for (var i in downloadedData) {
var d = downloadedData[i];
if (d.new < min) {
rowMin = i;
min = d.new;
}
dataTable.push([new Date(d.date), d.new]);
}
var data = google.visualization.arrayToDataTable(dataTable);
var options = {
title: "Price evolution",
legend: { position: "bottom" },
trendlines: { 0: {} }
};
var chart = new google.visualization.LineChart(
document.getElementById("curve_chart")
);
function placeMarker(dataTable) {
var cli = this.getChartLayoutInterface();
var chartArea = cli.getChartAreaBoundingBox();
document.querySelector(".min-bar").style.top =
Math.floor(cli.getYLocation(min)) + "px";
document.querySelector(".min-bar").style.left =
Math.floor(cli.getXLocation(dataTable.getValue(0,0))) - 25 + "px";
document.querySelector(".min-bar").style.right =
(document.querySelector("#container").offsetWidth - Math.floor(cli.getXLocation(dataTable.getValue(dataTable.getNumberOfRows()-1,0)))) - 25 + "px";
// document.querySelector(".min-bar").style.top =
// Math.floor(cli.getXLocation(dataTable.getValue(rowMin, 1))) +
// "px";
}
google.visualization.events.addListener(
chart,
"ready",
placeMarker.bind(chart, data)
);
chart.draw(data, options);
}
}
);
});
</script>
</head>
<body>
<div id="container">
<div id="curve_chart" style="width: 900px; height: 500px"></div>
<div class="min-bar"></div>
</div>
</body>
</html>
Jsfiddle demo => https://jsfiddle.net/jRubia/8z7ao1nh/
I want to hide the line in Line chart when ever the user clicks on the Line Chart legend. Is there any way that I can do it in Google Chart API ? I seen this feature on Highcharts.
Yes it is possible. Here is an example by asgallant:
function drawChart() {
var data = new google.visualization.DataTable();
data.addColumn('string', 'City');
data.addColumn('number', 'Foo');
data.addColumn('number', 'Foo');
data.addColumn('number', 'Bar');
data.addColumn('number', 'Bar');
data.addColumn('number', 'Baz');
data.addColumn('number', 'Baz');
data.addRow(['Boston', 5, null, 7, null, 2, null]);
data.addRow(['New York', 4, null, 8, null, 5, null]);
data.addRow(['Baltimore', 6, null, 2, null, 4, null]);
/* define the series object
* follows the standard 'series' option parameters, except it has two additonal parameters:
* hidden: true if the column is currently hidden
* altColor: changes the color of the legend entry (used to grey out hidden entries)
*/
var series = {
0: {
hidden: false,
visibleInLegend: false,
color: '#FF0000'
},
1: {
hidden: false,
color: '#FF0000',
altColor: '#808080'
},
2: {
hidden: false,
visibleInLegend: false,
color: '#00FF00'
},
3: {
hidden: false,
color: '#00FF00',
altColor: '#808080'
},
4: {
hidden: false,
visibleInLegend: false,
color: '#0000FF'
},
5: {
hidden: false,
color: '#0000FF',
altColor: '#808080'
}
};
var options = {
series: series,
height: 400,
width: 600
};
var view = new google.visualization.DataView(data);
var chart = new google.visualization.ColumnChart(document.getElementById('chart_div'));
google.visualization.events.addListener(chart, 'select', function () {
// if row is undefined, we clicked on the legend
if (typeof chart.getSelection()[0]['row'] === 'undefined') {
// column is the DataView column, not DataTable column
// so translate and subtract 1 to get the series index
var col = view.getTableColumnIndex(chart.getSelection()[0]['column']) - 1;
// toggle the selected column's data counterpart visibility
series[col - 1].hidden = !series[col - 1].hidden;
// swap colors
var tmpColor = series[col].color;
series[col].color = series[col].altColor;
series[col].altColor = tmpColor;
// reset the view's columns
view.setColumns([0,1,2,3,4,5,6]);
// build list of hidden columns and series options
var hiddenCols = [];
options.series = [];
for (var i = 0; i < 6; i++) {
if (series[i].hidden) {
// add 1 to the series index to get DataTable column
hiddenCols.push(i + 1);
}
else {
options.series.push(series[i]);
}
}
// hide the columns and draw the chart
view.hideColumns(hiddenCols);
chart.draw(view, options);
}
});
chart.draw(view, options);
}
Here is the solution. You can hide line in your line chart by clicking the legend.
google.visualization.events.addListener(chart, 'select', function () {
var sel = chart.getSelection();
// if selection length is 0, we deselected an element
if (sel.length > 0) {
// if row is undefined, we clicked on the legend
if (typeof sel[0].row === 'undefined') {
var col = sel[0].column;
if (columns[col] == col) {
// hide the data series
columns[col] = {
label: data.getColumnLabel(col),
type: data.getColumnType(col),
calc: function () {
return null;
}
};
// grey out the legend entry
series[col - 1].color = '#CCCCCC';
}
else {
// show the data series
columns[col] = col;
series[col - 1].color = null;
}
var view = new google.visualization.DataView(data);
view.setColumns(columns);
chart.draw(view, options);
}
}
});
Here is the working sample. jqfaq.com
As mentioned above, you can create a DataView for your DataTable and then
to show only the clicked line/column, call
view.setColumns(chart.getSelection()[0].column)
to hide the clicked line/column call
view.hideColumns(chart.getSelection()[0].column)
getSelection() will have the line/legend on the chart you have selected.
I have a Pie Charts generated by Google Chart API. The code for the chart goes as Below
google.load("visualization", "1", {packages:["corechart"]});
google.setOnLoadCallback(drawChart1);
function drawChart1()
{
var data = google.visualization.arrayToDataTable([
['Location', 'Value'],
["Location A", 20 ],
["Location B", 32],
["Location C", 12],
["Location D", 20],
["Location E", 2],
["Location F", 20],
["Location H", 10]
]);
var options = {
colors : ['#00918c', '#d0c500','#945a94', '#84ac43', '#ea8c1c', '#006daf', '#c54d4d'],
is3D : 'false',
isHTML : 'false',
height : 200,
width : 285,
backgroundColor : "transparent",
chartArea : {left:0,top:0,width:"100%",height:"100%"},
legend : {position: 'right', alignment: "end"}
};
var chart = new google.visualization.PieChart(document.getElementById('chart_div1'));
chart.draw(data, options);
}
The Link for the chart is as Below
Click to see Chart
I want to capture the event in the chart when they click any pie area.
Suppose if they click on Location A pie in pie chart I want a function that displays alert message as Location A Clicked and same for other pie's in chart.
Thanks for reply
I added the code below and its working fine now.
var chart = new google.visualization.PieChart(document.getElementById('chart_div1'));
function selectHandler()
{
var selectedItem = chart.getSelection()[0];
if (selectedItem)
{
var topping = data.getValue(selectedItem.row, 0);
alert('The user selected ' + topping);
}
}
google.visualization.events.addListener(chart, 'select', selectHandler);
chart.draw(data, options);
See the link for Binding Events in google pie chart.
<!--Div that will hold the pie chart-->
<div id="chart_div" style="width:400; height:300"></div>
<script type="text/javascript" src="https://www.google.com/jsapi"></script>
<script>
// Load the Visualization API and the piechart 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 pie chart, passes in the data and
// draws it.
function drawChart() {
// Create the data table.
var data = new google.visualization.DataTable();
data.addColumn('string', 'Topping');
data.addColumn('number', 'Slices');
data.addRows([
['Mushrooms', 3],
['Onions', 1],
['Olives', 1],
['Zucchini', 1],
['Pepperoni', 2]
]);
// Set chart options
var options = {'title':'How Much Pizza I Ate Last Night',
'width':400,
'height':300};
// Instantiate and draw our chart, passing in some options.
var chart = new google.visualization.PieChart(document.getElementById('chart_div'));
function selectHandler() {
var selectedItem = chart.getSelection()[0];
if (selectedItem) {
var topping = data.getValue(selectedItem.row, 0);
alert('The user selected ' + topping);
}
}
google.visualization.events.addListener(chart, 'select', selectHandler);
chart.draw(data, options);
} </script>
Consider drawing a column chart and I don't get any data from the data source, How do we draw an empty chart instead of showing up a red colored default message saying "Table has no columns"?
What I do is initialize my chart with 1 column and 1 data point (set to 0). Then whenever data gets added I check if there is only 1 column and that it is the dummy column, then I remove it. I also hide the legend to begin so that it doesn't appear with the dummy column, then I add it when the new column gets added.
Here is some sample code you can plug in to the Google Visualization Playground that does what I am talking about. You should see the empty chart for 2 seconds, then data will get added and the columns will appear.
var data, options, chart;
function drawVisualization() {
data = google.visualization.arrayToDataTable([
['Time', 'dummy'],
['', 0],
]);
options = {
title:"My Chart",
width:600, height:400,
hAxis: {title: "Time"},
legend : {position: 'none'}
};
// Create and draw the visualization.
chart = new google.visualization.ColumnChart(document.getElementById('visualization'));
chart.draw(data,options);
setTimeout('addData("12:00",10)',2000);
setTimeout('addData("12:10",20)',3000);
}
function addData(x,y) {
if(data.getColumnLabel(1) == 'dummy') {
data.addColumn('number', 'Your Values', 'col_id');
data.removeColumn(1);
options.legend = {position: 'right'};
}
data.addRow([x,y]);
chart.draw(data,options);
}
A even better solution for this problem might be to use a annotation column instead of a data column as shown below. With this solution you do not need to use any setTimeout or custom function to remove or hide your column. Give it a try by pasting the given code below into Google Code Playground.
function drawVisualization() {
var data = google.visualization.arrayToDataTable([
['', { role: 'annotation' }],
['', '']
]);
var ac = new google.visualization.ColumnChart(document.getElementById('visualization'));
ac.draw(data, {
title : 'Just a title...',
width: 600,
height: 400
});
}
The way I did this was by disabling the pie slices, turning off tooltips, stuffing in a pretend value and making it gray. I'm sure there are more clever ways to do this, but this worked for me where the other methods didn't.
The only drawback is that it sets both items in the legend to gray as well. I think you could perhaps just add a third item, and make it invisible on the legend only. I liked this way though.
function drawChart() {
// Define the chart to be drawn.
data = new google.visualization.DataTable();
data.addColumn({type: 'string', label: 'Result'});
data.addColumn({type: 'number', label: 'Count'});
data.addRows([
['Value A', 0],
['Value B', 0]
]);
var opt_pieslicetext = null;
var opt_tooltip_trigger = null;
var opt_color = null;
if (data.getValue(1,1) == 0 && data.getValue(0,1) == 0) {
opt_pieslicetext='none';
opt_tooltip_trigger='none'
data.setCell(1,1,.1);
opt_color= ['#D3D3D3'];
}
chart = new google.visualization.PieChart(document.getElementById('mydiv'));
chart.draw(data, {sliceVisibilityThreshold:0, pieSliceText: opt_pieslicetext, tooltip: { trigger: opt_tooltip_trigger }, colors: opt_color } );
}