以编程方式打开d3.js v4可折叠树节点? [英] Programmatically opening d3.js v4 collapsible tree nodes?
问题描述
我修改了d3noob的d3.js版本4
https://bl.ocks.org/d3noob/43a860bc0024792f8803bba8ca0d5ecd
麦克·波斯托克(Mike Bostock)可折叠树的衍生物
https://bl.ocks.org/mbostock/4339083
添加基于鼠标的平移和缩放,并从外部文件加载JSON数据.
https://jsfiddle.net/vstuart/acx5zfgn/31/ >
- [已更新,有解决方案] https://jsfiddle.net/vstuart/acx5zfgn/62/
尽管未显示在此小提琴中,但在我的HTML前端(基于AjaxSolr框架)中,我具有与Apache Solr方面相对应的超链接,这些超链接可以在单击时更新网页(通过更新的Solr请求)
所有这些都运行良好.
但是,当我单击这些方面的超链接时,我还希望能够扩展相应的d3.js节点.
任何建议将不胜感激.
附录.被接受的答案(Michael Rovinsky)效果很好.对于那些对答案感兴趣的人,我在两个地方更新了我的JSFiddle,HTML代码(如下)和GitHub Gist:在该代码中搜索每个答案".查看添加的内容.
为验证添加的代码,我将更新后的HTML内容保存在Gist中,保存到新的index.html文件中,该文件将在localhost(无需网络服务器)上运行的Firefox v88.0中按预期运行.
单页代码
<!DOCTYPE html>< html lang ="en-US"xmlns:xlink =" http://www.w3.org/1999/xlink">< head>< meta content =" text/html;charset = utf-8";http-equiv ="Content-Type"< style>.node {光标:指针;}.node circle {填充:#fff;中风:steelblue;笔划宽度:3px;}.node文字{字体:12px sans-serif;}.关联 {填充:无;中风:#ccc;笔划宽度:2px;}#includedContent {位置:静态!重要;显示:inline-block;}#d3_object {宽度:75%;保证金:0.5rem 0.5rem 1rem 0.25rem;}</style>< script type ="文本/javascript"src =" https://code.jquery.com/jquery-3.5.1.min.js"完整性="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0 ="crossorigin =匿名"</script>< script src =" https://d3js.org/d3.v4.min.js"</script></head><身体>< div id ="d3_object">< object>< div id ="includedContent"</div</object></div><!-****添加,例如将打开的超链接数据"d3.js树中的节点*****->< script>//设置图表的尺寸和边距var margin = {顶部:20,右侧:90,底部:30,左侧:90},宽度= 960-margin.left-margin.right,高度= 500-margin.top-margin.bottom;//----------------------------------------/*平移,缩放!*///https://www.d3-graph-gallery.com/graph/interactivity_zoom.htmlvar svg = d3.select("body").append("svg").attr("width",width + margin.right + margin.left).attr(身高",身高+ margin.top + margin.bottom).call(d3.zoom().on("zoom",function(){svg.attr("transform",d3.event.transform)})).append("g").attr("transform","translate("+ margin.left +,"+ margin.top +)");//----------------------------------------var i = 0,持续时间= 250根;//声明树形布局并指定大小var treemap = d3.tree().size([height,width]);//加载外部数据d3.json("https://gist.githubusercontent.com/mbostock/4339083/raw/9585d220bef18a0925922f4d384265ef767566f5/flare.json",函数(错误,treeData){如果(错误)抛出错误;//分配父项,子项,高度,深度root = d3.hierarchy(treeData,function(d){return d.children;});root.x0 =高度/2;root.y0 = 0;//在第二级之后折叠root.children.forEach(折叠);更新(根);});//折叠节点及其所有子节点函数collapse(d){if(d.children){d._children = d.childrend._children.forEach(折叠)d.children =空}}功能更新(源){//为节点分配x和y位置var treeData = treemap(root);//计算新的树布局.变量节点= treeData.descendants(),链接= treeData.descendants().slice(1);//归一化为固定深度.nodes.forEach(function(d){d.y = d.depth * 180});//**********节点部分*******************//更新节点...var node = svg.selectAll('g.node').data(nodes,function(d){return d.id ||(d.id = ++ i);});//在父级的上一个位置输入任何新模式.var nodeEnter = node.enter().append('g').attr('class','node')//--------------------------------------------//每个答案位于//https://stackoverflow.com/questions/67480339/programmatically-opening-d3-js-v4-collapsible-tree-nodes.attr('节点名称',d => d.data.name)//--------------------------------------------.attr("transform",function(d){返回"translate(" + source.y0 +," + source.x0 +)";}).on('click',click);//为节点添加CirclenodeEnter.append('circle').attr('class','node').attr('r',1e-6).style("fill",function(d){返回d._children吗?"lightsteelblue":#fff";});//为节点添加标签nodeEnter.append('text').attr("dy",.35em").attr("x",function(d){返回d.children ||d._children?-13:13;}).attr(文字锚",function(d){返回d.children ||d._children?结束":开始";}).text(function(d){return d.data.name;});//更新var nodeUpdate = nodeEnter.merge(node);//过渡到该节点的正确位置nodeUpdate.transition().duration(持续时间).attr("transform",function(d){返回"translate(" + d.y +," + d.x +)";});//更新节点属性和样式nodeUpdate.select('circle.node').attr('r',10).style("fill",function(d){返回d._children吗?"lightsteelblue":#fff";}).attr('cursor','pointer');//删除所有现有节点var nodeExit = node.exit().transition().duration(持续时间).attr("transform",function(d){返回"translate(" + source.y +``,+ + source.x +")";}).去掉();//在退出时,将节点圆圈的大小减小为0nodeExit.select('circle').attr('r',1e-6);//在退出时减少文本标签的不透明度nodeExit.select('文本').style('fill-opacity',1e-6);//**********链接部分*******************//更新链接...var link = svg.selectAll('path.link').data(links,function(d){return d.id;});//在父级的上一个位置输入任何新链接.var linkEnter = link.enter().insert('path',"g").attr("class","link").attr('d',function(d){var o = {x:source.x0,y:source.y0}返回对角线(o,o)});//更新var linkUpdate = linkEnter.merge(link);//过渡回父元素位置linkUpdate.transition().duration(持续时间).attr('d',function(d){return对角线(d,d.parent)});//删除所有现有链接var linkExit = link.exit().transition().duration(持续时间).attr('d',function(d){var o = {x:source.x,y:source.y}返回对角线(o,o)}).去掉();//存储旧职位以进行过渡.nodes.forEach(function(d){d.x0 = d.x;d.y0 = d.y;});//创建从父节点到子节点的弯曲(对角线)路径函数对角线(s,d){路径=`M $ {s.y} $ {s.x}C $ {(s.y + d.y)/2} $ {s.x},$ {(s.y + d.y)/2} $ {d.x},$ {d.y} $ {d.x}`返回路径}//----------------------------------------//在点击时切换孩子.功能click(d){如果(d.children){d._children = d.children;d.children = null;}否则,如果(d._children){d.children = d._children;d._children = null;} 别的 {//这是一个叶节点,因此重定向.console.log('d:',d)console.log('d.data:',d.data)console.log('d.name:',d.name)console.log('d.data.name:',d.data.name)console.log('urlMap [d.data.name]:',urlMap [d.data.name])window.location = d.data.url;//window.open("https://www.example.com","_self");}更新);}//----------------------------------------}//每个答案位于//https://stackoverflow.com/questions/67480339/programmatically-opening-d3-js-v4-collapsible-tree-nodessetTimeout(()=> {const node = d3.select('.node [node-name ="analytics"]').node();console.log('NODE:',node);node.dispatchEvent(new Event('click'));},2500);</script></body></html>
可以通过在特定节点上触发click事件来完成.这是一个示例,用于扩展节点"Analytics"初始渲染后几秒钟.
首先,为每个节点分配一个唯一的属性(或类名或 id )以在DOM中找到它:
node.enter().append('g').classed('node',true).attr('节点名称',d => d.data.name)....on('click',click);
然后,在特定节点上触发 click 事件:
d3.select('.node [node-name ="analytics"]').node().dispatchEvent(new Event('click'));
I have modified d3noob's d3.js version 4
https://bl.ocks.org/d3noob/43a860bc0024792f8803bba8ca0d5ecd
derivative of Mike Bostock's collapsible tree
https://bl.ocks.org/mbostock/4339083
adding mouse-based pan and zoom, and loading the JSON data from an external file.
https://jsfiddle.net/vstuart/acx5zfgn/31/
- [updated, with solution] https://jsfiddle.net/vstuart/acx5zfgn/62/
Although not shown in that fiddle, in my HTML frontend (based on the AjaxSolr framework) I have hyperlinks corresponding to Apache Solr facets that when clicked update the web page (via an updated Solr request)
All of that is working well.
However, I also want to be able to have the corresponding d3.js node expand, when I click those facet hyperlinks.
Any suggestions would be greatly appreciated.
Addendum. The accepted answer (Michael Rovinsky) works well. For those interested in the answer, I updated my JSFiddle, HTML code (below) and GitHub Gist -- all at two places: search that code for "per answer at" to view the additions.
To verify the code additions, I dumped my updated the HTML content in my Gist to a new index.html file, which runs as expected in Firefox v88.0 running on localhost (no webserver needed).
Single-page code
<!DOCTYPE html>
<html lang="en-US" xmlns:xlink="http://www.w3.org/1999/xlink">
<head>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
<style>
.node {
cursor: pointer;
}
.node circle {
fill: #fff;
stroke: steelblue;
stroke-width: 3px;
}
.node text {
font: 12px sans-serif;
}
.link {
fill: none;
stroke: #ccc;
stroke-width: 2px;
}
#includedContent {
position: static !important;
display: inline-block;
}
#d3_object {
width: 75%;
margin: 0.5rem 0.5rem 1rem 0.25rem;
}
</style>
<script type="text/javascript" src="https://code.jquery.com/jquery-3.5.1.min.js" integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script>
<script src="https://d3js.org/d3.v4.min.js"></script>
</head>
<body>
<div id="d3_object">
<object>
<div id="includedContent"></div>
</object>
</div>
<!-- **** ADD, e.g., A HYPERLINK HERE THAT WILL OPEN
the "data" NODE IN THE d3.js TREE ***** -->
<script>
// Set the dimensions and margins of the diagram
var margin = {top: 20, right: 90, bottom: 30, left: 90},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
// ----------------------------------------
/* Pan, zoom! */
// https://www.d3-graph-gallery.com/graph/interactivity_zoom.html
var svg = d3.select("body").append("svg")
.attr("width", width + margin.right + margin.left)
.attr("height", height + margin.top + margin.bottom)
.call(d3.zoom().on("zoom", function () {
svg.attr("transform", d3.event.transform)
}))
.append("g")
.attr("transform", "translate("
+ margin.left + "," + margin.top + ")");
// ----------------------------------------
var i = 0,
duration = 250,
root;
// declares a tree layout and assigns the size
var treemap = d3.tree().size([height, width]);
// load the external data
d3.json("https://gist.githubusercontent.com/mbostock/4339083/raw/9585d220bef18a0925922f4d384265ef767566f5/flare.json", function(error, treeData) {
if (error) throw error;
// Assigns parent, children, height, depth
root = d3.hierarchy(treeData, function(d) { return d.children; });
root.x0 = height / 2;
root.y0 = 0;
// Collapse after the second level
root.children.forEach(collapse);
update(root);
});
// Collapse the node and all it's children
function collapse(d) {
if(d.children) {
d._children = d.children
d._children.forEach(collapse)
d.children = null
}
}
function update(source) {
// Assigns the x and y position for the nodes
var treeData = treemap(root);
// Compute the new tree layout.
var nodes = treeData.descendants(),
links = treeData.descendants().slice(1);
// Normalize for fixed-depth.
nodes.forEach(function(d){ d.y = d.depth * 180});
// ********** Nodes section *******************
// Update the nodes...
var node = svg.selectAll('g.node')
.data(nodes, function(d) {return d.id || (d.id = ++i); });
// Enter any new modes at the parent's previous position.
var nodeEnter = node.enter().append('g')
.attr('class', 'node')
// --------------------------------------------
// per answer at
// https://stackoverflow.com/questions/67480339/programmatically-opening-d3-js-v4-collapsible-tree-nodes
.attr('node-name', d => d.data.name)
// --------------------------------------------
.attr("transform", function(d) {
return "translate(" + source.y0 + "," + source.x0 + ")";
})
.on('click', click);
// Add Circle for the nodes
nodeEnter.append('circle')
.attr('class', 'node')
.attr('r', 1e-6)
.style("fill", function(d) {
return d._children ? "lightsteelblue" : "#fff";
});
// Add labels for the nodes
nodeEnter.append('text')
.attr("dy", ".35em")
.attr("x", function(d) {
return d.children || d._children ? -13 : 13;
})
.attr("text-anchor", function(d) {
return d.children || d._children ? "end" : "start";
})
.text(function(d) { return d.data.name; });
// UPDATE
var nodeUpdate = nodeEnter.merge(node);
// Transition to the proper position for the node
nodeUpdate.transition()
.duration(duration)
.attr("transform", function(d) {
return "translate(" + d.y + "," + d.x + ")";
});
// Update the node attributes and style
nodeUpdate.select('circle.node')
.attr('r', 10)
.style("fill", function(d) {
return d._children ? "lightsteelblue" : "#fff";
})
.attr('cursor', 'pointer');
// Remove any exiting nodes
var nodeExit = node.exit().transition()
.duration(duration)
.attr("transform", function(d) {
return "translate(" + source.y + "," + source.x + ")";
})
.remove();
// On exit reduce the node circles size to 0
nodeExit.select('circle')
.attr('r', 1e-6);
// On exit reduce the opacity of text labels
nodeExit.select('text')
.style('fill-opacity', 1e-6);
// ********** links section *******************
// Update the links...
var link = svg.selectAll('path.link')
.data(links, function(d) { return d.id; });
// Enter any new links at the parent's previous position.
var linkEnter = link.enter().insert('path', "g")
.attr("class", "link")
.attr('d', function(d){
var o = {x: source.x0, y: source.y0}
return diagonal(o, o)
});
// UPDATE
var linkUpdate = linkEnter.merge(link);
// Transition back to the parent element position
linkUpdate.transition()
.duration(duration)
.attr('d', function(d){ return diagonal(d, d.parent) });
// Remove any exiting links
var linkExit = link.exit().transition()
.duration(duration)
.attr('d', function(d) {
var o = {x: source.x, y: source.y}
return diagonal(o, o)
})
.remove();
// Store the old positions for transition.
nodes.forEach(function(d){
d.x0 = d.x;
d.y0 = d.y;
});
// Creates a curved (diagonal) path from parent to the child nodes
function diagonal(s, d) {
path = `M ${s.y} ${s.x}
C ${(s.y + d.y) / 2} ${s.x},
${(s.y + d.y) / 2} ${d.x},
${d.y} ${d.x}`
return path
}
// ----------------------------------------
// Toggle children on click.
function click(d) {
if (d.children) {
d._children = d.children;
d.children = null;
} else if (d._children) {
d.children = d._children;
d._children = null;
} else {
// This was a leaf node, so redirect.
console.log('d:', d)
console.log('d.data:', d.data)
console.log('d.name:', d.name)
console.log('d.data.name:', d.data.name)
console.log('urlMap[d.data.name]:', urlMap[d.data.name])
window.location = d.data.url;
// window.open("https://www.example.com", "_self");
}
update(d);
}
// ----------------------------------------
}
// per answer at
// https://stackoverflow.com/questions/67480339/programmatically-opening-d3-js-v4-collapsible-tree-nodes
setTimeout(() => {
const node = d3.select('.node[node-name="analytics"]').node();
console.log('NODE: ', node);
node.dispatchEvent(new Event('click'));
}, 2500);
</script>
</body>
</html>
Can be done by triggering a click event on a specific node. Here is an example of expanding the node "Analytics" few seconds after initial render.
First, assign a unique attribute (or class name or id) to every node to find it in the DOM:
node.enter().append('g')
.classed('node', true)
.attr('node-name', d => d.data.name)
...
.on('click', click);
Then, trigger a click event on a specific node:
d3.select('.node[node-name="analytics"]').node().dispatchEvent(new Event('click'));
这篇关于以编程方式打开d3.js v4可折叠树节点?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!