Tarun Kumar
Tarun Kumar

Reputation: 99

how to put dynamic data text inside rectangle in d3

Update method : Thanks in advance. I am creating rectangles based on the api response data. The rectangles will will be removed and re-created when the new data come back from api. I want to achieve same thing for adding text inside the rectangles, means as soon as I receive the fresh data text should be overrided or re-created based on the data.

          /* update selection*/
      var rectangles = vis.ganttSvgRef.selectAll("rect").data(chartData);
         /*exit selection*/
       rectangles.exit().remove();
        /*enter selection*/
      var innerRects = rectangles.enter().append("rect").merge(rectangles)
    .attr("x", function (d) {
        return vis.timeScale(parseTime(d.arrivalTime_data)) + sidePadding;
    })
    .attr("y", function (d, i) {
        for (var j = 0; j < slotNumber.length; j++) {
            if (d.slot == slotNumber[j]) {
                return vis.yScale(d.slot);
            }
        }
    })
    .attr("width", function (d) {
        return (vis.timeScale(parseTime(d.departureTime_data)) - 
      vis.timeScale(parseTime(d.arrivalTime_data)));
    })
    .attr("height", barHeight)
    .attr("stroke", "none")
    .attr("fill", function (d) {
        for (var i = 0; i < vesselsNames.length; i++) {
            return serviceColorSelector[d.serviceName_data]
        }
    })

how to add the text in the rectangles in middle, which should also get update based on the data receive. Thanks

Updated code as suggested by @Michael Rovinsky : This code works perfectly fine for appending the text inside the rect, but on few rect the text is overflowing outside the rect area. I don't want to show the text if it overflow from rect area or how can i hide the text if it overflow from rect area ?

 var rectangles = vis.ganttSvgRef.selectAll("rect")
        .data(chartData);
    rectangles.exit().remove();

    var innerRects = rectangles.enter().append("g");
    let rectinst = innerRects.append("rect").merge(rectangles)
        .attr("x", function (d) {
            return vis.timeScale(parseTime(d.arrivalTime_data)) + 
                   sidePadding;
        })
        .attr("y", function (d, i) {
            for (var j = 0; j < slotNumber.length; j++) {
                if (d.slot == slotNumber[j]) {
                    return vis.yScale(d.slot);
                }
            }
        })
        .attr("width", function (d) {
            return (vis.timeScale(parseTime(d.departureTime_data)) - 
        vis.timeScale(parseTime(d.arrivalTime_data)));
        })
        .attr("height", barHeight)
        .attr("stroke", "none")
        .attr("fill", function (d) {
            for (var i = 0; i < vesselsNames.length; i++) {
                return serviceColorSelector[d.serviceName_data]
            }
        })
    let text = vis.ganttSvgRef.selectAll(".rect-text")
        .data(chartData);
    text.exit().remove();
    innerRects.append("text").merge(text)
        .attr("class", 'rect-text')
        .text(function (d) {
            let rectWidth = (vis.timeScale(parseTime(d.departureTime_data)) - 
          vis.timeScale(parseTime(d.arrivalTime_data)));
            console.log("rect width : ", rectWidth)
            console.log("d.vesselName_data : ", 
        vis.timeScale(d.vesselName_data.length))
            return d.vesselName_data;
        })
        .attr("x", function (d) {
            return (vis.timeScale(parseTime(d.departureTime_data)) -  
         vis.timeScale(parseTime(d.arrivalTime_data))) / 2 + 
         vis.timeScale(parseTime(d.arrivalTime_data)) + sidePadding;
           })
        .attr("y", function (d, i) {
            for (var j = 0; j < slotNumber.length; j++) {
                if (d.slot == slotNumber[j]) {
                    return vis.yScale(d.slot) + (barHeight / 2);
                }
            }
        })
        .attr("font-size", barHeight / 2)
        .attr("text-anchor", "middle")
        .attr("text-height", barHeight)
        .attr("fill", '#fff');

Upvotes: 0

Views: 931

Answers (2)

deeksha gupta
deeksha gupta

Reputation: 161

You can write your own text wrapping function d3 based on the rect dimensions and given padding. Please check following link for customised text wrapping and overflow control in d3.js-

Code- text-wrapping-in-d3

    function wrap(text) {
    text.each(function() {
        var text = d3.select(this);
        var words = text.text().split(/\s+/).reverse();
        var lineHeight = 20;
        var width = parseFloat(text.attr('width'));
        var y = parseFloat(text.attr('y'));
        var x = text.attr('x');
        var anchor = text.attr('text-anchor');
    
        var tspan = text.text(null).append('tspan').attr('x', x).attr('y', y).attr('text-anchor', anchor);
        var lineNumber = 0;
        var line = [];
        var word = words.pop();

        while (word) {
            line.push(word);
            tspan.text(line.join(' '));
            if (tspan.node().getComputedTextLength() > width) {
                lineNumber += 1;
                line.pop();
                tspan.text(line.join(' '));
                line = [word];
                tspan = text.append('tspan').attr('x', x).attr('y', y + lineNumber * lineHeight).attr('anchor', anchor).text(word);
            }
            word = words.pop();
        }
    });
}

function dotme(text) {
    text.each(function() {
        var text = d3.select(this);
        var words = text.text().split(/\s+/);
        
        var ellipsis = text.text('').append('tspan').attr('class', 'elip').text('...');
        var width = parseFloat(text.attr('width')) - ellipsis.node().getComputedTextLength();
        var numWords = words.length;
        
        var tspan = text.insert('tspan', ':first-child').text(words.join(' '));
        
        // Try the whole line
        // While it's too long, and we have words left, keep removing words
        
        while (tspan.node().getComputedTextLength() > width && words.length) {
            words.pop();
            tspan.text(words.join(' '));
        }
        
        if (words.length === numWords) {
            ellipsis.remove();
        }
    });
}

d3.selectAll('.wrapme').call(wrap);
d3.selectAll('.dotme').call(dotme);

Upvotes: 1

Michael Rovinsky
Michael Rovinsky

Reputation: 7210

Append "g" instead of "rect" on enter():

const containers = rectangles.enter().append("g");

Append "rect" and "text" under "g":

containers.append("rect").attr('width', ...).attr('height', ...)...

containers.append("text").text('My Text Here')...

Upvotes: 1

Related Questions