Stacked column Google chart overlapping label inside the column - google-visualization

I'm using stacked column google chart but annotation or label of each column of graph is overlapping as like the image below:
My code is as below:
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head>
<body>
<div id="chart_divgraph" style="width: 750px; height:500px;"></div>
<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
<script language="javascript">
google.charts.load('current', {'packages':['corechart']});
google.charts.setOnLoadCallback(drawVisualization32);
function drawVisualization32() {
// Some raw data (not necessarily accurate)
/*var jsonData = $.ajax({
url: "getndata.php?cntnew=Ghatwar",
dataType: "json",
async: false
}).responseText;*/
// Create our data table out of JSON data loaded from server.
var data = new google.visualization.DataTable({"cols":[{"id":"","label":"Caste Section","pattern":"","type":"string"},{"id":"","label":"Private","pattern":"","type":"number"},{"id":"","label":"Community","pattern":"","type":"number"},{"id":"","label":"Open Defecation","pattern":"","type":"number"}],"rows":[{"c":[{"v":"SC","f":null},{"v":"0","f":null},{"v":"1","f":null},{"v":"47","f":null}]},{"c":[{"v":"ST","f":null},{"v":"3","f":null},{"v":"7","f":null},{"v":"51","f":null}]},{"c":[{"v":"OBC","f":null},{"v":"5","f":null},{"v":"6","f":null},{"v":"84","f":null}]},{"c":[{"v":"GEN","f":null},{"v":"17","f":null},{"v":"1","f":null},{"v":"26","f":null}]}],"p":null});
var view = new google.visualization.DataView(data);
view.setColumns([0, 1,
{ calc: getpercentage,
sourceColumn: 1,
type: "string",
role: "annotation" },
2,
{ calc: getpercentagesecond,
sourceColumn: 2,
type: "string",
role: "annotation" },
3,
{ calc: getpercentagethird,
sourceColumn: 3,
type: "string",
role: "annotation" }])
function getpercentage(data, rowNum){
var firstval = data.getValue(rowNum, 1)
var secondval = data.getValue(rowNum, 2)
var thirdval = data.getValue(rowNum, 3)
var datavalueplus = parseInt(firstval) + parseInt(secondval) + parseInt(thirdval);
var finalpercentage = Math.abs( (firstval/datavalueplus)*100 ) ;
var numb = finalpercentage.toFixed(2);
return (numb + "%");
}
function getpercentagesecond(data, rowNum){
var firstval = data.getValue(rowNum, 1)
var secondval = data.getValue(rowNum, 2)
var thirdval = data.getValue(rowNum, 3)
var datavalueplus = parseInt(firstval) + parseInt(secondval) + parseInt(thirdval);
var finalpercentage = Math.abs( (secondval/datavalueplus)*100 ) ;
var numb = finalpercentage.toFixed(2);
return (numb + "%");
}
function getpercentagethird(data, rowNum){
var firstval = data.getValue(rowNum, 1)
var secondval = data.getValue(rowNum, 2)
var thirdval = data.getValue(rowNum, 3)
var datavalueplus = parseInt(firstval) + parseInt(secondval) + parseInt(thirdval);
var finalpercentage = Math.abs( (thirdval/datavalueplus)*100 ) ;
var numb = finalpercentage.toFixed(2);
return (numb + "%");
}
var options = {
title : 'Use of toilets across different prevailing caste section in village',
seriesType: 'bars',
/* width: 600,
height: 400,*/
/* bar: { groupWidth: 20 }, */
vAxis: {
/*minValue: 0,*/
/* scaleType: 'mirrorLog',*/
viewWindowMode:'pretty',
},
isStacked:"percent"
};
var chart = new google.visualization.ComboChart(document.getElementById('chart_divgraph'));
chart.draw(view, options);
}
</script>
</body>
</html>
I tried various solution on stackoverflow but didn't get result. Can any one help my on this please? Thanks in advance

Related

How to add vertical lines and annotations Google timeline chart

I am using a google timeline similar to the code snippet below. I want my chart to look like the one below. I have managed to get everything to work expect how to add the dashed lines and text notation. Unfortunately, when I am searching for annotations I keep getting the AnnotatedTimeline, which is a different google chart.
Is there a simple way to do this?
<html>
<head>
<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
<script type="text/javascript">
google.charts.load('current', {'packages':['timeline']});
google.charts.setOnLoadCallback(drawChart);
function drawChart() {
var container = document.getElementById('timeline');
var chart = new google.visualization.Timeline(container);
var dataTable = new google.visualization.DataTable();
dataTable.addColumn({ type: 'string', id: 'President' });
dataTable.addColumn({ type: 'date', id: 'Start' });
dataTable.addColumn({ type: 'date', id: 'End' });
dataTable.addRows([
[ 'Washington', new Date(1789, 3, 30), new Date(1797, 2, 4) ],
[ 'Adams', new Date(1797, 2, 4), new Date(1801, 2, 4) ],
[ 'Jefferson', new Date(1801, 2, 4), new Date(1809, 2, 4) ]]);
chart.draw(dataTable);
}
</script>
</head>
<body>
<div id="timeline" style="height: 180px;"></div>
</body>
</html>
I was able to get this to work by finding the position of the rects. I started by drawing divs for each line I would want to show. Then after the timeline is draw I repositions those divs based on the location of the rectangle. I was not able to get a good minimal working snippet here because of the window positions used in the snippet code, but I got pretty close. In my own code I have it working perfectly.
.hline {
border-left: 5px solid black;
height: 100px;
position:absolute;
visibility:hidden;
top:144px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<html>
<head>
<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
</head>
<body>
<div id="timeline" style="height: 180px;"></div>
<div id = "Hline1" class= "hline" > <div style = "position: relative; top:-18px">HLine1</div>
<div id = "Hline2" class= "hline" > <div style = "position: relative; top:-18px">HLine2</div>
<div id = "Hline3" class= "hline" > <div style = "position: relative; top:-18px">HLine3</div>
</div>
</body>
<script>
var options = {
timeline: { showRowLabels: false }
};
const lime="#00ff00" //color for average time
google.charts.load('current', {'packages':['timeline']});
google.charts.setOnLoadCallback(drawChart);
function drawChart() {
var container = document.getElementById('timeline');
var chart = new google.visualization.Timeline(container);
var dataTable = new google.visualization.DataTable();
dataTable.addColumn({ type: 'string', id: 'Project Stage', });
dataTable.addColumn({ type: 'string', id: 'Bar'});
dataTable.addColumn({ type: 'string', role: 'style'});
dataTable.addColumn({ type: 'date', id: 'Start' });
dataTable.addColumn({ type: 'date', id: 'End' });
dataTable.addRows([
[ 'Washington','Washington',lime, new Date(1789, 3, 30), new Date(1797, 2, 4) ],
[ 'Adams', 'Adams',lime, new Date(1797, 2, 4), new Date(1801, 2, 4) ],
[ 'Jefferson','Jefferson',lime, new Date(1801, 2, 4), new Date(1809, 2, 4) ]]);
chart.draw(dataTable,options);
function redraw (){
var rects = $('rect') //get all rectangles on plot.
function checkColor(arr){
var results = [];
for (let i of arr){
var colorCheck=$(i).attr('fill')
var x =$(i).attr('x')
var width = $(i).attr('width')
var x2 =parseFloat(x)+parseFloat(width)
if(colorCheck == lime){results.push(x2)}
};
return results
};
var linPositions = checkColor(rects) //get x coordinates for vertical lines
var yStart = $('rect')
//console.log(linPositions)
yStart = $(yStart[0]).offset().top;
xMargin=$("#timeline").offset().left;
var yHeight = $('rect')
yHeight = $(yHeight[0]).attr('height');
var lineNames=['Hline1','Hline2','Hline3']
for (let i = 0; i < linPositions.length; i++) {
var position = linPositions[i]+xMargin+"px"
var newTop = i*yHeight + yStart
/* set line information based on current chart positions */
document.getElementById(lineNames[i]).style.left = position;
document.getElementById(lineNames[i]).style.visibility = "visible";
document.getElementById(lineNames[i]).style.top = newTop;
document.getElementById(lineNames[i]).style.height = yHeight;
};
};
redraw()
function resizeChart () {
chart.draw(dataTable, options);
}
if (document.addEventListener) {
window.addEventListener('resize', resizeChart);
window.addEventListener('resize', redraw)
}
else if (document.attachEvent) {
window.attachEvent('onresize', resizeChart);
window.attachEvent('onresize', redraw);
}
else {
window.resize = resizeChart;
window.resize = redraw;
}
}
</script>
</html>

Chart.js usage error (v2.4)

I'm now working on chart.js(V2.4) and I have some problems.
I've looked up a lot of similar issues/questions but none of it solves my problem.
Error in console log shows: "Chart.controllers[meta.type] is not a constructor"
Here's my code:
<!DOCTYPE html>
<html>
<head>
<title>test</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.4.0/Chart.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.js"></script>
</head>
<body>
<label style="margin-left:3%;">X : </label>
<select id="selectxfield" style="width:20%;margin-top:2%;margin-left:1%;display:inline;">
<option>player</option>
</select>
<label style="margin-left:3%;">Y : </label>
<select name="selectyfield" style="width:20%;margin-left:1%;display:inline;">
<option>ppg</option>
</select>
<button id="btnchart" style="margin-left:3%;">Submit</button>
<canvas id="areaChart" style="height:250px"></canvas>
<canvas id="lineChart" style="height:250px"></canvas>
<canvas id="barChart" style="height:250px"></canvas>
</body>
<script type="text/javascript">
$(function () {
// This will get the first returned node in the jQuery collection.
function isEmpty(obj){
for(var key in obj){
if(obj.hasOwnProperty(key))
return false;
}
return true;
}
function randomColor() {
var colorVal = "rgb(";
for(i = 0; i < 3; i++) {
colorVal += Math.round(250*Math.random());
if (i < 2) {
colorVal += ",";
}
}
colorVal += ")";
return colorVal;
}
$('#btnchart').click(function(){
var jsdata = '{"name": "2011NBA.csv", "resource_id": "pao3ckw7b3lj8eh4ad0899oiy", "success": "true", "records": [{"id": 1, "player": "LeBron James", "division": "East", "ppg": "27.1", "rpg": "7.9", "apg": "6.2", "blk": "0.81", "stl": "1.85"}, {"id": 2, "player": "Kevin Durant", "division": "West", "ppg": "28", "rpg": "8", "apg": "3.5", "blk": "1.17", "stl": "1.33"}, {"id": 3, "player": "Dwight Howard", "division": "East", "ppg": "20.6", "rpg": "14.5", "apg": "1.9", "blk": "2.15", "stl": "1.5"}, {"id": 4, "player": "Christ Paul", "division": "West", "ppg": "19.8", "rpg": "3.6", "apg": "9.1", "blk": "0.07", "stl": "2.53"}, {"id": 5, "player": "Derrick Rose", "division": "East", "ppg": "21.8", "rpg": "3.4", "apg": "7.9", "blk": "0.72", "stl": "0.9"}]}'
var data = JSON.parse(jsdata);
var x = []; // use array to save the field's name
var y = []; // use array to save data
var xf = $( "#selectxfield option:selected" ).text();// get selected value
$.each(data.records, function(i, v) {
x.push(v[xf]);
});
var areaChartData = {
labels: x,
datasets: []
};
var selectyfield = document.getElementsByName('selectyfield') // selectyfield can be added dynamically in my code, but I set it to one just for debug convenience
var dt = data.records;
for (j=0;j<selectyfield.length;j++){
var color = randomColor();
var index = selectyfield[j].selectedIndex;
var k = selectyfield[j].options[index].text;
$.each(data.records, function(ky, vl) {
y.push(parseFloat(vl[k]));
});
if (isEmpty(data.records)){
$.each(dt, function(ky, vl) {
y.push(parseFloat(vl[k]));
});
}
var data ={
label: k,
fillColor: color,
strokeColor: color,
pointColor: color,
pointStrokeColor: "#c1c7d1",
pointHighlightFill: "#fff",
pointHighlightStroke: "rgba(220,220,220,1)",
data: y
}
areaChartData["datasets"].push(data);
y = [];
}
var areaChartOptions = {
// a lot of options
};
var barChartOptions = {
// a lot of options
};
var area = document.getElementById("areaChart")
var areaChartCanvas = area.getContext("2d");
var areaChart = new Chart(areaChartCanvas,{
type: "area",
data: areaChartData,
options: areaChartOptions
});
var line = document.getElementById("lineChart")
var lineChartCanvas = line.getContext("2d");
var lineChartOptions = areaChartOptions;
var lineChartData = areaChartData;
lineChartOptions.datasetFill = false;
var lineChart = new Chart(lineChartCanvas,{
type: "line",
data: lineChartData,
options: lineChartOptions
});
var bar = document.getElementById("barChart")
var barChartCanvas = bar.getContext("2d");
var barChartData = areaChartData;
barChartOptions.datasetFill = false;
var lineChart = new Chart(barChartCanvas,{
type: "bar",
data: barChartData,
options: barChartOptions
});
});
});
</script>
</html>
The select field is fixed just for convenience.
I am sure the code works fine in older chart.js (v1.X), I just have to change some code usage above.
Hope someone can help me finding the error, thanks
Few days later, I finally reached the contributors and members of chart.js.
They helped me and pointed out that there's no chart type named "area".
After deleting that part, the code works fine.
It's still strange that the debug message didn't show relative information but something not correlated to.
I just hit a similar problem. Looking into the source, it seems Chart.controllers is an object with all the different types of chart as properties. meta.type is whatever you pass as type in the options hash to the new Chart() constructor. So in your case it was complaining that Chart.controllers["area"] is not a constructor.
I appreciate that you've already found the answer to your specific problem, but I thought it would be worth expanding on this because (a) as you pointed out, the debug message is a bit unhelpful by itself, and (b) this might help anyone who has similar difficulties (for example, in my case I put in "Line" instead of "line" and if I'd understood what the error message actually meant it would have saved me a bit of digging).

Grid lines on google charts are not rendering as per data

Link to jsFiddle
google.charts.load('current', {
'packages': ['corechart']
});
//Input data
var data = [
['Data', 'CAT1', 'CAT2', 'CAT3', 'CAT4'],
['Provisions', 5, 0, 0, 0],
];
// Set a callback to run when the Google Visualization API is loaded.
google.charts.setOnLoadCallback(drawChart);
// Callback that creates and populates a data table,
// instantiates the pie chart, passes in the data and
// draws it.
function drawChart() {
var options = {
colors: ['#00699B', '#087EB4', '#CBE7F7', '8A6996'],
isStacked: true,
chartArea: {
width: '40%'
},
bar: {
groupWidth: "40%"
},
// tooltip: { isHtml: true },
trigger: 'both',
vAxis: {
gridlines: {
color: '#0000006b',
minValue: 0,
baseline: 0
},
format: "$ #,###"
},
};
var dataTable = google.visualization.arrayToDataTable(data);
//Formatters
var intergerFormatter = new google.visualization.NumberFormat({
groupingSymbol: ",",
fractionDigits: 0
});
for (var i = 0; i < data[0].length; i++) {
intergerFormatter.format(dataTable, i);
}
var view = new google.visualization.DataView(dataTable);
var cols =   [0];
for (var i = 1; i < data[0].length; i++) {
cols.push({
sourceColumn: i,
type: "number",
label: data[0][i]
});
cols.push({
calc: createTooltip(i),
type: "string",
role: "tooltip",
});
}
view.setColumns(cols);
var chart = new google.visualization.ColumnChart(document.getElementById('provision_chart'));
chart.draw(view, options);
function createTooltip(col) {
return function(dataTable, row) {
var html = dataTable.getColumnLabel(col) + ":" + "\n";
html += "4 " + dataTable.getValue(row, 0) + "\n";
html += "$ " + intergerFormatter.formatValue(dataTable.getValue(row, col)) + " total" + "\n";
return html;
};
}
}
The grid lines on a stacked bar type google charts are not rendering properly.
As per the data, $5 is recorded against Category1, but when it's rendered the bar is slightly over $5.
Can someone suggest a fix?
removing the option --> format: "$ #,###" -- reveals the problem
although the tick mark displays --> $ 5 -- the actual number used is 4.5
see following working snippet...
google.charts.load('current', {
'packages': ['corechart']
});
//Input data
var data = [
['Data', 'CAT1', 'CAT2', 'CAT3', 'CAT4'],
['Provisions', 5, 0, 0, 0],
];
// Set a callback to run when the Google Visualization API is loaded.
google.charts.setOnLoadCallback(drawChart);
// Callback that creates and populates a data table,
// instantiates the pie chart, passes in the data and
// draws it.
function drawChart() {
var options = {
colors: ['#00699B', '#087EB4', '#CBE7F7', '8A6996'],
isStacked: true,
chartArea: {
width: '40%'
},
bar: {
groupWidth: "40%"
},
// tooltip: { isHtml: true },
trigger: 'both',
vAxis: {
gridlines: {
color: '#0000006b',
minValue: 0,
baseline: 0
},
//format: "$ #,###"
},
};
var dataTable = google.visualization.arrayToDataTable(data);
//Formatters
var intergerFormatter = new google.visualization.NumberFormat({
groupingSymbol: ",",
fractionDigits: 0
});
for (var i = 0; i < data[0].length; i++) {
intergerFormatter.format(dataTable, i);
}
var view = new google.visualization.DataView(dataTable);
var cols =   [0];
for (var i = 1; i < data[0].length; i++) {
cols.push({
sourceColumn: i,
type: "number",
label: data[0][i]
});
cols.push({
calc: createTooltip(i),
type: "string",
role: "tooltip",
});
}
view.setColumns(cols);
var chart = new google.visualization.ColumnChart(document.getElementById('provision_chart'));
chart.draw(view, options);
function createTooltip(col) {
return function(dataTable, row) {
var html = dataTable.getColumnLabel(col) + ":" + "\n";
html += "4 " + dataTable.getValue(row, 0) + "\n";
html += "$ " + intergerFormatter.formatValue(dataTable.getValue(row, col)) + " total" + "\n";
return html;
};
}
}
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="provision_chart" style="width: 500px; height: 500px;"></div>
to correct, you can add a decimal place to the format --> $ #,##0.0
or provide your own vAxis.ticks in an array --> [0, 1, 2, 3, 4, 5, 6]
see following working snippet...
google.charts.load('current', {
'packages': ['corechart']
});
//Input data
var data = [
['Data', 'CAT1', 'CAT2', 'CAT3', 'CAT4'],
['Provisions', 5, 0, 0, 0],
];
// Set a callback to run when the Google Visualization API is loaded.
google.charts.setOnLoadCallback(drawChart);
// Callback that creates and populates a data table,
// instantiates the pie chart, passes in the data and
// draws it.
function drawChart() {
var options = {
colors: ['#00699B', '#087EB4', '#CBE7F7', '8A6996'],
isStacked: true,
chartArea: {
width: '40%'
},
bar: {
groupWidth: "40%"
},
// tooltip: { isHtml: true },
trigger: 'both',
vAxis: {
gridlines: {
color: '#0000006b',
minValue: 0,
baseline: 0
},
format: "$ #,###",
ticks: [0, 1, 2, 3, 4, 5, 6]
},
};
var dataTable = google.visualization.arrayToDataTable(data);
//Formatters
var intergerFormatter = new google.visualization.NumberFormat({
groupingSymbol: ",",
fractionDigits: 0
});
for (var i = 0; i < data[0].length; i++) {
intergerFormatter.format(dataTable, i);
}
var view = new google.visualization.DataView(dataTable);
var cols =   [0];
for (var i = 1; i < data[0].length; i++) {
cols.push({
sourceColumn: i,
type: "number",
label: data[0][i]
});
cols.push({
calc: createTooltip(i),
type: "string",
role: "tooltip",
});
}
view.setColumns(cols);
var chart = new google.visualization.ColumnChart(document.getElementById('provision_chart'));
chart.draw(view, options);
function createTooltip(col) {
return function(dataTable, row) {
var html = dataTable.getColumnLabel(col) + ":" + "\n";
html += "4 " + dataTable.getValue(row, 0) + "\n";
html += "$ " + intergerFormatter.formatValue(dataTable.getValue(row, col)) + " total" + "\n";
return html;
};
}
}
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="provision_chart" style="width: 500px; height: 500px;"></div>
the getColumnRange(colIndex) method can assist in building the ticks dynamically
the method returns an object {} with properties for min and max for the column index provided
see following working snippet for an example...
google.charts.load('current', {
'packages': ['corechart']
});
//Input data
var data = [
['Data', 'CAT1', 'CAT2', 'CAT3', 'CAT4'],
['Provisions', 5, 0, 0, 0],
];
// Set a callback to run when the Google Visualization API is loaded.
google.charts.setOnLoadCallback(drawChart);
// Callback that creates and populates a data table,
// instantiates the pie chart, passes in the data and
// draws it.
function drawChart() {
var options = {
colors: ['#00699B', '#087EB4', '#CBE7F7', '8A6996'],
isStacked: true,
chartArea: {
width: '40%'
},
bar: {
groupWidth: "40%"
},
// tooltip: { isHtml: true },
trigger: 'both',
vAxis: {
gridlines: {
color: '#0000006b',
minValue: 0,
baseline: 0
},
format: "$ #,###"
},
};
var dataTable = google.visualization.arrayToDataTable(data);
//Formatters
var intergerFormatter = new google.visualization.NumberFormat({
groupingSymbol: ",",
fractionDigits: 0
});
for (var i = 0; i < data[0].length; i++) {
intergerFormatter.format(dataTable, i);
}
var view = new google.visualization.DataView(dataTable);
var cols = [0];
var ticksY = [];
var maxY = null;
var minY = null;
for (var i = 1; i < view.getNumberOfColumns(); i++) {
var range = view.getColumnRange(i);
if (maxY === null) {
maxY = Math.ceil(range.max);
} else {
maxY = Math.max(maxY, Math.ceil(range.max));
}
if (minY === null) {
minY = Math.floor(range.min);
} else {
minY = Math.min(minY, Math.floor(range.min));
}
}
for (var i = minY; i <= maxY + 1; i++) {
ticksY.push(i);
}
options.vAxis.ticks = ticksY;
for (var i = 1; i < data[0].length; i++) {
cols.push({
sourceColumn: i,
type: "number",
label: data[0][i]
});
cols.push({
calc: createTooltip(i),
type: "string",
role: "tooltip",
});
}
view.setColumns(cols);
var chart = new google.visualization.ColumnChart(document.getElementById('provision_chart'));
chart.draw(view, options);
function createTooltip(col) {
return function(dataTable, row) {
var html = dataTable.getColumnLabel(col) + ":" + "\n";
html += "4 " + dataTable.getValue(row, 0) + "\n";
html += "$ " + intergerFormatter.formatValue(dataTable.getValue(row, col)) + " total" + "\n";
return html;
};
}
}
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="provision_chart" style="width: 500px; height: 500px;"></div>

Resource interpreted as Document but transferred with MIME type image/octet-stream

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>

Google halfdonut pie chart: is it possible to set total percentage?

I made half a donut chart with Google charts and I have a problem that the sum of visible percentage is equal to 50%. Is there any possible solution ?
Image of my chart
you can override the text displayed on the slice by using the following config option...
pieSliceText: 'value'
then in the data, set the formatted value of the cells to the correct percentage...
var data = [
['Task', 'Hours'],
// use formatted values
['A', {v: 19.2, f: '38.4%'}],
['B', {v: 30.8, f: '61.6%'}],
[null, 50]
];
the following working snippet uses the same approach,
but calculates the correct percentages,
rather than hard-coding...
google.charts.load('current', {
callback: function () {
var data = [
['Task', 'Hours'],
['A', 19.2],
['B', 30.8],
[null, 50.0]
];
var total = 0;
for (var i = 1; i < data.length; i++) {
if (data[i][0] !== null) {
total += data[i][1];
}
}
var numberFormat = new google.visualization.NumberFormat({
pattern: '#,##0.0',
suffix: '%'
});
var dataTable = google.visualization.arrayToDataTable(data);
for (var i = 0; i < dataTable.getNumberOfRows(); i++) {
if (dataTable.getValue(i, 0) !== null) {
dataTable.setFormattedValue(i, 1, numberFormat.formatValue(((dataTable.getValue(i, 1) / total) * 100)));
}
}
var chart = new google.visualization.PieChart(document.getElementById('chart_div'));
var options = {
height: 400,
chartArea: {
top: 24
},
colors: ['#8BC34A', '#64B5F6'],
legend: 'none',
pieHole: 0.4,
pieStartAngle: 270,
pieSliceText: 'value',
slices: {
2: {
color: 'transparent'
}
},
theme: 'maximized',
width: 400
};
chart.draw(dataTable, options);
},
packages: ['corechart']
});
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="chart_div"></div>