export const calcLayout = tree => { const root = d3.hierarchy(tree) const treeLayout = d3 .tree() .nodeSize([20, 50]) .separation(() => 1) treeLayout(root) const nodes = root .descendants() .filter(n => n.data.value != null) .map(n => ((n.id = n.data.path.join(',')), n)) const links = root.links().filter(l => l.target.data.value != null) console.debug('nodes', nodes) return { nodes, links } }
/** * sets global variables * creates and appends svg element to DOM * creates tree and hierarchy */ function treechartCreate(source13, source17) { const data = buildGraph(source17); data17 = source17; data13 = source13; svg = d3.select('body') .append('svg') .attr('width', width) .attr('height', height) .append('g') .attr('transform', 'translate(50,0)'); tree = d3.tree().size([height, width - 100]); root = d3.hierarchy(data); // initially close all leafs root.children.forEach(collapse); treechartUpdate(); }
_generate = (data) => { const { width, height } = styles.svg const { offsetWidth: wrapperWidth, offsetHeight: wrapperHeight } = this.wrapper this.tree = d3.tree().size([wrapperHeight, wrapperWidth]) this.zoom = d3.zoom().on('zoom', this._handleZoom) this.transition = d3.transition().duration(500) this.svg = d3.select(this.wrapper).append('svg') .attr('width', width) .attr('height', height) .call(this.zoom) this.container = this.svg.append('g') this.root = d3.hierarchy(data) this.root.x0 = wrapperHeight / 2 this.root.y0 = 0 this._update(this.root) this._center(this.root) }
westerosChart.tree = function Tree(_data) { const data = getMajorHouses(_data); const chart = this.container; const stratify = d3.stratify() .parentId(d => d.fatherLabel) .id(d => d.itemLabel); const root = stratify(data); const layout = d3.tree() .size([ this.innerWidth, this.innerHeight, ]); fixateColors(houseNames(root), 'id'); const line = d3.line().curve(d3.curveBasis); // Links const links = layout(root) .descendants() .slice(1); chart.selectAll('.link') .data(links) .enter() .append('path') .attr('fill', 'none') .attr('stroke', 'lightblue') .attr('d', d => line([ [d.x, d.y], [d.x, (d.y + d.parent.y) / 2], [d.parent.x, (d.y + d.parent.y) / 2], // [(d.x + d.parent.x) / 2, d.y], // [(d.x + d.parent.y) / 2, d.parent.y], [d.parent.x, d.parent.y]], )); // Nodes const nodes = chart.selectAll('.node') .data(root.descendants()) .enter() .append('circle') .attr('r', 4.5) .attr('fill', getHouseColor) .attr('class', 'node') .attr('cx', d => d.x) .attr('cy', d => d.y); const legendGenerator = legend.legendColor() .scale(colorScale); this.container .append('g') .attr('id', 'legend') .attr('transform', `translate(0, ${this.innerHeight / 2})`) .call(legendGenerator); nodes.call(tooltip(d => d.data.itemLabel, this.container)); };
export default (parentNode, data) => { const $svg = d3.select(parentNode).append('svg'); const $drawBox = $svg.append('g').attr('class', 'playground-d3'); const zoom = d3.zoom(); zoom.on('zoom.drawBox', () => { $drawBox.attr('transform', d3.event.transform); }); $svg.call(zoom).call(grid, zoom); zoom.translateBy($svg, window.innerWidth / 2, window.innerHeight / 2); const root = d3.hierarchy(data.node, (d) => d.childNodes); root.sum((d) => d.children ? d.children.length + 1 : 1); d3.tree().size([Math.PI * 2, 500])(root); root.descendants().forEach((d) => { const a = d.x; const r = d.y; d.x = Math.cos(a) * r; d.y = Math.sin(a) * r; d.f = d.parent ? (d.children ? d.children.length / d.parent.children.length : 0) : 1; }); const nodes = root.descendants(); const links = root.links(); const sim = d3.forceSimulation(nodes) .stop() .velocityDecay(.1) .alphaMin(.03) // .stop() .force('link', d3.forceLink(root.links(links)) .distance(10) .iterations(3) ) .force('charge', d3.forceManyBody() .theta(.2) .strength((d) => d.children ? d.children.length * -.1 : -10) // .strength((d) => d.children ? d.f * -.1 + d.value * -.01 : -10) // .strength((d) => (d.children ? -1 : -10) * .1) // .strength(-.1) // .strength(-1) ) .force('center', d3.forceCenter()) ; // let steps = 100; // while(steps--) { // sim.tick(10000); // if(!(steps % 10)) { // console.log(steps); // } // } const $nodes = $drawBox.append('g').selectAll('.node') .data(nodes) .enter() .append('circle') .attr('class', 'node') .attr('cx', (d) => d.x) .attr('cy', (d) => d.y) .attr('r', .6); $nodes.filter((d) => !d.depth).attr('r', 50).classed('root', true); const $links = $drawBox.append('g').selectAll('.link') .data(links) .enter() .append('path') .attr('class', 'link') .attr('vector-effect', 'non-scaling-stroke') .attr('d', (d) => { return 'M' + d.source.x + ',' + d.source.y + ' ' + 'L' + d.target.x + ',' + d.target.y; }); let ticks = 0; const update = () => { ticks++; $nodes .attr('cx', (d) => d.x) .attr('cy', (d) => d.y); $links .attr('d', (d) => { return 'M' + d.source.x + ',' + d.source.y + ' ' + 'L' + d.target.x + ',' + d.target.y; }); if(!(ticks % 10)) { console.log('Ticks: %d | Alpha: %f | Min alpha: ', ticks, sim.alpha(), sim.alphaMin()); } }; sim.on('tick', update); sim.restart(); // update(); }