Mario
Mario

Reputation: 4988

suggestion about how to adapt a function that wrap text in d3

I am tring to wrap text in d3, I have read about it and I understand that the way to do it in d3 is to separate the long text into substrings which are inserted in tspan elmenets or by adding the text to the foreignObject element.

I am trying to adapt this function using the tspan method

function wrap(text, width) {
    text.each(function() {
        var text = d3.select(this),
            words = text
                .text()
                .split(/\s+/)
                .reverse(),
            word,
            line = [],
            lineNumber = 0,
            lineHeight = 1.1,
            y = text.attr("y"),
            x = text.attr("x"),
            dy = text.attr("dy"),
            dx = text.attr("dx"),
            tspan = text
                .text(null)
                .append("tspan")
                .attr("x", x)
                .attr("y", y)
                .attr("dx", dx)
                .attr("dy", dy);
        while ((word = words.pop())) {
            line.push(word);
            tspan.text(line.join(" "));
            if (tspan.node().getComputedTextLength() > width) {
                line.pop();
                tspan.text(line.join(" "));
                line = [word];
                tspan = text
                    .append("tspan")
                    .attr("x", x)
                    .attr("y", y)
                    .attr("dx", dx)
                    .attr("dy", ++lineNumber * lineHeight + Math.abs(dy) + "em")
                    .text(word);
            }
        }
    });
}

This function works properly but the coordinates defined in dx anddy of the text element are lost, so that the text appears in incorrect positions within the graphic.

I have identified that by replacing the .attr("dy", ++lineNumber * lineHeight + Math.abs(dy) +" em ") line with .attr("dy", dy) the text is placed in the desired position but the tspan elements overlap.

Getting this

enter image description here

I am new to the concepts of d3 and I appreciate your comments

Update 1: Distribution of tspan elements once called the function wrap

<g class="category">
    <circle r="15" cx="112.58330249197704" cy="64.99999999999997"></circle>
    <text x="112.58330249197704" y="64.99999999999997" dx="20" dy="10" text-anchor="start">
        <tspan x="112.58330249197704" y="64.99999999999997" dx="20" dy="10"></tspan>
        <tspan x="112.58330249197704" y="64.99999999999997" dx="20" dy="11">Third</tspan>
        <tspan x="112.58330249197704" y="64.99999999999997" dx="20" dy="11">Bit</tspan>
        <tspan x="112.58330249197704" y="64.99999999999997" dx="20" dy="11">Category</tspan>
    </text>
</g>

Update 2: Graph state after applying updated function, text distribution detail

enter image description here

Upvotes: 0

Views: 141

Answers (1)

GSazheniuk
GSazheniuk

Reputation: 1384

I have been using this function for a while now, might work for you as well (maybe with slight adjustments):

function wrap(text, width) {
    text.each(function () {
        var text = d3.select(this),
            words = text.text().split(/\s+/).reverse(),
            word,
            line = [],
            lineNumber = 0,
            lineHeight = 1, 
            y = text.attr("y"),
            x = text.attr("x"),
            dy = 0,
            tspan = text.text(null).append("tspan").attr("x", x).attr("y", y).attr("dy", dy + "em");
        while (word = words.pop()) {
            line.push(word);
            tspan.text(line.join(" "));
            if (tspan.node().getComputedTextLength() > width) {
                line.pop();
                tspan.text(line.join(" "));
                line = [word];
                tspan = text.append("tspan").attr("x", x).attr("y", y).attr("dy", lineHeight + "em").text(word);
                lineHeight++;
            }
        }
    });
}

UPDATE: It looks like I copied the wrong function, I have multiple versions of it across my projects. I believe this one should work properly.

Your function has same issue as the first function that I shared had - we both were not increasing lineHeight (in your case it is called lineNumber) in the loop.

Upvotes: 1

Related Questions