代码之家  ›  专栏  ›  技术社区  ›  Mehdi Saffar

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

  •  1
  • Mehdi Saffar  · 技术社区  · 6 年前

    问题

    我有一个有向图。它有三种力量:

    • 对中力
    • 多体力
    • 连接力

    我想暂时禁用 centering 力。我不是在问如何使 整体 力布局,只有一个特定的力。

    我试过什么

    我已经广泛查阅了 d3.forceSimulation force 函数,但它没有提到如何暂停一个力。 我尝试删除,然后通过如下方式重置力:

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

    在里面 dragstart 然后

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

    在里面 dragend .问题是,当拖动结束时,节点立即跳回到中心,没有平滑的过渡。

    我也试过给一个习惯 检查是否 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 回复  |  直到 6 年前
        1
  •  0
  •   rioV8    6 年前

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

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