繁体   English   中英

使用D3.js v4对力定向图进行不规则缩放

[英]Erratic zoom on force directed graph with D3.js v4

我在D3.js(v4)中有这个强制控制图:

<!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>

tile1.json在下面; 为了简单起见,我使用只有两个节点的图。

{    "name": "test", "children": [{
            "name": "test"
        }]
}

除了缩放动作外,其他所有功能都工作正常:整个图形实际上并未转换为点击位置的中心,而是实际上转换为左上角[0,0]的原点,即使我的图形的原点是是屏幕的中心( d3.forceCenter(w/2, h/2) )。

我不是D3的专家,但是我知道我在代码中做错了什么,或者缺少了一些东西,我不知道是什么,为什么。

我需要你的帮助,提前。

几件事:

  1. 您调用的.call(zoom)就是事件处理程序,该元素查找要缩放的事件。 这不应直接是SVG。 通常的形式是在SVG顶部放置一个不可见的矩形来捕获这些事件。
  2. 您无法按照您的方式将SVG缩放应用于svg元素。 这有点反常,但是svg标记是HTML元素,其中的内容是svg元素。 所以你会怎么做? 将您的绘图包裹在应用缩放的g中。

将这两个想法放在一起,最终得到:

 <!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) var g = svg.append("g"); svg.append("rect") .attr("width", w) .attr("height", h) .style("fill", "none") .style("pointer-events", "all") .call(zoom); d3.json("https://jsonblob.com/api/eb8b41b1-0c23-11e7-a0ba-092e370a78bd", 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 = g.selectAll("line") .data(links) .enter().insert("line") .style("stroke", "#999") .style("stroke-width", "1px"); var nodeElements = g.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 = g.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 dx; }) .attr("cy", function(d) { return dy; }); labels.attr("x", function(d){ return dx -10; }) .attr("y", function (d) {return dy + 10; }); }); }); function dragStarted(d) { d.fx = dx; d.fy = dy; } function dragged(d) { d.fx = d3.event.x; d.fy = d3.event.y; } function dragEnded(d) { d.fx = null; d.fy = null; } function zoomed() { g.attr("transform", d3.event.transform); } </script> </body> </html> 

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM