使用拖动行为时,带链接力的D3.js v4力布局会导致奇怪的移动

时间:2017-07-25 08:03:53

标签: javascript d3.js force-layout

我尝试使用d3.js v4创建一个力布局,并且使用拖动行为时,市长部分正好可以接受一个问题。

当点击某个节点将其拖动到未连接到所单击节点的其他节点时,飞走:

var svg = d3.select("svg"),
width = +svg.attr("width"),
height = +svg.attr("height");

function drawNode(nodes) {
    return svg.selectAll("circle.node")
      .data(nodes, function (d, i) { return d.Id; })
      .enter().append("circle")
      .attr("class", "node")
      .attr("r", 5)
      .attr("fill", "blue")
      .call(d3.drag()
          .on("start", dragstarted)
          .on("drag", dragged)
          .on("end", dragended));
}

function drawMainNode(nodes) {
    return svg.selectAll("circle.mainnode")
      .data(nodes, function (d, i) { return d.Id; })
      .enter().append("circle")
      .attr("class", "mainnode")
      .attr("r", 15)
      .attr("fill", "red")
      .call(d3.drag()
          .on("start", dragstarted)
          .on("drag", dragged)
          .on("end", dragended));
}

function drawLinks(links) {
    return svg.selectAll("line")
      .data(links, function (d, i) { return d.source + "-" + d.target; })
      .enter().append("line")
      .attr("stroke-width", 3);
}

function dragstarted(d) {
    if (!d3.event.active) dragSimualtion.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) dragSimualtion.alphaTarget(0);
    d.fx = null;
    d.fy = null;
}

function ticked() {
    dLinks
        .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; });

    dNodes
        .attr("cx", function(d) { return d.x; })
        .attr("cy", function(d) { return d.y; });

    dMainNodes
        .attr("cx", function(d) { return d.x; })
        .attr("cy", function(d) { return d.y; });
}

var dLinks = drawLinks(mainLinks.concat(nodeLinks));
var dNodes = drawNode(nodes);
var dMainNodes = drawMainNode(mainNodes);

var simulation = d3.forceSimulation(mainNodes.concat(nodes))
                .force("charge", d3.forceManyBody())
                .force("center", d3.forceCenter(width / 2, height / 2))
                .force("collide", d3.forceCollide(20).radius(20))
                .force("links", d3.forceLink(mainLinks.concat(nodeLinks))
                    .id(function (d) { return d.Id; }))
                .alpha(0.9)
                .alphaDecay(0.1)
                .on("tick", ticked);

var dragSimualtion = d3.forceSimulation(mainNodes.concat(nodes))
                .force("collide", d3.forceCollide(20).radius(20))
                .force("links", d3.forceLink(mainLinks.concat(nodeLinks))
                    .id(function (d) { return d.Id; }))
                .alphaDecay(0.1)
                .on("tick", ticked)
                .stop()

Plunkr

我尝试对仅使用链接力和碰撞力的拖动事件使用单独的模拟 - 因为应该拖动节点,每个节点都连接到它们,并且应该推开其他非连接节点,但仅限于他们碰撞了。

所以问题是,如何防止其他节点飞来飞去?

编辑1:我的第一次尝试只使用了第一个模拟对象,但我认为观察到的效果是由d3.forceManyBody引起的,因为它的排斥力。我试图用distanceMax限制此效果,但没有成功。我的第二次尝试是使用单独的d3.forceSimulation,它只包含与拖动动画相关的力。

1 个答案:

答案 0 :(得分:0)

拖拽功能的forceCollide似乎是问题......

尝试:

    .force("collide", d3.forceCollide(20).radius(20).strength(0))

然后你得到相反的问题,然后在0和1之间尝试,找到你喜欢的。