Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

D3 force layout: links and nodes --- z-index(?)

D3: problems between nodes and links

I created the following jsfiddle to get an idea of what i'm trying to achieve:

enter image description here

I want nodes to over(?) links...

Please help me. I'm sorry for my English :)

Script looks like this:

function myGraph(el) {
this.addNode = function (id) {
    nodes.push({ "id": id });
    update();
}
this.removeNode = function (id) {
    var i = 0;
    var n = findNode(id);
    while (i < links.length) {
        if ((links[i]['source'] == n) || (links[i]['target'] == n)) links.splice(i, 1);
        else i++;
    }
    nodes.splice(findNodeIndex(id), 1);
    update();
}
this.addLink = function (source, target) {
    links.push({ "source": findNode(source), "target": findNode(target) });
    update();
}
var findNode = function (id) {
    for (var i in nodes) { if (nodes[i]["id"] === id) return nodes[i] };
}
var findNodeIndex = function (id) {
    for (var i in nodes) { if (nodes[i]["id"] === id) return i };
}
// set up the D3 svg in the specified element
var w = window.jQuery(el).innerWidth(),
    h = window.jQuery(el).innerHeight();
var svg = this.svg = d3.select(el).append("svg:svg")
    .attr("width", w)
    .attr("height", h);
var force = d3.layout.force()
    .gravity(.05)
    .distance(100)
    .charge(-120)
    .size([w, h]);
var nodes = force.nodes(),
    links = force.links();
var update = function () {
    var link = svg.selectAll(".link")
        .data(links, function (d) { return d.source.id + "-" + d.target.id; })
    link.enter().append("line")
        .attr("class", "link")
    link.exit().remove();
    var node = svg.selectAll(".node")
        .data(nodes, function (d) { return d.id; })
    node.enter().append("g")
        .attr("class", "node")
        .call(force.drag);
    node.append("circle")
        .attr("r", function (d) { return 30; })
        .style("fill", "#EFEFEF")
    node.append("text")
        .attr("text-anchor", "right")
        .text(function (d) { return d.id; });
    force.on("tick", function () {
        link.attr("x1", function (d) { return d.source.x; })
            .attr("y1", function (d) { return d.source.y; })
            .attr("x2", function (d) { return d.target.x; })
            .attr("y2", function (d) { return d.target.y; });
        node.attr("transform", function (d) { return "translate(" + d.x + "," + d.y + ")"; });
    });
    // Restart the force layout.
    force.start();
}
// Make it all go
update();
}
graph = new myGraph("#graph");
// You can do this from the console as much as you like...
graph.addNode("Cause");
graph.addNode("Effect");
graph.addLink("Cause", "Effect");
graph.addNode("A");
graph.addNode("B");
graph.addLink("A", "B");
like image 339
user3226872 Avatar asked Jan 23 '14 09:01

user3226872


People also ask

What is a force layout in D3?

First the formal, techie, definition: A Force Layout in D3 is a strategy for displaying data elements, visually, that position linked nodes using physical simulation. That basically means it is a way to draw a collection of data elements (nodes) and how they relate to each other...

Why is my force layout not showing the distance between nodes?

The force layout, through its iterations, will try to arrange the nodes so that all links are approximately this distance, but that won't always be possible. Even when it is technically able to make all links the desired distance, the resulting visualization may have other undesirable properties. Too many links may cross each other, for example.

Why is my force layout not showing all links?

The force layout, through its iterations, will try to arrange the nodes so that all links are approximately this distance, but that won't always be possible. Even when it is technically able to make all links the desired distance, the resulting visualization may have other undesirable properties.

What is the use of d3-force?

This allows users to easily see the relationships between elements and the most significant element within the dataset. This guide will demonstrate how to use the d3-force package to create force layout graphs.


1 Answers

There's no z-index property in SVG; the elements are rendered in the order in which they are specified. This means for you that all the link elements need to be before the node elements in the generated DOM.

The easiest way to achieve this is to have separate g elements for links and nodes, with the former first.

svg.append("g").attr("class", "links");
svg.append("g").attr("class", "nodes");

Then you can append links like this

var link = svg.select(".links").selectAll(".link")
         .data(links, function (d) { return d.source.id + "-" + d.target.id; })
// etc

and nodes likewise. Complete demo here.

like image 173
Lars Kotthoff Avatar answered Sep 29 '22 10:09

Lars Kotthoff