Issue
I have a bar chart and I want to change the colour when I click over a bar. I want to do this setting a CSS class on the clicked element. Everything work except that the fill style (the colour of the bar clicked) does not change, but the green stroke is applied. And I don't understand why.
This is a screen before and after having clicked on the last bar of the chart
And this is what I want to achieve
This is a part of my code, any suggestions?
JS
//CREATE THE BAR CHART
var bars = d3
.select("#bars")
.selectAll("rect")
.data(data);
bars
.enter()
.append("rect")
.attr("x", function(d) {
return xScale(d.year);
})
.attr("y", function(d) {
return yScale(d.cost);
})
.attr("width", xScale.bandwidth)
.attr("height", function(d) {
return height - yScale(d.cost);
})
.style("fill", function(d) {
return colorScale(d.cost);
});
//EVENT ON CLICK
d3.select("#bars")
.selectAll("rect")
.on("click", function() {
//reset the previus bar selected
d3.select("#bars")
.select(".selected")
.classed("selected", false)
.style("fill", function(d) {
return colorScale(d.cost); //reset the original color
});
//set the current bar as selected
d3.select(this).classed("selected", true);
});
CSS
.selected {
fill: red;
stroke: green;
stroke-width: 3;
}
Solution
In general, attribute styles get overwritten by CSS styles using a selector, which in turn get overwritten by inline CSS styles.
.attr("fill", "blue")
sets the attributefill="blue"
;.selected { fill: "red"; }
applies the stylefill: red;
;.style("fill", "green")
sets the attributestyle="fill: green;"
, an inline style.
If you apply all these to the same element, the last one has precedence. By deselecting a previously selected bar, you give it .style("fill"
, and thus overrides any potential future styles. I recommend checking whether you really need to apply those styles, and use .attr()
if you do.
I've added a small showcase below.
let settings = {
attr: false,
class: false,
style: false,
};
draw();
function draw() {
d3.select("rect")
.attr("fill", settings.attr ? "red" : null)
.attr("class", settings.class ? "blue" : "")
.style("fill", settings.style ? "green" : null);
}
d3.selectAll("[type='checkbox']")
.on("change", function() {
settings[this.getAttribute("id")] = this.checked;
draw();
});
.blue {
fill: blue;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<div>
<input type="checkbox" id="attr"/><label for="attr">attr</label>
<input type="checkbox" id="class"/><label for="class">class</label>
<input type="checkbox" id="style"/><label for="style">style</label>
</div>
<svg>
<rect width="30" height="30"></rect>
</svg>
Answered By - Ruben Helsloot
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.