【问题标题】:How to stop/pause a SPECIFIC force in d3?如何停止/暂停 d3 中的特定力?
【发布时间】:2019-01-19 20:45:18
【问题描述】:

问题

我有一个有向图。它有 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)
  }

总结

预期:强制暂时停止
实际:强制不停止或崩溃。

【问题讨论】:

    标签: javascript d3.js graph


    【解决方案1】:

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

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

    【讨论】:

    • 我不确定如何使用带有data-strength 的那个,因为我无法区分dragthis 和整个模拟都在里面发生的react 类的this .我最终做的是在拖动开始时设置strength(0),然后在结束时设置strength(0.1)。将其设置为1 使节点立即跳回中心,而0.1 使其平滑过渡。这是一种很老套的做法,但它仍然可以完成工作,所以谢谢你!
    • 动画版使用function所以this是DOM节点。
    猜你喜欢
    • 2013-04-13
    • 1970-01-01
    • 2019-07-16
    • 1970-01-01
    • 2017-11-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多