2

Wondering if you can help. I have tried different stylings and different d3js examples but they all fail to show the text on the node. Any ideas this would be?

The task is quite simple really. Show the text on top of a node. I really have no idea why this is not working so your help is much appreciated.

Many thanks for your help in advance.

Below is the code, but for convenience here is the fiddle http://jsfiddle.net/rg5pmrz1/

<!DOCTYPE html>
<html>
<head>
    <meta charset='utf-8'>
    <title>Force Layout Example 1</title>
    <style>

.node {
    fill: #ccc;
    stroke: #fff;
    stroke-width: 2px;
}

.link {
    stroke: #777;
    stroke-width: 2px;
}

.node text {
  font: 10px sans-serif;
  pointer-events: none;
}

text {
  font: 10px sans-serif;
  pointer-events: none;
}

    </style>
</head>
<body>
    <script src='http://d3js.org/d3.v3.min.js'></script>
    <script>

// Define the dimensions of the visualization. We're using
// a size that's convenient for displaying the graphic on
// http://jsDataV.is

var width = window.innerWidth - 20,
    height = innerHeight - 20;

var color = d3.scale.category10();

var force = d3.layout.force()
    .charge(-300)
    .linkDistance(function (l) { return l.value; })
    .gravity(0.03)
    .friction(0.9)
    .size([width, height]);

var svg = d3.select("body").append("svg")
    .attr("width", width)
    .attr("height", height);

var graph = getData();

var nodeMap = {};

graph.nodes.forEach(function(d) { 

    nodeMap[d.name] = d;
    //centering first element   
   if(d.main == true)
   {
        graph.nodes[0].x = width / 2;
        graph.nodes[0].y = height / 2;
    }

});

graph.links.forEach(function(l) {
    l.source = nodeMap[l.source];
    l.target = nodeMap[l.target];
    l.distance = l.value;
    l.size = l.value;
})

force.nodes(graph.nodes)
    .links(graph.links)
    .start();

var link = svg.selectAll(".link")
    .data(graph.links)
    .enter().append("line")
    .attr("class", "link")
    .style("stroke-width", function(d) {
        return 1 / (d.value / 1000);
    });



var node = svg.selectAll(".node")
    .data(graph.nodes)
    .enter().append("circle")
    .attr("class", "node")
    .attr("r", 30)
    .style("fill", function(d) { return color(d.group); })

    .on("mouseover", mouseover)
    .on("mouseout", mouseout)
    .call(force.drag);


node.append("title")
      .attr("dy", ".35em")
      .attr("text-anchor", "middle")
      .text(function(d) { return d.name});

node.append("text")
    .attr("x", 12)
    .attr("dy", ".35em")
    .text(function(d) { return d.name;console.log("name: " + d.name); });

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("cx", function(d) { return d.x; })
        .attr("cy", function(d) { return d.y; });
});

function mouseover() {
    console.log("mouse over");
  d3.select(this).transition()
      .duration(250)
      .attr("r", 60);
}

function mouseout() {
    console.log("mouse out");
  d3.select(this).transition()
      .duration(250)
      .attr("r", 30);
}

function click() {
    console.log("clicky clicky");
  d3.select(this).transition()
      .duration(250)
      .attr("r", 60);

}



function getData() {

  return {
  "nodes":[
      {"name":"John","group":1, "value": 1, "main": true},
    {"name":"Mike","group":2, "value": 2},
    {"name":"Ian","group":1, "value": 3},
    {"name":"James","group":2, "value": 4},
    {"name":"Sarah","group":2,"value": 5}
  ],
  "links":[
    {"source":"John","target":"Mike","value":100},
    {"source":"Ian","target":"John","value":200},
    {"source":"John","target":"James","value":100},
    {"source":"Sarah","target":"John","value":300},
  ] };    

}



    </script>
</body>
</html>
user2091936
  • 546
  • 2
  • 7
  • 28

2 Answers2

3

From the answers to duplicate questions here and here, it is because:

You can't add svg text to a svg circle. You should first create an svg g object (g stands for group) for each node, and than add a circle and a text for each g element, like in this code:

jsFiddle. Note the additional code in the tick function.

var width = window.innerWidth - 20,
    height = innerHeight - 20;

var color = d3.scale.category10();

var force = d3.layout.force()
    .charge(-300)
    .linkDistance(function (l) { return l.value; })
    .gravity(0.03)
    .friction(0.9)
    .size([width, height]);

var svg = d3.select("body").append("svg")
    .attr("width", width)
    .attr("height", height);

var graph = getData();

var nodeMap = {};

graph.nodes.forEach(function(d) { 

    nodeMap[d.name] = d;
    //centering first element   
   if(d.main == true)
   {
        graph.nodes[0].x = width / 2;
        graph.nodes[0].y = height / 2;
    }

});

graph.links.forEach(function(l) {
    l.source = nodeMap[l.source];
    l.target = nodeMap[l.target];
    l.distance = l.value;
    l.size = l.value;
})

force.nodes(graph.nodes)
    .links(graph.links)
    .start();

var link = svg.selectAll(".link")
    .data(graph.links)
    .enter().append("line")
    .attr("class", "link")
    .style("stroke-width", function(d) {
        return 1 / (d.value / 1000);
    });

var node = svg.selectAll(".node")
    .data(graph.nodes)
    .enter().append("g");

var circle = node.append("circle")
    .attr("class", "node")
    .attr("id", function (d) { return d.name; })
    .attr("r", 30)
    .style("fill", function (d) {
        return color(d.group);
    })
    .on("mouseover", mouseover)
    .on("mouseout", mouseout)
    .call(force.drag);

var label = node.append("svg:text")
    .text(function(d) { return d.name; });

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) {
        console.log(d);
        return 'translate(' + [d.x, d.y] + ')'; 
    });
});

function mouseover() {
    console.log("mouse over");
  d3.select(this).transition()
      .duration(250)
      .attr("r", 60);
}

function mouseout() {
    console.log("mouse out");
  d3.select(this).transition()
      .duration(250)
      .attr("r", 30);
}

function click() {
    console.log("clicky clicky");
  d3.select(this).transition()
      .duration(250)
      .attr("r", 60);
}



function getData() {

  return {
  "nodes":[
      {"name":"John","group":1, "value": 1, "main": true},
    {"name":"Mike","group":2, "value": 2},
    {"name":"Ian","group":1, "value": 3},
    {"name":"James","group":2, "value": 4},
    {"name":"Sarah","group":2,"value": 5}
  ],
  "links":[
    {"source":"John","target":"Mike","value":100},
    {"source":"Ian","target":"John","value":200},
    {"source":"John","target":"James","value":100},
    {"source":"Sarah","target":"John","value":300},
  ] };    

}
Community
  • 1
  • 1
davidhwang
  • 1,343
  • 1
  • 12
  • 19
  • That solved it indeed. I actually found another way to do this which is to change the node to draw the "g" before. That seems to reduce the flickering – user2091936 Mar 19 '15 at 11:50
0

This seems to reduce the flickering. Replace the var node = etc. with the following:

var node = svg.selectAll(".node")
.data(graph.connections)
.enter().append("g") //this appends the G to enable the text
.attr("class", "node")
.call(force.drag);


node.append("circle") //then we add the circle
.attr("class", "node")
.attr("r", function (d) {
    if (d.main == true)
    {
        return 45;
    }
    else
    {
        return 30;
    }
})

.style("fill", function(d) { return color(d.group); })
.on("mouseover", mouseover)
.on("mouseout", mouseout)
.call(force.drag);
user2091936
  • 546
  • 2
  • 7
  • 28