Search code examples
javascriptd3.jssvgwidth

How to wrap the text inside the SVG polygon without cutting the text


I have used SVG polygon in the sunburst which I got from GitHub. The text that is rendered on the breadcrumb is not fitting the polygon. I have changed the width of the polygon but it isn't working. How do I wrap the text inside that svg:polygon?

This is the code:

var entering = g.enter().append("svg:g");

entering.append("svg:polygon")
    .attr("width",100)//I have changed the width but it is not working
    .attr("height",100)
    .attr("points", breadcrumbPoints)
    .style("fill", function(d) {
        return color((d.children ? d : d.parent).name);
    })
//  .style("fill", function(d) { return colors[d.name]; });

entering.append("svg:text")
    .attr("x", (b.w + b.t)/2)
    .attr("y", b.h / 2)
    .attr("dy", "0.35em")
    .attr("text-anchor", "middle")
    .text(function(d) {
        return d.name;
    });

The sunburst looks like this. The text is not fitting into the polygon breadcrumb and is not displayed correctly. Some part of the text has been cut.


Solution

  • The approach I would take to solve this issue is to use plain html and css. Let css take care of arranging the elements by using a small set of rules.

    Instead of a svg lets create a container for the breadcrumbs

    <div id="main">    
        <div id="sequence-container">
            <div id="sequence" class="breadcrumbs-container"></div>
        </div>
        <!-- rest of html -->
    </div>
    

    Lets update a little your mouseover function:

    function mouseover(d) {
        // ...
        var sequenceArray = getAncestors(d);
        // updateBreadcrumbs(sequenceArray, percentageString); remove this!
        var breadcrumbs = d3.select('#sequence').selectAll('.breadcrumb-custom')
            .data(sequenceArray); // join data
        // usual update pattern 
        breadcrumbs.exit().remove();
        breadcrumbs.attr('class', 'breadcrumb-custom')
        breadcrumbs.enter()
            .append('li')
            .attr('class', 'breadcrumb-custom')
            .append('a')
            .style('background', function (d) {
                return color((d.children ? d : d.parent).name);
            })
            .style('border-left-color', function (d) {
                return color((d.children ? d : d.parent).name);
            })
            .html(function (d) {
                return d.name
            });
        // ...
    }
    

    And we will also need to update the mouseleave function:

    function mouseleave(d) {
        // ...
        // Remove breadcrumbs
        var breadcrumbs = d3.select('#sequence').selectAll('.breadcrumb-custom')
            .data([]);
        breadcrumbs.exit().remove();
        // ...
    }
    

    You had a function in charge of breadcrumb initialization, we will also need to remove the call to the function:

    function createVisualization(json) {
        // initializeBreadcrumbTrail(); remove!
    }
    

    And now lets declare the css rules (got them from here https://css-tricks.com/triangle-breadcrumbs/) in order to get the visual aspect we want to achieve:

    #sequence-container {
      width: auto;
      height: 80px;
    }
    .breadcrumbs-container {
       list-style: none;
       overflow: hidden;
       font: 18px Helvetica, Arial, Sans-Serif;
    }
    .breadcrumbs-container li {
       float: left;
    }
    .breadcrumbs-container li a {
       color: white;
       text-decoration: none;
       font-size: 10px;
       padding: 15px 0 10px 55px;
       position: relative;
       display: block;
       float: left;
    }
    .breadcrumbs-container li a:after {
       content: " ";
       display: block;
       width: 0;
       height: 0;
       border-top: 50px solid transparent;
       border-bottom: 50px solid transparent;
       border-left: 30px solid;
       border-left-color: inherit;
       position: absolute;
       top: 50%;
       margin-top: -50px;
       left: 100%;
       z-index: 2;
    }
    .breadcrumbs-container li a:before {
       content: " ";
       display: block;
       width: 0;
       height: 0;
       border-top: 50px solid transparent;
       border-bottom: 50px solid transparent;
       border-left: 30px solid white;
       position: absolute;
       top: 50%;
       margin-top: -50px;
       margin-left: 1px;
       left: 100%;
       z-index: 1;
    }
    .breadcrumbs-container li:first-child a {
       padding-left: 10px;
    }
    

    The end result looks like this: enter image description here

    Working fiddle: http://jsfiddle.net/zv3zvur6/1/