I'm puzzled as to why the d3 method for setting an element attribute fails (in this piece of code) while the traditional JS method works. (I'm trying to update the chloropleth colours as the user clicks a HTML button to change the data being plotted, all from the same JSON.)
The HTML is simple:
<div id="buttons">
<button id="party">Parties</button>
<button id="tenure">Tenure</button>
</div>
Here's the relevant JS with the two lines side-by-side. When I run it as is in Chrome, I get "Object # has no method 'attr'":
var paths = svg.selectAll("path");
var plot = {
"mode": "party",
"redraw": function() {
var e = e || window.event;
var targ = e.target || e.srcElement;
if (targ.nodeType == 3) targ = targ.parentNode;
switch (targ.id) {
case "party":
// some code in here
break;
case "tenure":
paths.each(function(d,i) {
this.setAttribute("class",""); // Same question here actually
if (d.In_Office_Full_Date) {
// This line errors:
this.attr("style", "fill: " + t_scale(getJSDateFromExcel(d.In_Office_Full_Date).getFullYear()));
// ... but this line works:
this.setAttribute("style", "fill: " + t_scale(getJSDateFromExcel(d.In_Office_Full_Date).getFullYear()));
}
else
this.setAttribute("style", "fill: #111"); // Neutral colour
});
break;
default:
console.log("Unknown event trigger in redraw()");
}
}
}
var t_scale = d3.scale.linear()
.domain([1973,2013])
.range(['red','white']);
d3.select("body").selectAll("#buttons button")
.on("click",plot.redraw);
I hope you can help!
The issue is with the way you're calling methods of this
from within each(function(d, i) { ... })
.
You're in the right direction: this
refers to the plain html element that you're modifying. However the attr
function you expect to call is a method of a d3 selection –– not of the html element. Hence, you need to wrap this
in a d3 selection:
paths.each(function(d,i) {
d3.select(this)
.attr("class","");
});
Calling setAttribute
worked because it's a method of the plain html element, but clearly d3's attr
is more robust.
But having said all that, the more idiomatic way to achieve what you're doing is this:
paths
.attr("class", "")
.style("fill", function(d, i) {
if (d.In_Office_Full_Date) {
return t_scale(getJSDateFromExcel(d.In_Office_Full_Date).getFullYear());
}
return "#111";
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With