使用D3.js v4在力有向图上进行不稳定的缩放

使用D3.js v4在力有向图上进行不稳定的缩放,d3.js,graph,zooming,D3.js,Graph,Zooming,我在D3.js(v4)中有一个力定向图: 除缩放操作外,一切正常:整个图形实际上是在左上角[0,0]原点平移,而不是在点击点居中缩放,即使图形的中心原点是屏幕的中心(d3.forceCenter(w/2,h/2)) 我不是D3方面的专家,但我知道我在代码中做了一些错误的事情,或者遗漏了一些东西,我不明白是什么和为什么 我需要您的帮助,请提前通知我。几件事: 调用.call(zoom)的是事件处理程序,该元素查找要缩放的事件。这不应该直接用于SVG。通常的形式是在SVG上放置一个不可见的rect来

我在D3.js(v4)中有一个力定向图:

除缩放操作外,一切正常:整个图形实际上是在左上角[0,0]原点平移,而不是在点击点居中缩放,即使图形的中心原点是屏幕的中心(
d3.forceCenter(w/2,h/2)

我不是D3方面的专家,但我知道我在代码中做了一些错误的事情,或者遗漏了一些东西,我不明白是什么和为什么

我需要您的帮助,请提前通知我。

几件事:

  • 调用
    .call(zoom)
    的是事件处理程序,该元素查找要缩放的事件。这不应该直接用于SVG。通常的形式是在SVG上放置一个不可见的rect来捕获这些事件
  • 您不能以当前的方式将SVG缩放应用于
    SVG
    元素。这有点违反直觉,但是
    svg
    标记是一个HTML元素,其中的内容是
    svg
    元素。那么,你是做什么的?将图形包装在应用缩放的
    g
  • 把这两个想法放在一起,你会得到:

    
    svg文本{
    指针事件:无;
    }   
    var r=7,w=window.innerWidth,h=window.innerHeight,nodes=[],colors=d3.scaleOrdinal(d3.schemeCategory20c);
    var force=d3.forceSimulation()
    .velocityDecay(0.9)
    .字母衰减(0)
    .force(“电荷”,d3.forceManyBody())
    .force(“排斥”,d3.forceManyBody()。强度(-140)。距离最大值(100)。距离最小值(10))
    .力(“中心”,d3.力中心(w/2,h/2))
    .力(“x”,d3.力x(w/2))
    .力(“y”,d3.力(h/2));
    var zoom=d3.zoom()
    .scaleExtent([0.3,8])
    。打开(“缩放”,缩放);
    var svg=d3.选择(“正文”).追加(“svg”)
    .attr(“宽度”,w)
    .attr(“高度”,h)
    var g=svg.append(“g”);
    svg.append(“rect”)
    .attr(“宽度”,w)
    .attr(“高度”,h)
    .style(“填充”、“无”)
    .style(“指针事件”、“全部”)
    .呼叫(缩放);
    d3.json(“https://jsonblob.com/api/eb8b41b1-0c23-11e7-a0ba-092e370a78bd,函数(数据){
    var root=d3.层次结构(数据);
    var nodes=root.subjects();
    var links=root.links();
    力节点(节点);
    力。力(“链接”,d3。力链接(链接)。强度(1)。距离(50));
    var link=g.selectAll(“行”)
    .数据(链接)
    .enter().insert(“行”)
    .style(“笔划”,“#999”)
    .样式(“笔划宽度”、“1px”);
    var nodeElements=g.selectAll(“circle.node”)
    .数据(节点)
    .enter().append(“圆”)
    .attr(“r”,r)
    .样式(“填充”,功能(d){
    返回颜色(d.parent&&d.parent.data.name);
    })
    .style(“笔划”,“#0b5698”)
    .call(d3.drag()
    .on(“开始”,拖动开始)
    .打开(“拖动”,拖动)
    。在(“结束”,dragEnded));
    var labels=g.selectAll(“.mytext”)
    .数据(节点)
    .输入()
    .append(“文本”)
    .attr(“dx”,12)
    .attr(“dy”,“.35em”)
    .text(函数(d){return d.data.name})
    .style(“文本锚定”、“中间”)
    .样式(“填充”、“#555”)
    .style(“字体系列”、“Arial”)
    .style(“字体大小”,7);
    强制开启(“勾选”),功能(e){
    attr(“x1”,函数(d){返回d.source.x;})
    .attr(“y1”,函数(d){返回d.source.y;})
    .attr(“x2”,函数(d){返回d.target.x;})
    .attr(“y2”,函数(d){返回d.target.y;});
    attr(“cx”,函数(d){return d.x;})
    .attr(“cy”,函数(d){返回d.y;});
    attr(“x”,函数(d){返回d.x-10;})
    .attr(“y”,函数(d){返回d.y+10;});
    });
    });
    函数dragStarted(d){
    d、 fx=d.x;
    d、 fy=d.y;
    }
    函数(d){
    d、 fx=d3.event.x;
    d、 fy=d3.event.y;
    }
    函数d(d){
    d、 fx=null;
    d、 fy=null;
    }
    函数缩放(){
    g、 attr(“transform”,d3.event.transform);
    }
    
    非常感谢马克,我理解你的决议,它有效。但是,它有一个(大)问题:节点上的鼠标拖动功能失败:通过勾号功能控制节点和链接位置的力模拟不再工作。当我尝试用鼠标拖动节点时,整个图形都在平移。
    <!DOCTYPE html>
    <html>
    <head>
      <script src="https://d3js.org/d3.v4.min.js"></script>
    </head>
    <style>
        svg text {
             pointer-events: none;     
        }   
    </style>
    <body>
    
    <script type="text/javascript">
        var  r = 7, w=window.innerWidth, h=window.innerHeight, nodes = [], colors = d3.scaleOrdinal(d3.schemeCategory20c);
        var force = d3.forceSimulation()
                .velocityDecay(0.9)
                .alphaDecay(0)
                .force("charge", d3.forceManyBody())   
                .force("repel", d3.forceManyBody().strength(-140).distanceMax(100).distanceMin(10))
                .force("center", d3.forceCenter(w /2, h/2))
                .force("x", d3.forceX(w / 2))
                .force("y", d3.forceY(h / 2));
    
        var zoom = d3.zoom()
            .scaleExtent([0.3, 8])
            .on("zoom", zoomed);
    
    
        var svg = d3.select("body").append("svg")
                .attr("width", w)
                .attr("height", h)
                .call(zoom);  
    
     d3.json("tiles1.json", function (data) {
            var root = d3.hierarchy(data); 
            var nodes = root.descendants(); 
            var links = root.links(); 
            force.nodes(nodes); 
            force.force("link", d3.forceLink(links).strength(1).distance(50));
              var link = svg.selectAll("line")
                  .data(links)
                  .enter().insert("line")
                  .style("stroke", "#999")
                  .style("stroke-width", "1px");
              var nodeElements = svg.selectAll("circle.node")
                  .data(nodes)
                  .enter().append("circle")
                  .attr("r", r)
                  .style("fill", function(d) {
                      return colors(d.parent && d.parent.data.name); 
                  })
                  .style("stroke", "#0b5698")
                    .call(d3.drag()
                          .on("start", dragStarted)
                          .on("drag", dragged)
                          .on("end", dragEnded));
    
            var labels = svg.selectAll(".mytext")
             .data(nodes)
             .enter()
             .append("text")
              .attr("dx", 12)
              .attr("dy", ".35em")
              .text(function(d) { return d.data.name })
                        .style("text-anchor", "middle")
                            .style("fill", "#555")
                            .style("font-family", "Arial")
                            .style("font-size", 7);
    
          force.on("tick", function(e) {
                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; });
                nodeElements.attr("cx", function(d) { return d.x; })
                    .attr("cy", function(d) { return d.y; });
                labels.attr("x", function(d){ return d.x -10; })
                     .attr("y", function (d) {return d.y + 10; });
              });
     });
    
        function dragStarted(d) {
            d.fx = d.x;
            d.fy = d.y;
        }
        function dragged(d) {
            d.fx = d3.event.x;
            d.fy = d3.event.y;
        }
        function dragEnded(d) {
            d.fx = null;
            d.fy = null;
        }
        function zoomed() {
            svg.attr("transform", d3.event.transform);
        }
    </script>
    </body>
    </html>
    
    {    "name": "test", "children": [{
                "name": "test"
            }]
    }