d3.js拖动节点边界不适用于链接路径

时间:2017-01-16 13:15:49

标签: javascript d3.js

我试图将可拖动节点保持在设定的边界内,这是我设法做到的。 我不确定为什么当我到达边界时节点停止并且路径继续到鼠标的任何地方。

以下是JSFiddle

发生的一个例子
    var width = 400,
      height = 400;

    var force = d3.layout.force()
      .size([width, height])
      .on("tick", tick);

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

    var link = svg.selectAll(".link"),
      node = svg.selectAll(".node");

    function tick() {
      text.attr("transform", transform);
      link.attr("d", linkArc);

      var radius = 15;
      var dx = function(d) {
        return Math.max(radius, Math.min(width - radius, d.x))
      }
      var dy = function(d) {
        return Math.max(radius, Math.min(height - radius, d.y))
      }

      node.attr("transform", function(d) {
        return "translate(" + dx(d) + "," + dy(d) + ")";
      });

      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;
        });




    }

    function explicitlyPosition() {
      node.each(function(d) {
        d.x = 0;
        d.y = 0;
        d.fixed = false;
      });
      tick();
      node.each(function(d) {
        d.fixed = true;
      });
      force.resume();
    }

    var graph = {
      "nodes": [{
        "id": "aa",
        "x": 100,
        "y": 250,
        "fixed": true
      }, {
        "id": "bb",
        "x": 200,
        "y": 200,
        "fixed": true
      }, {
        "id": "cc",
        "x": 200,
        "y": 300,
        "fixed": true
      }, {
        "id": "dd",
        "x": 300,
        "y": 250,
        "fixed": true
      }, {
        "id": "ee",
        "x": 350,
        "y": 300,
        "fixed": true
      }, {
        "id": "ff",
        "x": 250,
        "y": 250,
        "fixed": true
      }],
      "links": [{
        "source": "aa",
        "target": "bb",
        "type": "type1"
      }, {
        "source": "bb",
        "target": "cc",
        "type": "type1"
      }, {
        "source": "cc",
        "target": "dd",
        "type": "type3"
      }, {
        "source": "bb",
        "target": "dd",
        "type": "type1"
      }, {
        "source": "bb",
        "target": "dd",
        "type": "type2"
      }]
    };

    var edges = [];
    graph.links.forEach(function(e) {
      var sourceNode = graph.nodes.filter(function(n) {
          return n.id === e.source;
        })[0],
        targetNode = graph.nodes.filter(function(n) {
          return n.id === e.target;
        })[0];

      edges.push({
        source: sourceNode,
        target: targetNode,
        type: e.type
      });
    });
    console.log(edges);
    //any links with duplicate source and target get an incremented 'linknum'
    for (var i = 0; i < edges.length; i++) {
      if (i != 0 &&
        edges[i].source == edges[i - 1].source &&
        edges[i].target == edges[i - 1].target) {
        edges[i].linknum = edges[i - 1].linknum + 1;
      } else {
        edges[i].linknum = 1;
      };
    };

    force
      .nodes(graph.nodes)
      .links(edges)
      .start();

    link = link.data(edges)
      .enter().append("path")
      .attr("class", function(d) {
        return "link " + d.type;
      })
      .attr("marker-end", function(d) {
        return "url(#" + d.type + ")";
      })
      .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;
      })
      .attr("d", linkArc);

    var node_drag = self.force = d3.behavior.drag()
      .on("dragstart", dragstart)
      .on("drag", dragmove)
      .on("dragend", dragend);

    node = node.data(graph.nodes)
      .enter().append("circle")
      .attr("class", "node")
      .attr("r", 8)
      .call(node_drag);


    function linkArc(d) {
      var curve = 2;
      var homogeneous = 3.2;
      var dx = d.target.x - d.source.x,
        dy = d.target.y - d.source.y,
        dr = Math.sqrt(dx * dx + dy * dy) * (d.linknum + homogeneous) / (curve * homogeneous); //linknum is defined above
      return "M" + d.source.x + "," + d.source.y + "A" + dr + "," + dr + " 0 0,1 " + d.target.x + "," + d.target.y;
    }

    function transform(d) {

      return "translate(" + d.x + "," + d.y + ")";
    }

    function dragstart(d, i) {
      force.stop(); // stops the force auto positioning before you start dragging
    }

    function dragmove(d, i) {
      d.px += d3.event.dx;
      d.py += d3.event.dy;
      d.x += d3.event.dx;
      d.y += d3.event.dy;
      tick();
    }

    function dragend(d, i) {
      d.fixed = true; // of course set the node to fixed so the force doesn't include the node in its auto positioning stuff
      tick();
      force.resume();
    }

    var text = svg.append("g").selectAll("text")
      .data(graph.nodes)
      .enter().append("text")
      .attr("x", 8)
      .attr("y", ".31em")
      .text(function(d) {
        return d.id;
      });

    // Per-type markers, as they don't inherit styles.
    svg.append("svg:defs").selectAll("marker")
      .data(["type1", "type2", "type3"])
      .enter().append("svg:marker")
      .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");

我是使用d3.js的新手,而且我真的不知道要解决这个问题,任何帮助都会很棒!

由于

1 个答案:

答案 0 :(得分:1)

您可以在dragmove内设置边界,而不是在tick内设置边界:

function dragmove(d, i) {
    d.x = d.x > width ? width : d.x < 0 ? 0 : d.x + d3.event.dx;
    d.y = d.y > height ? height : d.y < 0 ? 0 : d.y + d3.event.dy;
    tick();
}

这是你的小提琴:https://jsfiddle.net/0v21Lhk3/