42

我正在使用 d3 创建一个表,供FooTable jquery 插件使用,这需要在标题行中有一些数据属性。但并非所有列都具有所有数据属性,并且想知道是否有办法做到这一点。

这种方法通过添加所有可能的数据属性并留下一些空白来起作用,但我确信这不是一个好习惯。

var th = d3.select(selection).select("thead").selectAll("th")
            .data(colspec)
            .enter().append("th")
            .text(function(d) { return d["data-name"]; })
            .attr("data-class", function(d) {
                if ("data-class" in d) {
                    return d["data-class"];
                } else {
                    return "";
                }
            })
            .attr("data-hide", function(d) {
                if ("data-hide" in d) {
                    return d["data-hide"];
                } else {
                    return "";
                }
            })
            .attr("data-ignore", function(d) {
                if ("data-ignore" in d) {
                    return d["data-ignore"];
                } else {
                    return "";
                }
            })

       etc.

colspec 示例:

[{"data-name": "username"}, {"data-name": "Date Joined", "data-hide": "true"}]

目前获得:

  <th data-class="" data-hide="true" data-ignore="" data-type="">Joined</th>

   <th  data-hide="true" >Joined</th>

有什么建议么?

4

5 回答 5

63

您不需要调用 each() 或 filter()... attr() 函数将在内部为您执行此操作。只需使用函数而不是值调用它,并让该函数为每个数据返回所需的值,如果特定数据不需要该属性,则返回 null,如下所示:

...
.attr('data-class', function(d) {
    return 'data-class' in d ? d['data-class'] : null;
});

如果您的函数返回 null,则不会添加该属性。您甚至可以通过向函数提供 attr 名称的映射来将多个属性组合到一个调用中,如下所示:

...
.attr({
    'data-class': function(d) {
        return 'data-class' in d ? d['data-class'] : null;
    }, 
    'data-hide': function(d) {
        return 'data-hide' in d ? d['data-hide'] : null;
    },
    'data-ignore': function(d) {
        return 'data-ignore' in d ? d['data-ignore'] : null;
    }
});

或者,如果您像我一样不想输入太多,您可以将属性名称列表减少到适当的映射中:

...
.attr(['data-class', 'data-hide', 'data-ignore'].reduce(function(result, attr) {
    result[attr] = function(d) {
        return attr in d ? d[attr] : null;
    }
    return result;
}, {}));
于 2013-08-15T01:16:04.477 回答
33

似乎是一个很好的候选人.each()

var th = d3.select(selection).select("thead").selectAll("th")
        .data(colspec)
    .enter().append("th")
        .text(function(d) { return d["data-name"]; })
        // now address each item individually
        .each(function(d) {
            var header = d3.select(this);
            // loop through the keys - this assumes no extra data
            d3.keys(d).forEach(function(key) {
                if (key != "data-name")
                    header.attr(key, d[key]);
            });
        });

.each当每个项目的范围比试图为每个项目找出一堆属性更有意义时,我经常使用它。

对于属性的简短列表,特别是如果您担心对象中的额外数据,可能更容易遍历所需的键而不是所有内容:

        .each(function(d) {
            var header = d3.select(this);
            ['data-class', 'data-hide', 'data-ignore'].forEach(function(key) {
                if (key in d)
                    header.attr(key, d[key]);
            });
        });
于 2013-08-13T16:55:30.460 回答
7

您可以使用该.filter()功能仅对需要设置属性的选择子集进行操作,例如

var th = d3.select(selection).select("thead").selectAll("th")
        .data(colspec)
        .enter().append("th")
        .text(function(d) { return d["data-name"]; });
th.filter(function(d) { return ("data-class" in d); })
        .attr("data-class", function(d) {
            return d["data-class"];
        });
于 2013-08-13T09:52:48.683 回答
0

清洁剂是使用过滤器

.filter(d => !!d["data-class"]) // filter only data with the "data-class" property
.attr("data-class", d => d["data-class"])
于 2019-05-01T15:41:19.563 回答
0

投票最多的解决方案是完美的,因为当为空.attr(a,b)时作为条件工作,b

 d3chain.attr('data-class', d=>'data-class' in d ? d['data-class'] : null );

但是这个解决方案不是一般的,对于其他链接方法无效,除了使用.each(),.filter.call()。一般来说最简单的就是call()

.call(condFunc,参数)

假设这param是一个在条件中用作参数的全局变量,并且 g是一个用于返回值的全局对象。

  // inconditional
  d3chain.attr(param, g[param])

  // conditional case using globals
  d3chain.call( s => { if (g[param]) s.attr(param,g[param]) })

  // conditional case passing the parameter
  d3chain.call( (s,p) => {
     if (g[p]) s.attr(p, g[p])
  }, param)

.each(d => condFunc)

典型用途:

 d3chain.each( d=> {
     if (param && d) d3.select(this).attr(d, g[param])
 })

有关详细示例,请参阅@nrabinowitz 答案。

.filter(d=>condFunc).etc

典型用途:

 d3chain.filter( d=> param in d ).attr(param, d=> g[param])

有关详细示例,请参阅@LarsKotthoff 答案。

于 2019-12-17T15:45:15.707 回答