Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to add a background color to d3 text elements?

Tags:

d3.js

I'm trying to add a rect element behind text with d3 to simulate background-color which doesn't exist for d3 text elements. I would like the rect to have the exact same size as the text itself.

node.append("text") 
    .attr("class", "text")
    .attr("text-anchor", "middle")
    .attr("dx", 0)
    .attr("dy", ".35em")
    .text(function(d) {
          var bbox = this.getBBox();
          node.insert("rect",":first-child")
          .attr("x", bbox.x)
          .attr("y", bbox.y)
          .attr("width", bbox.width)
          .attr("height", bbox.height)
          .style("fill", "yellow");
        return d.name;
    });

this.getBBox() returns 0 for both x and y.

The following code display the box, but it size doesn't very with text size, and the box is drawn even when text is not (when an image exists).

node.filter(function(d) {return (!d.image)}).append("text") 
    .attr("class", function(d) { return "text "+d.type; })
    .attr("text-anchor", "middle")
    .attr("dx", 0)
    .attr("dy", ".35em")
    //.text(function(d) { if (!d.imgB64) { return d.label; }
    .text(function(d) {
        return d.name;
    })
    .each(function(d) {
       var bbox = this.getBBox();
          node.insert("rect", "text")
          .style("fill", "#FFE6F0")
          .attr("x", bbox.x)
          .attr("y", bbox.y)
          .attr("width", bbox.width)
          .attr("height", bbox.height);
    });

SOLUTION

Thanks to Cool Blue, the following code now properly works: display a rect behind the text so that it is readable when larger than the node circle. In the futur it could be improved with a sphere arc rather than the rect to only hide the circle frame behind the text...

enter image description here

// only display node labels if node has no image 
node.filter(function(d) {return (!d.image)}).append("text") 
    .attr("class", function(d) { return "text "+d.type; })
    .attr("text-anchor", "middle")
    .attr("dx", 0)
    .attr("dy", ".35em")
    .text(function(d) {
        return d.name;
    })
    .call(getTextBox);

// only display a rect behind labels if node has no image 
node.filter(function(d) {return (!d.image)}).insert("rect","text")
    .attr("x", function(d){return d.bbox.x})
    .attr("y", function(d){return d.bbox.y})
    .attr("width", function(d){return d.bbox.width})
    .attr("height", function(d){return d.bbox.height})
    .style("fill", "#FFE6F0");

function getTextBox(selection) {
    selection.each(function(d) { d.bbox = this.getBBox(); })
}
like image 349
Pierre Avatar asked Aug 15 '15 15:08

Pierre


1 Answers

As mentioned in the comments, use this pattern and add whatever details you need...

var textNode = node.filter(function(d) {return (!d.image)})

textNode.append("text") 
    .attr("class", "text")
    .attr("text-anchor", "middle")
    .attr("dx", 0)
    .attr("dy", ".35em")
    .text(function(d) {
        return d.name;
    }).call(getBB);   
textNode.insert("rect","text")
    .attr("width", function(d){return d.bbox.width})
    .attr("height", function(d){return d.bbox.height})
    .style("fill", "yellow");

function getBB(selection) {
    selection.each(function(d){d.bbox = this.getBBox();})
}
like image 129
Cool Blue Avatar answered Oct 23 '22 07:10

Cool Blue