Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to properly add and use D3 Events?

I'm having trouble understanding using D3 events and dispatch functions. I have a chart example that I've been working on called: "Vertical Bar Charts With Legends."

Drawing the charts and the legends was easy enough but I'd like to add the ability to highlight each bar as I mouseover its correlating text legend, located to the right of the chart.

I've read through all of the event documentation and even looked at a number of examples, most of which are pretty complicated, but I seem to be missing something. Would anyone know how to best accomplish the text legend mouseover functionality that dispatches events to automatically change colors of the corresponding vertical bars?

like image 601
Information Technology Avatar asked Mar 27 '12 01:03

Information Technology


People also ask

What can d3js do?

D3 allows you to bind arbitrary data to a Document Object Model (DOM), and then apply data-driven transformations to the document. For example, you can use D3 to generate an HTML table from an array of numbers. Or, use the same data to create an interactive SVG bar chart with smooth transitions and interaction.

What is D3 explain about the big data visualization using D3 with example?

D3. js is a JavaScript library for creating visualizations like charts, maps, and more on the web. Unlike many other data visualization libraries that provide ready made charts, D3 gives you lots of creative freedom as you have total control over the visualizations you create.

What does the every () method do in D3?

each() function in D3. js is used to call the particular function for each selected HTML elements. In function datum(d) and index(i) are given as the parameters.

What is D3 event target?

"To access the current event within a listener, use the global d3. event. This allows you to access everything related to the event, including mouse position and event source/target (print d3. event in console.


2 Answers

This question is similar to the one you posted in the d3-js Google Group. Without duplicating what I wrote there, I would reiterate that you probably don't want d3.dispatch; that is intended for custom event abstractions (such as brushes and behaviors). It'll be simpler to use native events.

If you want your legend to change the color of the corresponding bar on mouseover, then breakdown the problem into steps:

  1. Detect mouseover on the legend.
  2. Select the corresponding bar.
  3. Change the bar's fill color.

First, use selection.on to listen for "mouseover" events on the legend elements. Your listener function will be called when the mouse goes over a legend element, and will be called with two arguments: the data (d) and the index (i). You can use this information to select the corresponding bar via d3.select. Lastly, use selection.style to change the "fill" style with the new color.

If you're not sure how to select the corresponding bar on legend mouseover, there are typically several options. The most straightforward is to select by index, assuming that the number of legend elements and number of rect elements are the same, and they are in the same order. In that case, if a local variable rect contains the rect elements, you could say:

function mouseover(d, i) {   d3.select(rect[0][i]).style("fill", "red"); } 

If you don't want to rely on index, another option is to scan for the matching bar based on identical data. This uses selection.filter:

function mouseover(d, i) {   rect.filter(function(p) { return d === p; }).style("fill", "red"); } 

Yet another option is to give each rect a unique ID, and then select by id. For example, on initialization, you could say:

rect.attr("id", function(d, i) { return "rect-" + i; }); 

Then, you could select the rect by id on mouseover:

function mouseover(d, i) {   d3.select("#rect-" + i).style("fill", "red"); } 

The above example is contrived since I used the index to generate the id attribute (in which case, it's simpler and faster to use the first technique of selecting by index). A more realistic example would be if your data had a name property; you could then use d.name to generate the id attribute, and likewise select by id. You could also select by other attributes or class, if you don't want to generate a unique id.

like image 198
mbostock Avatar answered Oct 04 '22 05:10

mbostock


Mike's answer is great.

I used it come up with this for selecting a cell in a grid I was drawing:

.on('click', (d, i) ->       console.log("X:" + d.x, "Y:" + d.y) #displays the cell x y location       d3.select(this).style("fill", "red"); 

So when I am entering the data in I added the event listener and using d3.select(this).

See the code in context below:

 vis.selectAll("rect")     .data(singleArray)     .enter().append("svg:rect")     .attr("stroke", "none")     .attr("fill", (d) ->        if d.lifeForm         return "green"        else         return "white")     .attr("x", (d) -> xs(d.x))     .attr("y", (d) -> ys(d.y))     .attr("width", cellWidth)     .attr("height", cellHeight)     .on('click', (d, i) ->       console.log("X:" + d.x, "Y:" + d.y)       d3.select(this).style("fill", "red");       return     )  
like image 42
ChickenFur Avatar answered Oct 04 '22 05:10

ChickenFur