gpt4 book ai didi

javascript - 基于过滤器下拉列表在 d3 中的力图中添加和删除节点和链接

转载 作者:行者123 更新时间:2023-11-29 19:49:10 25 4
gpt4 key购买 nike

我正在尝试制作一个力图,其中有几个下拉框可以过滤显示的数据。第一个(这是我现在几乎要做的地方)检查类型,并且只显示具有与类型匹配的源或目标的节点和链接。

我现在拥有的是选择过滤器和图形更新的能力,它删除不必要的节点,并重新格式化剩余的节点以使其正确。但它只在第一次起作用。如果我“重新过滤”,它就会开始失控。

这是我的完整代码,我是 javascript (&d3) 的新手,而且我一直毫不掩饰地从 bl.ocks.org 窃取,所以请随时用“菜鸟”回答。提前致谢。

另外,我已经把它放在 jsfiddle 上了:http://jsfiddle.net/J85Vu/

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
<title>Enterprise Collaboration Map</title>
<script type="text/javascript" src="d3.v3.js"></script>
<script type="text/javascript" src="jquery-1.10.2.min.js"></script>

<style type="text/css">

path.link {
fill: none;
stroke: #666;
stroke-width: 1.5px;
}

marker#a {
fill: green;
}
path.link.a {
stroke: green;
}
circle.a {
fill: green;
stroke: #333;
stroke-width: 1.5px;
}
marker#b {
fill: blue;
}
path.link.b {
stroke: blue;
}
circle.b {
fill: blue;
stroke: #333;
stroke-width: 1.5px;
}
marker#c {
fill: orange;
}
path.link.c {
stroke: orange;
}
circle.c {
fill: orange;
stroke: #333;
stroke-width: 1.5px;
}

circle {
fill: #ccc;
stroke: #333;
stroke-width: 1.5px;
}


text {
font: 10px sans-serif;
pointer-events: none;
}

text.shadow {
stroke: #fff;
stroke-width: 3px;
stroke-opacity: .8;
}

</style>
</head>
<body>
<select class="BU">
<option value="a">A</option>
<option value="b">B</option>
<option value="c">C</option>
</select>


<script type="text/javascript">


var links = [
{source:"one",target:"two", type:"a", typeKBP:"a"},
{source:"two",target:"three", type:"a", typeKBP:"a"},
{source:"three",target:"four", type:"a", typeKBP:"a"},
{source:"four",target:"five", type:"a", typeKBP:"b"},
{source:"five",target:"six", type:"b", typeKBP:"b"},
{source:"six",target:"seven", type:"b", typeKBP:"b"},
{source:"seven",target:"eight", type:"b", typeKBP:"b"},
{source:"eight",target:"nine", type:"b", typeKBP:"c"},
{source:"nine",target:"ten", type:"c", typeKBP:"c"},
{source:"ten",target:"one", type:"c", typeKBP:"a"},
{source:"one",target:"three", type:"a", typeKBP:"a"},
{source:"two",target:"four", type:"a", typeKBP:"a"},
{source:"three",target:"five", type:"a", typeKBP:"b"},
{source:"four",target:"six", type:"a", typeKBP:"b"},
{source:"five",target:"seven", type:"b", typeKBP:"b"},
{source:"six",target:"eight", type:"b", typeKBP:"b"},
{source:"seven",target:"nine", type:"b", typeKBP:"c"},
{source:"eight",target:"ten", type:"b", typeKBP:"c"},
{source:"nine",target:"one", type:"c", typeKBP:"a"},
{source:"ten",target:"two", type:"c", typeKBP:"a"},
{source:"one",target:"four", type:"a", typeKBP:"a"},
{source:"two",target:"five", type:"a", typeKBP:"b"},
{source:"three",target:"six", type:"a", typeKBP:"b"},
{source:"four",target:"seven", type:"a", typeKBP:"b"},
{source:"five",target:"eight", type:"b", typeKBP:"b"},
{source:"six",target:"nine", type:"b", typeKBP:"c"},
{source:"seven",target:"ten", type:"b", typeKBP:"c"},
{source:"eight",target:"one", type:"b", typeKBP:"a"},
{source:"nine",target:"two", type:"c", typeKBP:"a"},
{source:"ten",target:"three", type:"c", typeKBP:"a"}
];

var inputlinks=[];
var nodes = {};

inputlinks.push(links);
// Compute the distinct nodes from the links.
links.forEach(function(link) {
link.source = nodes[link.source] || (nodes[link.source] = {name: link.source, type:link.type});
link.target = nodes[link.target] || (nodes[link.target] = {name: link.target, type:link.typeKBP});
});

var w = 1024,
h = 800;
//setup initial force layout
var force = d3.layout.force()
.gravity(0.4)
.size([w, h])
.nodes(d3.values(nodes))
.links(links)
.linkDistance(100)
.charge(-1000)
.on("tick", tick)
.start();

var svg = d3.select("body").append("svg:svg")
.attr("width", w)
.attr("height", h);

// Per-type markers, as they don't inherit styles.
svg.append("svg:defs").selectAll("marker")
.data(["a","b","c"])
.enter().append("svg:marker")
.attr("id", String)
.attr("viewBox", "0 -5 10 10")
.attr("refX", 15)
.attr("refY", -1.5)
.attr("markerWidth", 6)
.attr("markerHeight", 6)
.attr("orient", "auto")
.append("svg:path")
.attr("d", "M0,-5L10,0L0,5");

var path = svg.append("svg:g").selectAll("path")
.data(force.links())
.enter().append("svg:path")
.attr("class", function(d) { return "link " + d.type; })
.attr("marker-end", function(d) { return "url(#" + d.type + ")"; });

var circle = svg.append("svg:g").selectAll("circle")
.data(force.nodes())
.enter().append("svg:circle")
.attr("r", 6)
.attr("class", function(d) { return d.type; })
.call(force.drag);

var text = svg.append("svg:g").selectAll("g")
.data(force.nodes())
.enter().append("svg:g");

// A copy of the text with a thick white stroke for legibility.
text.append("svg:text")
.attr("x", 8)
.attr("y", ".31em")
.attr("class", "shadow")
.text(function(d) { return d.name; });

text.append("svg:text")
.attr("x", 8)
.attr("y", ".31em")
.attr("class","write")
.text(function(d) { return d.name; });

//jQuery update parts for drop downs.
$(document).ready(function(){
$('.BU').on('change',function(){
curBU=$('.BU').val();
//alert('The selected BU is ' + curBU);

//Filter links and rebuild nodes based on this.
minLinks={};
minLinks=links.filter(function(d){
if ((d.type==curBU) || (d.typeKBP==curBU)) {
return d
}
})
//new nodes
nodes2={};
nodes2=force.nodes().filter(function(d){return d3.keys(minLinks.filter(function(e){return e.source.name==d.name || e.target.name==d.name;})).length>0});

// minLinks.forEach(function(d) {
// d.source = nodes2[d.source] || (nodes2[d.source] = {name: d.source, type:d.type});
// d.target = nodes2[d.target] || (nodes2[d.target] = {name: d.target, type:d.typeKBP});
// });

force
.nodes(nodes2)
.links(minLinks)
.start();

//circle.remove();
newCirc=circle.data(force.nodes());
newCirc.enter().append("svg:circle")
.attr("r", 6)
.attr("class", function(d) { return d.type; })
.call(force.drag);
newCirc.exit().remove();

newPath=path.data(force.links());
newPath
.enter().append("svg:path")
.attr("class", function(d) { return "link " + d.type; })
.attr("marker-end", function(d) { return "url(#" + d.type + ")"; });
newPath.exit().remove();

newText=text.data(force.nodes());
newText.exit().remove();
newText.select(".shadow").text(function(d){return d.name;});
newText.select(".write").text(function(d){return d.name;});

});

});

// Use elliptical arc path segments to doubly-encode directionality.
function tick() {
path.attr("d", function(d) {
var dx = d.target.x - d.source.x,
dy = d.target.y - d.source.y,
dr = Math.sqrt((dx * dx)/2 + (dy * dy));
return "M" + d.source.x + "," + d.source.y + "A" + dr + "," + dr + " 0 0,1 " + d.target.x + "," + d.target.y;
});

circle.attr("transform", function(d) {
return "translate(" + d.x + "," + d.y + ")";
});

text.attr("transform", function(d) {
return "translate(" + d.x + "," + d.y + ")";
});
}


</script>
</body>
</html>

最佳答案

在您的更新代码中,您应该在与新数据进行数据绑定(bind)之前重新选择现有节点。在当前代码中,您使用变量 circlepath这实际上是指新添加的节点 enter选择。

在每次数据连接之前重新选择是确保您连接的是 DOM 中最新的实际状态的最佳方式:

svg.selectAll("path")
.data(force.links());

svg.selectAll("circle")
.data(force.nodes());

以某种方式对圆圈和路径进行分类可能是个好主意,这样您就可以更直接地选择它们,这样您就不会不小心在 svg 中选择其他路径或圆圈。

另外,在输入选项和更新选项上操作时要小心。考虑到您没有为数据连接定义键,这尤其如此,这意味着默认情况下将使用索引,从而导致现有节点被新数据更新。例如,在您的代码中,您只设置了 class新添加的节点上的属性,您可能希望在所有节点上更新它。

本教程是更好地理解这一点的良好起点:Thinking with Joins .

关于javascript - 基于过滤器下拉列表在 d3 中的力图中添加和删除节点和链接,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18334704/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com