我创建了一个简单的 D3 Force 布局图。 Please check it out in the JSFiddle here.
该图非常基本 - 它以城市为节点,连接到代表其所在国家的节点。为简单起见,我只创建了六个节点。
我创建了一个名为 deleteNodeOnClick()
的函数并将其设置为 nodes
像这样
var nodeEnter = node.enter()
.append('g')
.attr('class', 'node')
.on("click", deleteNodeOnClick)
当您单击图表中的节点时,该节点将从数据中删除(实际上,为了简单起见,暂时从数据中删除第一个节点)但是它不会从可 View 表中删除强>。您可以在控制台中查看,发现它实际上已从数据中删除。
为什么不呢?我完全被难住了。
代码
var data = {
nodes: [{
name: "Canada"
}, {
name: "Montreal"
}, {
name: "Toronto"
}, {
name: "USA"
}, {
name: "New York"
}, {
name: "Los Angeles"
}],
links: [{
source: 0,
target: 1
}, {
source: 0,
target: 2
}, {
source: 3,
target: 4
}, {
source: 3,
target: 5
}, ]
};
var node;
var link;
var force;
var width = 400,
height = 400;
var svg = d3.select("body").append("svg")
.attr("width", window.innerWidth)
.attr("height", window.innerHeight);
force = d3.layout.force()
.size([width, length])
.nodes(data.nodes)
.links(data.links)
.gravity(.1)
.alpha(0.01)
.charge(-400)
.friction(0.5)
.linkDistance(100)
.on('tick', forceLayoutTick);
var link = svg.selectAll(".link")
.data(data.links);
var linkEnter = link.enter()
.append('line')
.attr('class', 'link');
link.exit().remove();
node = svg.selectAll('.node')
.data(data.nodes, function(d){
return d.name;
});
node.exit().remove();
var nodeEnter = node.enter()
.append('g')
.attr('class', 'node')
.on("click", deleteNodeOnClick)
//.attr('r', 8)
//.attr('cx', function(d, i){ return (i+1)*(width/4); })
//.attr('cy', function(d, i){ return height/2; })
.call(force.drag);
nodeEnter
.append("circle")
.attr("cx", 0)
.attr("cy", 0)
.attr("r", 10)
.style("fill", "purple");
nodeEnter
.append("text")
.text(function(d) { return d.name })
.attr("class", "label")
.attr("dx", 0)
.attr("dy", ".35em");
force.start();
function forceLayoutTick(){
node.attr("transform", function(d) {
// Keep in bounding box
d.x = Math.max(10, Math.min(width - 10, d.x));
d.y = Math.max(10, Math.min(height - 10, d.y));
return "translate(" + d.x + "," + d.y + ")";
});
link
.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; });
};
function deleteNodeOnClick(d){
var dataBefore = JSON.parse(JSON.stringify(data.nodes));
// Just delete the first node, for demonstration purposes
data.nodes.splice(0, 1);
console.info("Node should be removed", dataBefore, data.nodes);
}
CSS
#graph {
width: 100%;
height: 100%;
}
#graph svg {
background-color: #CCC;
}
.link {
stroke-width: 2px;
stroke: black;
}
.node {
background-color: darkslategray;
stroke: #138;
width: 10px;
height: 10px;
stroke-width: 1.5px;
}
.node text {
pointer-events: none;
font: 10px sans-serif;
}
.label {
display: block;
}
最佳答案
在 D3 中,更改数据不会自动更改 SVG(或 Canvas 、HTML...)元素。您必须“重新绘制”您的数据可视化。
好消息是您拥有(几乎)所有选择。因此,为了向您展示总体思路,我将所有渲染代码放在 draw
函数中,该函数在单击时调用:
function deleteNodeOnClick(d){
data.nodes = data.nodes.filter(function(e){
return e.name !== d.name;
});
draw();
}
查看演示:
var data = {
nodes: [{
name: "Canada"
}, {
name: "Montreal"
}, {
name: "Toronto"
}, {
name: "USA"
}, {
name: "New York"
}, {
name: "Los Angeles"
}],
links: [{
source: 0,
target: 1
}, {
source: 0,
target: 2
}, {
source: 3,
target: 4
}, {
source: 3,
target: 5
}, ]
};
var node;
var link;
var force;
var width = 400,
height = 400;
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
draw();
function draw() {
force = d3.layout.force()
.size([width, height])
.nodes(data.nodes)
.links(data.links)
.alpha(0.01)
.charge(-400)
.friction(0.5)
.linkDistance(100)
.on('tick', forceLayoutTick);
var link = svg.selectAll(".link")
.data(data.links);
var linkEnter = link.enter()
.append('line')
.attr('class', 'link');
link.exit().remove();
node = svg.selectAll('.node')
.data(data.nodes, function(d) {
return d.name;
});
node.exit().remove();
var nodeEnter = node.enter()
.append('g')
.attr('class', 'node')
.on("click", deleteNodeOnClick)
//.attr('r', 8)
//.attr('cx', function(d, i){ return (i+1)*(width/4); })
//.attr('cy', function(d, i){ return height/2; })
.call(force.drag);
nodeEnter
.append("circle")
.attr("cx", 0)
.attr("cy", 0)
.attr("r", 10)
.style("fill", "purple");
nodeEnter
.append("text")
.text(function(d) {
return d.name
})
.attr("class", "label")
.attr("dx", 0)
.attr("dy", ".35em");
force.start();
function forceLayoutTick() {
node.attr("transform", function(d) {
// Keep in bounding box
d.x = Math.max(10, Math.min(width - 10, d.x));
d.y = Math.max(10, Math.min(height - 10, d.y));
return "translate(" + d.x + "," + d.y + ")";
});
link
.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;
});
};
};
function deleteNodeOnClick(d) {
data.nodes = data.nodes.filter(function(e) {
return e.name !== d.name;
});
draw();
}
#graph svg {
background-color: #CCC;
}
.link {
stroke-width: 2px;
stroke: black;
}
.node {
background-color: darkslategray;
stroke: #138;
width: 10px;
height: 10px;
stroke-width: 1.5px;
}
.node text {
pointer-events: none;
font: 10px sans-serif;
}
.label {
display: block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<body></body>
当然,正如我所说,这只是为了给您提供总体思路:例如,单击不会删除链接。但现在您知道如何让它发挥作用了。
关于javascript - exit().remove() 在我的 D3.js 强制布局图中不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41365884/