Posted by & filed under Content - Highlights and Reviews, Programming & Development.

code A guest post by John Williams, a web developer who has worked for media, education, and government organizations for seventeen years. For the last seven, he has been working for NewCity in Blacksburg, VA, assisting with several data visualization projects in bioinformatics. He can be found on Twitter @thudfactor.

Once things get sufficiently complex with D3.js, somebody somewhere is going to insist that you add a right-click context menu to your application. Yes, it overrides browser behavior, violates user expectations, and makes debugging your own apps a bit more difficult.

So, with full acknowledgement of the problems overriding the use of the right menu, but also aware that it’s sometimes unavoidable, I’m going to tell you how to do it with D3.js. Our goal is a right-clickable information panel that:

  • Only fires on specific objects
  • Behaves consistently with the standard context menu
  • Uses only the D3.js framework and native JavaScript

First, here’s a chart we’re adding the panel to: http://jsfiddle.net/thudfactor/6YyvZ/.

As you can see, we have a data set with several unused fields. We’d like to share that, but we don’t want to clutter up this gorgeous chart. This is what will go in our right-click popup panel. Here’s an example with a right-click menu embedded: http://jsfiddle.net/thudfactor/T8hpd/.

Let’s walk through how that works:

Common behavior for context menus is for the menu to appear on a right-click and stay open until a menu item is selected or the user right-clicks again. So we need a flag to keep track of state.

Now we’ll listen for the event that fires when a context menu is being requested. That event is cleverly called contextmenu.

Here we use D3′s selectAll to choose which elements we’ll listen for the contextmenu event on, and bind the event listener with on. The result: all three of our bars have the same listener.

Now we’ll set up the event listener. When you bind an event using D3.js’s on, the handler gets passed d (datum) and i (index) parameters, just like other D3.js operator functions.

It doesn’t get the actual event object, but you can still access it through d3.event so you can do things like:

Everything you expect is still there, readily accessible.

The rest of the handler uses D3.js to assemble the popover from the datum object passed to the event handler. There’s no need to go into that, but it’s in the example if you want to play around with it.

So where are we here? We have, with just a handful of lines, and without resorting to using another library, overridden the context menu with a context-specific popover.

And that’s great. But it doesn’t quite behave like a context menu, does it?

Here are the ways we fail:

  • The context menu does not display near the mouse cursor. Context menus do. Ours should, too.
  • To dismiss the information panel you have to click another bar. Open context menus are dismissed by clicking anywhere outside of the context menu.

Let’s see how we would go about making these changes.

A better popup menu

Our interaction for dismissing the context menu, “click anywhere,” sounds a lot like “click on body.” So, we’ll start by attaching our listener to the body element instead of to each bar.

I used select here instead of selectAll for two reasons. First, I really only want (or expect) the event to be bound to one none. select() returns the first matching node. Secondly, I do not plan to do any data-binding to the result.

The listener is similar, but since our event is bound to something that doesn’t have data in it, we’re not going to get those parameters. What we need is some other way to get at that data. But first, let’s handle our click-to-dismiss interaction.

Note that we don’t preventDefault() at the top of the handler because there is a case where we want the default behavior to occur: when our context menu is not showing and the right-click happens on an ineligible target. But we don’t want the system menu to open when we are closing ours, so we’ll preventDefault() here.

Now let’s check our target to see if it is eligible:

There are a number of ways to check to see if the event target is elligible. Here, I’ve chosen to see if the event target has a class I know I’ve assigned to my bars. The target of the event, remember, is the actual node clicked on — not the node where the event listener is listening. And we have to select it to be able to run D3.js operations on it, just as we would with jQuery.

Finally, here’s how we get at the bar’s data:

datum takes a D3.js node and returns the data associated with it. This demonstrates that a copy of the data is actually stored in the DOM. If you can get ahold of the DOM element, you can always get the data.

Conclusion

You now know how to create right-click contextual popups with D3.js. Here’s the complete working example: http://jsfiddle.net/thudfactor/WwdT3/.

And here’s a version where the context menu is positioned near the mouse but not outside of the visualization’s borders: http://jsfiddle.net/thudfactor/dzw9h/.

Hopefully you’ve seen enough to appreciate the power of being able to define every aspect of a D3.js visualization (CSS/HTML/JS) in one place. By packaging it all up in a custom element we hide the complexity and gave designers or other non-technical members of the team the ability to leverage this code.

Look below for some great D3.js books from Safari Books Online.

Not a subscriber? Sign up for a free trial.

Safari Books Online has the content you need

Interactive Data Visualization for the Web shows you how to create and publish your own interactive data visualization projects on the Web – even if you have little or no experience with data visualization or web development. It’s easy and fun with this practical, hands-on introduction. Author Scott Murray teaches you the fundamental concepts and methods of D3, a JavaScript library that lets you express data visually in a web browser.
Developing a D3.js Edge D3 is a powerful framework for producing interactive data visualizations. Many examples created in the real world with D3, however, can best be described as “spaghetti code.” So, if you are interested in using D3 in a reusable and modular way, which is of course in line with modern development practices, then this book is for you!
Data Visualization with d3.js walks you through 20 examples. You can finally stop struggling to piece together examples you’ve found online. With this book, you will learn enough of the core concepts to conceive of and build your own visualizations from scratch.
It begins with the basics of putting lines on the screen, and builds on this foundation all the way to creating interactive animated visualizations using d3.js layouts.
Visual Storytelling with D3: An Introduction to Data Visualization in JavaScript provides readers with a strong framework of principles for making well-conceived and well-crafted infographics, as well as detailed and practical instructions for how to really wield D3, the best tool for making web infographics available. An extended example is used in the book to explain how to put theory to practical use.

Tags: contextmenu, contextual popup, D3, D3.js, jQuery, right-click,

Comments are closed.