角度2 D3树不能正确渲染
问题描述:
我有一个用d3(v3)制作的树,在纯javascript中,我试图转换成Angular2组件。不过,我无法正确显示它。角度2 D3树不能正确渲染
这里是我的代码的内容tree.component.ts:
import { Component, OnInit, OnChanges, ViewChild, ElementRef, Input, ViewEncapsulation } from '@angular/core';
import * as d3 from 'd3';
@Component({
selector: 'app-tree',
templateUrl: './tree.component.html',
styleUrls: ['./tree.component.css']
})
export class TreeComponent {
@ViewChild('tree') private chartContainer: ElementRef;
@Input() private data: Array<any>;
private dataInfo2 = {
"name": "rootAlert",
"alert": "true",
"children": [{
"name": "Child1",
"alert": "true",
"children": [{
"name": "Child1-1",
"alert": "false"
}, {
"name": "Child1-2",
"alert": "false"
}, {
"name": "Child1-3",
"alert": "true"
}]
}, {
"name": "Child2",
"alert": "false",
"children": [{
"name": "Child2-1",
"alert": "false"
}, {
"name": "Child2-2",
"alert": "false"
}, {
"name": "Child2-3",
"alert": "false"
}]
}, {
"name": "Child3",
"alert": "false"
}]
}
private values = this.dataInfo2
//console.log(JSON.stringify(values))
//private element = this.chartContainer.nativeElement;;
private div = d3.select("body")
.append("div") // declare the tooltip div
.attr("class", "tooltip")
.style("opacity", 0);
private switcher = true;
private margin = { top: 20, right: 120, bottom: 20, left: 120 };
private width = 960 - this.margin.right - this.margin.left;
private height = 800 - this.margin.top - this.margin.bottom;
private i = 0;
private duration = 750;
private root;
private select2_data;
private diameter = 960;
private tree = d3.layout.tree()
.size([this.height, this.width]);
private diagonal = d3.svg.diagonal()
.projection(function (d) { return [d.y, d.x]; });
private svg = d3.select("body").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 + ")");
ngOnInit(){
this.root = this.values;
//values is the flare.json
//select2_data = extract_select2_data(values, [], 0)[1];//I know, not the prettiest...
this.root.x0 = this.height/2;
this.root.y0 = 0;
this.root.children.forEach((item)=>this.collapse(item));
this.update(this.root);
d3.select(self.frameElement).style("height", "800px");
}
setAllFalse(root){
if (!root.childAlerts){
root.severity = false
root.class = 'nf'
console.log("set " + root.sourceName + "to false")
return
}
else{
for (var i = 0; i < root.childAlerts.length; i++){
this.setAllFalse(root.childAlerts[i])
}
}
root.severity = false
root.class = 'nf'
return
}
//recursively collapse children
collapse(d: any) {
if (d.children) {
d._children = d.children;
//var clps = this.collapse;
d._children.forEach((item)=>this.collapse(item));
d.children = null;
}
}
// Toggle children on click.
click(d) {
if (d.children) {
d._children = d.children;
d.children = null;
}
else {
d.children = d._children;
d._children = null;
}
this.update(d);
}
openPaths(paths) {
for (var i = 0; i < paths.length; i++) {
if (paths[i].id !== "1") {//i.e. not root
paths[i].class = 'found';
if (paths[i]._children) { //if children are hidden: open them, otherwise: don't do anything
paths[i].children = paths[i]._children;
paths[i]._children = null;
}
this.update(paths[i]);
}
}
}
openPaths2(paths) {
for (var i = 0; i < paths.length; i++) {
if (paths[i].id !== "1") {//i.e. not root
paths[i].class = 'nf';
if (paths[i]._children) { //if children are hidden: open them, otherwise: don't do anything
paths[i].children = paths[i]._children;
paths[i]._children = null;
}
this.update(paths[i]);
}
}
}
update(source) {
// Compute the new tree layout.
var nodes = this.tree.nodes(this.root).reverse(),
links = this.tree.links(nodes);
// Normalize for fixed-depth.
nodes.forEach(function (d) { d.y = d.depth * 180; });
// Update the nodes…
var 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 (d) { return "translate(" + source.y0 + "," + source.x0 + ")"; })
.on("click", this.click);
nodeEnter.append("circle")
.attr("r", 1e-6)
.style("fill", function (d) { return d._children ? "lightsteelblue" : "#fff"; });
nodeEnter.append("text")
.attr("x", function (d) { return d.children || d._children ? -10 : 10; })
.attr("dy", ".35em")
.attr("text-anchor", function (d) { return d.children || d._children ? "end" : "start"; })
.text(function (d) { return d.name; })
.style("fill-opacity", 1e-6);
// Transition nodes to their new position.
var nodeUpdate = node.transition()
.duration(this.duration)
.attr("transform", function (d) { return "translate(" + d.y + "," + d.x + ")"; });
nodeUpdate.select("circle")
.attr("r", 4.5)
.style("fill", function (d) {
if (d.class === "found") {
return "#ff4136"; //red
}
else if (d._children) {
return "lightsteelblue";
}
else {
return "#fff";
}
})
.style("stroke", function (d) {
if (d.class === "found") {
return "#ff4136"; //red
}
});
nodeUpdate.select("text") //NOCARRY
.style("fill-opacity", 1);
// Transition exiting nodes to the parent's new position.
var nodeExit = node.exit().transition()
.duration(this.duration)
.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);
// Update the links…
var link = this.svg.selectAll("path.link")
.data(links, function (d: any) { return d.target.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)
.style("stroke", function (d) {
console.log("d IS")
console.log(d)
console.log("AND ITS TARGET IS")
console.log(d.target)
if (d.target.class === "found") {
return "#ff4136";
}
});
// Transition exiting nodes to the parent's new position.
link.exit().transition()
.duration(this.duration)
.attr("d", function (d) {
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;
});
}
searchTree(obj, search, path) {
console.log("ROOT IS ")
console.log(obj)
if (obj.name === search) { //if search is found return, add the object to the path and return it
path.push(obj);
return path;
}
else if (obj.children || obj._children) { //if children are collapsed d3 object will have them instantiated as _children
var children = (obj.children) ? obj.children : obj._children;
for (var i = 0; i < children.length; i++) {
path.push(obj);// we assume this path is the right one
var found = this.searchTree(children[i], search, path);
if (found) {// we were right, this should return the bubbled-up path from the first if statement
return found;
}
else {//we were wrong, remove this parent from the path and continue iterating
path.pop();
}
}
}
else {//not the right object, return false so it will continue to iterate in the loop
return false;
}
}
}
这里是tree.component.css
.node {
cursor: pointer;
}
.node circle {
fill: #fff;
stroke: steelblue;
stroke-width: 1.5px;
}
.found {
fill: #ff4136;
stroke: #ff4136;
}
.node text {
font: 10px sans-serif;
}
.link {
fill: none;
stroke: #ccc;
stroke-width: 1.5px;
}
我从平原JS唯一改变的为此,将所有变量作为TreeComponent类的一部分,并让类方法相应地对其执行操作。我已经尝试将原始svg锚定到其他元素,但是从来没有渲染过,所以在这里它将svg安装在body元素上。这是我看到的一个例子。
我在寻找它类似于此:(如何,将在纯JS渲染) 任何人有任何深入了解这是怎么回事呢?它看起来像只有一个节点和路径被追加,并在此之后停止。
答
好了,所以我已经想通了什么我的问题是。
d3将它自己的元素附加到DOM,而角度2不知道这个,所以当我以角度方式添加css元素时,它们被忽略,因为角度没有看到D3添加的元素。于是,我只好下面从D3增加,使我的CSS将适用,甚至动态生成的元素:
@Component({
selector: 'tree',
template:`
<div></div>
`,
styleUrls: ['./tree.component.css'],
encapsulation: ViewEncapsulation.None //No view encapsulation for D3 components
})
加入之后,该组件的CSS应用本身。
现在,我遇到的其他问题其实很简单。我对组件方法中提到的this
做出了错误的假设。这就是为什么只有一个节点和一个链接被绘制的根源。
首先,为什么你不采取d3版本4?那么,你能准确解释你想要做什么,以及你想要什么结果? – pirs
@pirs使用版本4将需要重写相当大量的代码。我们有一些利基功能,我们并不热衷于随着v4带来的变化重新开始。我已经上传了可视化基本应该看起来像的图像。 – jzeef
这显然是理解如何掌握代码的最佳方式,并且有很多遍历互联网的例子:https://bl.ocks.org/d3noob/43a860bc0024792f8803bba8ca0d5ecd – pirs