【问题标题】:Control arrowheads dimension on a force-directed layout in d3.js在 d3.js 中控制力导向布局上的箭头尺寸
【发布时间】:2017-11-17 16:32:25
【问题描述】:

我已经做了一个图表,现​​在我想添加定向链接。

我有一个问题,因为我想要一个功能,当我将鼠标移到链接上时它会变大,当我点击节点时它会变大,这两个函数会弄乱我在链接上的箭头。

我尝试了许多在 stackoverflow 上找到的解决方案,但对我没有任何帮助...有人可以帮助我吗?谢谢

这是我的代码:

<!DOCTYPE html>
      <meta charset="utf-8">
      <title>Modifying a force layout v4</title>

      <style>

        .link {
          stroke: #3B3B3B;
          /*stroke-width: 1px;*/
        }

        .node {
          stroke: #000;
          stroke-width: 1.5px;
        }

        .svg {
          border:3px solid black;
          border-radius:12px; 
          margin:auto; 
        }
        #arrow {
          fill:green;
        }

      </style>
      <body>
      Node:
      <div id="log"></div>
      Link:
      <div id="log2"></div>
        <script src="//d3js.org/d3.v4.js"></script>
        <script>



          var width = 960,
          height = 500;
          radius = 17;

          var expnsed = false;

          var color = d3.scaleOrdinal(d3.schemeCategory20);

          var nodes = [],
          links = [];


          var charge =  d3.forceManyBody().strength(-150);
          var simulation = d3.forceSimulation()
            .force("link", d3.forceLink().distance(130).strength(.7))
            .force("charge", charge)
            // use forceX and forceY instead to change the relative positioning
            // .force("centering", d3.forceCenter(width/2, height/2))
            .force("x", d3.forceX(width/2))
            .force("y", d3.forceY(height/2))
            .on("tick", tick);


          var svg = d3.select("body").append("svg").attr("class","svg")
            .attr("width", width)
            .attr("height", height);

          svg.append("defs").append("marker")
              .attr("id", "arrow")
              .attr("viewBox", "0 -5 10 10")
              .attr("refX", 15)
              .attr("refY", 0)
              .attr("markerWidth", 6)
              .attr("markerHeight", 6)
              .attr("orient", "auto")
              //.attr("fill","red") 
            .append("svg:path")
              .attr("d", "M0,-5L10,0L0,5");
          var url = "https://api.myjson.com/bins/lj6ob";
          d3.json(url, function(error, graph) {
            if (error) throw error;
            nodes = graph.nodes;
            links=graph.links;
            console.log("graph.links.length: "+links.length)

            for (var i = 0; i < links.length; i++){
              links[i].source = find(links[i].source);
              links[i].target = find(links[i].target);
            }

            console.log("Link source: " + links[0].target)


            start();
          })

        function find(name){
          for(var i = 0; i < nodes.length; i++){
            if (name == nodes[i].id){
              console.log("name: " + name)
              console.log("id: " + nodes[i].id)
              return i;
            }
          }
        }


        function start() {
          var nodeElements = svg.selectAll(".node").data(nodes, function(d){return d.id});
          var linkElements = svg.selectAll(".line").data(links).attr("class","links");
          //console.log(nodes)
          nodeElements.enter().append("circle").attr("class", function(d) {return "node " + d.index; }).attr("r", 17).attr("fill", function(d) { return color(d.group); });
          linkElements.enter().insert("line", ".node").attr("class", "link").attr("stroke-width", function(d) { return Math.sqrt(d.value)*2;});

          d3.selectAll("line").attr("marker-end", "url(#arrow)");

          nodeElements.exit().remove();
          linkElements.exit().remove();

          simulation.nodes(nodes)
          simulation.force("link").links(links)  
    // NOTE: Very important to call both alphaTarget AND restart in conjunction
        // Restart by itself will reset alpha (cooling of simulation)
        // but won't reset the velocities of the nodes (inertia)

        //remove alpha for slow incoming!!
        //.alpha(1)
          simulation.alpha(1).restart();
        }

        function tick() {
          var nodeElements = svg.selectAll(".node");
          var linkElements = svg.selectAll(".link");

          linkElements.append("title")
            .text(function(d) { return "value link: " + d.value; });

          linkElements.on("mouseover", function(d) {
                  var g = d3.select(this); // The node
                  document.getElementById('log2').innerHTML = '<br> '+d.value;
                  g.attr("stroke-width", function(d) { return Math.sqrt(d.value)*4; })
                });

          linkElements.on("mouseout", function(d) {
            var g = d3.select(this); // The node
            g.attr("stroke-width", function(d) { return Math.sqrt(d.value)*2; })
          });


          nodeElements.append("title")
            .text(function(d) {
              return "node name: "+d.id + ", node group: "+d.group; 
            });

          nodeElements.on("mouseout", function(d) {
                  var g = d3.select(this); // The node
                  g.attr("fill", function(d) { return color(d.group); })
                })
                .on("mouseover", function(d) {
                  document.getElementById('log').innerHTML = '<br> '+d.id;
                  var g = d3.select(this); // The node
                  g.attr("fill", "red")
                });
          nodeElements.on("click",click);

          nodeElements.call(d3.drag()
              .on("start", dragstarted)
              .on("drag", dragged)
              .on("end", dragended));

          /*nodeElements.attr("cx", function(d,i) {return d.x; })
          .attr("cy", function(d) { return d.y; })*/
          nodeElements.attr("cx", function(d) { return d.x = Math.max(radius, Math.min(width - radius, d.x)); })
            .attr("cy", function(d) { return d.y = Math.max(radius, Math.min(height - radius, d.y)); });

          linkElements
            .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 click(d) {
            d3.select(this).attr("r", 
              function(d){if (d3.select(this).attr("r")==17) {radius = 23;return "23"}else{radius = 17; return "17"}}
            );
          //expand();
          var E = "E";
          if(d.id == E && expand){
            expand=false;
            //expand_2();
          }
        };

        function expand(){
          console.log("expand")
          b = createNode("A")
          nodes.push(b);
          start();
        }

        function expand_2(){
          d3.json("nodes_2.json", function(error, graph) {
            for(var i = 0; i < graph.nodes.length; i++){
              var n = graph.nodes[i];
              nodes.push(n);
            }
            for(var i = 0; i < graph.links.length; i++){
              graph.links[i].source = find(graph.links[i].source)
              graph.links[i].target = find(graph.links[i].target)
              var l = graph.links[i];
              links.push(l);
            }
            start();
          })
        }

        function zoomed() {
            g.attr("transform", d3.event.transform);
        }

        function dragstarted(d) {
          if (!d3.event.active) simulation.alphaTarget(0.3).restart();
          d.fx = d.x;
          d.fy = d.y;
        }

        function dragged(d) {
          d.fx = d3.event.x;
          d.fy = d3.event.y;
        }

        function dragended(d) {
          if (!d3.event.active) simulation.alphaTarget(0);
          d.fx = null;
          d.fy = null;
        }
        function createNode(id) {
          return {id: id, x: width/2, y:height/2}
        }

      </script>

【问题讨论】:

    标签: javascript json d3.js svg


    【解决方案1】:

    如果你定义了markerUnits="userSpaceOnUse",你可以给箭头一个固定的大小。要重新创建您当前的尺寸:

          svg.append("defs").append("marker")
              .attr("id", "arrow")
              .attr("viewBox", "0 -5 10 10")
              .attr("refX", 15)
              .attr("refY", 0)
              .attr("markerUnits", "userSpaceOnUse")
              .attr("markerWidth", 30)
              .attr("markerHeight", 30)
              .attr("orient", "auto")
    

    如果您想在悬停时调整标记的大小,最好的解决方案可能是拥有第二个更大的标记元素 arrow-hover,并通过 CSS 临时交换:

    line {
        marker-end: url(#arrow);
    }
    line:hover {
        marker-end: url(#arrow-hover);
    }
    

    【讨论】:

    • 谢谢,您的解决方案很好,但是当我在悬停线时调整大小时如何选择右箭头?
    • 我的意思是在悬停时调整链接的大小,我使用这个函数:linkElements.on("mouseover", function(d) { var g = d3.select(this); g.attr("stroke -width", function(d) { return Math.sqrt(d.value)*4; }) g.attr("markerWidth", 20) .attr("markerHeight", 20); });但我无法选择该行的正确标记...我也尝试过 g.selectAll("marker") 但没有工作...
    • 您需要为标记使用不同的身份,否则它们要么全部,要么没有,都会被重新定义。见编辑。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-25
    • 1970-01-01
    • 1970-01-01
    • 2013-03-21
    • 1970-01-01
    相关资源
    最近更新 更多