So I am trying to make html axis labels in google charts. However there does not seem to be any support for creating the axis labels or the title as HTML objects. The title is easy enough to fix, just add it in as a separate HTML object to the page, but the axis labels are more challenging. Has anyone been able to do this? As an example the below jsfiddle should show what happens when you attempt to use simple sub and sup html tags.
https://jsfiddle.net/jqmya8j9/1/
google.charts.load('current', {packages: ['corechart']});
google.charts.setOnLoadCallback(function () {
var data = [['X','Y']], i, options,
chart, dataTable;
for (i = 0; i < 20; i += 1) {
data.push([i, i * i]);
}
dataTable =
google.visualization.arrayToDataTable(data);
options = {
legend: 'none',
title: 'X<sub>m</sub> versus X<sup>2</sup>',
//best guess, does nothing
titleTextStyle: {isHtml: true},
hAxis: {title: 'X<sub>m</sub>'},
vAxis: {title: 'X<sup>2</sup>'}
};
chart = new
google.visualization.ScatterChart(document.body);
chart.draw(dataTable, options);
});
Based on the below answer (Thanks!), and what I am actually doing, I wrote the following general rule for this using _{} and ^{} instead of < sub > and < sup >
https://jsfiddle.net/jqmya8j9/2/
google.charts.load('current', {packages: ['corechart']});
google.charts.setOnLoadCallback(function () {
var data = [['X','Y']], i, options,
chart, dataTable;
for (i = 0; i < 20; i += 1) {
data.push([i, i * i]);
}
dataTable =
google.visualization.arrayToDataTable(data);
options = {
legend: 'none',
title: 'X_{m} versus X^2',
hAxis: {title: 'X_m'},
vAxis: {title: 'X^{2}'}
};
chart = new
google.visualization.ScatterChart(document.body);
google.visualization.events.addListener(chart, 'ready', function () {
$.each($('text'), function (index, label) {
var labelText = $(label).text();
if (labelText.match(/_|\^/)) {
labelText = labelText.replace(/_([^\{])|_\{([^\}]*)\}/g, '<tspan style="font-size: smaller;" baseline-shift="sub">$1$2</tspan>')
labelText = labelText.replace(/\^([^\{])|\^\{([^\}]*)\}/g, '<tspan style="font-size: smaller;" baseline-shift="super">$1$2</tspan>')
$(label).html(labelText);
}
});
});
chart.draw(dataTable, options);
});
the labels will only accept text...
the chart is drawn with svg, which can be changed manually when the 'ready' event fires
the labels will be <text> elements
to change the font style inline, use svg <tspan> elements within <text>
e.g.
<text>X<tspan baseline-shift="super">m</tspan></text>
see following working snippet...
google.charts.load('current', {
callback: function () {
var data = [['X','Y']], i, options,
chart, dataTable;
for (i = 0; i < 20; i += 1) {
data.push([i, i * i]);
}
dataTable = google.visualization.arrayToDataTable(data);
options = {
legend: 'none',
title: 'Xm versus X2',
hAxis: {title: 'Xm'},
vAxis: {title: 'X2'}
};
chart = new google.visualization.ScatterChart(document.getElementById('chart_div'));
google.visualization.events.addListener(chart, 'ready', function () {
$.each($('text'), function (index, label) {
var labelText = $(label).text();
if (labelText.indexOf('X') > -1) {
labelText = labelText.replace(new RegExp(/m/g), '<tspan baseline-shift="super">m</tspan>');
labelText = labelText.replace(new RegExp(/2/g), '<tspan baseline-shift="super">2</tspan>');
$(label).html(labelText);
}
});
});
chart.draw(dataTable, options);
},
packages: ['corechart']
});
<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="chart_div"></div>
Related
I am facing a problem that I cannot custom the default legend color of this chart to multiple colors, please help me.
This is image describe my problem , I am using stacked bar chart. This is my code:
//dump data arr
var data = google.visualization.arrayToDataTable([[["","0 times (never)",{"role":"style"},"1 times",{"role":"style"},"2 times",{"role":"style"},"3 times or more",{"role":"style"}],["A class",0.581,"#b4ddfd",0.109,"#84bfef",0.21,"#559ad2",0.1,"#4277a1"],["nationality",0.481,"#ffddba",0.209,"#ffc384",0.25,"#ffac5b",0.06,"#fa993f"]],[["","0 times (never)",{"role":"style"},"1 times",{"role":"style"},"2 times",{"role":"style"},"3 times or more",{"role":"style"}],["A class",0.1,"#b4ddfd",0.2,"#84bfef",0.3,"#559ad2",0.4,"#4277a1"],["nationality",0.4,"#ffddba",0.3,"#ffc384",0.2,"#ffac5b",0.1,"#fa993f"]],[["","0 times (never)",{"role":"style"},"1 times",{"role":"style"},"2 times",{"role":"style"},"3 times or more",{"role":"style"}],["A class",0.5,"#b4ddfd",0.5,"#84bfef",0,"#559ad2",0,"#4277a1"],["nationality",0,"#ffddba",0,"#ffc384",0,"#ffac5b",1,"#fa993f"]],[["","0 times (never)",{"role":"style"},"1 times",{"role":"style"},"2 times",{"role":"style"},"3 times or more",{"role":"style"}],["A class",0.01,"#b4ddfd",0.02,"#84bfef",0.03,"#559ad2",0.94,"#4277a1"],["nationality",0.4,"#ffddba",0.3,"#ffc384",0.2,"#ffac5b",0.1,"#fa993f"]]]);
var options = {
series: {
0: {
color: '#b4ddfd'
},
1: {
color: '#84bfef'
},
2: {
color: '#559ad2'
},
3: {
color: '#4277a1'
},
},
vAxis: {
textStyle: {fontSize: 11},
titleTextStyle: {italic: false},
},
chartArea: {
width: '85%',
height: areaHeight,
top: 30,
left: '13%'
},
bar: {groupWidth: '35%'},
legend: {
position: 'bottom',
textStyle: {fontSize: 11},
},
isStacked: 'percent',
hAxis: {
ticks: [0, 1],
textStyle: {fontSize: 13},
minValue: 0,
maxValue: 1,
},
callbackLegend: function(legend) {
// my problem here
// var legend_div = document.getElementById(graphId + '_legend');
// legend_div.innerHTML = legend.innerHTML;
},
width: 920,
height: areaHeight + 100
};
var chart = new google.visualization.BarChart(document.getElementById('#chart_div'));
chart.draw(data, options);
Please help me, I am deadlocking.
the standard legend on a google chart will not display multiple colors.
in fact, when using the style column role,
the legend will not match the colors used in the style columns in the data table.
instead, we can build a custom legend to display the multiple colors for each series.
to build the legend, we need to add a container to hold the legend entries.
we can use a <div> element placed just below the chart.
<div id="chart_div"></div>
<div id="legend_div"></div>
we can use css to style the legend container and use the same width of the chart.
#legend_div {
font-family: Arial;
font-size: 11px;
text-align: center;
width: 920px;
}
in the following example, I extract the colors for each series from the data table.
using the values provided in the style column roles.
to create the legend content, I use the following html templates.
one for the legend entry itself...
<script id="template-legend-entry" type="text/html">
<div class="legend-entry" data-columnIndex="{{index}}">
{{colors}}
<span>{{label}}</span>
</div>
</script>
and another for each color to be displayed for that series...
<script id="template-legend-entry-color" type="text/html">
<div class="legend-entry-color" style="background-color: {{color}}"></div>
</script>
in this example, only two rows exist in the data table,
so two colors will be displayed for each legend entry.
the legend is built during the chart's 'ready' event,
so as soon as the chart is finished drawing,
the legend will be displayed.
during which, the colors are extracted from the data table and used to build the legend entries.
a click event is added for example purposes, in case there are actions you would like to take when a legend entry is clicked.
in this example, the chart series is selected to highlight which legend entry was clicked.
google.charts.load('current', {
packages: ['corechart']
}).then(function () {
var data = google.visualization.arrayToDataTable([
["","0 times (never)",{"role":"style"},"1 times",{"role":"style"},"2 times",{"role":"style"},"3 times or more",{"role":"style"}],
["A class",0.581,"#b4ddfd",0.109,"#84bfef",0.21,"#559ad2",0.1,"#4277a1"],
["nationality",0.481,"#ffddba",0.209,"#ffc384",0.25,"#ffac5b",0.06,"#fa993f"]
]);
var options = {
vAxis: {
textStyle: {
fontSize: 11
},
titleTextStyle: {
italic: false
}
},
chartArea: {
width: '85%',
top: 30,
left: '13%'
},
bar: {
groupWidth: '35%'
},
legend: {
position: 'none'
},
isStacked: 'percent',
hAxis: {
ticks: [0, 1],
textStyle: {
fontSize: 13
},
minValue: 0,
maxValue: 1
},
width: 920,
height: '100%'
};
var chart = new google.visualization.BarChart(document.getElementById('chart_div'));
// chart ready event
google.visualization.events.addListener(chart, 'ready', function () {
// legend container
var legend = document.getElementById('legend_div');
legend.innerHTML = '';
// build legend from chart data
var colorPallette = [];
for (var colIndex = 0; colIndex < data.getNumberOfColumns(); colIndex++) {
// determine if style column
if (data.getColumnRole(colIndex) === 'style') {
// save colors for entire series (all rows)
var seriesColors = '';
for (var rowIndex = 0; rowIndex < data.getNumberOfRows(); rowIndex++) {
seriesColors += renderTemplate('template-legend-entry-color', {
color: data.getValue(rowIndex, colIndex)
});
}
// add legend for series (all colors)
legend.insertAdjacentHTML('beforeEnd', renderTemplate('template-legend-entry', {
colors: seriesColors,
index: colIndex - 1,
label: data.getColumnLabel(colIndex - 1)
}));
}
}
// add click event to legend entries
var legendEntries = legend.getElementsByClassName('legend-entry');
Array.prototype.forEach.call(legendEntries, function(entry) {
entry.addEventListener('click', function (e) {
// find legend entry
var entry = e.target || e.srcElement;
if (entry.className.toLowerCase() !== 'legend-entry') {
entry = entry.parentNode;
}
// get data table column index from legend entry
var columnIndex = parseInt(entry.getAttribute('data-columnIndex'));
// display legend entry that was clicked
document.getElementById('message_div').innerHTML = 'legend entry clicked = ' + data.getColumnLabel(columnIndex);
// select chart series
chart.setSelection([{row: null, column: columnIndex}]);
}, false);
});
});
// render html template
function renderTemplate(templateId, templateProps) {
var content = document.getElementById(templateId).innerHTML;
for (var handle in templateProps) {
if (templateProps.hasOwnProperty(handle)) {
content = content.replace('{{' + handle + '}}', templateProps[handle]);
}
}
return content.trim();
}
// draw chart
chart.draw(data, options);
});
#legend_div {
font-family: Arial;
font-size: 11px;
text-align: center;
width: 920px;
}
.legend-entry {
display: inline-block;
padding: 16px 4px 8px 4px;
}
.legend-entry-color {
display: inline-block;
height: 12px;
width: 12px;
}
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="chart_div"></div>
<div id="legend_div"></div>
<div id="message_div"></div>
<script id="template-legend-entry" type="text/html">
<div class="legend-entry" data-columnIndex="{{index}}">
{{colors}}
<span>{{label}}</span>
</div>
</script>
<script id="template-legend-entry-color" type="text/html">
<div class="legend-entry-color" style="background-color: {{color}}"></div>
</script>
i'm trying to implement a bar chart with "zebra" background instead of having the default grid lines using google charts.
is there a way to achieve so? so far couldn't figure out how.
here's what i'm trying to achieve:
and here's what i've got so far:
there are no configuration options you can use to change the width of the gridlines.
however, you can manually change, on the chart's 'ready' event.
see following working snippet...
here, the minor gridlines are moved to align with the axis labels.
and the width is increased to the position of the next axis label.
google.charts.load('current', {
packages: ['corechart']
}).then(function () {
var data = google.visualization.arrayToDataTable([
['X', 'Y'],
['school_score', 80],
['salary_score', 72],
['benefits_score', 50],
['work_environment', 42],
['security_score', 35]
]);
var container = document.getElementById('chart');
var chart = new google.visualization.BarChart(container);
google.visualization.events.addListener(chart, 'ready', function () {
// find gridlines
var gridlines = container.getElementsByTagName('rect');
var minor = [];
Array.prototype.forEach.call(gridlines, function(gridline) {
if ((gridline.getAttribute('width') === '1') && (gridline.getAttribute('fill') === '#ebebeb')) {
minor.push(gridline);
}
});
// increase width of every other minor gridline, make the rest transparent
var index = 0;
var labelBounds;
var labelBoundsNext;
var chartLayout = chart.getChartLayoutInterface();
while ((labelBounds !== null) && (index < minor.length)) {
if (index % 2 === 0) {
// use axis label bounds to determine width
labelBounds = chartLayout.getBoundingBox('hAxis#0#label#' + index);
labelBoundsNext = chartLayout.getBoundingBox('hAxis#0#label#' + (index + 1));
minor[index].setAttribute('x', labelBounds.left);
minor[index].setAttribute('width', (labelBoundsNext.left - labelBounds.left + labelBounds.width));
} else {
minor[index].setAttribute('fill', 'transparent');
}
index++;
}
});
chart.draw(data);
});
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="chart"></div>
The y asis labels of my google charts are aligned with respect to the vertical bar while I want them to be aligned with the margin of the chart. I looked everywhere. Can anyone help. The left to right and right to left uses thechart margin as reference not the chart area left margin.
no options for label alignment...
but you can move them manually when the chart's 'ready' event fires
you can use the following chart method to get the bounds of each label
getChartLayoutInterface().getBoundingBox(id)
then set the labels's x attribute to the same value as the width
if the labels need more room, use option --> chartArea.left
see following working snippet...
google.charts.load('current', {
packages: ['corechart']
}).then(function () {
var data = new google.visualization.DataTable();
data.addColumn('string', 'x');
data.addColumn('number', 'y0');
data.addRows([
['Brain Tree', 200],
['One Touch', 220],
['PayPal Email', 240],
['PayPal Here', 260],
['PayPal Invoice', 280],
['PayPal Mas', 300]
]);
var container = document.getElementById('chart_div');
var chart = new google.visualization.BarChart(container);
google.visualization.events.addListener(chart, 'click', function (gglClick) {
console.log(JSON.stringify(gglClick));
});
google.visualization.events.addListener(chart, 'ready', function () {
var chartLayout = chart.getChartLayoutInterface();
var labelIndex = -1;
var labelWidth;
var axisLabels = container.getElementsByTagName('text');
Array.prototype.forEach.call(axisLabels, function(label) {
if (label.getAttribute('text-anchor') === 'end') {
labelIndex++;
labelWidth = chartLayout.getBoundingBox('vAxis#0#label#' + labelIndex).width;
label.setAttribute('x', labelWidth);
}
});
});
chart.draw(data, {
chartArea: {
left: 128
},
height: 600
});
});
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="chart_div"></div>
Just provide is-stacked as true in option if you want to align Y-axis names with bar
options={ isStacked: true}
I'm trying to draw a Google Chart whose x-axis represents the week numbers. As we're crossing a new year, the axis goes 50, 51, 52, 1, 2, 3, ....
I'm properly ordering my data, but Google Charts insists on reordering my x-axis, and I end up with a weird graph:
var chartData = [
["Week","Revenue"],
[40,227],
[41,317],
[42,320],
[43,482],
[44,418],
[45,345],
[46,313],
[47,316],
[48,380],
[49,467],
[50,349],
[51,256],
[52,393],
[1,276],
[2,349],
[3,312]
];
google.load("visualization", "1", {
packages:["corechart"],
callback: function() {
var div = document.getElementById('chart');
var chartDataTable = google.visualization.arrayToDataTable(chartData);
var chart = new google.visualization['LineChart'](div);
chart.draw(chartDataTable);
}});
<div id="chart" style="height: 400px;">test</div>
<script src="//www.google.com/jsapi"></script>
How can I prevent it from reordering my data?
google's object notation allows you to provide a value (v:) and a formatted value (f:)
thus, you can use a value of 1 with a format of '40'
e.g. --> {v: 1, f: '40'}
in a row --> [{v: 1, f: '40'},227]
the following working snippet uses object notation to re-format the values for the x-axis,
and re-use those values for the x-axis labels (hAxis.ticks)
var chartData = [
["Week","Revenue"],
[40,227],
[41,317],
[42,320],
[43,482],
[44,418],
[45,345],
[46,313],
[47,316],
[48,380],
[49,467],
[50,349],
[51,256],
[52,393],
[1,276],
[2,349],
[3,312]
];
var hAxisTicks = [];
chartData.forEach(function (row, index) {
if (index === 0) {
return;
}
row[0] = {
v: index,
f: row[0].toString()
};
hAxisTicks.push(row[0]);
});
google.charts.load('current', {
callback: function () {
var div = document.getElementById('chart');
var chartDataTable = google.visualization.arrayToDataTable(chartData);
var chart = new google.visualization['LineChart'](div);
chart.draw(chartDataTable, {
hAxis: {
ticks: hAxisTicks
}
});
},
packages:['corechart']
});
<div id="chart"></div>
<script src="https://www.gstatic.com/charts/loader.js"></script>
note:
recommend using loader.js to load the the library, instead of jsapi
according to the release notes...
The version of Google Charts that remains available via the jsapi loader is no longer being updated consistently. Please use the new gstatic loader from now on.
this only changes the load statement, see snippet above...
EDIT:
there are more options available for continuous axis
which must be sorted, or in reverse sort order ('number', 'date' values)
but the chart will respect the original sort order for a discrete axis ('string' values)
see following snippet for 'string' values
and discrete vs. continuous for more...
var chartData = [
["Week","Revenue"],
[40,227],
[41,317],
[42,320],
[43,482],
[44,418],
[45,345],
[46,313],
[47,316],
[48,380],
[49,467],
[50,349],
[51,256],
[52,393],
[1,276],
[2,349],
[3,312]
];
chartData.forEach(function (row, index) {
if (index === 0) {
return;
}
row[0] = row[0].toString();
});
google.charts.load('current', {
callback: function () {
var div = document.getElementById('chart');
var chartDataTable = google.visualization.arrayToDataTable(chartData);
var chart = new google.visualization['LineChart'](div);
chart.draw(chartDataTable);
},
packages:['corechart']
});
<div id="chart"></div>
<script src="https://www.gstatic.com/charts/loader.js"></script>
Having a Barchart like the following
I want to be able to draw an horizontal reference line (For example at 80%). However this doesn't seem to be possible on Google Charts.
I've tried several things, including combo charts with multiple series.
However it won't look very nice since the hAxis is discrete :(
Your help would be very appreciated.
add another series for the Reference Line
use the same value for all rows and change the series type to 'line'
see following working snippet...
google.charts.load('current', {
callback: drawChart,
packages: ['corechart']
});
function drawChart() {
var data = google.visualization.arrayToDataTable([
['Category', 'Value', 'Reference'],
['Quant', 0.10, 0.80],
['Verbal', 0.30, 0.80],
['Total', 0.20, 0.80]
]);
var chartDiv = document.getElementById('chart_div');
var chart = new google.visualization.ColumnChart(chartDiv);
chart.draw(data, {
colors: ['lime', 'magenta'],
legend: 'none',
series: {
1: {
type: 'line'
}
},
title: 'Percentile Score',
vAxis: {
format: 'percent',
viewWindow: {
min: 0,
max: 1
}
}
});
}
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="chart_div"></div>
EDIT
in the above snippet, the reference line stops at the center of the first and last columns
extend the line to the edges of the columns by changing the coordinates of the reference line,
use the 'ready' listener to know when the chart has been drawn
the key is finding the specific chart elements you need to work with,
in the following snippet, the series color is used to find the columns and reference line
google.charts.load('current', {
callback: drawChart,
packages: ['corechart']
});
function drawChart() {
var data = google.visualization.arrayToDataTable([
['Category', 'Value', 'Reference'],
['Quant', 0.10, 0.80],
['Verbal', 0.30, 0.80],
['Total', 0.20, 0.80]
]);
var chartDiv = document.getElementById('chart_div');
var chart = new google.visualization.ColumnChart(chartDiv);
// use colors to find chart elements
var colorMagenta = '#ff00ff';
var colorLime = '#00ff00';
var xBeg; // save first x coord
var xWidth; // save width of column
var rowIndex = -1; // find first column
google.visualization.events.addListener(chart, 'ready', function () {
// columns
Array.prototype.forEach.call(chartDiv.getElementsByTagName('rect'), function(rect, index) {
if (rect.getAttribute('fill') === colorLime) {
rowIndex++;
xWidth = parseFloat(rect.getAttribute('width')) / 2;
if (rowIndex === 0) {
xBeg = parseFloat(rect.getAttribute('x'));
}
}
});
// reference line
Array.prototype.forEach.call(chartDiv.getElementsByTagName('path'), function(path, index) {
if (path.getAttribute('stroke') === colorMagenta) {
// change line coords
var refCoords = path.getAttribute('d').split(',');
refCoords[0] = 'M' + xBeg;
var refWidth = refCoords[2].split('L');
refWidth[1] = parseFloat(refWidth[1]) + xWidth;
refCoords[2] = refWidth.join('L');
path.setAttribute('d', refCoords.join(','));
}
});
});
chart.draw(data, {
colors: [colorLime, colorMagenta],
legend: 'none',
series: {
1: {
type: 'line'
}
},
title: 'Percentile Score',
vAxis: {
format: 'percent',
viewWindow: {
min: 0,
max: 1
}
}
});
}
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="chart_div"></div>