0
votes

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!

2
only standard configuration options for hAxis are --> minValue and maxValue -- from October, 2 2015 release - WhiteHat
Thanks for the response WhiteHat.Is there no other way to do it, even in javascript? - bbb
sure, in javascript, once the 'ready' event fires, you could either change the text of the existing labels, or remove them and add your own. - WhiteHat
Hi @Whitehat, I'm sorry my javascript expertise is in beginner's level. I have tried some suggestions found in this forum and other sites but to no avail. I have also tried formatting it as for example: ['Biking', {v: new Date(2016, 9, 30), f: "Week 1"}, {v: new Date(2016, 10, 6), f: "W 701"}], and hAxis ticks: ticks: [{v: (2016, 9, 30), f: "Week 1"}, Would it be possible that you provide me a short example of 'ready' event? - bbb

2 Answers

0
votes

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>
0
votes

    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', '<a href="link_to_subj_desc" target="_blank">Trigonometry</a>', new Date(2016, 9, 30), new Date(2016, 10, 06)],
	['Student 2', 'IT', 'DB Management', '<a href="link_to_subj_desc" target="_blank">DB Management</a>', new Date(2016, 9, 30), new Date(2016, 10, 13)],
	['Student 3', 'CS', 'Introduction to Programming', '<a href="link_to_subj_desc" target="_blank">Introduction to Programming</a>', 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>