我有一个力图,其中节点实际上是一个“g”元素,带有一个附加的圆圈和一个附加的文本元素。
我的节点遇到了问题,因为它们在拖动时不移动,并且没有定位在链接的尖端上。
如果我只把我的节点改成简单的圆,那么它就能正常工作。但是我无法让它与“g”元素一起工作。
有人建议我使用“.attr(“transform”,函数(d){ return“translate(“+ d.x +“,”+ d.y +“)";});”,因为“g”元素没有cx和cy值(因为这些值特定于圆)。
我认为问题出在我创建drag()函数的方式上。
任何帮助都是非常欢迎的
ForceGraph(){
var links = [
{src:"John",target:"Aurora"},
{src:"John",target:"Mary"},
{src:"John",target:"Erik"},
{src:"John",target:"Susan"},
{src:"John",target:"Mel"},
]
var nodes = [
{id:"John"},
{id:"Aurora"},
{id:"Mary"},
{id:"Erik"},
{id:"Susan"},
{id:"Mel"},
]
var width = this.$refs.mapFrame.clientWidth // scale to parent container
var height = this.$refs.mapFrame.clientHeight // scale to parent container
// Compute values.
var nodeId = d => d.id // given d in nodes, returns a unique identifier (string)
const N = d3.map(nodes, nodeId);
const nodeTitle = (_, i) => N[i];
const T = d3.map(nodes, nodeTitle);
// Replace the input nodes and links with mutable objects for the simulation.
nodes = nodes.map(n => Object.assign({}, n));
links = links.map(l => ({
orig: l,
source: l.src,
target: l.target
}));
// Construct the forces.
const forceNode = d3.forceManyBody();
const forceLink = d3.forceLink(links).id(({index: i}) => N[i]);
forceNode.strength(-450);
forceLink.strength(1);
forceLink.distance(100)
const simulation = d3.forceSimulation(nodes)
.force(link, forceLink)
.force("charge", forceNode)
.force("x", d3.forceX())
.force("y", d3.forceY())
.on("tick", ticked);
const svg = d3.create("svg")
.attr("id", "svgId")
.attr("preserveAspectRatio", "xMidYMid meet")
.attr("viewBox", [-width/2,-height/2, width,height])
.classed("svg-content-responsive", true)
const link = svg.append("g")
.selectAll("line")
.data(links)
.join("line").attr("stroke", "white")
.attr("stroke-width", "5")
;
var node = svg
.selectAll(".circle-group")
.data(nodes)
.join(enter => {
node = enter.append("g")
.attr("class", "circle-group")
.call(drag(simulation));
node.append("circle")
.attr("class", "background")
.style("fill", "blue")
.attr("r", 30)
// .call(drag(simulation));
node.append("text")
.attr("class", "foreground")
.attr("dx", function(){return -20})
.style('font-size', 30 * 0.4 + 'px')
.text(({index: i}) => T[i])
// .call(drag(simulation))
node.attr("stroke", "grey");
})
node.call(drag(simulation));
function ticked() {
link
.attr("x1", d => d.source.x)
.attr("y1", d => d.source.y)
.attr("x2", d => d.target.x)
.attr("y2", d => d.target.y);
node
.attr("transform", function (d) { return "translate(" + d.x + "," + d.y + ")";});
// .attr("cx", d => d.x)
// .attr("cy", d => d.y);
}
function drag(simulation) {
function dragstarted(event) {
if (!event.active) simulation.alphaTarget(0.3).restart();
event.subject.fx = event.subject.x;
event.subject.fy = event.subject.y;
}
function dragged(event) {
event.subject.fx = event.x;
event.subject.fy = event.y;
}
function dragended(event) {
if (!event.active) simulation.alphaTarget(0);
event.subject.fx = null;
event.subject.fy = null;
}
return d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended);
}
return Object.assign(svg.node() );
}
1条答案
按热度按时间2wnc66cl1#
变量
node
应该是空的,这意味着tick函数中没有更新任何内容。下面是一个简单的join示例,我随后调用了selection.size()
,以查看node
选择了多少项:第一个
这是预期的,联接返回合并的输入和更新选择;但是,由于我们提供了一个自定义的enter函数,因此需要显式返回输入的节点(如果提供自定义的update函数,我们也需要这样做)。
由enter和update函数返回的选择被合并,然后由selection返回。join
如果我们把
return node
加到enter函数的末尾,我们可以看到我们的选择大小现在是3。第一次
现在,由于
node
包括输入的节点,tick函数应该按预期工作。另一种方法是使用
d3.select(".circle-group")
而不是node
在每个节拍选择g
元素,但是,这不是很好的性能。