I am trying to create collapsible trees with d3 ( https://bl.ocks.org/mbostock/4339083 ) in Angular4 project using typescript. My trees is not getting generated for all nodes only last node is displaying. Can someone help how to create d3 collapsible trees in typescript
There is some iteration or loop issues i guess all nodes are not iterated.
const data =
{
"name": "Top Level",
"children": [
{
"name": "Level 2: A",
"children": [
{ "name": "Son of A" },
{ "name": "Daughter of A" }
]
},
{ "name": "Level 2: B" }
]
};
export class ClusterChartComponent implements OnInit{
//@ViewChild('container') private chartContainer: ElementRef;
private margin: any = {top: 20, right: 120, bottom: 20, left: 120};
private width: number;
private height: number;
private i = 0;
private duration = 750;
private root: any;
private tree;
private svg;
private diagonal;
constructor() {
}
ngOnInit() {
this.width = 960 - this.margin.right - this.margin.left;
this.height = 800 - this.margin.top - this.margin.bottom;
this.tree = d3.layout.tree()
.size([this.height, this.width]);
this.diagonal = d3.svg.diagonal()
.projection((d) => { return [d.y, d.x]; });
this.svg = d3.select('.container').append("svg")
.attr("width", this.width + this.margin.right + this.margin.left)
.attr("height", this.height + this.margin.top + this.margin.bottom)
.append("g")
.attr("transform", "translate(" + this.margin.left + "," + this.margin.top + ")");
console.log("flare inside",data);
this.root = data;
this.root.x0 = this.height / 2;
this.root.y0 = 0;
this.root.children.forEach(this.collapse);
this.update(this.root);
//d3.select(self.frameElement).style("height", "800px");
}
collapse = (d) => {
if (d.children) {
d._children = d.children;
d._children.forEach(this.collapse);
d.children = null;
}
};
click = (d) => {
if (d.children) {
d._children = d.children;
d.children = null;
} else {
d.children = d._children;
d._children = null;
}
this.update(d);
};
update (source): any {
let nodes = this.tree.nodes(this.root).reverse()
let links = this.tree.links(nodes);
nodes.forEach(function(d){ d.y = d.depth * 180});
// Update the nodes…
let node = this.svg.selectAll('g.node')
.data(nodes, function (d: any) {
return d.id || (d.id = ++this.i);
});
// Enter any new nodes at the parent's previous position.
var nodeEnter = node.enter().append('g')
.attr('class', 'node')
.attr('transform', function () {
return 'translate(' + source.y0 + ',' + source.x0 + ')';
})
.on('click', this.click);
// Add Circle for the nodes
nodeEnter.append('circle')
.attr('r', 1e-6)
.style('fill', function (d: any) {
return d._children ? 'lightsteelblue' : '#fff';
});
// Add labels to the nodes
nodeEnter.append('text')
.attr('x', function (d: any) {
return d.children || d._children ? -10 : 10;
})
.attr('dy', '.35em')
.attr('text-anchor', function (d: any) {
return d.children || d._children ? 'end' : 'start';
})
.text(function (d: any) {
return d.name;
})
.style('fill-opacity', 1e-6);
//i have to see whats this
d3.select('svg').transition()
.duration(this.duration)
.attr("height", this.height);
nodeEnter.append('svg:title').text(function (d: any) {
return d.name;
});
// Transition to the proper position for the node
var nodeUpdate = node.transition()
.duration(this.duration)
.attr('transform', function(d) {
return 'translate(' + d.y + "," + d.x + ')';
});
// Update the node attributes and style
nodeUpdate.select('circle')
.attr('r', 10)
.style('fill', function (d: any) {
return d._children ? 'lightsteelblue' : '#fff';
})
.attr('cursor', 'pointer');
nodeUpdate.select('text')
.style('fill-opacity', 1);
// Transition exiting nodes to the parent's new position (and remove the nodes)
var nodeExit = node.exit().transition()
.duration(this.duration);
nodeExit
.attr('transform', function (d) {
return 'translate(' + source.y + ',' + source.x + ')';
})
.remove();
nodeExit.select('circle')
.attr('r', 1e-6);
nodeExit.select('text')
.style('fill-opacity', 1e-6);
// ****************** links section ***************************
// Update the links…
var link = this.svg.selectAll('path.link')
.data(links, function (d: any) {
return d.id;
}
);
// Enter any new links at the parent's previous position.
link.enter().insert('path', 'g')
.attr('class', 'link')
.attr('d', (d) => {
var o = {x: source.x0, y: source.y0};
return this.diagonal({source: o, target: o});
});
// Transition links to their new position.
link.transition()
.duration(this.duration)
.attr('d', this.diagonal);
// // Transition exiting nodes to the parent's new position.
let linkExit = link.exit().transition()
.duration(this.duration)
.attr('d', (d: any) => {
var o = {x: source.x, y: source.y};
return this.diagonal({source: o, target: o});
})
.remove();
// Stash the old positions for transition.
nodes.forEach(function (d: any) {
d.x0 = d.x;
d.y0 = d.y;
});
}
}
Here is an exemple I did from this link : https://github.com/tomwanzek/d3-v4-definitelytyped/blob/master/tests/d3-hierarchy/d3-hierarchy-test.ts
import { Component, Inject } from '@angular/core';
import { Http } from '@angular/http';
import {
hierarchy,
HierarchyNode,
HierarchyPointNode,
HierarchyLink,
HierarchyPointLink,
StratifyOperator,
TreeLayout,
tree,
ClusterLayout,
cluster
} from 'd3-hierarchy'
import * as d3 from 'd3';
import { forEach } from '@angular/router/src/utils/collection';
interface HierarchyDatum {
name: string;
value: number;
children?: Array<HierarchyDatum>;
}
const data: HierarchyDatum = {
name: "A1",
value: 100,
children: [
{
name: "B1",
value: 100,
children: [
{
name: "C1",
value: 100,
children: undefined
},
{
name: "C2",
value: 300,
children: [
{
name: "D1",
value: 100,
children: undefined
},
{
name: "D2",
value: 300,
children: undefined
}
]
},
{
name: "C3",
value: 200,
children: undefined
}
]
},
{
name: "B2",
value: 200,
children: [
{
name: "C4",
value: 100,
children: undefined
},
{
name: "C5",
value: 300,
children: undefined
},
{
name: "C6",
value: 200,
children: [
{
name: "D3",
value: 100,
children: undefined
},
{
name: "D4",
value: 300,
children: undefined
}
]
}
]
}
]
};
@Component({
selector: 'chart',
templateUrl: './chart.component.html',
styleUrls: ['./chart.component.scss']
})
export class ChartComponent {
private margin: any = { top: 20, right: 120, bottom: 20, left: 120 };
private width: number;
private height: number;
private root: HierarchyPointNode<HierarchyDatum>;
private tree: TreeLayout<HierarchyDatum>;
private svg: any;
private diagonal: any;
constructor() {
}
ngOnInit() {
this.width = 720 - this.margin.right - this.margin.left;
this.height = 640 - this.margin.top - this.margin.bottom;
this.svg = d3.select('.container').append("svg")
.attr("width", this.width + this.margin.right + this.margin.left)
.attr("height", this.height + this.margin.top + this.margin.bottom)
.append("g")
.attr("class", "g")
//.attr("transform", "translate(5,5)");
.attr("transform", "translate(" + this.margin.left + "," + this.margin.top + ")");
d3.select('svg g.g')
.append("g")
.attr("class", "links");
d3.select('svg g.g')
.append("g")
.attr("class", "nodes");
console.log("flare inside", data);
this.tree = tree<HierarchyDatum>();
this.tree.size([this.height, this.width]);
this.root = this.tree(hierarchy<HierarchyDatum>(data));
this.draw(this.root);
}
private draw(root: HierarchyPointNode<HierarchyDatum>) {
// Nodes
d3.select('svg g.nodes')
.selectAll('circle.node')
.data(root.descendants())
.enter()
.append('circle')
.classed('node', true)
.attr('style', "fill: steelblue;stroke: #ccc;stroke-width: 3px;")
.attr('cx', function (d) { return d.x; })
.attr('cy', function (d) { return d.y; })
.attr('r', 10);
// Links
d3.select('svg g.links')
.selectAll('line.link')
.data(root.links())
.enter()
.append('line')
.classed('link', true)
.attr('style', "stroke: #ccc;stroke-width: 3px;")
.attr('x1', function (d) { return d.source.x; })
.attr('y1', function (d) { return d.source.y; })
.attr('x2', function (d) { return d.target.x; })
.attr('y2', function (d) { return d.target.y; });
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.