2

I am trying to modify this example. On mouseover I want a word to appear on the center of the donut chart like this:

enter image description here

I have added code for mouse over but it is not working.

Code

const eventObj = {
          'mouseover': function (d, i, j) {
              pathAnim(d3.select(this).select('path'), 1);
              centerTxt.text(function () {
                  return d.data.label;
              })
              // .call(wrap, 40);
          },
          'mouseout': function (d, i, j) {
              const thisPath = d3.select(this).select('path');
              if (!thisPath.classed('clicked')) {
                  pathAnim(thisPath, 0);
              }
              centerTxt.text(function (d) {
                  return '';
              });
          },


                'click': function(d, i, j) {


                    var thisPath = d3.select(this);
                    var clicked = thisPath.classed('clicked');
                    pathAnim(thisPath, ~~(!clicked));
                    thisPath.classed('clicked', !clicked);

                    //setCenterText(thisDonut);
                }
            };

            var pathAnim = function(path, dir) {
            switch(dir) {
                case 0:
                    path.transition()
                        .duration(500)
                        .ease('bounce')
                        .attr('d', d3.svg.arc()
                            .innerRadius((radius-100))
                            .outerRadius(radius-50)
                        );
                    break;

                case 1:
                    path.transition()
                        .attr('d', d3.svg.arc()
                            .innerRadius((radius-100))
                            .outerRadius((radius-50) * 1.08)
                        );
                    break;
            }
        }  
altocumulus
  • 21,179
  • 13
  • 61
  • 84
Pravu
  • 598
  • 1
  • 8
  • 29

1 Answers1

2

I think this is what you are looking for:

var data = [{
    label: 'Star Wars',
    instances: 207
}, {
    label: 'Lost In Space',
    instances: 3
}, {
    label: 'the Boston Pops',
    instances: 20
}, {
    label: 'Indiana Jones',
    instances: 150
}, {
    label: 'Harry Potter',
    instances: 75
}, {
    label: 'Jaws',
    instances: 5
}, {
    label: 'Lincoln',
    instances: 1
}];

svg = d3.select("svg");
canvas = d3.select("#canvas");
art = d3.select("#art");
labels = d3.select("#labels");

canvas.append("circle")
    .attr('cx', 0)
    .attr('cy', 0)
    .attr('fill', 'pink')
    .attr('r', 48);
canvas.append("text")
    .attr("text-anchor", "middle")
    .attr('font-size', '12px')
    .attr('y', 0)
    .attr('id', 'center-text')
    .text('TEEST FOR A LONG VEERY TEXT');

// Wrap text in a rectangle.
    d3plus.textwrap()
      .container(d3.select("#center-text"))
      .resize(true)
      .draw();

// Create the pie layout function.
// This function will add convenience
// data to our existing data, like 
// the start angle and end angle
// for each data element.
jhw_pie = d3.layout.pie()
jhw_pie.value(function(d, i) {
    // Tells the layout function what
    // property of our data object to
    // use as the value.
    return d.instances;
});

// Store our chart dimensions
cDim = {
    height: 500,
    width: 500,
    innerRadius: 50,
    outerRadius: 150,
    labelRadius: 175
}

// Set the size of our SVG element
svg.attr({
    height: cDim.height,
    width: cDim.width
});

// This translate property moves the origin of the group's coordinate
// space to the center of the SVG element, saving us translating every
// coordinate individually. 
canvas.attr("transform", "translate(" + (cDim.width / 2) + "," + (cDim.width / 2) + ")");

pied_data = jhw_pie(data);

// The pied_arc function we make here will calculate the path
// information for each wedge based on the data set. This is 
// used in the "d" attribute.
pied_arc = d3.svg.arc()
    .innerRadius(50)
    .outerRadius(150);


const eventObj = {
    mouseover: function(d, i, j) {
        d3.select('#center-text').text(d.data.label);
        d3plus.textwrap()
      .container(d3.select("#center-text"))
      .resize(true)
      .draw();
    },
    mouseout: function(d, i, j) {
        d3.select('#center-text').text('');
        d3plus.textwrap()
      .container(d3.select("#center-text"))
      .resize(true)
      .draw();
    },


    click: function(d, i, j) {
        {
            {
                /* console.log(d, i, j);
                              var thisPath = d3.select(this);
                              var clicked = thisPath.classed('clicked');
                              pathAnim(thisPath, ~~(!clicked));
                              thisPath.classed('clicked', !clicked); */
            }
        }
    }
};

var pathAnim = function(path, dir) {
    switch (dir) {
        case 0:
            path.transition()
                .duration(500)
                .ease('bounce')
                .attr('d', d3.svg.arc()
                    .innerRadius((radius - 100))
                    .outerRadius(radius - 50)
                );
            break;

        case 1:
            path.transition()
                .attr('d', d3.svg.arc()
                    .innerRadius((radius - 100))
                    .outerRadius((radius - 50) * 1.08)
                );
            break;
    }
}

// This is an ordinal scale that returns 10 predefined colors.
// It is part of d3 core.
pied_colors = d3.scale.category10();

// Let's start drawing the arcs.
enteringArcs = art.selectAll(".wedge").data(pied_data).enter();

enteringArcs.append("path")
    .attr("class", "wedge")
    .attr("d", pied_arc)
    .on('click', (d) => {
        eventObj.click(d)
    })
    .on('mouseover', (d) => {
        eventObj.mouseover(d)
    })
    .on('mouseout', (d) => {
        eventObj.mouseout(d)
    })
    .style("fill", function(d, i) {
        return pied_colors(i);
    });

// Now we'll draw our label lines, etc.
enteringLabels = labels.selectAll(".label").data(pied_data).enter();
labelGroups = enteringLabels.append("g").attr("class", "label");
labelGroups.append("circle").attr({
    x: 0,
    y: 0,
    r: 2,
    fill: "#000",
    transform: function(d, i) {
        centroid = pied_arc.centroid(d);
        return "translate(" + pied_arc.centroid(d) + ")";
    },
    'class': "label-circle"
});

// "When am I ever going to use this?" I said in 
// 10th grade trig.
textLines = labelGroups.append("line").attr({
    x1: function(d, i) {
        return pied_arc.centroid(d)[0];
    },
    y1: function(d, i) {
        return pied_arc.centroid(d)[1];
    },
    x2: function(d, i) {
        centroid = pied_arc.centroid(d);
        midAngle = Math.atan2(centroid[1], centroid[0]);
        x = Math.cos(midAngle) * cDim.labelRadius;
        return x;
    },
    y2: function(d, i) {
        centroid = pied_arc.centroid(d);
        midAngle = Math.atan2(centroid[1], centroid[0]);
        y = Math.sin(midAngle) * cDim.labelRadius;
        return y;
    },
    'class': "label-line"
});

textLabels = labelGroups.append("text").attr({
    x: function(d, i) {
        centroid = pied_arc.centroid(d);
        midAngle = Math.atan2(centroid[1], centroid[0]);
        x = Math.cos(midAngle) * cDim.labelRadius;
        sign = (x > 0) ? 1 : -1
        labelX = x + (5 * sign)
        return labelX;
    },
    y: function(d, i) {
        centroid = pied_arc.centroid(d);
        midAngle = Math.atan2(centroid[1], centroid[0]);
        y = Math.sin(midAngle) * cDim.labelRadius;
        return y;
    },
    'text-anchor': function(d, i) {
        centroid = pied_arc.centroid(d);
        midAngle = Math.atan2(centroid[1], centroid[0]);
        x = Math.cos(midAngle) * cDim.labelRadius;
        return (x > 0) ? "start" : "end";
    },
    'class': 'label-text'
}).text(function(d) {
    return d.data.label
});

alpha = 0.5;
spacing = 12;

function relax() {
    again = false;
    textLabels.each(function(d, i) {
        a = this;
        da = d3.select(a);
        y1 = da.attr("y");
        textLabels.each(function(d, j) {
            b = this;
            // a & b are the same element and don't collide.
            if (a == b) return;
            db = d3.select(b);
            // a & b are on opposite sides of the chart and
            // don't collide
            if (da.attr("text-anchor") != db.attr("text-anchor")) return;
            // Now let's calculate the distance between
            // these elements. 
            y2 = db.attr("y");
            deltaY = y1 - y2;

            // Our spacing is greater than our specified spacing,
            // so they don't collide.
            if (Math.abs(deltaY) > spacing) return;

            // If the labels collide, we'll push each 
            // of the two labels up and down a little bit.
            again = true;
            sign = deltaY > 0 ? 1 : -1;
            adjust = sign * alpha;
            da.attr("y", +y1 + adjust);
            db.attr("y", +y2 - adjust);
        });
    });
    // Adjust our line leaders here
    // so that they follow the labels. 
    if (again) {
        labelElements = textLabels[0];
        textLines.attr("y2", function(d, i) {
            labelForLine = d3.select(labelElements[i]);
            return labelForLine.attr("y");
        });
        setTimeout(relax, 20)
    }
}

relax();
.label-text {
  alignment-baseline: middle;
  font-size: 12px;
  font-family: arial,helvetica,"sans-serif";
  fill: #393939;
}
.label-line {
  stroke-width: 1;
  stroke: #393939;
}
.label-circle {
  fill: #393939;
}
<svg>
  <g id="canvas">
  <g id="art" />
  <g id="labels" /></g>
</svg>
<p>It could be worse, I could have been named "Michael Bolton."</p>
<script type="text/javascript" src="//d3js.org/d3.v3.js"></script>
<script src="//d3plus.org/js/d3plus.js"></script>

Note:

The issue was your code didn't attach the events object to your chart arcs, also the events wasn't properly changing attributes.

I changed the code based on your comment above, so you might need to change it a bit to fit your needs.

ROOT
  • 11,363
  • 5
  • 30
  • 45
  • Thank you so much... yes.., true.. this what I m looking for...I've one more question..How to make word-break to prevent word make extra width? – Pravu Jan 14 '20 at 12:39
  • 1
    @Pravu, there is an issue with text wrapping in SVG as I remember, check this https://stackoverflow.com/questions/4991171/auto-line-wrapping-in-svg-text, but I guess you will be fine using font-size on `canvas.append("text")` that I added also you can play around with `y` attribute. – ROOT Jan 14 '20 at 12:51
  • I've found example [https://bl.ocks.org/davelandry/a39f0c3fc52804ee859a](https://bl.ocks.org/davelandry/a39f0c3fc52804ee859a) but when I try to implemen in my [jsfiddle](https://jsfiddle.net/shahjihan78/4xfncro7/24/) the donut chart not appear... If not trouble you.. Could you advice me how to fix it? – Pravu Jan 15 '20 at 04:27
  • 1
    Ok, I will check it once I have time, maybe in couple of hours. – ROOT Jan 15 '20 at 04:28
  • I've found [https://jsfiddle.net/shahjihan78/n460hwgc/](https://jsfiddle.net/shahjihan78/n460hwgc/) new reference but I new to d3. Thank you so much brother.. – Pravu Jan 15 '20 at 04:42
  • 1
    @Pravu I added the text wrapper lib, check it out, it's a bit off, I believe you can tweak it , but I will leave it to you from here. – ROOT Jan 15 '20 at 07:56