Harrison Cramer
Harrison Cramer

Reputation: 4506

D3 Click Event Handler

I'm currently learning D3 and had a question relating to interactivity.

The following example works to resize a group of circles on-screen based on the button clicked. It works (I am following a tutorial). Essentially, key names from a CSV file are bound to each button, which when clicked, relays that key name to an attached function (named buttonClick in this example) which is used to access the values for that key/value pair in each object of my data. The d3.max() function then is used to calculate the max value, which is used to determine a new scale and redraw the circles accordingly.

My question is: How does the function buttonClick know to accept the "data" attribute bound to each button as an argument? Why are there no parentheses for the function when it is called inside the onclick event handler?

Thanks for any help you can provide.

function createSoccerViz() {

d3.csv("worldcup.csv", data => {overallTeamViz(data)

});

function overallTeamViz(incomingData) {   
d3.select("svg")
.append("g")
.attr("id","teamsG")
.attr("transform", "translate(50,300)")
.selectAll("g").data(incomingData).enter()
.append("g")
.attr("class", "overallG")
.attr("transform", (d,i) => "translate(" + i * 60 + "," + 0 +")");
var teamG = d3.selectAll("g.overallG")
teamG.append("circle")
.attr("r",20)
teamG.append("text")
.text(d => d.team)
.attr("y", 30)

dataKeys = Object.keys(incomingData[0])
.filter(d => d !== "team" && d !== "region")

d3.select("#controls").selectAll("button.teams")
.data(dataKeys).enter()
.append("button")
.html(d => d)
.on("click", buttonClick) ////// Why no parentheses here?


function buttonClick(datapoint) {
var maxValue = d3.max(incomingData, d => parseFloat(d[datapoint]))
var radiusScale = d3.scaleLinear().domain([0, maxValue]).range([2,20])
d3.selectAll("g.overallG").select("circle")
    .attr("r", d => radiusScale(d[datapoint]))
}

Upvotes: 5

Views: 12257

Answers (1)

Gerardo Furtado
Gerardo Furtado

Reputation: 102218

You have two questions here:

  1. Why are there no parentheses for the function when it is called inside the onclick event handler?

Regarding the parenthesis, if you had them...

.on("click", buttonClick())

... you'd be passing the result of the function to the event listener (in your case, undefined), and that's not what you want.

Instead, you want the function to be called when you click the button, hence:

.on("click", buttonClick)

Or, alternatively:

.on("click", function(){
    buttonClick()
})
  1. How does the function buttonClick know to accept the "data" attribute bound to each button as an argument?

Regarding the first argument the API is clear:

When a specified event is dispatched on a selected element, the specified listener will be evaluated for the element, being passed the current datum (d), the current index (i), and the current group (nodes), with this as the current DOM element (nodes[i]). (emphasis mine)

Therefore, you don't need to explicitly specify the first argument: it will be the datum by default.

Upvotes: 7

Related Questions