D3力布局图 - 弧路径

时间:2016-03-20 21:01:17

标签: d3.js

我有以下代码可以使用,但我有两个问题需要帮助。

  1. 路径线通过图标下方的箭头。我怎么能 强制路径线停在箭头点?
  2. 某些节点可以有两个链接并且它们重叠。我怎么才能换掉 第二个链接上的ARC方向是为了防止这种情况发生?

    var json_data = data;
    
    var hash_lookup = [];
    json_data.nodes.forEach(function (d, i) {
      hash_lookup[d.id] = d;
    });
    json_data.links.forEach(function (d, i) {
      d.source = hash_lookup[d.source];
      d.target = hash_lookup[d.target];
    });
    
    var width = ($("#dependency_map").width()-10);
    var height = ($("#dependency_map").height()-10);
    
    d3.select("#dependency_map").selectAll("*").remove();
    
    
    var force = d3.layout.force()
        .gravity(.05)
        .distance(100)
        .linkStrength(.4)
        .charge(-200)
        .size([width, height]);
    
    
    
    var zoom = d3.behavior.zoom()
        .scaleExtent([1, 10])
        .on("zoom", zoomed);
    
    var svg = d3.select("#dependency_map")
        .append("svg:svg")
        .attr("width", width)
        .attr("height", height)
        .attr("pointer-events", "all")
        .append('svg:g')
        .call(zoom).on("dblclick.zoom", null)
    
    var rect = svg.append("rect")
        .attr("width", width)
        .attr("height", height)
        .style("fill", "none")
        .style("pointer-events", "all");
    
    function dblclick(d) {
      d3.select(this).classed("fixed", d.fixed = false);
    }
    
    function dragstarted(d) {
      if(d3.event.sourceEvent.button == 0) {
        d3.event.sourceEvent.stopPropagation();
        force.start();
      }
    }
    
    function dragged(d) {
      if(d3.event.sourceEvent.button == 0) {
        d3.select(this).attr("cx", d.x = d3.event.x).attr("cy", d.y = d3.event.y);
      }
    }
    
    function dragended(d) {
      if(d3.event.sourceEvent.button == 0) {
        d3.select(this).classed("fixed", d.fixed = true);
        d3.select(this).classed("dragging", false);
      }
    }
    
    var drag = d3.behavior.drag()
        .on("dragstart", dragstarted)
        .on("drag", dragged)
        .on("dragend", dragended);
    
    
    var nodes = json_data.nodes,
        links = json_data.links;
    
    var container = svg.append("g");
    
    
    // build the arrow.
    container.append("svg:defs").selectAll("marker")
        .data(["end"])      // Different link/path types can be defined here
        .enter().append("svg:marker")    // This section adds in the arrows
        .attr("id", String)
        .attr("viewBox", "0 -5 10 10")
        .attr("refX", 15)
        .attr("refY", -1.5)
        .attr("markerWidth", 6)
        .attr("markerHeight", 6)
        .attr("orient", "auto")
        .append("svg:path")
        .attr("d", "M0,-5L10,0L0,5");
    
    // make an arch between nodes and a text label in the middle
    var path = container.selectAll("path.link").data(links);
    path.enter().append("path")
        .attr("class", "link")
        .attr("id",function(d,i) { return "linkId_" + i; })
        .attr("marker-end", "url(#end)");
    
    var linktext = container.append("svg:g").selectAll("g.linklabelholder").data(links);
    
    linktext.enter().append("g").attr("class", "linklabelholder")
        .append("text")
        .attr("class", "linklabel")
        .style("font-size", "0.5em")
        .attr("dy", "-2")
        .style("fill","#000")
        .append("textPath")
        .attr("startOffset","50%")
        .style("text-anchor","middle")
        .attr("xlink:href",function(d,i) { return "#linkId_" + i;})
        .text(function(d) {
          return d.text;
        });
    
    
    var node = container.selectAll("g.node")
        .data(nodes)
        .enter()
        .append("svg:g")
        .attr("class", "node")
        .on("dblclick", dblclick)
        .call(drag)
        .on("contextmenu", function(data, index) {
          console.log("Context Menu Click");
          if (data.knownworkload == true)
          {
            d3.select('#cntxtMenu')
                .style('position', 'absolute')
                .style('left', data.px + 50 + "px")
                .style('top', data.py + "px")
                .style('display', 'block')
                .on('mouseleave', function() {
                  d3.select('#cntxtMenu').style('display', 'none');
                  context = null;
                });
            d3.selectAll('.workload_menu').on('click' , function(d) {
              var action = d3.select(this).attr("action");
              var workload_id = data.guid;
              if (action == "information")
              {
                $.ajax({
                  async:true,
                  url: "<%= url(format: :js) %>",
                  data: {
                    workload_id: workload_id
                  }
                });
                $('#cntxtMenu').hide();
              }
              else
              {
                var servicestack_id = d3.select(this).attr("guid");
                $.ajax({
                  async:false,
                  url: "<%= url %>",
                  data: {
                    workload_id: workload_id,
                    servicestack_id: servicestack_id,
                    success: function (data, status, jqXHR) {
                    },
                  }
                });
                draw_map();
                $('#cntxtMenu').hide();
              }
    
            });
          }
          d3.event.preventDefault();
        });
    
    function zoomed() {
      container.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
    }
    
    
    nodes.forEach(function(d, i) {
      d.x = width/2 + i;
      d.y = height/2 + (1500 * d.depth);
    });
    
    force.nodes(nodes)
        .links(links)
        .start();
    
    
    
    node.append('svg:text')
        .attr('font-family', function (d) {
          return d.icon.fontfamily;
        })
        .attr('font-size', '0.8em')
        .attr('fill', function (d) {
          return d.icon.color;})
        .text(function (d) {return d.icon.icon;})
        .attr("x", "-5px")
        .attr("y", "5px");
    
    node.append("svg:text")
        .attr("y", "15px")
        .attr('font-size', '0.6em')
        .attr("text-anchor", "middle")
        .each(function (d) {
          var arr = d.name.split(" ");
          if (arr != undefined) {
            for (i = 0; i < arr.length; i++) {
              d3.select(this).append("tspan")
                  .text(arr[i])
                  .attr("cy", (i == 0) ? 0 : 10)
                  .attr("text-anchor", "left")
                  .attr("class", "nodetext");
            }
          }
        });
    
    for (var i=0; i<path.length; i++) {
      if (i != 0 &&
          path[i].source == path[i-1].source &&
          path[i].target == path[i-1].target) {
        path[i].linknum = path[i-1].linknum + 1;
      }
      else {path[i].linknum = 1;};
    };
    
    node.append("svg:title")
        .text(function (d) {
          return d.tooltip;
        });
    
    force.on("tick", function(e) {
      path.attr("d", function(d) {
        console.log(d);
        var dx = d.target.x - d.source.x,
            dy = d.target.y - d.source.y,
            dr = Math.sqrt(dx * dx + dy * dy);
        return "M" +
            d.source.x + "," +
            d.source.y + "A" +
            dr + "," + dr + " 0 0,1 " +
            d.target.x + "," +
            d.target.y;
      });
      node.attr("transform", function (d) {
        return "translate(" + d.x + "," + d.y + ")";
      });
    
    });
    

    }, });

0 个答案:

没有答案