我正在创建一个d3表,供FooTable jquery plugin使用,这需要在标题行中包含一些数据属性。但并非所有列都具有所有数据属性,并且想知道是否有办法执行此操作。
这种方法有点工作,通过添加所有可能的数据属性并留下一些空白,但我确信这不是好的做法。
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>
有什么建议吗?
答案 0 :(得分:54)
您不需要调用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;
}, {}));
答案 1 :(得分:31)
似乎是.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]);
});
});
答案 2 :(得分:6)
您可以使用.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"];
});
答案 3 :(得分:0)
更清洁的是使用过滤器
.filter(d => !!d["data-class"]) // filter only data with the "data-class" property
.attr("data-class", d => d["data-class"])
答案 4 :(得分:0)
投票最多的解决方案是完美的,因为.attr(a,b)
为空时,b
是有条件的,
d3chain.attr('data-class', d=>'data-class' in d ? d['data-class'] : null );
但该解决方案不是通用的,对于其他链接方法无效,除非使用.each()
,.filter
或.call()
。通常,最简单的是call()
。
假设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)
典型用途:
d3chain.each( d=> {
if (param && d) d3.select(this).attr(d, g[param])
})
有关详细示例,请参见@nrabinowitz答案。
典型用途:
d3chain.filter( d=> param in d ).attr(param, d=> g[param])
有关详细示例,请参见@LarsKotthoff答案。