res = {
function renderNode(selection, rcd) {
selection.append('input')
.attr('type', 'checkbox')
.on('change', function () {
d3.select('#selected').text(checkboxValues(d3.select('#view')));
});
selection.append('span')
.text(rcd.id);
}
function checkboxValues(selection) {
return selection.select('.body')
.selectAll('input:checked').data().map(d => d.id);
}
function nextLevel(selection, node) {
const label = selection.append('span');
const arrow = label.append('span').classed('arrow', true);
label.call(renderNode, node.data);
if (!node.hasOwnProperty('children')) return;
const items = selection.append('ul')
.style('list-style-type', 'none')
.selectAll('li')
.data(node.children, d => d.id);
items.exit().remove();
items.enter()
.append('li').merge(items)
.each(function (d) {
d3.select(this).call(nextLevel, d);
});
label.select('.arrow')
.text('▼ ')
.on('click', function () {
const childList = selection.select('ul');
if (!childList.size()) return;
const expanded = childList.style('display') !== 'none';
d3.select(this).text(expanded ? '▶ ' : '▼ ');
childList.style('display', expanded ? 'none' : 'inherit');
});
}
function tree(selection) {
selection
.classed('viewport', true)
.style('overflow-y', 'scroll')
.style('height', '500px')
.append('div')
.classed('body', true)
.style('transform', 'scale(1.5)')
.style('transform-origin', 'top left');
}
function updateTree(selection, items) {
const root = d3.stratify()
.id(d => d.id)
.parentId(d => d.parent)(items);
selection.select('.body')
.call(nextLevel, root);
selection.select('.body > span').remove();
selection.select('.body > ul').style('padding-left', 0);
}
d3.select('#view div').remove();
d3.select('#view').append('div')
.call(tree)
.call(updateTree, data);
}