I have created a donut chart from Google Charts API. When clicking on each slice, it should increase by 10 units and decrease the adjacent slice (clockwise) by 10 units. What I have thus far is a alert popup that explains this, but I would like to redraw the chart with the new values.
Here is my code:
<html>
<head>
<!--Load the AJAX API-->
<script type="text/javascript" src="https://www.google.com/jsapi"></script>
<script type="text/javascript">
// 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', 'Option');
data.addColumn('number', 'Value');
data.addRows([
['Option A', 40],
['Option B', 30],
['Option C', 30]
]);
// Set chart options
var options = {
height: 300,
fontName: 'Lato, sans-serif',
title: 'Values per option',
titleTextStyle: {
color: '#5a5a5a',
fontSize: 20,
bold: true,
align: 'center'
},
pieHole: 0.6,
slices: {
0: {color: 'red'},
1: {color: 'blue'},
2: {color: 'green'}
},
legend: {
position: 'bottom',
textStyle: {
color: '#5a5a5a',
fontSize: 14
}
},
enableInteractivity: true,
pieSliceText: 'none'
};
// 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 && selectedItem.row <2) {
var activeTrait = data.getValue(selectedItem.row, 0);
activePerc = data.getValue(selectedItem.row, 1);
activePercNew = parseInt(activePerc)+10
adjaceTrait = data.getValue(selectedItem.row+1, 0);
adjacePerc = data.getValue(selectedItem.row+1, 1);
adjacePercNew = parseInt(adjacePerc)-10
alert(activeTrait + ' has a value of ' + activePerc + '%. The new value will now be set to ' + activePercNew + '% and ' + adjaceTrait + ' will be corrected to ' + adjacePercNew + '%.');
}
if (selectedItem && selectedItem.row == 2) {
var activeTrait = data.getValue(selectedItem.row, 0);
activePerc = data.getValue(selectedItem.row, 1);
activePercNew = parseInt(activePerc)+10
adjaceTrait = data.getValue(selectedItem.row-2, 0);
adjacePerc = data.getValue(selectedItem.row-2, 1);
adjacePercNew = parseInt(adjacePerc)-10
alert(activeTrait + ' has a value of ' + activePerc + '%. The new value will now be set to ' + activePercNew + '% and ' + adjaceTrait + ' will be corrected to ' + adjacePercNew + '%.');
}
}
google.visualization.events.addListener(chart, 'select', selectHandler);
chart.draw(data, options);
}
</script>
</head>
<body>
<!--Div that will hold the pie chart-->
<div id="chart_div" style="width:800; height:300"></div>
</body>
</html>
I would just like to resize the selected and adjacent slices by clicking on a single slice. Not sure if I should create a var newdata with the changed values and use chart.draw(newdata, option)?
Yeah you're pretty much there, and you're definitely on the right track with your answer. You can use data.setValue() to adjust your values then you would have something like this in your second "if" statement:
data.setValue(selectedItem.row,1, activePercNew);
data.setValue(selectedItem.row-2,1, adjacePercNew);
chart.draw(data, options);
// the thing we just clicked on was redrawn so it lost its handler, reinstate it:
google.visualization.events.addListener(chart, 'select', selectHandler);
And the same in the first but with selectedItem.row+1 instead of selectedItem.row-2. Or, ideally, tidy that section up a little so the two if statements figure out which things you're referring to and then one bit of code does the redraw. For example, here's an adjusted handler function which also doesn't rely on there being 3 sections:
function selectHandler() {
var selectedItem = chart.getSelection()[0];
var numRows = data.getNumberOfRows();
// verify the selection isn't inexplicibly invalid
if (selectedItem && selectedItem.row < numRows && selectedItem.row >= 0) {
// find the two items we're looking at
var curItem = selectedItem.row;
// we either want selected.row + 1 or we want 0 if the selected item was the last one
var otherItem = selectedItem.row == numRows - 1 ? 0 : selectedItem.row + 1;
// calculate the new values
var activePerc = data.getValue(curItem , 1);
var activePercNew = parseInt(activePerc)+10;
var adjacePerc = data.getValue(otherItem , 1);
var adjacePercNew = parseInt(adjacePerc )-10;
// update the chart
data.setValue(curItem,1, activePercNew);
data.setValue(otherItem,1, adjacePercNew);
chart.draw(data, options);
// the thing we just clicked on was redrawn so it lost its handler, reinstate it:
google.visualization.events.addListener(chart, 'select', selectHandler);
}
}
You might want to then also consider what should happen if a value is forced right to zero - with this solution it'll disappear from the chart, and then the next click will force an invalid negative value.
Related
In Google Charts, the 'hAxis': {'gridlines': {'count': 3} } statement seems to work, but when I'm using chartWrapper as part of an interactive plot, it does not. I don't really care about vertical gridlines, but I want to control how many labels are on the X axis. I think labels are usually attached to gridlines - one label per gridline.
I have an example from the Google Charts website, where the only thing I changed was to put try and put in 3 gridlines:
https://jsfiddle.net/emorris/gLcq1h2j/
chart option ticks is only supported by a continuous axis
in the fiddle you shared, the view placed on the chart,
converts the first column from type 'date' to 'string',
which results in a discrete axis
// Convert the first column from 'date' to 'string'.
'view': {
'columns': [{
'calc': function(dataTable, rowIndex) {
return dataTable.getFormattedValue(rowIndex, 0);
},
'type': 'string'
}, 1, 2, 3, 4]
}
to control how many labels are on the X axis, remove the view
to build the ticks dynamically here, use the state of the range filter,
to know the date range currently displayed on the chart
the chart will need to be redrawn when the control's 'statechange' event fires
see following working snippet, an axis label is created for every 5 days...
google.charts.load('current', {
callback: drawChartRangeFilter,
packages: ['corechart', 'controls']
});
function drawChartRangeFilter() {
var data = new google.visualization.DataTable();
data.addColumn('date', 'Date');
data.addColumn('number', 'Stock low');
data.addColumn('number', 'Stock open');
data.addColumn('number', 'Stock close');
data.addColumn('number', 'Stock high');
var open, close = 300;
var low, high;
for (var day = 1; day < 121; ++day) {
var change = (Math.sin(day / 2.5 + Math.PI) + Math.sin(day / 3) - Math.cos(day * 0.7)) * 150;
change = change >= 0 ? change + 10 : change - 10;
open = close;
close = Math.max(50, open + change);
low = Math.min(open, close) - (Math.cos(day * 1.7) + 1) * 15;
low = Math.max(0, low);
high = Math.max(open, close) + (Math.cos(day * 1.3) + 1) * 15;
var date = new Date(2012, 0, day);
data.addRow([date, Math.round(low), Math.round(open), Math.round(close), Math.round(high)]);
}
var dashboard = new google.visualization.Dashboard(
document.getElementById('dashboard')
);
var control = new google.visualization.ControlWrapper({
controlType: 'ChartRangeFilter',
containerId: 'control',
options: {
filterColumnIndex: 0,
ui: {
chartType: 'LineChart',
chartOptions: {
chartArea: {
width: '92%'
},
hAxis: {
baselineColor: 'none'
},
height: 72
},
chartView: {
columns: [0, 3]
},
minRangeSize: 86400000
}
},
state: {
range: {
start: new Date(2012, 1, 9),
end: new Date(2012, 2, 20)
}
}
});
var chart = new google.visualization.ChartWrapper({
chartType: 'CandlestickChart',
containerId: 'chart',
options: {
chartArea: {
height: '100%',
width: '100%',
top: 12,
left: 48,
bottom: 48,
right: 48
},
vAxis: {
viewWindow: {
min: 0,
max: 2000
}
},
legend: {
position: 'none'
}
}
});
google.visualization.events.addListener(control, 'statechange', setAxisTicks);
function setAxisTicks() {
var oneDay = (1000 * 60 * 60 * 24);
var dateRange = control.getState().range;
var ticksAxisH = [];
for (var i = dateRange.start.getTime(); i <= dateRange.end.getTime(); i = i + (oneDay * 5)) {
ticksAxisH.push(new Date(i));
}
if (ticksAxisH.length > 0) {
ticksAxisH.push(new Date(ticksAxisH[ticksAxisH.length - 1].getTime() + (oneDay * 5)));
}
chart.setOption('hAxis.ticks', ticksAxisH);
if (chart.getDataTable() !== null) {
chart.draw();
}
}
setAxisTicks();
dashboard.bind(control, chart);
drawDashboard();
$(window).resize(drawDashboard);
function drawDashboard() {
dashboard.draw(data);
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="dashboard">
<div id="chart"></div>
<div id="control"></div>
</div>
Using the following code to save a Google chart. But it is getting downloaded as a file and not an image, it was throwing following
"Resource interpreted as Document but transferred with MIME type image/octet-stream: "data:image/octet-stream;base64,..."
And the code:
function getImgData(chartContainer) {
var chartArea = chartContainer.getElementsByTagName('div')[1];
var svg = chartArea.innerHTML;
var doc = chartContainer.ownerDocument;
var canvas = doc.createElement('canvas');
canvas.setAttribute('width', chartArea.offsetWidth);
canvas.setAttribute('height', chartArea.offsetHeight);
canvas.setAttribute(
'style',
'position: absolute; ' +
'top: ' + (-chartArea.offsetHeight * 2) + 'px;' +
'left: ' + (-chartArea.offsetWidth * 2) + 'px;');
doc.body.appendChild(canvas);
canvg(canvas, svg);
var imgData = canvas.toDataURL("image/png");
canvas.parentNode.removeChild(canvas);
return imgData;
}
function saveAsImg(chartContainer) {
var imgData = getImgData(chartContainer);
window.location = imgData.replace("image/png", "image/octet-stream");
}
you can use an anchor tag with a download attribute to assign the file name
and most charts have a getImageURI method
also, don't see the need to replace("image/png", "image/octet-stream")
see following working snippet...
google.charts.load('current', {
callback: function () {
var chart = new google.visualization.PieChart(document.getElementById('chart_div'));
google.visualization.events.addListener(chart, 'ready', function () {
// set anchor tag
var saveLink = document.getElementById('saveLink');
saveLink.href = chart.getImageURI();
// cause download to occur
saveLink.click();
});
chart.draw(google.visualization.arrayToDataTable([
['Task', 'Hours'],
['A', 19.2],
['B', 30.8],
['C', 50.0]
]), {
height: 200,
chartArea: {
top: 24
},
legend: 'none',
pieHole: 0.4,
theme: 'maximized',
width: 200
});
},
packages: ['corechart']
});
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="chart_div"></div>
<a id="saveLink" download="chart.png">Save Chart</a>
i'm using Chart.js to build a line graph by specific directions from a designer, and I want my tooltip to include a small icon.
is it possible ?
You can override the customTooltips function.
var myLineChart = new Chart(ctx).Line(data, {
customTooltips: function (tooltip) {
var tooltipEl = $('#chartjs-tooltip');
if (!tooltip) {
tooltipEl.css({
opacity: 0
});
return;
}
tooltipEl.removeClass('above below');
tooltipEl.addClass(tooltip.yAlign);
// split out the label and value and make your own tooltip here
var parts = tooltip.text.split(":");
var innerHtml = '<img src="pathTomyImage/myImage.png"> <span>' + parts[0].trim() + '</span> : <span><b>' + parts[1].trim() + '</b></span>';
tooltipEl.html(innerHtml);
tooltipEl.css({
opacity: 1,
left: tooltip.chart.canvas.offsetLeft + tooltip.x + 'px',
top: tooltip.chart.canvas.offsetTop + tooltip.y + 'px',
fontFamily: tooltip.fontFamily,
fontSize: tooltip.fontSize,
fontStyle: tooltip.fontStyle,
});
}
});
Replace pathTomyImage/myImage.png with your image URL (you could also pick this from a lookup using parts[0] - which is the x axis label, or easier still give your images a name depending on the axis label. eg. January.png, February.png)
Make sure you add the following markup as well
<div id="chartjs-tooltip"></div>
Fiddle - http://jsfiddle.net/02xrgy10/
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>