This is a migrated thread and some comments may be shown as answers.

Donut chart with curved series name?

2 Answers 151 Views
Charts
This is a migrated thread and some comments may be shown as answers.
Jay
Top achievements
Rank 2
Iron
Iron
Veteran
Jay asked on 16 Dec 2020, 02:12 PM

I know the original thread got moved to the Feedback Portal, but just in case someone else is looking for a way to do this until it is provided by kendo. When the thread got moved to the portal, this was added: Note: DOM manipulation over SVG elements is not a great approach, and I would not recommend it, unless it is absolutely unavoidable. Unfortunately, there is nothing more reasonable that can be done instead.

Here is a dojo and here is the code:

<!DOCTYPE html>
<html>
<head>
    <style>html { font-size: 14px; font-family: Arial, Helvetica, sans-serif; }</style>
    <title>Donut chart with curved series name</title>
 
</head>
<body>
    <div id="example">
    <div class="demo-section k-content wide">
        <div id="chart" style="background: center no-repeat url('../content/shared/styles/world-map.png');"></div>
    </div>
    <script>
        function createChart() {
          var center;
          var caption1;
          var radius1;
          var caption2;
          var radius2;
           
            $("#chart").kendoChart({
                title: {
                    position: "bottom",
                    text: "Share of Internet Population Growth"
                },
                legend: {
                    visible: false
                },
                chartArea: {
                    background: ""
                },
                seriesDefaults: {
                    type: "donut",
                    startAngle: 150
                },
                series: [{
                    name: "Population Growth 2011",
                    visual: function (e) {
                        // Obtain parameters for the segments
                        // Will run many times, but that's not an issue
                        center = e.center;
                        radius1 = e.radius;
                        caption1 = e.series.name;
 
                        // Create default visual
                        return e.createVisual();
                    },
                    data: [{
                        category: "Asia",
                        value: 30.8,
                        color: "#9de219"
                    },{
                        category: "Europe",
                        value: 21.1,
                        color: "#90cc38"
                    },{
                        category: "Latin America",
                        value: 16.3,
                        color: "#068c35"
                    },{
                        category: "Africa",
                        value: 17.6,
                        color: "#006634"
                    },{
                        category: "Middle East",
                        value: 9.2,
                        color: "#004d38"
                    },{
                        category: "North America",
                        value: 4.6,
                        color: "#033939"
                    }]
                }, {
                    name: "spacer1",
                    data: []
                }, {
                    name: "Population Growth 2012",
                    visual: function (e) {
                        // Obtain parameters for the segments
                        // Will run many times, but that's not an issue
                        radius2 = e.radius;
                        caption2 = e.series.name;
 
                        // Create default visual
                        return e.createVisual();
                    },
                    data: [{
                        category: "Asia",
                        value: 53.8,
                        color: "#9de219"
                    },{
                        category: "Europe",
                        value: 16.1,
                        color: "#90cc38"
                    },{
                        category: "Latin America",
                        value: 11.3,
                        color: "#068c35"
                    },{
                        category: "Africa",
                        value: 9.6,
                        color: "#006634"
                    },{
                        category: "Middle East",
                        value: 5.2,
                        color: "#004d38"
                    },{
                        category: "North America",
                        value: 3.6,
                        color: "#033939"
                    }],
                    labels: {
                        visible: false,
                        background: "transparent",
                        position: "outsideEnd",
                        template: "#= category #: \n #= value#%"
                    }
                }],
                tooltip: {
                    visible: true,
                    template: "#= category # (#= series.name #): #= value #%"
                },
                render: function (e) {
                    var chartsvg = $("#example svg");
                    var svg = chartsvg[0];
                   
                    // +5 so not resting right on the donut
                    addCaption(svg, caption1, center, radius1 + 5, false);
                    addCaption(svg, caption2, center, radius2 + 5, true);
                }
            });
        }
 
        function addCaption(svg, caption, center, radius, top) {
            var draw = kendo.drawing;
 
            var text = new draw.Text(caption, [0, 0], {});
            var bbox = text.bbox();
 
            // bump the radius to outside for bottom caption
            var rr = top ? radius : radius + bbox.size.height / 2 + 2;
            var captionsvg = getPath(center, rr, top);
 
            // Unique id
            var id = caption.replace(/\s+/g, '') + Math.random();
            var captionpath = "<path id='" + id + "' fill='transparent' d='" + captionsvg + "' />";
            var captiontext = "<text style='text-anchor: middle;' width='" + bbox.size.width + "'><textpath startOffset='25%' xlink:href='#" + id + "'>" + caption + "</textpath></text>";
            var captionsvg = captionpath + captiontext;
 
            svg.appendChild(parseSVG(captionsvg));
        }
       
        function parseSVG(s) {
            var div= document.createElementNS('http://www.w3.org/1999/xhtml', 'div');
            div.innerHTML= '<svg xmlns="http://www.w3.org/2000/svg">'+s+'</svg>';
            var frag= document.createDocumentFragment();
            while (div.firstChild.firstChild)
                frag.appendChild(div.firstChild.firstChild);
            return frag;
        }
       
        function getPath(center, radius, top) {
            var cx = center.x;
            var cy = center.y;
            var rx = radius;
            var ry = radius;
 
            var sweep = top ? "1 " : "0 ";
 
            var path = "M" + (cx - rx).toString() + "," + cy.toString();
            path += " a" + rx.toString() + "," + ry.toString() + " 0 0," + sweep + (2 * rx).toString() + ",0";
            path += " a" + rx.toString() + "," + ry.toString() + " 0 " + largeArcSweep + (-2 * rx).toString() + ",0";
 
            return path;
        }     
       
        $(document).ready(createChart);
        $(document).bind("kendo:skinChange", createChart);
    </script>
</div>
 
</body>
</html>

2 Answers, 1 is accepted

Sort by
0
Anton Mironov
Telerik team
answered on 18 Dec 2020, 10:24 AM

Hi Jay,

Thank you for sharing the approach below with the community!

It will be helpful for other cases as a workaround.

Let me know if I could assist with anything else, or this thread should be closed. It could be re-opened at any time.

Kind Regards,
Anton Mironov
Progress Telerik

Virtual Classroom, the free self-paced technical training that gets you up to speed with Telerik and Kendo UI products quickly just got a fresh new look + new and improved content including a brand new Blazor course! Check it out at https://learn.telerik.com/.

0
Jay
Top achievements
Rank 2
Iron
Iron
Veteran
answered on 21 Dec 2020, 08:16 PM

Hi Anton.This thread can be closed. I just noticed a typo, though, but for some reason I can't edit my original post. The line in getPath before the return should be

path += " a" + rx.toString() + "," + ry.toString() + " 0 0," + sweep + (-2 * rx).toString() + ",0";
Tags
Charts
Asked by
Jay
Top achievements
Rank 2
Iron
Iron
Veteran
Answers by
Anton Mironov
Telerik team
Jay
Top achievements
Rank 2
Iron
Iron
Veteran
Share this question
or