我想创建多个函数,这些函数根据数据以不同的方式“设置”矩形(即调用不同的 .attr()
或 .style()
函数甚至根据数据附加其他元素)。
我设法使用 .call(myDecorator)
将样式分派(dispatch)给一个单独的函数,但在这里我有点吃惊。在rectDecorator
中,我希望根据d.type
调用不同的子选择。目前 (.style('fill'...).style(...).style(...)
) 仅显示装饰矩形的可能方法之一,但理想情况下,我想根据 d.type
“分支”到不同的链式命令。知道如何实现吗?
function rectDecorator(selection) {
// call different selection.xyz functions to style rect differently based on `d.type`
return selection
.style('fill', function(d) {
return d.color;
})
.style('fill-opacity', 1)
.style('stroke-width', 0);
}
d3.select('svg')
.selectAll('g')
.data(data)
.join(
enter => enter
.append('g')
.append('rect')
.attr('x', ...)
.attr('y', ...)
.attr('height', 20)
.attr('width', 40)
.call(rectDecorator)
update => update(),
exit => exit.remove()
最佳答案
对此有多种可能的解决方案,但在某些时候,您将不得不遍历选择以检查每个元素的单独类型以找到特定的装饰器。您可以设置一个 Map
,从而将类型映射到它们相应的装饰器。
const decorators = new Map([
["type1", selection => selection.attr("attr1", "...")],
["type2", selection => selection.attr("attr2", "...")]
]);
之后,您可以使用 .each()
轻松循环选择。并根据数据的 type
属性从 map 中获取合适的装饰器:
.each(function(d) {
d3.select(this).call(decorators.get(d.type));
})
对于工作演示,请查看以下代码片段:
const decorators = new Map([
["red", selection => selection.attr("fill", "red")],
["green", selection => selection.attr("fill", "none").attr("stroke", "green")]
]);
const data = [{ type: "green" }, { type: "red" }];
d3.select('body').append("svg")
.selectAll('g')
.data(data)
.join(
enter => enter
.append('g')
.append('rect')
.attr('x', (_, i) => i * 50 + 50)
.attr('y', 50)
.attr('height', 20)
.attr('width', 40)
.each(function(d) {
d3.select(this).call(decorators.get(d.type));
})
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.15.0/d3.js"></script>
关于javascript - 基于数据属性的 d3 节点子结构/样式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60294414/