【问题标题】:D3 sort function always passes undefined argumentsD3 排序函数总是传递未定义的参数
【发布时间】:2012-08-02 16:18:09
【问题描述】:

使用 D3 2.4.2,我创建了许多路径元素,如下所示:

for (var i = 0; i < pathIndices.length; i++) {
  graph.append("svg:path")
    .style("stroke", colors[pathIndices[i]])
    .style("stroke-width", "2.5px")
    .style("fill", "none")
    .attr("class", PATH_CLASS)
    .attr("id", PATH_ID_PREFIX + pathIndices[i])
    .attr("d", lineFunc(data))[0];
}

它们都按预期绘制到屏幕上。稍后,当用户进行一些输入时,我想将其中一个放在前面,所以我有一个事件处理程序来执行此操作:

var pathToHighlight = selectPath(pathIndex);
var paths = d3.selectAll("." + PATH_CLASS);
paths.sort(
  function(a, b) {
    if (a === pathToHighlight) {
      return -1;
    }
    else if (b === pathToHighlight) {
      return 1;
    }
    else {
      return 0;
    }
  }
);

在 Chrome 中设置断点表明我这里的路径选择是成功的(paths 是一个 SVGPathElements 的数组)。但是代码什么也不做,并且在 sort 函数中设置断点表明 ab 始终未定义。进入 d3 代码,我看到当内部函数 d3_selection_sortComparator 使用适当的参数调用我的比较器时,除了它们与自己的未定义 __data__ 成员进行与运算,这会导致 undefined 被传入:

// a and b are correct, but a.__data__ and b.__data__ are undefined
return comparator(a && a.__data__, b && b.__data__);

我在这里做错了什么?我的路径正确地绘制到屏幕上,所以看起来它们应该有正确的数据。对吧?

编辑:图片:

【问题讨论】:

  • 那么,paths 是一个原生数组,不包含 undefined 项?
  • 它看起来像 Chrome 调试器中的原生数组。没有未定义的项目,只有预期的 svg 路径元素。
  • Afaik 许多对象在调试器中看起来像数组。检查其原型链,并测试paths.sort === [].sort
  • console.log(typeof paths); 给了我object。公平地说,console.log(typeof []); 也是如此。 D3 文档说它希望从它的 selectAll() 中返回一个“选择”。你的paths.sort === [].sort 给了我错误的信息。

标签: javascript svg d3.js


【解决方案1】:

当您使用 selection.sort 时,您听起来像是在期待 Array.sortselection.sort 方法用于根据绑定到元素ab数据 对选择进行排序。如果您的元素没有绑定到它们的数据,那么这将不起作用。如果您想根据其他内容对选择进行排序(例如测试一个元素引用是否等于另一个),您应该在调用.sort() 之前从选择中获取元素数组,如下所示:

// `paths` is a Selection
var paths = d3.selectAll("." + PATH_CLASS);
// `pathElements` is an Array
var pathElements = paths[0];

pathElements.sort(function(a,b) {
  // now `a` and `b` are Element references
  // ...
})

那么您将不得不采取额外的步骤,将 DOM 顺序与结果数组的顺序相匹配。

也就是说,如果您只想将 pathToHighlight 放在前面,更好的解决方法是将单个元素重新附加到 DOM。

如果pathToHighlight 是一个选择,你会这样做:

var el = pathToHighlight.node();
el.parentNode.appendChild(el);

或者,如果它已经是一个元素引用,你可以这样做:

pathToHighlight.parentNode.appendChild(pathToHighlight);

【讨论】:

    【解决方案2】:

    正如@jshanley 提到的,您选择的元素没有绑定任何数据(__data__ 属性未定义)。传递给 selection.sort 的函数将接收绑定到元素的数据,在您的情况下它是未定义的。

    您可以使用 datum() 函数将所选元素绑定到数据。

    试试这个:

    paths.datum(function () { return this };).sort(...)
    

    这会将元素绑定到自身,您将能够在排序函数中引用它。

    【讨论】:

      【解决方案3】:

      您可以尝试使用.datum() 函数而不是.__data__ 吗?

      https://github.com/mbostock/d3/wiki/Selections#wiki-datum

      selection.datum([值])
      获取或设置每个选定元素的绑定数据

      【讨论】:

      • 我可能在这里遇到过与您类似的问题:stackoverflow.com/questions/11688615/selecting-arc-element/…
      • 我没有设置a.__data__,该代码来自d3内部,并显示comparator(...),这是我的排序函数的回调,正在为a获取undefinedb,因为虽然ab 的定义符合我的预期,但它们的成员__data__ 没有。
      • 它们是 ANDed 在一起的。 (a &amp;&amp; a.__data__)
      猜你喜欢
      • 2018-08-28
      • 2012-04-11
      • 1970-01-01
      • 2013-11-06
      • 1970-01-01
      • 2011-10-21
      • 2016-06-14
      • 2019-04-25
      • 2016-01-30
      相关资源
      最近更新 更多