如何在d3中停止/暂停特定的力量?

时间:2019-01-19 20:45:18

标签: javascript d3.js graph

问题

我有向图。它有3种力量:

  • 定心力
  • 多身力量
  • 链接力

我想暂时禁用centering强制。我不是在问如何禁用整个力布局,而是只禁用一种特定的力。

我尝试过的

我对d3.forceSimulationforce函数的文档进行了广泛的研究,但是没有地方提到如何暂停作用力。 我试图通过以下方式删除然后重置力:

this.simulation.force("center", null);

dragstart中,然后

this.simulation.force("center", oldCenterForce)
dragend

。问题在于,当拖动结束时,节点立即跳回中心,没有平滑的过渡。

我还尝试提供一个自定义的force函数来检查是否this.isDragging。如果它在拖动,则返回一个哑函数(alpha) => {},如果不是,则返回d3.forceCenter(...),但它抱怨缺少node数组。在调用该函数之前,我尝试做过.bind(this.simulation),但仍然无法正常工作。

代码

我创建力模拟并将其存储在this.simulation

中的部分
  createForceSimulation = (nodeData: G.Node[], edgeData: G.Link[]) => {
     d3.forceSimulation(nodeData)
      .force("link", d3.forceLink(edgeData).id((d: any) => d.id))
      .force("charge", d3.forceManyBody())
      .force("center", d3.forceCenter(this.props.width / 2, this.props.height / 2))
      .force("collide", d3.forceCollide(this.circleSize * 2))
      .velocityDecay(this.simulationVelocityDecay)
  }

我处理拖动节点的部分:

  drag = simulation => {
    const dragStarted = d => {
      if (!d3.event.active) {
        simulation.alphaTarget(0.7).restart()
      }
      d.fx = d.x
      d.fy = d.y
    }

    const dragged = d => {
      d.fx = d3.event.x
      d.fy = d3.event.y
    }

    const dragEnded = d => {
      if (!d3.event.active) simulation.alphaTarget(0)
      d.fx = null
      d.fy = null
    }

    return d3
      .drag()
      .on("start", dragStarted)
      .on("drag", dragged)
      .on("end", dragEnded)
  }

摘要

预期:强制立即停止
实际:力量不会停止或崩溃。

1 个答案:

答案 0 :(得分:0)

使用带有强度参数的自定义中心力。

.force("center", myCenterForce(this.props.width / 2, this.props.height / 2))

在拖动功能调用中

simulation.force("center").strength(0);

simulation.force("center").strength(1.0);

或者您可以在刻度功能中对强度进行动画/内插。

var dragNode = null;

  drag = simulation => {
    const dragStarted = function (d) {
      if (!d3.event.active) {
        simulation.alphaTarget(0.7).restart()
      }
      dragNode = null;
      d.fx = d.x
      d.fy = d.y
    }

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

    const dragEnded = function (d) {
      if (!d3.event.active) simulation.alphaTarget(0);
      dragNode = this;
      d3.select(this).attr("data-strength", 0)
          .transition().duration(2000)
          .attr("data-strength", 1.0)
          .on("end", function () { dragNode = null; } );
      d.fx = null
      d.fy = null
    }

    return d3
      .drag()
      .on("start", dragStarted)
      .on("drag", dragged)
      .on("end", dragEnded)
  }

function tick() {
    if (dragNode)
        simulation.force("center")
            .strength(d3.select(dragNode).attr("data-strength"));

    // update nodes
}

海关部队

function myCenterForce(x, y) {
  var nodes;
  var strength = 1.0;

  if (x == null) x = 0;
  if (y == null) y = 0;

  function force() {
    var i,
        n = nodes.length,
        node,
        sx = 0,
        sy = 0;

    for (i = 0; i < n; ++i) {
      node = nodes[i], sx += node.x, sy += node.y;
    }

    for (sx = sx / n - x, sy = sy / n - y, i = 0; i < n; ++i) {
      node = nodes[i], node.x -= strength * sx, node.y -= strength * sy;
    }
  }

  force.initialize = function(_) {
    nodes = _;
  };

  force.x = function(_) {
    return arguments.length ? (x = +_, force) : x;
  };

  force.y = function(_) {
    return arguments.length ? (y = +_, force) : y;
  };

  force.strength = function(_) {
    return arguments.length ? (strength = +_, force) : strength;
  };

  return force;
}