d3.js 力定向图,节点不移动,停留在图的中心

cig3rfwq  于 2022-11-24  发布在  其他
关注(0)|答案(1)|浏览(267)

我有一个力图,其中节点实际上是一个“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() );
    }
2wnc66cl

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元素,但是,这不是很好的性能。

相关问题