JSFiddle - React, Tailwind, and code Playground

by paulL

HTML

<div id="chart"></div>

<div id="chart2"></div>

CSS

.donut {
   shape-rendering: auto;
}
 .legend-label {
   text-anchor: middle;
}
.units-label {
   font-size: .7em;
   font-weight: normal;
   text-transform: uppercase;
}
.data-label {
   font-weight: bold;
   font-size: 1.5em;
}
.value-1 {
   fill: orange;
}
.value-2 {
   fill: blue;
}
.value-3 {
   fill: green;
}

JavaScript

function donutChart() {
    var width = 420,
        height = 420,
        radius = 0,
        factor = 0.7;

    var legend = ['Low', 'Medium', 'High'];

    function chart(selection) {
        selection.each(function(data) {
            if (radius == 0) {
               radius = Math.min(width, height) / 2 - 10;
            }
            
            // hardcoding 36 here, you could use getBBox to get the actual SVG text height using sample text if you really wanted.
            var legendHeight = 36;
            
            // calculated height of all legend items together
            var actualLegendHeight = data.length * legendHeight;
            
            // inner diameter
            var availableLegendHeight = radius * factor * 2;
            
            // y-coordinate of first legend item (relative to the center b/c the main svg <g> element is translated
            var legendOffset = (availableLegendHeight - actualLegendHeight) / 2 - (radius*factor);
            
            var arc = d3.svg.arc()
                .innerRadius(radius * factor)
                .outerRadius(radius);

            var pie = d3.layout.pie()
                .sort(null)
                .value(function(d) { return d; });

            var svg = d3.select(this).append('svg')
                .attr('width', width)
                .attr('height', height)
                .attr('class', 'donut')
                .attr('dominant-baseline', 'hanging')
                .append('g')
                .attr('transform', 'translate(' + width / 2 + ',' + height / 2 + ')');
            
            var g = svg.selectAll('.arc')
                .data(pie(data))
                .enter().append('g')
                .attr('class', 'arc');

            g.append('path')
                .attr('d', arc)
                .attr('class', function(d, i){return 'value-' + (i+1)})
                .style('stroke', '#fff');

            // append all the legend items to a common group which is translated
   ...