0

Not able to wrap labels of semi donut pie chart which is developed using d3 js.

I tried using CSS by giving word-wrap, max-width etc., but it's not working. How can I warp the text labels if the labels are having more than three to fours words?

Here is my fiddle: https://jsfiddle.net/SampathPerOxide/hcvuqjt2/22/

        var width = 400;
        var height = 300; //this is the double because are showing just the half of the pie
        var radius = Math.min(width, height) / 2;

        var labelr = radius + 30; // radius for label anchor
        //array of colors for the pie (in the same order as the dataset)
        var color = d3.scale.ordinal()
        .range(['#2b5eac', '#0dadd3', '#ffea61', '#ff917e', '#ff3e41']);

        data = [{
        label: 'CDU',
        value: 10
        },
        {
        label: 'SPD',
        value: 15
        },
        {
        label: 'Die Grünen',
        value: 8
        },
        {
        label: 'Die Mitte',
        value: 1
        },
        {
        label: 'Frei Wähler',
        value: 3
        }
        ];

        var vis = d3.select("#chart")
        .append("svg") //create the SVG element inside the <body>
        .data([data]) //associate our data with the document
        .attr("width", width) //set the width and height of our visualization (these will be attributes of the <svg> tag
        .attr("height", height)
        .append("svg:g") //make a group to hold our pie chart
        .attr('transform', 'translate(' + (width / 2) + ',' + (height / 2) + ')'); //move the center of the pie chart from 0, 0 to radius, radius

        var arc = d3.svg.arc() //this will create <path> elements for us using arc data
        .innerRadius(79)
        //                                  .outerRadius(radius);
        .outerRadius(radius - 10) // full height semi pie
        //.innerRadius(0);


        var pie = d3.layout.pie() //this will create arc data for us given a list of values
        .startAngle(-90 * (Math.PI / 180))
        .endAngle(90 * (Math.PI / 180))
        .padAngle(.02) // some space between slices
        .sort(null) //No! we don't want to order it by size
        .value(function(d) {
        return d.value;
        }); //we must tell it out to access the value of each element in our data array

        var arcs = vis.selectAll("g.slice") //this selects all <g> elements with class slice (there aren't any yet)
        .data(pie) //associate the generated pie data (an array of arcs, each having startAngle, endAngle and value properties) 
        .enter() //this will create <g> elements for every "extra" data element that should be associated with a selection. The result is creating a <g> for every object in the data array
        .append("svg:g") //create a group to hold each slice (we will have a <path> and a <text> element associated with each slice)
        .attr("class", "slice"); //allow us to style things in the slices (like text)

        arcs.append("svg:path")
        .attr("fill", function(d, i) {
        return color(i);
        }) //set the color for each slice to be chosen from the color function defined above
        .attr("d", arc); //this creates the actual SVG path using the associated data (pie) with the arc drawing function

        const textEl = arcs.append("svg:text")
        .attr("class", "labels") //add a label to each slice
        .attr("fill", "grey")
        .attr("transform", function(d) {
        var c = arc.centroid(d),
        xp = c[0],
        yp = c[1],
        // pythagorean theorem for hypotenuse
        hp = Math.sqrt(xp * xp + yp * yp);
        return "translate(" + (xp / hp * labelr) + ',' +
        (yp / hp * labelr) + ")";
        })
        .attr("text-anchor", "middle"); //center the text on it's origin

        textEl.append('tspan')
        .text(function(d, i) {
        return data[i].label;
        });

        textEl.append('tspan')
        .text(function(d, i) {
        return data[i].value;
        })
        .attr('x', '0')
        .attr('dy', '1.2em');

        arcs.append("svg:text")      
        .attr("class", "labels")//add a label to each slice
        .attr("fill", "grey")
        .attr("transform", function(d) {
        var c = arc.centroid(d),
        xp = c[0],
        yp = c[1],
        // pythagorean theorem for hypotenuse
        hp = Math.sqrt(xp*xp + yp*yp);
        return "translate(" + (xp/hp * labelr) +  ',' +
        (yp/hp * labelr) +  ")"; 
        })
        .attr("text-anchor", "middle")    //center the text on it's origin
        .text(function(d, i) { return d.data.value; })
        .text(function(d, i) { return d.data.label; });  

        //tooltip
        arcs.on("mouseover", function(d) {
        d3.select("#tooltip")
        .style("left", `${d3.event.clientX}px`)
        .style("top", `${d3.event.clientY}px`)
        .classed("hidden", false);
        d3.select("#tooltip-data")
        .html(`Label: ${d.data.label}<br>Value: ${d.data.value}`);
        });

        arcs.on("mouseout", function(d) {
        d3.select("#tooltip")
        .classed("hidden", true);
        });
ksav
  • 20,015
  • 6
  • 46
  • 66
Sampath
  • 153
  • 2
  • 13
  • 1
    Unfortunately SVG does not really do text wrapping. So you either need to do it yourself https://bl.ocks.org/mbostock/7555321 or use html in a `foreignObject` – ksav Jan 17 '19 at 09:44
  • Possible duplicate of [Auto line-wrapping in SVG text](https://stackoverflow.com/questions/4991171/auto-line-wrapping-in-svg-text) – ksav Jan 17 '19 at 09:44

0 Answers0