如何正确使用D3中的call()来绑定拖动行为?

时间:2017-10-25 03:54:30

标签: javascript d3.js

我需要创建一个矩形并让它听一个拖动事件。根据文档,我必须首先附加'rect'并调用dragR(event)

d3.select('#rectangle').on('click', function(){ new Rectangle(); });

function Rectangle(preloaded = false, box = []) {

    .......
    var dragR = d3.behavior.drag().on('drag', dragRect);

    function dragRect() {
      var e = d3.event;
      for(var i = 0; i < self.rectData.length; i++){
        d3.select(self.rectangleElement[0][0])
          .attr('x', self.rectData[i].x += e.dx )
          .attr('y', self.rectData[i].y += e.dy );
      }
      rect.style('cursor', 'move');
      updateRect();
    }

    rectangleElement = d3.select('svg').append('rect').attr('class', 'rectangle').call(dragR);

}

现在我的问题是rectangleElement究竟是什么?它是功能还是其他什么?任何人都可以解释这段代码的工作流程是什么?另外,如果我想将另一个事件(所说的点击)绑定到它,该怎么办?

2 个答案:

答案 0 :(得分:2)

编辑:@altocumulus答案带来有关方法结果的更多细节:)

  

究竟是什么rectangleElement

rectangleElementd3 Selection,包含您的rect svg元素。

  

任何人都可以解释这段代码的工作流程

var dragR = d3.behavior.drag().on('drag', dragRect);

使用此行,您将定义d3 Drag behavior,为拖动事件(和触摸)创建事件侦听器。使用.on()方法,您可以将处理程序附加到事件。在这里,您在dragRect事件上附加了drag函数。 drag事件是您在拖动元素时触发的事件(您还有dragStartdragEnd)。此行仅定义行为,但尚未与您的rect元素相关联。

rectangleElement = d3.select('svg').append('rect').attr('class', 'rectangle').call(dragR);

在此行中,您将创建rect元素。您首先选择第一个匹配的svg元素,然后在其中添加rect,在新创建的rectangle上添加类rect,最后将拖动侦听器附加到您的rect元素call() function doc)。

function dragRect() {
  var e = d3.event;
  for(var i = 0; i < self.rectData.length; i++){
     d3.select(self.rectangleElement[0][0])
     .attr('x', self.rectData[i].x += e.dx )
     .attr('y', self.rectData[i].y += e.dy );
  }
     rect.style('cursor', 'move');
     updateRect();
  }

这是您drag事件的处理程序,每次触发drag事件时都会调用此函数。此函数使用您未在问题上添加的变量,但看起来这样会更改rect的x / y属性,然后移动它。

  

如果我想让它绑定另一个事件(表示点击)

,该怎么办?

有多种方法:您可以在创建rect元素时附加点击处理程序:

d3.select('svg')
    .append('rect')
    .attr('class', 'rectangle')
    .on('click', function(){ console.log('clicked'); })
    .call(dragR);

稍后通过选择rect元素来附加它:

d3.select('rect.rectangle')
    .on('click', function(){ console.log('clicked'); })

这是on() documentation(对于d3v3)

答案 1 :(得分:2)

首先,通过您使用d3.behavior.drag()我们可以告诉您,您仍在使用D3 v3(在v4中这将是d3.drag()以及其他微妙的差异。)

您提供的代码包含在SVG元素上设置drag behavior所需的三个部分。

<强> 1。拖动行为本身

var dragR = d3.behavior.drag().on('drag', dragRect);

这是通过自动为拖动事件创建事件侦听器来处理元素上拖动手势的D3方法。对此行为调用.on()将注册一个处理函数(即dragRect),该函数将由其注册的事件(在您的情况下为drag)触发。

<强> 2。处理函数

function dragRect() {
  // ...
}

对于应用拖动行为的元素上的拖动手势触发的每个事件,都将调用此函数。在这个函数中,您将完成所有的工作,即数据操作,DOM更新等等,这些都是以图形方式对拖动手势做出反应所必需的。

第3。将拖动行为应用于选择

rectangleElement = d3.select('svg').append('rect').attr('class', 'rectangle').call(dragR);

创建拖动行为实例并指定正确的事件处理函数后,可以将此行为应用于D3选择。或者,用documentation

的话来说
  

构建后,您可以将拖动行为应用于所选元素   使用selection.call

查看selection.call()的文档可以回答您的问题:该函数的返回值是什么:

  

无论如何,呼叫操作员始终返回当前选择   指定函数的返回值。

因此,rectangleElement将保留对包含之前附加的<rect>的D3选择的引用。

由于你要求它,在v3中,选择将是一个数组数组,如处理函数中所示,其中元素被访问为self.rectangleElement[0][0])。但是,在初学者级别,您不应过多关注实现细节。只需知道它是D3选择就足够了,它具有定义良好的API。

由于rectangleElement是D3选择,您可以通过链接对selection.on()的进一步调用轻松地在其上注册更多事件处理程序:

rectangleElement.on("click", function(d) { });

为了避免在组合点击和拖动处理程序时常见的陷阱,您可能需要查看Mike Bostock的Click vs. Drag阻止。