【问题标题】:How to use d3.js drag properly?如何正确使用 d3.js 拖动?
【发布时间】:2020-10-29 17:12:03
【问题描述】:

我正在使用 d3.js 和 Vue js 创建平面图。我想添加一个功能,用户单击一个按钮,该按钮创建一个矩形(门口),用户可以更改比例和 X、Y 位置。我对 vue js 和 d3.js 很陌生,所以我使用 this 作为参考。该按钮起作用并为 X 次按下添加 X 个矩形。但是,当我添加第一个门口并尝试拖动矩形时,它完全脱离了用户的鼠标坐标。此外,当我添加第二个、第三个、第四个等矩形时,我无法更改这些矩形的位置,只能更改第一个矩形。我认为这是因为我在拖动功能中只选择了一个矩形。但是我更关心在矩形上拖动。请问有人能指出我正确的方向吗?

<template>
  <div id = "app">

    <header>
      <Navbar />
    </header>

      <div class = "floor"> 
        <div id = "tooltip"></div>
        <svg width = "850" height = "800">
        </svg>
      </div>
    
    <div class = "buttons"> 
      <button v-on:click="addRec()"> Add Doorway </button>
    </div>

    
  </div>
</template>
addRec(){

        console.log("Doorway Added")
        var doorGroup = d3.selectAll("svg")
          .append("g")

        //setting attributes for doorway
        var doorway = doorGroup.append("rect")
          .attr("width",100)
          .attr("height", 25)
          .attr("x", 150)
          .attr("y", 200)

        //setting style attributes for doorway
          .attr("fill","#F5F5F5")
            
          .attr("stroke", "black")
            .attr("stroke-width", 2.5)
          .attr("cursor", "move")
          
          //binding drag method onto rectangle
          .call(d3.drag()
            .on('start', dragStart)
            .on('drag', dragging)
            .on('end', dragEnd)
          )
          
      },
      //this is to be called once used has clicked on the doorway
      dragStart(d,i,nodes){
        d3.select(nodes[i])
          .style("stroke", "red")
      },
      /*
      this is to be called once used has started dragging the doorway
      dragging(d) upadtes the position of the doorway, from the mouse X,Y Coors
      */
      dragging(d,i,nodes){
        var width = 850
        var height = 800
        var xCoor = d3.pointer(event)[0]
        var yCoor = d3.pointer(event)[1]

        // d3.select(nodes[i])
        //   .attr("transform", "translate(" + (xCoor - 200) + "," + (yCoor - 300) + ")")

        d3.select(nodes[i])
          .attr("x", xCoor)
          .attr("y", yCoor)
      },
      //this is to be called once user has clicked off the doorway
      dragEnd(d,i,nodes){
        d3.select(nodes[i])
          .style("stroke", "black")
      },

【问题讨论】:

  • 在拖拽功能中,event定义在哪里?此外,您对 x 和 y 使用相同的值 pointer(event)[0]。不过,如果使用 d3v6,event.xevent.y 可能 是合适的。是否有缩放应用到 SVG?你能做一个最小的 sn-p 来复制你的问题吗?因为有很多可能有用也可能没用的建议。
  • @AndrewReid 谢谢,我什至没有意识到我对 X 和 Y 坐标使用了相同的值。学习了,谢谢。我正在使用 d3v5。不,没有缩放应用到任何东西。最小的 sn-p 是什么意思?

标签: javascript d3.js drag


【解决方案1】:

您的代码中有两个问题:

  1. 您只能选择同一个矩形:

您使用的所有拖动功能:

d3.select("rect")

这将选择 DOM 中的第一个匹配元素。这将始终是同一个矩形,它不对应于被拖动的矩形。相反,您可以使用以下命令访问正确的矩形:

function dragFunction() {
  d3.select(this);
}

在 d3v5 及更早版本中,如果 this 不可用,您可以使用:

dragFunction(d,i,nodes) => d3.select(nodes[i])

如果您在 d3v6 中还不能访问 this,则没有一种很好的方法来获取您的矩形 - migration guide 显示了一种获取 this 的“旧”方法,其中涉及过滤元素基准匹配。我从未见过在 d3v5 或更早版本中使用过这种方法,如果 this 不可用,d3.select(nodes[i]) 总是后退。因此,理想情况下,您可以访问 this - 不要为侦听器使用箭头函数

  1. 您通过 x,y 应用变换和位置。

最初附加您按 x,y 定位的矩形时。拖动时应用平移,但不要删除初始 x,y 定位。这会导致 x,y 坐标被应用两次,一次使用它们的原始值,一次使用它们相对于原点(而不是它们的起始位置)的拖动值。您应该为初始放置和拖动修改相同的属性 - x,y 属性或变换,但不要将两者都用于放置。


D3v5

除了使用 d3.event.x 和 d3.event.y,(d3.pointer 是在 d3v6 中添加的),我已经进行了上述更改,并相信我已经创建了下面的预期效果。

var svg = d3.select("body")
  .append("svg")
  .attr("width", 500)
  .attr("height", 300);
  
d3.select("button")
  .on("click", function() {
  
   svg.append("rect")
      .attr("width",10)
      .attr("height", 25)
      .attr("x", 150)
      .attr("y", 100)
      .attr("fill","#1b1c3b")
      .attr("opacity", ".5")
      .attr("stroke", "black")
      .attr("stroke-width", "2")
      .attr("cursor", "move")
      .call(d3.drag()
        .on('start', dragStart)
        .on('drag', dragging)
        .on('end', dragEnd)
      )
  
    function dragStart(d,i,nodes){
        d3.select(nodes[i])
          .style("stroke", "red")  
      }
      
    function dragging(d,i,nodes){
        var xCoor = d3.event.x;
        var yCoor = d3.event.y;

        d3.select(nodes[i])
          .attr("x", xCoor)
          .attr("y", yCoor);
      }
      
      function dragEnd(d,i,nodes){
         d3.select(nodes[i])
          .style("stroke", "black")
      }
  
  
  
  })
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<button>Add Rect</button>

D3v6

var svg = d3.select("body")
  .append("svg")
  .attr("width", 500)
  .attr("height", 300);
  
d3.select("button")
  .on("click", function() {
  
   svg.append("rect")
      .attr("width",10)
      .attr("height", 25)
      .attr("x", 150)
      .attr("y", 100)
      .attr("fill","#1b1c3b")
      .attr("opacity", ".5")
      .attr("stroke", "black")
      .attr("stroke-width", "2")
      .attr("cursor", "move")
      .call(d3.drag()
        .on('start', dragStart)
        .on('drag', dragging)
        .on('end', dragEnd)
      )
  
    function dragStart(event,d){
        d3.select(this)
          .style("stroke", "")  
      }
      
    function dragging(event,d){
        var xCoor = event.x;
        var yCoor = event.y;

        d3.select(this)
          .attr("x", xCoor)
          .attr("y", yCoor);
      }
      
      function dragEnd(event,d){
        d3.select(this)
          .style("stroke", "black")
      }
  
  })
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/6.1.0/d3.min.js"></script>
<button>Add Rect</button>

【讨论】:

  • 这是有道理的。我明白现在发生了什么。当我添加节点参数并使用 d3.select(nodes[i]) 时,我收到错误消息“TypeError: Cannot read property 'undefined' of undefined”显然这是因为我在任何地方都定义了节点。我会在哪里这样做。我很困惑,因为当我添加矩形时,它们不会进入节点数组。节点是 d3.js 中对象的通用标识符吗?我还更新了代码。感谢您的帮助
  • d3 将 d、i、节点传递给 d3v5 及更早版本中的事件侦听器,当您将它们作为参数包含在事件侦听函数中时:function(d,i,nodes)nodes 以相同的方式定义 @987654337 @ 是 - 您也没有在任何地方明确地为 d 提供值,它由 d3 完成。
  • 是的,但是当我 console.log nodes or nodes[i] 它在控制台中显示为未定义。但是当我log d 它显示为DragEvent ... active: 0 dx: 0 dy: 0 identifier: "mouse" subject: {x: 211.5, y: 216} x: 211.5 y: 216 _: Dispatch {_: {…}} __proto__: Object 但我不能使用d3.select(d) 因为我收到错误Uncaught TypeError: Cannot read property 'setProperty' of undefined
  • 您使用的是 d3v6,而不是上面提到的 d3v5。
  • 是的,我正在使用 d3v5
猜你喜欢
  • 1970-01-01
  • 2013-04-03
  • 2018-10-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-07-25
  • 1970-01-01
  • 2021-01-25
相关资源
最近更新 更多