Chartjs-How to add an extra legend item in chart.js?

0👍

Here is a naïve approach using legendCallback.

If you want multiple legend items, out of the box, you will need multiple datasets. Typically, each dataset gets its own label.

const ctx = document.getElementById('canvas').getContext('2d');
const data = [
  { Name: 'John'    , FeesPaid: 100 , MemberType: 'NonMember' },
  { Name: 'Mary'    , FeesPaid:  87 , MemberType: 'Member'    },
  { Name: 'Charles' , FeesPaid: 108 , MemberType: 'Member'    },
  { Name: 'Fern'    , FeesPaid:  91 , MemberType: 'Member'    },
  { Name: 'Robert'  , FeesPaid: 100 , MemberType: 'NonMember' },
  { Name: 'Andrea'  , FeesPaid: 114 , MemberType: 'Member'    },
]

const fields = [
  { label: 'Member'    , color: 'rgb(255, 99, 132)' , active: true },
  { label: 'NonMember' , color: '#f5be0b'           , active: true }
];

const Colors = fields.reduce((obj, field) => ({ ...obj, [field.label]: field.color }), {});

const labels = data.map(item => item.Name);
const values = data.map(item => item.FeesPaid);

const getColor = record => {
  const r = data.find(d => d.Name === record.chart.data.labels[record.dataIndex]);
  return r ? Colors[r.MemberType] : Colors.NonMember;
};

const customLegendRenderer = (chart) => {
  return `
    <ul class="custom-legend ${chart.id}-legend">
      ${fields.map(field => `
        <li data-field="${field.label}" data-active="${field.active}">
          <span style="background-color:${field.color}"></span>
          ${field.label}
        </li>
      `).join('')}
    </ul>
  `;
};

const chart = new Chart(ctx, {
  type: 'bar',
  data: {
    labels: labels,
    datasets: [{
      backgroundColor: getColor,
      borderColor: getColor,
      data: values
    }]
  },
  options: {
    legend: false,
    legendCallback: customLegendRenderer
  }
});

const handleClick = (e) => {
  const labels = chart.data.labels;
  const dataset = chart.data.datasets[0];
  const item = e.target.closest('li');
  if (item === null) return;
  const selected = fields.find(field => field.label === item.dataset.field);
  selected.active = !selected.active;
  const activeFields = fields.filter(field => field.active).map(field => field.label);
  while (dataset.data.length && labels.length) {
    dataset.data.pop();
    labels.pop();
  }
  const filteredData = data.filter(record => activeFields.includes(record.MemberType));
  filteredData.forEach(item => {
    dataset.data.push(item.FeesPaid);
    labels.push(item.Name);
  });
  chart.update();
  customLegend.innerHTML = chart.generateLegend();
};

const customLegend = document.querySelector('#chartjs-legend');
customLegend.innerHTML = chart.generateLegend();
customLegend.addEventListener('click', handleClick);
.custom-legend {
  display: flex;
  flex-direction: row;
  justify-content: space-evenly;
  list-style-type: none;
}

.custom-legend li[data-active="false"] {
  color: #777;
  text-decoration: line-through;
}

.custom-legend li span {
  display: inline-block;
  width: 1em;
  height: 1em;
  cursor: pointer;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.js"></script>
<canvas id="canvas"></canvas>
<div id="chartjs-legend" class="noselect"></div>

Leave a comment