[Chartjs]-How to wrap legend text in Chartjs?

6👍

Unfortunately there is no option for automatically wrap long legend labels.

You’ll have to generate custom HTML legend using legendCallback together with some CSS. The following code expects that dataset.label to be either a string or an array of strings in case of a multi-line label (For some types of charts (i.e. pie chart), individual legend labels represent a value from a unique dataset. In such cases, the code looks slightly different as shown in this answer).

legendCallback: chart => {
  let html = '<ul>';
  chart.data.datasets.forEach((ds, i) => {
    html += '<li>' +
      '<span style="width: 36px; height: 14px; background-color:' + ds.backgroundColor + '; border:' + ds.borderWidth + 'px solid ' + ds.borderColor + '" onclick="onLegendClicked(event, \'' + i + '\')">&nbsp;</span>' +
      '<span id="legend-label-' + i + '" onclick="onLegendClicked(event, \'' + i + '\')">' +
      (Array.isArray(ds.label) ? ds.label.join('<br/>') : ds.label) + '</span>' +
      '</li>';
  });
  return html + '</ul>';
},

To make this behave the same as standard Chart.js charts, the function onLegendClicked is invoked when a mouse click occurs on a legend label. This function toggles the hidden state of individual datasets and changes label text style between normal and strike-through.

function onLegendClicked(e, i) {
  const hidden = !chart.data.datasets[i].hidden;
  chart.data.datasets[i].hidden = hidden;
  const legendLabelSpan = document.getElementById("legend-label-" + i);
  legendLabelSpan.style.textDecoration = hidden ? 'line-through' : '';
  chart.update();
};

Please take a look at the executable code below and see how it works in action:

function onLegendClicked(e, i) {
  const hidden = !chart.data.datasets[i].hidden;
  chart.data.datasets[i].hidden = hidden;
  const legendLabelSpan = document.getElementById("legend-label-" + i);
  legendLabelSpan.style.textDecoration = hidden ? 'line-through' : '';
  chart.update();
};

const chart = new Chart(document.getElementById("chart"), {
  type: "bar",
  data: {
    labels: ['A', 'B', 'C'],
    datasets: [{
        label: ['Legend label', 'on two lines'],
        data: [5, 8, 4],
        fill: false,
        backgroundColor: "rgba(255, 99, 132, 0.2)",
        borderColor: "rgb(255, 99, 132)",
        borderWidth: 1
      },
      {
        label: ['Legend label', 'spread over', 'three lines'],
        data: [3, 5, 4],
        fill: false,
        backgroundColor: "rgba(255, 159, 64, 0.2)",
        borderColor: "rgb(255, 159, 64)",
        borderWidth: 1
      },
      {
        label: "Short legend label",
        data: [6, 5, 7],
        fill: false,
        backgroundColor: "rgba(255, 205, 86, 0.2)",
        borderColor: "rgb(255, 205, 86)",
        borderWidth: 1
      }
    ]
  },
  options: {
    legend: {
      display: false
    },
    legendCallback: chart => {
      let html = '<ul>';
      chart.data.datasets.forEach((ds, i) => {
        html += '<li>' +
          '<span style="width: 36px; height: 14px; background-color:' + ds.backgroundColor + '; border:' + ds.borderWidth + 'px solid ' + ds.borderColor + '" onclick="onLegendClicked(event, \'' + i + '\')">&nbsp;</span>' +
          '<span id="legend-label-' + i + '" onclick="onLegendClicked(event, \'' + i + '\')">' +
          (Array.isArray(ds.label) ? ds.label.join('<br/>') : ds.label) + '</span>' +
          '</li>';
      });
      return html + '</ul>';
    },
    scales: {
      yAxes: [{
        ticks: {
          beginAtZero: true
        }
      }]
    }
  }
});
document.getElementById("legend").innerHTML = chart.generateLegend();
#legend>ul {
  display: flex;
  justify-content: center;
}

#legend li {
  cursor: pointer;
  margin: 0px 10px;
  display: flex;
}

#legend li span {
  padding-left: 8px;
  font-family: Arial, Helvetica, sans-serif;
  font-size: 12px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.js"></script>
<div>  
  <canvas id="chart" height="60"></canvas>
  <div id="legend"></div>
</div>

Leave a comment