关于d3.js:检查d3.select还是d3.selectAll

check if d3.select or d3.selectAll

我在可重用图表上有一个可以传递选择的方法,如果传递了d3.select('#id')选择,则返回一个值;如果传递了d3.selectAll('.class')选择,则返回一个值数组。 我目前正在用context._groups[0] instanceof NodeList询问传递的参数,但是使用未记录的属性会感到有些脆弱,因为在将来的版本中可能会有所变化。 是否存在确定选择来自select还是selectAll的更多内置方法?

selection.size()在这里无济于事,因为它仅告诉我们选择的结果,而不是如何调用的。

编辑:
这是用法的上下文。 我正在使用Mike Bostock的可重用图表模式,此实例包括一种获取/设置甜甜圈标签的方法。

对我来说,这种API的用法遵循最小惊讶的原则,因为这是我期望返回结果的方式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
var donut = APP.rotatingDonut();

// set label for one element
d3.select('#donut1.donut')
    .call(donut.label, 'Donut 1')

d3.select('#donut2.donut')
    .call(donut.label, 'Donut 2')

// set label for multiple elements
d3.selectAll('.donut.group-1')
    .call(donut.label, 'Group 1 Donuts')


// get label for one donut
var donutOneLabel = d3.select('#donut1').call(donut.label)
// donutOnelabel === 'Donut 1'

// get label for multiple donuts
var donutLables = d3.selectAll('.donut').call(donut.label)
// donutLabels === ['Donut 1', 'Donut 2', 'Group 1 Donuts', 'Group 1 Donuts']

和内部方法定义:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
App.rotatingDonut = function() {

  var label = d3.local();

  function donut() {}

  donut.label = function(context, value) {
    var returnArray;
    var isList = context._groups[0] instanceof NodeList;

    if (typeof value === 'undefined' ) {

      // getter
      returnArray = context.nodes()
          .map(function (node) {return label.get(node);});

      return isList ? returnArray : returnArray[0];
    }

    // settter
    context.each(function() {label.set(this, value);});

    // allows method chaining
    return donut;
  };

  return donut
}


好吧,有时在S.O.根本没有答案(之前已经发生过)。

您的问题似乎就是这种情况:"是否有更多内置的方法来确定选择来自select还是selectAll?"。可能没有。

为了证明这一点,让我们看一下d3.selectd3.selectAll的源代码(重要的是:它们不是selection.selectselection.selectAll,它们彼此之间有很大的不同)。

首先,d3.select:

1
2
3
4
5
export default function(selector) {
    return typeof selector ==="string"
        ? new Selection([[document.querySelector(selector)]], [document.documentElement])
        : new Selection([[selector]], root);
}

现在,d3.selectAll:

1
2
3
4
5
export default function(selector) {
    return typeof selector ==="string"
        ? new Selection([document.querySelectorAll(selector)], [document.documentElement])
        : new Selection([selector == null ? [] : selector], root);
}

如您所见,我们这里只有两个区别:

  • d3.selectAll接受null。那对你没有帮助。
  • d3.selectAll使用querySelectorAll,而d3.select使用querySelector
  • 从现在开始,第二个差异是唯一适合您的差异,因为querySelectorAll:

    Returns a list of the elements within the document (using depth-first pre-order traversal of the document's nodes) that match the specified group of selectors. The object returned is a NodeList. (emphasis mine)

    和仅限querySelector ...:

    Returns the first Element within the document that matches the specified selector, or group of selectors.

    因此,您现在正在使用的未记录文档(而且很hack,因为您使用的是_groups,这不是一个好主意)selection._groups[0] instanceof NodeList似乎是从创建的选择中区分出d3.select创建的选择的唯一方法通过d3.selectAll