如何防止完整的树渲染一次又一次当一个节点被点击?Power BI自定义可折叠树使用typescript和d3



我正在为power bi自定义视觉制作可折叠树。我想实现一个切换功能,允许我在单击节点时向上或向下钻取它。下面我提供了渲染树的当前代码,以及在单击节点时执行的另一个方法。我认为当一个节点被点击时,renderTree方法会从click方法中再次被调用,这将导致整个树再次被渲染。因此,我无法看到正在切换的节点。我需要什么改变或任何额外的方法。提前谢谢。

这是我到目前为止所尝试的,但它没有给我正确的结果。在这种情况下,测量的数据实际上是一个json树,并且tree()和diagonal()已经在类Visual的全局作用域中声明,就像这样:

// Declare an interface for the links/connections
interface LinkCoords {
x: number;
y: number;
}
// Declare an interface for a tree node
interface TreeNode {
name: string;
children?: TreeNode[];
// Dynamic addition of any incoming columns from analyze by data role
[key: string]: number | string | undefined | TreeNode[];
}
// Create a tree layout
private tree = d3
.tree()
// Height and width of the separations
.nodeSize([50, 300])
// Wether or not the nodes have same parent, there should be a separation of 2 units between nodes
.separation(function separation(a, b) {
return a.parent == b.parent ? 2 : 2;
});
// Links properties
private diagonal = d3
.linkHorizontal<{}, LinkCoords>()
.x((d) => d.y)
.y((d) => d.x);
// Function that would render the tree on the canvas
private renderTree(measuredData: TreeNode) {
// Compute the hierarchy
const root = d3.hierarchy(measuredData);
// Call the tree function
this.tree(root);
// Node variable
const node = this.treeContainer
.selectAll(".node")
.data(root.descendants())
.enter()
.append("g")
.attr("transform", function (d: any) {
return "translate(" + (d.y + 20) + "," + (d.x + 307) + ")";
})
.attr("font-size", 10)
.on("click", (event, d) => this.click(d.data));
// Node properties
node
.append("rect")
.attr("width", 150)
.attr("height", 50)
.style("stroke", function (d) {
return d.children ? "#5CCE8A" : "#D45F5F";
})
.attr("fill", "grey");
// Node text properties
node
.append("text")
.attr("x", 70)
.attr("y", 25)
.attr("text-anchor", "middle")
.text(
(d) => `name: ${d.data.name}, value: ${d.data.V}, import: ${d.data.I}`
)
.attr("fill", "white");
// Create links
const link = this.treeContainer
.selectAll(".link")
.data(root.links())
.enter();
// Define the path source and target for the links
link
.append("path")
.attr("class", "link")
.attr("fill", "none")
.attr("stroke", "white")
.attr("d", (d) => {
// Define the source
const source: LinkCoords = {
x: (d.source as any).x + 332,
y: (d.source as any).y + 170,
};
// Define the target
const target: LinkCoords = {
x: (d.target as any).x + 332,
y: (d.target as any).y + 20,
};
return this.diagonal({ source, target });
})
.attr("stroke-width", "1px")
.attr("stroke-dasharray", "1, 0");
}
// Toggle the node
private click(d: any) {
if (d.children) {
// If the clicked node has children
d._children = d.children; // Hide its children
d.children = null;
} else {
// If the clicked node does not have children
d.children = d._children; // Show its children
d._children = null;
}
this.renderTree(d);
}

不能看到被切换的节点的原因是,每次单击一个节点时,都在用更新的数据重新呈现整个树。您应该通过更新需要切换的节点的属性来修改现有树,而不是重新呈现整个树。

为了达到这个目的,你可以添加"collapsed"属性设置为每个节点,该属性将根据节点是折叠还是展开设置为true或false。然后,在点击功能中,您可以切换"折叠"。属性,然后更新SVG中相应节点的属性。

你可以这样修改

private click(d: any) {
if (d.children || d._children) {
if (d.collapsed) {
d.children = d._children;
d._children = null;
d.collapsed = false;
} else {
// If the clicked node is collapsed, expand it
d._children = d.children;
d.children = null;
d.collapsed = true; // using this property to change the behavior on click
}
const descendants = this.treeContainer
.selectAll(".node")
.data(this.tree(root).descendants());
descendants
.select("rect")
.style("stroke", function (d) {
return d.children || d._children ? "#5CCE8A" : "#D45F5F";
});
const links = this.treeContainer.selectAll(".link").data(this.tree(root).links());
links.exit().remove(); // removes the elements for those deleted in data 
links.enter() 
.append("path")
.attr("class", "link")
.attr("fill", "none")
.attr("stroke", "white")
.attr("stroke-width", "1px")
.attr("stroke-dasharray", "1, 0")
.merge(links)
.attr("d", (d) => {
const source: LinkCoords = {
x: (d.source as any).x + 332,
y: (d.source as any).y + 170,
};
const target: LinkCoords = {
x: (d.target as any).x + 332,
y: (d.target as any).y + 20,
};
return this.diagonal({ source, target });
});
}
}

最新更新