Google Timeline Chart Change HAxis to string value - javascript

I would like to ask if it is possible that the haxis value (The one with dates below) for Google Timeline change to string format?
For example, Oct. 30 will be changed to Week 1, Nov. 6 to Week 2, and so on.
Any help and suggestions are welcomed and appreciated.
Thanks in advance!

the timeline chart is very limited compared to the core charts
both in terms of options available and helper methods for finding chart coordinates, etc...
but like core charts, timelines produce svg, which can be modified using javascript
see following working snippet...
once the chart's 'ready' event fires, all of the haxis labels are removed
then custom labels are added back for the week numbers
before removing all the labels, one is cloned, in order to keep the same font, color, y-coordinate, etc...
then the timeline bars are used to find the x-coordinate and add the new label
google.charts.load('current', {
callback: function () {
var container = document.getElementById('chart_div');
var chart = new google.visualization.Timeline(container);
var dataTable = new google.visualization.DataTable();
dataTable.addColumn({type: 'string', id: 'Category'});
dataTable.addColumn({type: 'date', id: 'Start'});
dataTable.addColumn({type: 'date', id: 'End'});
dataTable.addRows([
['Category A', new Date(2016, 9, 30), new Date(2016, 10, 5)],
['Category B', new Date(2016, 10, 6), new Date(2016, 10, 12)],
['Category C', new Date(2016, 10, 13), new Date(2016, 10, 19)]
]);
google.visualization.events.addListener(chart, 'ready', function () {
var rowIndex = 0; // data table row index
var weekLabel = null; // clone of text node - keep font settings, y-coord, etc...
// remove haxis labels
var labels = container.getElementsByTagName('text');
while (labels.length > dataTable.getNumberOfRows()) {
// ignore "category" labels
if (dataTable.getFilteredRows([{column: 0, value: labels[labels.length - 1].innerHTML}]).length === 0) {
if (weekLabel === null) {
weekLabel = labels[labels.length - 1].cloneNode(true);
}
labels[labels.length - 1].parentNode.removeChild(labels[labels.length - 1]);
}
}
// use timeline bars to find x coordinate for week labels
rowIndex = 0;
var svgParent = container.getElementsByTagName('svg')[0];
Array.prototype.forEach.call(container.getElementsByTagName('rect'), function(bar) {
var bounds; // bounding box of text element
// ignore rect if not a timeline bar
if (parseFloat(bar.getAttribute('x')) > 0) {
weekLabel = weekLabel.cloneNode(true);
weekLabel.innerHTML = 'Week ' + (rowIndex + 1);
svgParent.appendChild(weekLabel);
bounds = weekLabel.getBBox();
weekLabel.setAttribute('x', parseFloat(bar.getAttribute('x')) + bounds.width);
rowIndex++;
}
});
});
chart.draw(dataTable);
},
packages:['timeline']
});
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="chart_div"></div>

google.charts.load("current", {packages:["timeline"], callback: drawChart});
function drawChart() {
var container = document.getElementById('chart_div');
var chart = new google.visualization.Timeline(container);
// hAxis put on top
google.visualization.events.addListener(chart, 'ready', afterDraw);
// Link in tooltip
google.visualization.events.addListener(chart, 'select', function(e) {
var tooltip = document.querySelector('.google-visualization-tooltip:not([clone])');
if (chart.ttclone) {
chart.ttclone.parentNode.removeChild(chart.ttclone)
}
chart.ttclone = tooltip.cloneNode(true);
chart.ttclone.setAttribute('clone', true);
chart.ttclone.style.pointerEvents = 'auto';
tooltip.parentNode.insertBefore(chart.ttclone, chart.tooltip);
});
var dataTable = new google.visualization.DataTable();
dataTable.addColumn({ type: 'string', id: 'Name' });
// for colorMap
dataTable.addColumn({ type: 'string', id: 'Course' });
dataTable.addColumn({ type: 'string', id: 'Subject' });
dataTable.addColumn({ type: 'string', id: 'ToolTip', role: 'tooltip', p:{html:true} });
dataTable.addColumn({ type: 'date', id: 'Start' });
dataTable.addColumn({ type: 'date', id: 'End' });
dataTable.addRows([
// Timeline Start
['Student 1', 'ENGR', 'Trigonometry', 'Trigonometry', new Date(2016, 9, 30), new Date(2016, 10, 06)],
['Student 2', 'IT', 'DB Management', 'DB Management', new Date(2016, 9, 30), new Date(2016, 10, 13)],
['Student 3', 'CS', 'Introduction to Programming', 'Introduction to Programming', new Date(2016, 9, 30), new Date(2016, 10, 27)],
]);
var colors = [];
var colorMap = {
ENGR: '#2ECC71', // Green
IT: '#E67E22', // Brown
CS: '#9B59B6', // Violet
}
for (var i = 0; i < dataTable.getNumberOfRows(); i++) {
colors.push(colorMap[dataTable.getValue(i, 1)]);
}
var rowHeight = 41;
var chartHeight = (dataTable.getNumberOfRows() + 1) * rowHeight;
var options = {
timeline: {
groupByRowLabel: true,
rowLabelStyle: {
fontName: 'Century Gothic',
fontSize: 14,
color: '#333333',
bold: 'true',
},
barLabelStyle: {
fontName: 'Century Gothic',
fontSize: 11,
},
showRowLabels: true,
showBarLabels: true,
},
hAxis: {
minValue: new Date(2016, 9, 30),
maxValue: new Date(2017, 9, 28),
},
avoidOverlappingGridLines: true,
height: chartHeight,
width: '100%',
colors: colors,
};
// use a DataView to hide the category column from the Timeline
var view = new google.visualization.DataView(dataTable);
view.setColumns([0, 2, 3, 4, 5]);
// Change HAxis labels to Week
google.visualization.events.addListener(chart, 'ready', function () {
var rowIndex = 0; // data table row index
var weekLabel = null; // clone of text node - keep font settings, y-coord, etc...
// remove haxis labels
var labels = container.getElementsByTagName('text');
while (labels.length > dataTable.getNumberOfRows()) {
// ignore "category" labels
if (dataTable.getFilteredRows([{column: 5, value: labels[labels.length - 1].innerHTML}]).length === 0) {
if (weekLabel === null) {
weekLabel = labels[labels.length - 1].cloneNode(true);
}
labels[labels.length - 1].parentNode.removeChild(labels[labels.length - 1]);
}
}
// use timeline bars to find x coordinate for week labels
rowIndex = 0;
var svgParent = container.getElementsByTagName('svg')[0];
Array.prototype.forEach.call(container.getElementsByTagName('rect'), function(bar) {
var bounds; // bounding box of text element
// ignore rect if not a timeline bar
if (parseFloat(bar.getAttribute('x')) > 0) {
weekLabel = weekLabel.cloneNode(true);
weekLabel.innerHTML = 'WW 70' + (rowIndex + 1);
svgParent.appendChild(weekLabel);
bounds = weekLabel.getBBox();
weekLabel.setAttribute('x', parseFloat(bar.getAttribute('x')) + bounds.width);
rowIndex++;
}
});
});
chart.draw(
view,
options,
dataTable, {
tooltip: {
isHtml: true,
},
timeline: {
showBarLabels: false,
}
});
}
// hAxis put on top
function afterDraw() {
var g = document.getElementsByTagName("svg")[0].getElementsByTagName("g")[1];
document.getElementsByTagName("svg")[0].parentNode.style.top = '40px';
document.getElementsByTagName("svg")[0].style.overflow = 'visible';
var height = Number(g.getElementsByTagName("text")[0].getAttribute('y')) + 15;
g.setAttribute('transform','translate(0,-'+height+')');
g = null;
}
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="chart_div"></div>

Related

Google Chart Resize on Window Resize

How can I get my google chart to resize properly, currently it gets bigger when I expand the window but it does not shrink when i shrink the window. Essentially I've wrapped the entire google chart in a resize function but it isn't quite right:
function resize() {
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: 'Type' });
dataTable.addColumn({ type: 'string', id: 'Organisation' });
dataTable.addColumn({ type: 'date', id: 'Start' });
dataTable.addColumn({ type: 'date', id: 'End' });
dataTable.addRows([
[ 'Work Experience', 'GE', new Date(2010, 8, 1 ), new Date(2011, 8, 30) ],
[ 'Work Experience', 'Shell', new Date(2015, 2, 1), new Date(2016, 1, 1) ],
[ 'Work Experience', 'British Gas', new Date(2016, 1, 1), new Date(2017, 9, 1) ],
[ 'Work Experience', 'British Telecom', new Date(2017, 9, 1), new Date() ],
[ 'Work Experience', 'University', new Date(2011, 8, 30), new Date(2015, 2,1) ]
]);
var options = {
timeline: {showRowLabels: false},
backgroundColor: '#161616',
barLabelStyle: { fontName: 'Roboto', color: '#ffffff' },
height: 100,
hAxis: {textStyle:{color: '#ffffff'}}
};
google.visualization.events.addListener(chart, 'ready', function () {
var labels = container.getElementsByTagName('text');
Array.prototype.forEach.call(labels, function(label) {
if (label.getAttribute('text-anchor') === 'middle') {
label.setAttribute('fill', '#ffffff');
}
});
});
google.visualization.events.addListener(chart, 'ready', function () {
var rects = container.getElementsByTagName('rect');
Array.prototype.forEach.call(rects, function(rect) {
// find chart <rect> element
if ((rect.getAttribute('x') === '0') && (rect.getAttribute('y') === '0')) {
// remove stroke from last <rect> element
rect.setAttribute('stroke', 'none');
rect.setAttribute('stroke-width', '0');
}
});
});
chart.draw(dataTable, options);
}
}
window.onload = resize;
window.onresize = resize;
when resizing, you need to clear the chart, before re-drawing.
if the chart is not cleared, it can prevent the chart's container from shrinking.
then when re-drawn, it is the same size.
(this all depends on the page layout, but clearing will resolve most issues)
use method --> chart.clearChart()
also, the load callback only needs to be called once per page load.
no need to include the load statement in the resize event handler.
and, google's load statement will wait for the page to load by default.
and can be used in place of --> window.onload
see following working snippet...
google.charts.load('current', {
packages: ['timeline']
}).then(function () {
var container = document.getElementById('timeline');
var chart = new google.visualization.Timeline(container);
var dataTable = new google.visualization.DataTable();
dataTable.addColumn({ type: 'string', id: 'Type' });
dataTable.addColumn({ type: 'string', id: 'Organisation' });
dataTable.addColumn({ type: 'date', id: 'Start' });
dataTable.addColumn({ type: 'date', id: 'End' });
dataTable.addRows([
['Work Experience', 'GE', new Date(2010, 8, 1 ), new Date(2011, 8, 30)],
['Work Experience', 'Shell', new Date(2015, 2, 1), new Date(2016, 1, 1)],
['Work Experience', 'British Gas', new Date(2016, 1, 1), new Date(2017, 9, 1)],
['Work Experience', 'British Telecom', new Date(2017, 9, 1), new Date()],
['Work Experience', 'University', new Date(2011, 8, 30), new Date(2015, 2,1)]
]);
var options = {
timeline: {showRowLabels: false},
backgroundColor: '#161616',
barLabelStyle: {fontName: 'Roboto', color: '#ffffff'},
height: 100,
hAxis: {textStyle:{color: '#ffffff'}}
};
google.visualization.events.addListener(chart, 'ready', function () {
var labels = container.getElementsByTagName('text');
Array.prototype.forEach.call(labels, function(label) {
if (label.getAttribute('text-anchor') === 'middle') {
label.setAttribute('fill', '#ffffff');
}
});
var rects = container.getElementsByTagName('rect');
Array.prototype.forEach.call(rects, function(rect) {
// find chart <rect> element
if ((rect.getAttribute('x') === '0') && (rect.getAttribute('y') === '0')) {
// remove stroke from last <rect> element
rect.setAttribute('stroke', 'none');
rect.setAttribute('stroke-width', '0');
}
});
});
window.addEventListener('resize', drawChart);
drawChart();
function drawChart() {
chart.clearChart();
chart.draw(dataTable, options);
}
});
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="timeline"></div>

Remove borders and gridlines around google chart timeline

I need to remove the border and the gridlines from the google charts timetable (see documentation)
Right now it looks like this: with borders
It should look like this: without borders
I made a stackblitz for it: https://stackblitz.com/edit/js-ozv5hr?file=index.html
It seems like the config options that you can use for example with line charts do not work with timelines.
there are no config options available for removing the borders,
but we can remove them manually on the chart's 'ready' event.
see following working snippet...
google.charts.load("current", {
packages: ["timeline"]
}).then(function () {
var container = document.getElementById("timeline");
var chart = new google.visualization.Timeline(container);
var dataTable = new google.visualization.DataTable();
dataTable.addColumn({ type: "string", id: "Label" });
dataTable.addColumn({ type: "string", id: "Type" });
dataTable.addColumn({ type: "date", id: "Start" });
dataTable.addColumn({ type: "date", id: "End" });
dataTable.addRows([
["A", "A", new Date(2021, 0, 0, 0), new Date(2021, 0, 0, 1)],
["A", "B", new Date(2021, 0, 0, 1), new Date(2021, 0, 0, 2)],
["A", "C", new Date(2021, 0, 0, 2), new Date(2021, 0, 0, 3)]
]);
var options = {
timeline: {
groupByRowLabel: true,
showRowLabels: false,
showBarLabels: false
},
avoidOverlappingGridLines: false,
hAxis: {
format: "HH:mm"
},
gridlines: {
color: "none"
}
};
google.visualization.events.addListener(chart, 'ready', function () {
// find <rect> elements
var rects = container.getElementsByTagName('rect');
Array.prototype.forEach.call(rects, function(rect) {
if (rect.getAttribute('stroke') === '#9a9a9a') {
// remove border
rect.setAttribute('stroke-width', '0');
}
});
// find <path> elements
var paths = container.getElementsByTagName('path');
Array.prototype.forEach.call(paths, function(path) {
if ((path.getAttribute('stroke') === '#ffffff') || (path.getAttribute('stroke') === '#e6e6e6')) {
// remove border
path.setAttribute('stroke-width', '0');
}
});
});
chart.draw(dataTable, options);
});
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="timeline"></div>

How to set different color by row in TimeLine Google charts?

I have a timeline chart made with Google charts, what I do is send a json with color values ​​and other information, the size of the json is variable, what I want to do is that each row is painted with the color it has in the json, implement the following:
dataTable.addColumn({type: 'string', role: 'style'});
But it seems not to work, it gives me automatic colors.
The following is an image of my graph with the colors thrown by defautl, and not with the colors that I have in the json.
For example in this case, 'Production' has to be orange and 'Fusion' has to be purple.
This is my code:
function drawChart() {
$(".timeline").each(function () {
var obje = {{ devicejson|safe }};
var elem = $(this),
id = elem.attr('id');
var container = document.getElementById(id);
var chart = new google.visualization.Timeline(container);
var dataTable = new google.visualization.DataTable();
dataTable.addColumn({type: 'string', id: 'Role'});
dataTable.addColumn({type: 'string', id: 'Name'});
dataTable.addColumn({type: 'date', id: 'Start'});
dataTable.addColumn({type: 'date', id: 'End'});
dataTable.addColumn({type: 'string', id: 'TimeEst'});
dataTable.addColumn({type: 'string', role: 'style'});
for (n = 0; n < obje.length; ++n) {
if (obje[n].device_id == id) {
dataTable.addRows([
['Department', obje[n].digitaloutput_user_description, new Date('"' + obje[n].startdatetime + '"'), new Date('"' + obje[n].enddatetime + '"'), obje[n].lighstate_user_description, obje[n].color],
]);
var options = {
tooltip: {isHtml: true},
timeline: {
showRowLabels: false,
},
avoidOverlappingGridLines: false,
{#hAxis: {format: 'dd-MMM-yyyy HH:mm:ss'}#}
};
}
}
for (n = 0; n < obje.length; ++n) {
if (obje[n].device_id == id) {
console.log(obje[n].color)
}
}
var formatTime = new google.visualization.DateFormat({
pattern: 'yyyy-MM-dd HH:mm:ss a'
});
var view = new google.visualization.DataView(dataTable);
view.setColumns([0, 1, {
role: 'tooltip',
type: 'string',
calc: function (dt, row) {
// build tooltip
var dateBegin = dt.getValue(row, 2);
var dateEnd = dt.getValue(row, 3);
var oneHour = (60 * 1000);
var duration = (dateEnd.getTime() - dateBegin.getTime()) / oneHour;
var tooltip = '<div><div class="ggl-tooltip"><span>';
tooltip += dt.getValue(row, 0) + ':</span> ' + dt.getValue(row, 1) + '</div>';
tooltip += '<div class="ggl-tooltip"><div>' + formatTime.formatValue(dateBegin) + ' - ';
tooltip += formatTime.formatValue(dateEnd) + '</div>';
tooltip += '<div><span>Duration: </span>' + duration.toFixed(0) + ' minutes</div>';
tooltip += '<div><span>Estate: </span>' + dt.getValue(row, 5) + '</div></div>';
return tooltip;
},
p: {html: true}
}, 2, 3]);
google.visualization.events.addListener(chart, 'ready', function () {
var labels = container.getElementsByTagName('text');
Array.prototype.forEach.call(labels, function (label) {
label.setAttribute('font-weight', 'normal');
});
});
chart.draw(view.toDataTable(), options);
})
}
on the timeline chart, the style role will only work when used as the third column (column index 2).
see following working snippet...
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: 'string',
id: 'Bar'
});
dataTable.addColumn({ // <-- add style role here...
type: 'string',
role: 'style'
});
dataTable.addColumn({
type: 'date',
id: 'Start'
});
dataTable.addColumn({
type: 'date',
id: 'End'
});
dataTable.addRows([
['Washington', 'test1', 'cyan', new Date(1789, 3, 30), new Date(1797, 2, 4)],
['Adams', 'test2', 'magenta', new Date(1797, 2, 4), new Date(1801, 2, 4)],
['Jefferson', 'test3', 'lime', new Date(1801, 2, 4), new Date(1809, 2, 4)]
]);
chart.draw(dataTable);
}
<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
<div id="timeline" style="height: 180px;"></div>

Why custom tooltip doesn't show up?

I'm trying to show a custom tooltip on mouve over the bars, it show always the default tooltip.
I'm just trying to show a simple html code in the tooltip, so I can modify it after
What am I missing? thanks
google.charts.load('current', {
'packages': ['timeline'],
'language': 'fr'
});
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: 'Code'
});
dataTable.addColumn({
type: 'string',
id: 'Color'
});
dataTable.addColumn({
type: 'string',
role: 'tooltip',
'p': {
'html': true
}
});
dataTable.addColumn({
type: 'string',
id: 'Libelle'
});
dataTable.addColumn({
type: 'date',
id: 'Start'
});
dataTable.addColumn({
type: 'date',
id: 'End'
});
var objects = [];
objects.push({
code: "PRV1001",
color: "Color1",
zz: "<div><strong>2010</strong></div>",
id: "PRV1001",
dateStart: new Date(2016, 3, 1),
dateFinnish: new Date(2016, 3, 15)
});
objects.push({
code: "PRV1002",
color: "Color2",
zz: "<div><strong>2010</strong></div>",
id: "PRV1002",
dateStart: new Date(2016, 3, 4),
dateFinnish: new Date(2016, 3, 9)
});
objects.push({
code: "PRV1003",
color: "Color3",
zz: "<div><strong>2010</strong></div>",
id: "PRV1003",
dateStart: new Date(2016, 3, 3),
dateFinnish: new Date(2016, 3, 12)
});
var rows = [];
for (var i = 0; i < objects.length; i++) {
rows.push([objects[i].code, objects[i].color, objects[i].zz, objects[i].id, objects[i].dateStart, objects[i].dateFinnish]);
}
console.log(rows);
dataTable.addRows(rows);
/****************Colors*************************/
var colors = [];
var colorMap = {
// should contain a map of category -> color for every category
Color1: '#e63b6f',
Color2: '#19c362',
Color3: '#592df7'
}
for (var i = 0; i < dataTable.getNumberOfRows(); i++) {
colors.push(colorMap[dataTable.getValue(i, 1)]);
}
var options = {
colors: colors,
focusTarget: 'category',
tooltip: {
//trigger: 'none'
isHtml: true
}
};
google.visualization.events.addListener(chart, 'select', function() {
selection = chart.getSelection();
if (selection.length > 0) {
console.log(dataTable.getValue(selection[0].row, 0));
}
});
// use a DataView to hide the category column from the Timeline
var view = new google.visualization.DataView(dataTable);
view.setColumns([0, 2, 3, 4, 5]);
chart.draw(view, options);
}
<!DOCTYPE html>
<html>
<head>
<meta name="description" content="Goolge Chart HTML Tooltips">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
</head>
<body>
<div id="timeline" style="height: 180px;"></div>
</body>
</html>
see the data format for a timeline chart...
Column 0 - Row label
Column 1 - Bar label (optional)
Column 2 - Tooltip (optional)
Column 3 - Start
Column 4 - End
the issue stems from the view...
view.setColumns([0, 2, 3, 4, 5]);
so the chart thinks Column 2 is the Bar label
the issue can be corrected by swapping Column 2 with 3
view.setColumns([0, 3, 2, 4, 5]);
see following working snippet...
google.charts.load('current', {
'packages': ['timeline'],
'language': 'fr'
});
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: 'Code'
});
dataTable.addColumn({
type: 'string',
id: 'Color'
});
dataTable.addColumn({
type: 'string',
role: 'tooltip',
'p': {
'html': true
}
});
dataTable.addColumn({
type: 'string',
id: 'Libelle'
});
dataTable.addColumn({
type: 'date',
id: 'Start'
});
dataTable.addColumn({
type: 'date',
id: 'End'
});
var objects = [];
objects.push({
code: "PRV1001",
color: "Color1",
zz: "<div><strong>2010</strong></div>",
id: "PRV1001",
dateStart: new Date(2016, 3, 1),
dateFinnish: new Date(2016, 3, 15)
});
objects.push({
code: "PRV1002",
color: "Color2",
zz: "<div><strong>2010</strong></div>",
id: "PRV1002",
dateStart: new Date(2016, 3, 4),
dateFinnish: new Date(2016, 3, 9)
});
objects.push({
code: "PRV1003",
color: "Color3",
zz: "<div><strong>2010</strong></div>",
id: "PRV1003",
dateStart: new Date(2016, 3, 3),
dateFinnish: new Date(2016, 3, 12)
});
var rows = [];
for (var i = 0; i < objects.length; i++) {
rows.push([objects[i].code, objects[i].color, objects[i].zz, objects[i].id, objects[i].dateStart, objects[i].dateFinnish]);
}
dataTable.addRows(rows);
/****************Colors*************************/
var colors = [];
var colorMap = {
// should contain a map of category -> color for every category
Color1: '#e63b6f',
Color2: '#19c362',
Color3: '#592df7'
}
for (var i = 0; i < dataTable.getNumberOfRows(); i++) {
colors.push(colorMap[dataTable.getValue(i, 1)]);
}
var options = {
colors: colors,
focusTarget: 'category',
tooltip: {
isHtml: true
}
};
google.visualization.events.addListener(chart, 'select', function() {
selection = chart.getSelection();
if (selection.length > 0) {
console.log(dataTable.getValue(selection[0].row, 0));
}
});
// use a DataView to hide the category column from the Timeline
var view = new google.visualization.DataView(dataTable);
view.setColumns([0, 3, 2, 4, 5]);
chart.draw(view, options);
}
<!DOCTYPE html>
<html>
<head>
<meta name="description" content="Goolge Chart HTML Tooltips">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
</head>
<body>
<div id="timeline" style="height: 180px;"></div>
</body>
</html>

How to reload data in Google Charts Calendar while keeping selected cell?

I use jQuery and I use the following JS function to load and reload / redraw the Google Chart Calendar.
It works, however, it also removes the border from the selected item. I want to reload the calendar data, while keeping the currently selected item selected.
Any ideas?
function refreshCalendar( rows)
{
//if( calendar != 0 )
{
calendar = new google.visualization.Calendar(document.getElementById('calendar_basic'))
google.visualization.events.addListener(calendar, 'select', calendarSelectHandler);
calendarData = new google.visualization.DataTable();
calendarData.addColumn({ type: 'date', id: 'Date' });
calendarData.addColumn({ type: 'number', id: 'Logs' });
calendarData.addRows( rows );
calendarOptions = {
title: "Logs",
height: 175,
colorAxis: {minValue: 0, colors: ['#FFFFFF', '#FF0000']},
calendar: {
focusedCellColor: {
background: '#00FF00',
stroke: '#004400',
strokeOpacity: 1,
strokeWidth: 2,
},
cellColor: {
stroke: '#76a7fa',
strokeOpacity: 0.5,
strokeWidth: 1,
}
}
};
calendar.draw(calendarData, calendarOptions);
}
}
Normally, you would use chart.getSelection and chart.setSelection.
Get selection on 'select' event
Set selection on 'ready' event
getSelection works fine, but setSelection doesn't work with the Calendar chart.
No error is thrown, but nothing is selected.
I tried versions '41' thru 'current'...
To demonstrate, the following example uses both a Calendar chart and a Column chart.
Make a selection on both charts, then click "Redraw Chart".
The selection for the Column chart remains but not on the Calendar.
google.charts.load('current', {
callback: drawChart,
packages: ['calendar', 'corechart']
});
function drawChart() {
var selectionCal;
var selectionCol;
var calendar = new google.visualization.Calendar(document.getElementById('calendar'))
google.visualization.events.addListener(calendar, 'select', function () {
selectionCal = calendar.getSelection();
});
google.visualization.events.addListener(calendar, 'ready', function () {
if (selectionCal) {
calendar.setSelection(selectionCal);
}
});
var column = new google.visualization.ColumnChart(document.getElementById('column'))
google.visualization.events.addListener(column, 'select', function () {
selectionCol = column.getSelection();
});
google.visualization.events.addListener(column, 'ready', function () {
if (selectionCol) {
column.setSelection(selectionCol);
}
});
document.getElementById('test_button').addEventListener('click', function () {
calendar.draw(calendarData, calendarOptions);
column.draw(calendarData, {});
}, false);
var calendarData = new google.visualization.DataTable();
calendarData.addColumn({ type: 'date', id: 'Date' });
calendarData.addColumn({ type: 'number', id: 'Logs' });
calendarData.addRows([
[ new Date(2012, 3, 13), 37032 ],
[ new Date(2012, 3, 14), 38024 ],
[ new Date(2012, 3, 15), 38024 ],
[ new Date(2012, 3, 16), 38108 ],
[ new Date(2012, 3, 17), 38229 ],
]);
var calendarOptions = {
title: "Logs",
height: 175,
colorAxis: {minValue: 0, colors: ['#FFFFFF', '#FF0000']},
calendar: {
focusedCellColor: {
background: '#00FF00',
stroke: '#004400',
strokeOpacity: 1,
strokeWidth: 2,
},
cellColor: {
stroke: '#76a7fa',
strokeOpacity: 0.5,
strokeWidth: 1,
}
}
};
calendar.draw(calendarData, calendarOptions);
column.draw(calendarData, {});
}
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="calendar"></div>
<div id="column"></div>
<input type="button" id="test_button" value="Redraw Chart" />
I can also confirm that the setSelection() method doesn't change anything on the UI for the calendar chart.
So I looked up what happens after selecting a day in the chart with the mouse. Then I implemented a simple DOM manipulation logic which does the same. You can use that logic as a replacement of the setSelection() use case. (It is just a quick prototype, but I hope it helps you, too).
For a litte demo I adjusted #WhiteHat snippet / the selected day survives now the refresh action (doesn't work with charts which needs to display more than one year!):
google.charts.load('current', {
callback: drawChart,
packages: ['calendar', 'corechart']
});
function drawChart() {
var selectionCal;
var selectionDate;
var selectionCol;
var calendar = new google.visualization.Calendar(document.getElementById('calendar'))
google.visualization.events.addListener(calendar, 'select', function () {
selectionCal = calendar.getSelection();
selectionDate = new Date(selectionCal[0].date);
});
google.visualization.events.addListener(calendar, 'ready', function () {
if (selectionDate) {
// google calendar setSelection BUG :/
// https://stackoverflow.com/a/36093217/810944
// do it manually
var doy = selectionDate.getDOY();
markDayInChart(doy);
}
});
var column = new google.visualization.ColumnChart(document.getElementById('column'))
google.visualization.events.addListener(column, 'select', function () {
selectionCol = column.getSelection();
});
google.visualization.events.addListener(column, 'ready', function () {
if (selectionCol) {
column.setSelection(selectionCol);
}
});
document.getElementById('test_button').addEventListener('click', function () {
calendar.draw(calendarData, calendarOptions);
column.draw(calendarData, {});
}, false);
var calendarData = new google.visualization.DataTable();
calendarData.addColumn({ type: 'date', id: 'Date' });
calendarData.addColumn({ type: 'number', id: 'Logs' });
calendarData.addRows([
[ new Date(2012, 3, 13), 37032 ],
[ new Date(2012, 3, 14), 38024 ],
[ new Date(2012, 3, 15), 38024 ],
[ new Date(2012, 3, 16), 38108 ],
[ new Date(2012, 3, 17), 38229 ],
]);
var calendarOptions = {
title: "Logs",
height: 175,
colorAxis: {minValue: 0, colors: ['#FFFFFF', '#FF0000']},
calendar: {
focusedCellColor: {
background: '#00FF00',
stroke: '#004400',
strokeOpacity: 1,
strokeWidth: 2,
},
cellColor: {
stroke: '#76a7fa',
strokeOpacity: 0.5,
strokeWidth: 1,
}
}
};
calendar.draw(calendarData, calendarOptions);
column.draw(calendarData, {});
}
function markDayInChart(dayOfYear) {
// clones the logic for clicking / selecting a day via mouse
// keep in mind to clean up the adjusted and added `rect`-elements if you do not use full page reloads!
// doesn't work with charts which needs to display more than one year!
var days_all_svg_group = $('#calendar svg').children('g')[1];
var days_marked_svg_group = $('#calendar svg').children('g')[4];
var day_svg_rect = $('rect:nth-of-type('+dayOfYear+')',$(days_all_svg_group));
// hide the original rect
$(day_svg_rect).css('display: none;');
// add a cloned rect with a different stroke
var day_marked_svg_rect = $(day_svg_rect).clone();
$(day_marked_svg_rect).attr({stroke: '#000000', 'stroke-width': 2});
$(day_marked_svg_rect).attr('stroke-opacity', null);
$(days_marked_svg_group).append(day_marked_svg_rect);
}
// https://stackoverflow.com/a/26426761/810944
Date.prototype.isLeapYear = function() {
var year = this.getFullYear();
if((year & 3) != 0) return false;
return ((year % 100) != 0 || (year % 400) == 0);
};
// Get Day of Year
Date.prototype.getDOY = function() {
var dayCount = [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334];
var mn = this.getMonth();
var dn = this.getDate();
var dayOfYear = dayCount[mn] + dn;
if(mn > 1 && this.isLeapYear()) dayOfYear++;
return dayOfYear;
};
<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="calendar"></div>
<div id="column"></div>
<input type="button" id="test_button" value="Redraw Chart" />

Categories

Resources