Search code examples
javascriptchart.jscustomizationlegendpie-chart

Chartjs Custom Legend for Doughnut Chart Having Labelled Lines Sticking Out of Each Section


I know how to draw doughnut chart for a data set in Chartjs and its legend customization but I want to have a chart like the one shown in the image below in which lines from each section sticking out with text above and below the line. I can't find this level of customization in Chartjs. Does anyone know how to do it? Any help would be really appreciated. Thanksenter image description here


Solution

  • I found out a solution by taking multiple canvases and drawing the stuck out lines and texts above and below it using JavaScript's 2d contexts. I brought the lines to touch the chartjs's doughnut chart by giving negative margins. Responsiveness is still an issue but at least that's one way of doing it. I am posting the code here. Screen size might dislocate the lines. You might wanna see the result on with full screen on your laptop.

    <!DOCTYPE html>
    <!--
    To change this license header, choose License Headers in Project Properties.
    To change this template file, choose Tools | Templates
    and open the template in the editor.
    -->
    <html>
        <head>
            <meta charset="UTF-8">
            <title></title>
            <style>
                
                .chart-wrapper
                {
                    width: 24rem;
                    height: 24rem;
                }
                .debt-savings
                {
                    margin-right: -15rem;
                }
                .needs
                {
                    margin-left: -5.5rem;
                }
                .wants
                {
                    margin-top: -6.8rem;
                }
            </style>
            <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
        </head>
        <body>
            <div class="row">
                <br><br><br><br><br><br><br><br>
            </div>
            <div class="row d-flex justify-content-center">
                <div class="col-4 chart-wrapper debt-savings">
                    <canvas id="debt-savings"></canvas>
                </div>
                <div class="col-4 d-flex justify-content-center">
                    <div class="chart-wrapper">
                        <canvas    id="budget-chart"></canvas>
                    </div>
                    
                </div>
                <div class="col-4 chart-wrapper needs">
                    <canvas id="needs"></canvas>
                </div>
                
            </div>
            <div  class="row d-flex justify-content-end">
                <div class="col-6 chart-wrapper wants">
                    <canvas id="wants"></canvas>
                </div>
            </div>
            <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
        <script type="text/javascript">
           
                // Data for doughnut chart
            const data = {
                labels: [
                  'Debt & Saving',
                  'Needs',
                  'Wants'
                ],
                datasets: [{
                  label: 'My First Dataset',
                  data: [20//debtAndSavingsPercet
                      , 30//needsPercet
                      , 50//wantsPercet
                  ],
                  backgroundColor: [
                    'rgb(255, 99, 132)',
                    'rgb(54, 162, 235)',
                    'rgb(255, 205, 86)'
                  ],
                  hoverOffset: 4
                }]
              };
            var ctx = document.getElementById("budget-chart").getContext("2d");
            var myDoughnutChart = new Chart(ctx, {
                type: 'doughnut',
                data: data,
                options: {
                    legend:{
                        display:false,
                    },
                    responsive:true,
                    maintainAspectRatio:true,
                }
            });
            var debtAndSavingCanvas = document.getElementById("debt-savings");
            debtAndSavingCanvas.width  = 300;
            debtAndSavingCanvas.height = 300;
            var debtAndSavingCtx = debtAndSavingCanvas.getContext("2d");        
            debtAndSavingCtx.font = "normal normal 500 40px Georgia";
            debtAndSavingCtx.fillStyle = "green";
            debtAndSavingCtx.fillText("20%", 0, 100);
            debtAndSavingCtx.font = "16px Georgia";
            debtAndSavingCtx.fillText("Debt &", 100, 70);
            debtAndSavingCtx.fillText("savings", 100, 100);
            debtAndSavingCtx.font = "20px Georgia";
            debtAndSavingCtx.fillStyle = "grey";
            debtAndSavingCtx.fillText("Emergency savings,", 0, 134);
            debtAndSavingCtx.fillText("student loans, credit", 0, 154);
            debtAndSavingCtx.fillText("cards, etc.", 0, 174);
            debtAndSavingCtx.beginPath();
            debtAndSavingCtx.moveTo(300, 150);
            debtAndSavingCtx.lineTo(230, 110);
            debtAndSavingCtx.lineTo(0, 110);
            debtAndSavingCtx.stroke();
            //
            // Needs context 
            //
             var needsCanvas = document.getElementById("needs");
            needsCanvas.width  = 300;
            needsCanvas.height = 300;
            var needsCtx = needsCanvas.getContext("2d");        
            needsCtx.font = "normal normal 500 40px Georgia";
            needsCtx.fillStyle = "purple";
            needsCtx.fillText("53%", 30, 95);
            needsCtx.font = "20px Georgia";
            needsCtx.fillText("needs", 110, 95);
            needsCtx.font = "20px Georgia";
            needsCtx.fillStyle = "grey";
            needsCtx.fillText("Mortgage/rent, utilities,", 50, 134);
            needsCtx.fillText("phone/internet, etc", 50, 154);
            //draw the line
            needsCtx.beginPath();
            needsCtx.moveTo(0, 130);
            needsCtx.lineTo(30, 110);
            needsCtx.lineTo(200, 110);
            needsCtx.stroke();
            
            //
            // Wants context 
            //
             var wantsCanvas = document.getElementById("wants");
            wantsCanvas.width  = 300;
            wantsCanvas.height = 300;
            var wantsCanvas = wantsCanvas.getContext("2d");        
            wantsCanvas.font = "normal normal 500 40px Georgia";
            wantsCanvas.fillStyle = "purple";
            wantsCanvas.fillText("25%", 50, 95);
            wantsCanvas.font = "20px Georgia";
            wantsCanvas.fillText("wants", 130, 95);
            wantsCanvas.font = "20px Georgia";
            wantsCanvas.fillStyle = "grey";
            wantsCanvas.fillText("Mortgage/rent, utilities,", 50, 134);
            wantsCanvas.fillText("phone/internet, etc", 50, 154);
            //draw the line
            wantsCanvas.beginPath();
            wantsCanvas.moveTo(0, 80);
            wantsCanvas.lineTo(30, 110);
            wantsCanvas.lineTo(200, 110);
            wantsCanvas.stroke();
        </script>
        </body>
    </html>