D3 Add Text to Circle

d3 add text to circle

Here is an example showing some text in circles with data from a json file: http://bl.ocks.org/4474971. Which gives the following:

Sample Image

The main idea behind this is to encapsulate the text and the circle in the same "div" as you would do in html to have the logo and the name of the company in the same div in a page header.

The main code is:

var width = 960,
height = 500;

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

d3.json("data.json", function(json) {
/* Define the data for the circles */
var elem = svg.selectAll("g")
.data(json.nodes)

/*Create and place the "blocks" containing the circle and the text */
var elemEnter = elem.enter()
.append("g")
.attr("transform", function(d){return "translate("+d.x+",80)"})

/*Create the circle for each block */
var circle = elemEnter.append("circle")
.attr("r", function(d){return d.r} )
.attr("stroke","black")
.attr("fill", "white")

/* Create the text for each block */
elemEnter.append("text")
.attr("dx", function(d){return -20})
.text(function(d){return d.label})
})

and the json file is:

{"nodes":[
{"x":80, "r":40, "label":"Node 1"},
{"x":200, "r":60, "label":"Node 2"},
{"x":380, "r":80, "label":"Node 3"}
]}

The resulting html code shows the encapsulation you want:

<svg width="960" height="500">
<g transform="translate(80,80)">
<circle r="40" stroke="black" fill="white"></circle>
<text dx="-20">Node 1</text>
</g>
<g transform="translate(200,80)">
<circle r="60" stroke="black" fill="white"></circle>
<text dx="-20">Node 2</text>
</g>
<g transform="translate(380,80)">
<circle r="80" stroke="black" fill="white"></circle>
<text dx="-20">Node 3</text>
</g>
</svg>

jsfiddle with working code: http://jsfiddle.net/chrisJamesC/DY7r4/

Adding text to d3 circle

Another option, close to @cyril's is to use a g element and place both the circle and text inside. This saves you the double data-bind and double movement update:

var nodes = svg.selectAll("g")
.data(data);

var g = nodes.enter().append("g")

g.append("circle")
.attr("class", function(d) {
return d.ratingCategory;
})
.attr("r", 2)
.attr("id", function(d){return d.objectName;})
.on("mouseover", function(d) {
showPopover.call(this, d);
})
.on("mouseout", function(d) {
removePopovers();
});

g.append("text")
.attr("dx",12)
.attr("dy",".35em")
.text(function(d){
return d.objectName;
});

And update the node position in the tick function as:

nodes.each(collide(.2))
.attr("transform", function(d){ //<-- use transform it's not a g
return "translate(" + d.x + "," + d.y + ")";
});

Updated block.

Add label/text to D3 circles?

You cannot append text to circles with svg - but you can append both to a g; this is your easiest and cleanest solution.

When appending the g, use the projection values to set a transform, this allows the center of the circle to be placed at [0,0] relative to the transform:

var g = svg.selectAll(null)
.data(data)
.enter()
.append("g")
.attr("transform", function(d) {
return "translate(" + projection([d.longitude, d.latitude]) + ")" ;
})

As the datum for each g holds the datum you want to display for each circle, you can now append circles and text easily as child elements:

g.append("circle")
.attr("r", function(d) {return Math.sqrt(d.population * 0.00004);})
.attr("fill","red")
.attr("etc",...)

g.append("text")
.text(function(d) { return d.city; })
.attr("x"...)
.attr("y"...)

Note that the circle doesn't need positioning anymore: cx and cy will default to zero - which is fine as we transformed the g's coordinates. Also, using transform rather than both cx and cy is a little cleaner, especially when using projections (and by transforming the g, you don't need to use your projection to place the text either).

Lastly, you probably want to modify the x,y, and text-anchor properties of the text to suit your needs, but the default x,y of zero will place text starting at the center of the circle.

Append circles first, then text, so text appears above.

D3: How to set text inside a circle

Following the advice of @Pablo EM and thanks to @Andrew Reid for your appreciated help I publish the solution to my problem.

How @Andrew Reid said if I have problems with selectAll("text") I have to change it for another text grouper. How I had it, I changed by selectAll("textCircle") and everything works fine to me.

This is the code which writes the text inside each circle. This piede of code you can find it inside of "setPointsToCanvas" method.

//Ad label for each circle
canvas
.selectAll("textCircle")
.data(data)
.enter()
.append("text")
.attr("x", function(d) {
return scales.xScale(parseFloat(d.value_x));
})
.attr("y", function(d) {
return scales.yScale(parseFloat(d.value_y) - 0.9);
})
.text(function(d) {
return d.name.substring(0, 3);
})
.style("text-anchor", "middle")
.style("font-weight", "bold")
.style("font-size", "10pt")
.style("fill", "#344761");

Now, here you've got an image of the final result:

Sample Image

If you access to the code through CodeSandBox posted before you can access to all the code and check how it works perfectly.

How to add text to svg circle in d3

There are numerous ways to add text labels to circles. In your code, you've added title elements to the circles, which usually show up as tooltips when you hover over the element. Unlike title elements, text elements cannot be added as children of the circle elements. One common way to handle them is to use g elements to group together the circle and the related text, so that you can then perform any transformations (or removals, etc.) on the g instead of having to apply them separately to text and circle.

To convert your code sample, first, I've altered the selectAll / enter code to act on g elements instead of circles:

const node = svg
[...]
.selectAll('.circle')
.data(nodes)
.enter()
.append('g') // for each item in nodes, add <g class='circle'>
.classed('circle', true)

You can then append the circle and text elements to node:

node
.append("circle")
.attr('r', 5)

node
.append("text")
.text(d => "Node: " + d.id)

See the code snippet for a full example.

var nodes = [{  "x": 80,  "y": 60,  id: 'foo'}, {  "x": 20,  "y": 70,  id: 'bar'}, {  "x": 40,  "y": 40,  id: 'baz'}, {  "x": 50,  "y": 90,  id: 'bop'}];const svg = d3.select('svg')
const node = svg .append("g") .attr("stroke", "#fff") .attr("stroke-width", 1.5) .selectAll(".circle") .data(nodes) .enter() .append('g') .classed('circle', true) .attr('transform', d => 'translate(' + d.x + ',' + d.y + ')');
node .append("circle") .attr("r", 5) .attr("fill", 'deepskyblue')// .call(drag(simulation));
node .append("text") .classed('circleText', true) .attr('dy', '0.35em') .attr('dx', 5) .text(d => "Node: " + d.id);
svg .circleText {  font-family: Helvetica, Arial, sans-serif;  font-size: 12px;  fill: black;  stroke-width: 0;}
<script src="http://d3js.org/d3.v5.js"></script><svg width="200" height="200"></svg>

How to add text to d3.js force directed circles?

You cannot append a text element to a circle.
First, create a g for each node:

var node = svg.append("g")
.attr("class", "nodes")
.selectAll("g")
.data(props.data)
.enter()
.append("g")

Then, append a circle and a text to each g:

node.append('circle').attr('r', ...)
node.append('text').text(...)
...

Replace

node.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; });

with:

node.attr('transform', d => `translate(${d.x},${d.y})`);

Text in the circle

From what I can see there's a couple of things going on.

Firstly, instead of:

...
.append(Text)

which is trying to pass in a variable called Text to the append function, it should be:

...
.append('text')

i.e. append an svg text element.

However, this is still appending text elements to circle elements. If you look at the elements via Chrome Devtools, you can see that there will be a text element inside each circle element, which doesn't actually display anything.

Instead, the label text needs to be rendered separately from the circles using something like.

svg.selectAll("mytext")
.data(data)
.enter()
.append('text')
.attr("x", function (d) { return x(d.Value) + 10; })
.attr("y", function (d) { return y(d.Country) + 4; })
.text(function (d) { return d.Value})
.attr("font-family", "sans-serif")
.attr("font-size", "10px")
.attr("fill", "black")
.style("text-anchor", "start")
.style('opacity', 0)
.transition()
.delay(1500)
.duration(500)
.style('opacity', 1);

I've made the font a bit bigger, and adjusted the x and y values and used text-anchor: start so that now the text appears just off the right of the circles. I've also put in a transition based on opacity with a delay so that the text only appears at the end of the circles' animation.



Related Topics



Leave a reply



Submit