Search code examples
d3.jsforce-layout

How do I capture keystroke events in D3 force layout?


I would like to respond to keystroke events directed at nodes in my force layout. I've tried adding all the variants of "keystroke", "keypress", "keyup", "keydown" that I could think of, but none of them is firing. My mouse events fire just fine. I couldn't find any keystroke events in the d3 source.... is there a way to capture key strokes?

        nodes.enter().append("circle")
            .on("click", function(d) { return d.clickHandler(self); })
            .on("mouseover", function(d) { return d.mouseOverHandler(self); })
            .on("mouseout", function(d) { return d.mouseOutHandler(self); })
            .on("keyup", function(d) { 
                console.log("keypress", d3.event); // also tried "keyup", "keydown", "key"
            })
            .classed("qNode", true)
            .call(force.drag);

Solution

  • I think the problem here is you are trying to add keyboard events to elements that are not focusable, try adding a keydown event to a focusable element (body in this case):

    d3.select("body")
        .on("keydown", function() { ...
    

    here you can use properties of d3.event, for instance d3.event.keyCode, or for more specialized cases, d3.event.altKey, d3.event.ctrlKey, d3.event.shiftKey, etc..

    Looking at the KeyboardEvent Documentation might be helpful as well.

    I've made a simple fiddle with keyboard interaction here: http://jsfiddle.net/qAHC2/292/

    You can extend this to apply these keyboard interactions to svg elements by creating a variable to 'select' the current object:

    var currentObject = null;
    

    Then update this current object reference during appropriate mouse event methods:

    .on("mouseover", function() {currentObject = this;})
    .on("mouseout", function() {currentObject = null;});
    

    Now you can use this current object in your keyboard interactions set up earlier.

    here's a jsfiddle of this in action: http://jsfiddle.net/qAHC2/295/