1

I am using d3.js visualization for depicting nodes. I am getting the text as of now. I have a code to resize the width of the rect depending on the length of text going into it. But, sometimes it is not working, the text is going out of the rect box. Here is the code for that.

nodeEnter.append("rect").attr("x",
        function(d) {
            var x = d.name.length;
            x = x + 150;
            return -(x) / 2;
        }).attr("y", -10).attr(
        "width",
        function(d) {
            var x = d.name.length;
            x = x + 150;
            return x;
        }).attr("height", 20).style({
        "fill": function(d) {
            return d._children ? "lightsteelblue" : "#fff";
        },
        "stroke": "steelblue",
        "stroke-width": "1.5px"
    });

    nodeEnter.append("text").attr("x", 0).attr("y", 0)
        .attr("dy", ".35em").attr(
            "text",
            function(d) {
                return d.children || d._children ? "end" : "start";
            }).text(function(d) {
            return d.name;
        }).style({
            "fill-opacity": 1e-6,
            "font-size": "10px",
            "font-family": "sans-serif"
        }).attr(
            "text-anchor", "start");

Here I took the length of the text to go into the box and added 150. But, not working beyond a point. Can I get any help here ?

As per the suggestion of using getBBox(). I tried using it and here is the edited code

var text = nodeEnter.append("svg:text").attr("x", 0).attr("y", 0)
    .attr("dy", ".35em").attr(
        "text",
        function(d) {
            return d.children || d._children ? "end" : "start";
        }).text(function(d) {
        return d.name;
    }).style({
        "fill-opacity": 1e-6,
        "font-size": "10px",
        "font-family": "sans-serif"
    }).attr(
        "text-anchor", "middle");
    
    var bbox = text.node().getBBox();
    nodeEnter.append("rect").attr("x",
        function(d) {
            var x = d.name.length;
            x = x + 150;
            return -(x) / 2;
        }).attr("y", -10).attr(
        "width", bbox.width).attr("height", bbox.height)
        .style({
        "fill": function(d) {
            return d._children ? "lightsteelblue" : "#fff";
        },
        "stroke": "steelblue",
        "stroke-width": "1.5px"
    });

This is making the text inside the rectangle box disappear and only the overflown text is visible

BIndu_Madhav
  • 577
  • 1
  • 8
  • 21
  • See https://stackoverflow.com/questions/20115090/d3-js-auto-font-sizing-based-on-nodes-individual-radius-diameter -- this works similarly the other way round where you adjust the rectangle and not the text. – Lars Kotthoff Jul 28 '15 at 16:36

2 Answers2

1

First create the rects with constant width.
Then create the text elements and add the width of the bounding box getBBox().width as a property to the data set (e.g. twidth).
Finally update the rect elements by the width based on the added property (twidth).

Pavel Gatnar
  • 3,987
  • 2
  • 19
  • 29
0

Tested & working in production GitHub

    //FUNCTION
    //  This function attempts to create a new svg "text" element, chopping
    //  it up into "tspan" pieces, if the text is too long
    static textToSvg(caption, x, y) {

        //svg "text" element to hold smaller text lines
        var svgTextHolder = document.createElementNS('http://www.w3.org/2000/svg', 'text');
        svgTextHolder.setAttributeNS(null, 'x', x);
        svgTextHolder.setAttributeNS(null, 'y', y);
        svgTextHolder.setAttributeNS(null, 'font-size', 10);
        svgTextHolder.setAttributeNS(null, 'fill', '#FFF');
        svgTextHolder.setAttributeNS(null, 'text-anchor', 'left');

        //The following two variables can be passed as parameters
        var maximumCharsPerLine = 30;
        var lineHeight = 10;

        var words = caption.split(" ");
        var line = "";

        //process text and create rows
        var svgTSpan;
        var lineCount = 0; //number of lines to calculate height
        var tSpanTextNode;
        for (var n = 0; n < words.length; n++) {
            var testLine = line + words[n] + " ";
            if (testLine.length > maximumCharsPerLine) {
                //  Add a new <tspan> element
                svgTSpan = document.createElementNS('http://www.w3.org/2000/svg', 'tspan');
                svgTSpan.setAttributeNS(null, 'x', x);
                svgTSpan.setAttributeNS(null, 'y', y);

                tSpanTextNode = document.createTextNode(line);
                svgTSpan.appendChild(tSpanTextNode);
                svgTextHolder.appendChild(svgTSpan);

                line = words[n] + " ";
                y += lineHeight; //place next text row lower
                lineCount++; //count a line
            }
            else {
                line = testLine;
            }
        }

        //calculate final height in px, save global to be accessed later
        window.EventDescriptionTextHeight = lineCount * lineHeight;

        svgTSpan = document.createElementNS('http://www.w3.org/2000/svg', 'tspan');
        svgTSpan.setAttributeNS(null, 'x', x);
        svgTSpan.setAttributeNS(null, 'y', y);

        tSpanTextNode = document.createTextNode(line);
        svgTSpan.appendChild(tSpanTextNode);

        svgTextHolder.appendChild(svgTSpan);

        return svgTextHolder;
    }
user160357
  • 865
  • 10
  • 14