我正在尝试使用d3(https://bl.ocks.org/mbostock/4339083)创建可折叠树 在Angular4项目中使用typescript。仅为最后一个节点显示的所有节点都没有生成我的树。 有人可以帮助如何在打字稿中创建d3可折叠树
有一些迭代或循环问题,我猜所有节点都没有迭代。
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;
});
}
}
答案 0 :(得分:3)
以下是我在此链接中所做的示例: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; });
}
}