我正在学习d3并且正在编写一个可视化,需要在初始颜色和灰色之间切换形状。另一个例子并不能完全满足我的需要(d3 javascript alternate colors on click),因为我希望这两种颜色是“初始”和“灰色”而不是两种硬编码颜色。
我高兴地注意到我的矩形有两种相似的颜色,看起来像原始和当前的颜色:
我在下方的尝试让您可以将形状单击为灰色,但它们不会单击回原始颜色。你能告诉我我做错了什么吗?我也愿意完全修改方法。
谢谢!
var w = 300;
var h = 200;
var colors = ["Red","Green","Blue"];
var svg = d3.select("body")
.append("svg")
.attr("width", w)
.attr("height",h);
var squares = svg.selectAll("rect")
.data(colors)
.enter()
.append("rect")
.on("click", function(){
if(d3.select(this).style("fill") != "Gray"){
d3.select(this).style("fill", "Gray")
}
else{
d3.select(this).style("fill", d3.select(this).fill)
};
});
squares.attr("x", function(d, i){
return 100+i*80;
})
.attr("y", 100)
.attr("width", 40)
.attr("height", 40)
.attr("fill", function(d){
return d;
});;
答案 0 :(得分:3)
您正在采用的方法读取对象的fill
样式属性的当前值,以决定如何对点击作出反应。有人可能会说你“在DOM中存储真相”,这并不理想。例如,如果您console.log(d3.select(this).style("fill"))
预期"Gray"
,则最有可能获得#808080
。
相反,您可以将rect的状态存储在其基准面上。在点击处理程序中,可以使用d3.select(this).datum()
获取数据。然后你可以说:
var clicked = d3.select(this);
var datum = clicked.datum();
if(!datum.isToggled) { datum.isToggled = true; }
else { datum.isToggled = false; }
这样,您将在绑定到该对象的基准上存储状态(切换或不切换)。此时,您可以根据clicked
为true来设置datum.isToggled
的颜色。在你的情况下:
if(datum.isToggled) { clicked.style("fill", "Gray"); }
else { clicked.style("fill", datum); }
在您设置填充的代码中,您有一个错误,因为您将填充设置为d3.select(this).fill
未定义。在您的情况下,您想要的填充是分配给datum
的值,因为您将节点绑定到字符串数组。
顺便提一下,请注意,由于您绑定了一个字符串数组,datum.isToggled
最终解析为"Red".isToggled
,这在JS中令人惊讶地起作用,但看起来很怪异,并且出乎意料。要解决它,你想要绑定到一个对象数组,如:
[
{ fill: "Red" },
{ fill: "Green" },
{ fill: "Blue" }
]
然后,当您要应用填充时,使用datum.fill
或
.attr("fill", function(d){
return d.fill;
});
最后,请注意您在一个地方使用.attr("fill", ...)
和另一个.style("fill", ...)
的情况?这是有风险的,因为一个优先于另一个。相反,只使用这两者中的一个。
我在上面引用的数据是由于在d3选择上调用.data(...)
而绑定到DOM元素的东西。在您的情况下,您使用字符串数组调用data(colors)
,因此3个结果DOM元素中的每一个将最终具有这3个字符串之一的数据("Red"
,{{1 }或"Green"
)。在您的代码中,正如您目前所拥有的那样,如果单击Red DOM元素,则从单击处理程序内部运行"Blue"
将返回字符串d3.select(this).datum()
。这就是d3中DOM元素与基准相关联(或绑定)的含义。
我的一个建议是绑定到一个通用JavaScript对象数组,而不是一个字符串数组。您可以将每个对象视为属性的容器。在您的情况下,每个对象只有1个属性"Red"
。因此,如果您这样做,调用fill
将返回javascript对象clicked.datum()
(或绿色或蓝色)。
{ fill: "Red" }
并非与d3内置或完全相关(如果您愿意,可以将其称为isToggled
)。它只是你在基准面上设置的属性。像一个标记。即在最后一段中的“红色”数据上,运行foo
会产生datum.isToggled = true
。下次与此红色关联的DOM元素被点击时,{ fill: "Red", isToggled: true }
将返回该同一个对象,.datum()
设置为isToggled
。这就是我的意思是让数据表示DOM元素的状态。然后,您的代码可以决定将true
设置为isToggled
,产生false
,然后相应地设置DOM元素的颜色。
我还指出,由于您的代码目前使用的是字符串数组 - 而不是{ fill: "Red", isToggled: false }
的数组 - 如果您保持这种方式,可能会将{}
指定为任何这些字符串的属性都不起作用。但事实上,由于JavaScript的特性,这将起作用。但我觉得这里解释得太多了......