google.load('visualization', '1', {
packages: ['table']
});
google.setOnLoadCallback(drawTable);
function drawTable() {
var data = new google.visualization.DataTable();
data.addColumn('string', 'id');
data.addColumn('string', 'parentId');
data.addColumn('boolean', 'visible');
data.addColumn('number', 'level');
data.addColumn('string', 'Name');
data.addColumn('number', 'Value');
data.addRows([
['1', null, true, 1, 'Foo', 10],
['1.1', '1', false, 2, 'Foo 1', 2],
['1.1.1', '1.1', false, 3, 'Foo 1a', 2],
['1.1.2', '1.1', false, 3, 'Foo 1b', 2],
['1.2', '1', false, 2, 'Foo 2', 3],
['1.3', '1', false, 2, 'Foo 3', 5],
['1.3.1', '1.3', false, 3, '<input type="checkbox" id="cbox1" value="second_checkbox">', 1],
['1.3.2', '1.3', false, 3, '<input type="checkbox" id="cbox2" value="second_checkbox">', 4],
['2', null, true, 1, 'Bar', 14],
['2.1', '2', false, 2, 'Bar 1', 6],
['2.2', '2', false, 2, 'Bar 2', 7],
['2.2.1', '2.2', false, 3, 'Bar 2a', 3],
['2.2.2', '2.2', false, 3, 'Bar 2b', 2],
['2.2.3', '2.2', false, 3, 'Bar 2c', 2]
]);
// get all rows with children
// start by finding all child rows (ie, rows with parents)
var children = data.getFilteredRows([{
column: 1,
minValue: '1'
}]);
var parentsArray = [];
var parentId;
// identify the parents of all children
for (var i = 0; i < children.length; i++) {
parentId = data.getValue(children[i], 1);
if (parentsArray.indexOf(parentId) === -1) {
parentsArray.push(parentId);
}
}
//format the parent rows
var parent = data.getFilteredRows([{
column: 3,
value: 1
}]);
for (var j = 0; j < parent.length; j++) {
parentId = data.getValue(parent[j], 0);
if (parentsArray.indexOf(parentId) !== -1) {
data.setProperty(parent[j], 4, 'className', 'parentcl close');
}
else {
data.setProperty(parent[j], 4, 'className', 'parentcl');
}
};
//format the 2level rows
var leveltwo = data.getFilteredRows([{
column: 3,
value: 2
}]);
for (var j = 0; j < leveltwo.length; j++) {
parentId = data.getValue(leveltwo[j], 0);
if (parentsArray.indexOf(parentId) !== -1) {
data.setProperty(leveltwo[j], 4, 'className', 'leveltwo close');
}
else {
data.setProperty(leveltwo[j], 4, 'className', 'leveltwo');
}
};
//format the 3level rows
var levelthree = data.getFilteredRows([{
column: 3,
value: 3
}]);
for (var j = 0; j < levelthree.length; j++) {
data.setProperty(levelthree[j], 4, 'className', 'levelthree');
};
var view = new google.visualization.DataView(data);
// hide the first four columns
view.setColumns([4, 5]);
view.setRows(data.getFilteredRows([{
column: 2,
value: true
}]));
var table = new google.visualization.Table(document.getElementById('table_div'));
var cssClassNames = {
headerRow: 'gtableheader',
oddTableRow: 'rowodd',
headerCell: 'gtableheader'
};
var options = {
showRowNumber: false,
allowHtml: true,
cssClassNames: cssClassNames,
sort: 'disable'
};
var checkboxStates = {'cbox1' : false, 'cbox2': false};
google.visualization.events.addListener(table, 'select', function () {
var sel = table.getSelection();
recurseTree(view.getTableRowIndex(sel[0].row), false);
view.setRows(data.getFilteredRows([{
column: 2,
value: true
}]));
table.setSelection(null);
google.visualization.events.addOneTimeListener(table, 'ready', function(){
//load checkboxes state
for(var id in checkboxStates){
var checkbox = document.getElementById(id);
if(checkbox !== null) {
checkbox.checked = checkboxStates[id];
}
}
//update state
if(event.target.type == "checkbox"){
var checkbox = document.getElementById(event.target.id);
checkbox.checked = !event.target.checked;
checkboxStates[event.target.id] = checkbox.checked;
}
});
table.draw(view, options);
function recurseTree(row, hideOnly) {
// get the id of the row
var id = data.getValue(row, 0);
// get the parent row
var parentrow = data.getFilteredRows([{
column: 0,
value: id
}]);
var parentlevel = data.getValue(parentrow[0], 3);
// find all child rows
var rows = data.getFilteredRows([{
column: 1,
value: id
}]);
for (var i = 0; i < rows.length; i++) {
if (data.getValue(rows[i], 2)) {
// hide the row and recurse down the tree
data.setValue(rows[i], 2, false);
switch (parentlevel) {
case 1:
data.setProperty(parentrow[0], 4, 'className', 'parentcl close');
break;
case 2:
data.setProperty(parentrow[0], 4, 'className', 'leveltwo close');
break;
default:
data.setProperty(parentrow[0], 4, 'className', 'levelthree close');
}
recurseTree(rows[i], true);
}
else if (!hideOnly) {
// if the row is hidden, show it
data.setValue(rows[i], 2, true);
switch (parentlevel) {
case 1:
data.setProperty(parentrow[0], 4, 'className', 'parentcl open');
break;
case 2:
data.setProperty(parentrow[0], 4, 'className', 'leveltwo open');
break;
default:
data.setProperty(parentrow[0], 4, 'className', 'levelthree open');
}
}
}
}
});
table.draw(view, options);
}
.parentcl{
font-weight: bold !important;
}
.close:before{
content:"→ "
}
.open:before{
content:"↘ "
}
.leveltwo{
padding-left: 20px !important;
}
.levelthree{
padding-left: 45px !important;
font-style:italic;
}
.gtableheader {
font-weight: bold;
background-color: grey;
}
.rowodd {
background-color: beige;
}
<script type="text/javascript" src="https://www.google.com/jsapi"></script>
<div id="table_div"></div>