Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get web element (id) from the element position in D3.js force graph

I am working with the D3.js force graph but I am not able to find out the element id from the element position (which I know).

I am using Leap motion. I need to simulate a mouse event (a click, a move, a drag, etc.) without a mouse. And, if I am right, in order to be able to do this, I need to find out what is the the element id from the coordinates x and y (these coordinates I know from the Leap motion pointer). So from what you wrote above, I need to find out the ('.node’). Here is what I already tried but it did not work:

Is it possible to use non-mouse, non-touch events to interact with a D3.js graph? If so, what is the most efficient way to go about it?

So I used this function (see below), but I need to know the element id to make it work correctly:

//graph.simulate(document.getElementById("r_1"), 'dblclick', {pointerX: posX, pointerY: posY});
//here id r_1 is hardcoded, but I need to find out id from x and y coordinates.

this.simulate = function (element, eventName) {
    function extend(destination, source) {
        for (var property in source)
            destination[property] = source[property];
        return destination;
    }

    var eventMatchers = {
        'HTMLEvents': /^(?:load|unload|abort|error|select|change|submit|reset|focus|blur|resize|scroll)$/,
        'MouseEvents': /^(?:click|dblclick|mouse(?:down|up|over|move|out))$/
    };

    var defaultOptions = {
        pointerX: 0,
        pointerY: 0,
        button: 0,
        ctrlKey: false,
        altKey: false,
        shiftKey: false,
        metaKey: false,
        bubbles: true,
        cancelable: true
    };

    var options = extend(defaultOptions, arguments[2] || {});
    var oEvent, eventType = null;

    for (var name in eventMatchers) {
        if (eventMatchers[name].test(eventName)) {
            eventType = name;
            break;
        }
    }

    if (!eventType)
        throw new SyntaxError('Only HTMLEvents and MouseEvents interfaces are supported');

    if (document.createEvent) {
        oEvent = document.createEvent(eventType);
        if (eventType == 'HTMLEvents') {
            oEvent.initEvent(eventName, options.bubbles, options.cancelable);
        }
        else {
            oEvent.initMouseEvent(eventName, options.bubbles, options.cancelable, document.defaultView,
                options.button, options.pointerX, options.pointerY, options.pointerX, options.pointerY,
                options.ctrlKey, options.altKey, options.shiftKey, options.metaKey, options.button, element);
        }
    element.dispatchEvent(oEvent);
    }
    else {
        options.clientX = options.pointerX;
        options.clientY = options.pointerY;
        var evt = document.createEventObject();
        oEvent = extend(evt, options);
        element.fireEvent('on' + eventName, oEvent);
    }
    return element;
}

Many thanks for your help and ideas.

like image 217
Jirka Avatar asked Oct 16 '25 17:10

Jirka


2 Answers

If you want access to the element, it's implicit in D3's iterators via this.

d3.selectAll('.node').each(function(d) {
  console.log(this); // Logs the element attached to d.
});

If you really need access to the id, you can get it with selection.attr():

d3.selectAll('.node').each(function() {
  console.log(d3.select(this).attr('id')); // Logs the id attribute.
});

You don't have to use each. Any of the iterators, such as attr or style, etc., have 'this' as the bound element:

d3.selectAll('.node').style('opacity', function(d) {
  console.log(this);// Logs the element attached to d.
});

If you want the x and y coordinates of a node, it's part of the data:

d3.selectAll('.node').each(function(d) {
  console.log(d.x, d.y); // Logs the x and y position of the datum.
});

If you really need the node attributes themselves, you can use the attr accessor.

d3.selectAll('.node').each(function(d) {
  // Logs the cx and cy attributes of a node.
  console.log(d3.select(this).attr('cx'), d3.select(this).attr('cy'));
});

EDIT: It looks like you need an element reference, but the only thing you know about the node in context is its position. One solution is to search through all nodes for a node with matching coordinates.

// Brute force search of all nodes.
function search(root, x, y) {
  var found;
  function recurse(node) {
    if (node.x === x && node.y === y)
      found = node;
    !found && node.children && node.children.forEach(function(child) {
      recurse(child);
    });
  }
  recurse(root);
  return found;
}

However this only gives you the node object, not the element itself. You will likely need to store the element references on the nodes:

// Give each node a reference to its dom element.
d3.selectAll('.node').each(function(d) {
  d.element = this;
});

With that in place, you should be able to access the element and get its id.

var id, node = search(root, x, y);
if (node) {
  id = node.element.getAttribute('id');
}

The brute-force search is fine for a small number of nodes, but if you're pushing a large number of nodes you might want to use D3's quadtree (example) to speed up the search.

like image 163
t.888 Avatar answered Oct 19 '25 00:10

t.888


Use d3.select('#yourElementId')

For more info check this out: https://github.com/mbostock/d3/wiki/Selections

like image 45
AvgustinTomsic Avatar answered Oct 18 '25 23:10

AvgustinTomsic



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!