【问题标题】:How to set multiple attributes with one value function?如何用一个值函数设置多个属性?
【发布时间】:2014-01-16 07:56:24
【问题描述】:

给定一个包含多个数据元素(例如对象或数组)的数据,是否可以使用单个值函数在选择上设置多个属性?

例如类似:

var data = [{ 'x': 10, 'y': 20, 'r': 5 }];
d3.select('body').append('svg').selectAll('circle')
    .data(data)
    .enter().append('circle')
    .attr('cx cy r', function (d) {
        return [d.x, d.y, d.r];
    });

代替:

var data = [{ 'x': 10, 'y': 20, 'r': 5 }];
d3.select('body').append('svg').selectAll('circle')
    .data(data)
    .enter().append('circle')
    .attr('cx', function (d) {
        return d.x;
    });
    .attr('cy', function (d) {
        return d.y;
    });
    .attr('r', function (d) {
        return d.r;
    });

【问题讨论】:

    标签: javascript d3.js attributes


    【解决方案1】:

    更新(2016 年 7 月 8 日)此答案适用于 d3 v3.x — 不是 v4.x。对于后一个版本,请参阅Tim Hayes's answer,也在此页面上。或者......只需在下面的答案中将attrattrs 交换,并且不要忘记要求/导入/脚本嵌入d3-selection-multi。还有...不要错过有关使用.each 的信息,这可能对您有用。


    是的,可以通过传入一个哈希值(如 jQuery 的 css() 方法):

    d3.select('body').append('svg').selectAll('circle')
      .data(data)
    .enter().append('circle')
      .attr({
        cx: function (d) { return d.x; },
        cy: function (d) { return d.y; },
        r:  function (d) { return d.r; }
      });
    

    这也适用于style()

    如果重复出现的function (d) {} 开始感觉太多,这是另一种方法:

    d3.select('body').append('svg').selectAll('circle')
      .data(data)
      .enter().append('circle')
      .each(function (d) {
        d3.select(this).attr({
          cx: d.x,
          cy: d.y,
          r:  d.r
        });
      })
    

    注意:此功能仅存在于 d3.js v2.10.0 或更高版本中

    【讨论】:

    • 我问的原因有两个:一是能够写出更简洁的代码,二是尽量减少函数调用。您提供的第一个语法很方便,但第二个更接近我正在寻找的 - 每个节点的一个函数调用。有什么方法可以避免在 d3 选择器中包装 this 并仍然设置属性? (我想我可以只使用本机 JS,但这样会非常危险地接近牺牲易读性来换取性能。)
    • 无法跳过this afaik 的包装。我也曾经忙于优化,但现在我试着放松一下,因为这通常不是问题。仍然...正如您所指出的,您可以使用本机 JS,也许还可以使用抽象的东西以提高可读性。就像.each(function (d) { applyAttr(this, { cx: d.x, cy: dy, r: d.r }); }) 一样,如果你愿意,applyAttr 的实现可以使用原生 JS。或者,如果 data 和 dom 元素之间存在一对一的关系,则可以将包装后的 d3.select(this) 缓存为 d 的属性,以避免在后续刷新时重新包装。
    • 顺便说一句,最后一条评论的抽象也可以看起来像这样:.each( applyAttr(function (d) { return { cx: d.x, cy: dy, r: d.r }; })
    • @ericsoco re:减少函数调用。 d3-selection-multidocs for .attrs 将其描述为 "A convenience method on top of selection.attr for setting multiple attributes." 查看 the source code 确认它只是在循环中调用 .attr
    【解决方案2】:

    这是一篇旧帖子,但我在谷歌搜索时发现了它。接受的答案在 D3 v4.0 中不再有效。

    接下来,您可以使用attrs() 方法来做同样的事情。但只有在加载可选的d3-selection-multi 脚本时才支持attrs()

    所以使用上面的例子,它在 D3 v4.0 中看起来像这样:

    // load d3-selection-multi as separate script
    <script src="https://d3js.org/d3-selection-multi.v0.4.min.js"></script>
    
    d3.select('body').append('svg').selectAll('circle')
      .data(data)
      .enter().append('circle')
      .attrs({
        cx: function (d) { return d.x; },
        cy: function (d) { return d.y; },
        r:  function (d) { return d.r; }
      });
    

    【讨论】:

    • 如果你能对接受的答案进行版本化就好了,对吧?感谢您添加此内容。
    • 查看4.0 release notes的最后一段:...the multi-value methods—where you pass an object to set multiple attributes, styles or properties simultaneously—have been extracted to d3-selection-multi and are no longer part of the default bundle. The multi-value map methods have also been renamed to plural form to reduce overload...d3-selection-multi备注状态:the single-value methods such as selection.attr are recommended for most users, as there is little benefit to the shorter syntax...
    • 很好的参考@brichins - “......没有什么好处......”是如此主观。一个巨大的好处是能够将属性视为一个对象并将其传递给 D3 版本 3 中的多个 attr 调用 - 奇怪的是他们对此采取了如此强硬的立场。
    • 对于那些希望将样式传递给多个attr() 调用的人,您也可以这样做,例如svg.append("style").text("text {font-family: sans-serif;}");
    猜你喜欢
    • 2016-09-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-03
    • 1970-01-01
    • 2021-04-15
    相关资源
    最近更新 更多