47

I'm trying to create a custom legend template in ChartJS v2.0. In v1* of ChartJS I simply added a property to the new Chart constructor such as...

legendTemplate : '<ul>'
+'<% for (var i=0; i<datasets.length; i++) { %>'
+'<li>'
+'<span style=\"background-color:<%=datasets[i].lineColor%>\"></span>'
+'<% if (datasets[i].label) { %><%= datasets[i].label %><% } %>'
+'</li>'
+'<% } %>'
+'</ul>'

I can't seem to find any documentation in v2.0 for this option. Is it even available anymore? Can anyone show an example of how to accomplish this?

Thank you!

Update - Working code below

legendCallback: function(chart) {
                console.log(chart.data);
                var text = [];
                text.push('<ul>');
                for (var i=0; i<chart.data.datasets[0].data.length; i++) {
                    text.push('<li>');
                    text.push('<span style="background-color:' + chart.data.datasets[0].backgroundColor[i] + '">' + chart.data.datasets[0].data[i] + '</span>');
                    if (chart.data.labels[i]) {
                        text.push(chart.data.labels[i]);
                    }
                    text.push('</li>');
                }
                text.push('</ul>');
                return text.join("");
            }
Craicerjack
  • 6,203
  • 2
  • 31
  • 39
Phil
  • 4,029
  • 9
  • 62
  • 107
  • 9
    Is it possible if you could post a snippet of the whole chart options? – Dev Aug 23 '16 at 05:01
  • 4
    [4 charts | Chart JS | with a single custom legend](https://codepen.io/shivabhusal/pen/zdpOgy) – Shiva Aug 16 '17 at 16:53

6 Answers6

33

If you guys run through this post and tried the posted answer and didn't work, try this one:

  legendCallback: function(chart) {
    var text = [];
    text.push('<ul>');
    for (var i=0; i<chart.data.datasets.length; i++) {
      console.log(chart.data.datasets[i]); // see what's inside the obj.
      text.push('<li>');
      text.push('<span style="background-color:' + chart.data.datasets[i].borderColor + '">' + chart.data.datasets[i].label + '</span>');
      text.push('</li>');
    }
    text.push('</ul>');
    return text.join("");
  },

Then add this below:

document.getElementById('chart-legends').innerHTML = myChart.generateLegend();

To create the legends. Make sure you have an element <div id="chart-legends"></div>

Robin Carlo Catacutan
  • 13,249
  • 11
  • 52
  • 85
28

There is a legendCallback function:

legendCallback Function function (chart) { }
Function to generate a legend. Receives the chart object to generate a legend from. Default implementation returns an HTML string.

Details can be found here

see this issue for the default legend callback:

legendCallback: function(chart) { 
    var text = []; 
    text.push('<ul class="' + chart.id + '-legend">'); 
    for (var i = 0; i < chart.data.datasets.length; i++) { 
        text.push('<li><span style="background-color:' + 
                   chart.data.datasets[i].backgroundColor + 
                   '"></span>'); 
        if (chart.data.datasets[i].label) { 
            text.push(chart.data.datasets[i].label); 
        } 
        text.push('</li>'); 
    } 
    text.push('</ul>'); 
    return text.join(''); 
}
DazBaldwin
  • 4,125
  • 3
  • 39
  • 43
Craicerjack
  • 6,203
  • 2
  • 31
  • 39
  • 5
    Possible to show example of how this is to be used to generate custom legend? – Phil May 03 '16 at 13:27
  • also how do you HIDE the default legend that is generated? Any ideas? – Phil May 03 '16 at 13:30
  • This method generates the legend so I would imagine that if you added your own implementation it would automatically overide the default – Craicerjack May 03 '16 at 13:38
  • it does not appear to do so. I have implemented a custom legend using the legendCallback (updated my post above too to show my function) and it does generate my legend properly, however the default legend above the chart is still present. – Phil May 03 '16 at 13:41
  • 11
    figured it out... I had to add legend: { display: false } to the options – Phil May 03 '16 at 13:43
  • Hey, I havent used chart.js so was having a look for some examples, glad you got it sorted. – Craicerjack May 03 '16 at 13:44
17

I hope this will helpful you

var configd = {
    type: 'doughnut',
    data: {
        datasets: [{
            data: [
                50,
                60,
                20
            ],           
            backgroundColor: [
                '#33b35a',
                "#ffce56",
                "#4bc0c0",
                "#CDDC39",
                "#9C27B0",
                "#fb7145",
                "#5971f9"
            ],
            label: 'Energy usage'
        }],
        labels: [
            'E1',
            'E2',
            'E3'
        ]
    },
    options: {
        responsive: true,
        legend: {
            display: false
        },
        legendCallback: function (chart) {             
            // Return the HTML string here.
            console.log(chart.data.datasets);
            var text = [];
            text.push('<ul class="' + chart.id + '-legend">');
            for (var i = 0; i < chart.data.datasets[0].data.length; i++) {
                text.push('<li><span id="legend-' + i + '-item" style="background-color:' + chart.data.datasets[0].backgroundColor[i] + '"   onclick="updateDataset(event, ' + '\'' + i + '\'' + ')">');
                if (chart.data.labels[i]) {
                    text.push(chart.data.labels[i]);
                }
                text.push('</span></li>');
            }
            text.push('</ul>');
            return text.join("");
        },
        title: {
            display: false,
            text: 'Chart.js Doughnut Chart'
        },
        animation: {
            animateScale: true,
            animateRotate: true
        },
        tooltips: {
            mode: 'index',
            intersect: false,
            callbacks: {
                label: function (tooltipItem, data) {
                    let label = data.datasets[tooltipItem.datasetIndex].label + ' - ' + data.labels[tooltipItem.index];
                    let datasetLabel = data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index];
                    return label + ': ' + datasetLabel.toLocaleString();
                }
            }
        },
    }
};

 var ctxd = document.getElementById('canvas').getContext('2d');
    
    window.myDoughnut = new Chart(ctxd, configd);
    $("#do_legend").html(window.myDoughnut.generateLegend());

// Show/hide chart by click legend
updateDataset = function (e, datasetIndex) {    
    var index = datasetIndex;
    var ci = e.view.myDoughnut;
    var meta = ci.getDatasetMeta(0);    
    var result= (meta.data[datasetIndex].hidden == true) ? false : true;
    if(result==true)
    {
        meta.data[datasetIndex].hidden = true;
        $('#' + e.path[0].id).css("text-decoration", "line-through");
    }else{
        $('#' + e.path[0].id).css("text-decoration","");
        meta.data[datasetIndex].hidden = false;
    }
     
    ci.update();   
};
#do_legend{
   height:62px;
}

#do_legend{
    width:100%;     
}

#do_legend> ul{
    padding: 0;
    text-align: center;
}
 

#do_legend {   
  width:100%;
  bottom:10%;
}
#do_legend li {
    cursor: pointer;
    margin: 4px 3px;
    display: inline-table;
}
#do_legend li span {
    position: relative;
    padding: 3px 10px;
    border-radius: 13px;
    color: white;
    z-index: 2;
    font-size: 11px;
}

#do_legend{
    height: 62px;
    overflow-y: auto;
}

.donut-area{
    height:calc(100% - 62px)
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.5.0/Chart.min.js"></script>


<div style="width:40%">
   <div id="do_legend"></div>
  <canvas id="canvas"></canvas>
</div>

Codepen Example

Udara Kasun
  • 2,182
  • 18
  • 25
1

If people come here looking for a solution for this in ChartJS 3.6.0. (Maybe other versions too)

They offer an HTML legend where you can specify the exact HTML you want using the plugins option. Here is an example of the configuration along with the link to the documentation below.

  const config = {
  type: 'line',
  data: data,
  options: {
    plugins: {
      htmlLegend: {
        // ID of the container to put the legend in
        containerID: 'legend-container',
      },
      legend: {
        display: false,
      }
    }
  },
  plugins: [htmlLegendPlugin],
};

ChartJS HTML Legend

Rmalmoe
  • 993
  • 11
  • 13
0

This code is working for me

updateDataset = function(target, chart, label, color, data) {
    var store = chart.data.datasets[0].label;
    var bgcolor = chart.data.datasets[0].backgroundColor;
    var dataSets = chart.data.datasets[0].data;
    var exists = false;
    for (var i = 0; i < chart.data.datasets[0].label.length; i++) {
        if (chart.data.datasets[0].label[i] === label) {
            chart.data.datasets[0].label
            exists = true;
            chart.data.datasets[0].label.push(store.splice(i, 1)[0][1]);
            chart.data.datasets[0].backgroundColor.push(bgcolor.splice(i, 1)[0][1]);
            chart.data.datasets[0].data.push(dataSets.splice(i, 1)[0][1]);      
        }
    }
    if (!exists) {
        chart.data.datasets[0].label.push(label);
        chart.data.datasets[0].backgroundColor.push(color);
        chart.data.datasets[0].data.push(data);
        exists = false;
    }
    chart.update();  
};
Enstage
  • 2,106
  • 13
  • 20
Raji
  • 9
  • 1
  • Please read [answer] and [edit] your answer to contain an explanation as to why this code would actually solve the problem at hand. Always remember that you're not only solving the problem, but are also educating the OP and any future readers of this post. – Adriaan Oct 06 '22 at 10:07
0

ChartJS 3.0+

I know this question is specifically asking about chartJS 2.0, but this is one of the biggest threads I've found addressing custom legends in chartJS, so I wanted to share my finding for adding a custom legend in chartJS 3.0+ which deprecated the use of the generateLegend() function.

Adding a legend in chartJS 3.0+ requires the use of plugins.

Basically you can create a custom plugin when you instantiate the chart. For example:

const context = document.querySelector("#chart-id");
const chart = new Chart(context, {
  type: "doughnut",
  data,
  options,
  plugins: [{
    beforeInit: function(chart, args, options) {
      // Make sure we're applying the legend to the right chart
      if (chart.canvas.id === "chart-id") {
        const ul = document.createElement('ul');
        chart.data.labels.forEach((label, i) => {
          ul.innerHTML += `
            <li>
              <span style="background-color: ${ chart.data.datasets[0].backgroundColor[i] }">
                ${ chart.data.datasets[0].data[i] }
              </span>
              ${ label }
            </li>
          `;
        });

        return document.getElementById("js-legend").appendChild(ul);
      }

      return;
    }
  }]  
});

Here's a working jsfiddle illustrating this method of adding a custom legend.

kingliam
  • 315
  • 3
  • 8