【问题标题】:check if d3.select or d3.selectAll检查 d3.select 还是 d3.selectAll
【发布时间】:2017-08-14 21:03:42
【问题描述】:

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

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

编辑: 这是使用的上下文。我正在使用 Mike Bostock 的 reusable chart pattern,这个实例包括一个获取/设置甜甜圈标签的方法。

对我而言,此 API 用法遵循 principle of least astonishment,因为这是我期望返回结果的方式。

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']

以及内部方法定义:

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
}

【问题讨论】:

  • 非常好的和有趣的问题。我写了一个答案,这不是您期望的答案。如果有人证明我错了,我会很乐意删除它。
  • 只是好奇:为什么你要这样做?为什么不简单地将第二个参数传递给函数,告知方法的类型?你看,这是XY problem 的有力候选人
  • 我已经更新了我的帖子以提供完整的上下文。这里的目标是找到实现这个 getter/setter 方法的“最类似 d3”的方式。 “最佳”答案将是 d3 对其一种方法执行相同操作的示例。

标签: d3.js


【解决方案1】:

嗯,有时在 S.O.根本没有答案(它有happened before)。

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

为了证明这一点,让我们看看d3.selectd3.selectAll 的源代码(重要:它们不是 selection.selectselection.selectAll,它们是非常不同)。

首先,d3.select

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

现在,d3.selectAll

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

如您所见,我们这里只有 两个 不同:

  1. d3.selectAll 接受 null。这对你没有帮助。
  2. d3.selectAll 使用querySelectorAll,而d3.select 使用querySelector

第二个区别是唯一适合你的,正如你现在所知道的,因为querySelectorAll

返回文档中匹配指定选择器组的元素列表(使用文档节点的深度优先前序遍历)。返回的对象是一个NodeList。 (强调我的)

只有querySelector...:

返回文档中与指定选择器或选择器组匹配的第一个元素。

因此,您现在使用的未记录的(而且很hacky,因为您使用的是_groups,这不是一个好主意)selection._groups[0] instanceof NodeList 似乎是告诉d3.select 创建的选择来自的唯一方法由d3.selectAll 创建的选择。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多