Billy Bones
Billy Bones

Reputation: 2965

Chart.js Legend Padding-Left

I have been playing with the solution found here from user Frosty Z (chart.js 2.5+) to try and apply padding to my legend. The solution works great if the legend is above the chart but trying to add padding in between the chart and legend when the legend is on the left right side is proving difficult.

    plugins: [{
        beforeInit: function(pdChart, options) {
            pdChart.legend.afterFit = function() {
                this.width = this.width + 50;
            };
        }
    }],

The picture below depicts my legend as of right now. Again I am hoping to add space between the legend and the chart.

enter image description here

Upvotes: 3

Views: 2366

Answers (1)

uminder
uminder

Reputation: 26150

You can generate a custom HTML legend using legendCallback together with some CSS.

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 + '\')">' +
      ds.label + '</span>' +
      '</li>';
  });
  return html + '</ul>';
}

Note that the default legend must be disabled through the option legend.display: false.

To make this still 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();
};

The padding of the legend is defined through CSS as follows:

#legend {
  padding-left: 20px;
  padding-top: 10px;
}

Please take a look at below runnable code sample and see how it works for your particular case.

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('myChart', {
  type: 'line',
  data: {
    labels: ['A', 'B', 'C', 'D'],
    datasets: [
      {
        label: 'Dataset 1',
        data: [205, 275, 359, 329],
        borderColor: "#fd7730",
        backgroundColor: "#fd7730",
        fill: false
      },
      {
        label: 'Dataset 2',
        data: [262, 302, 290, 180],
        borderColor: "#ffd35c",
        backgroundColor: "#ffd35c",
        fill: false
      },
      {
        label: 'Dataset 3',
        data: [359, 329, 262, 302],
        borderColor: "#3fc6f3",
        backgroundColor: "#3fc6f3",
        fill: false
      },
      {
        label: 'Dataset 4',
        data: [105, 175, 259, 129],
        borderColor: "#28a745",
        backgroundColor: "#28a745",
        fill: false
      },
      {
        label: 'Dataset 5',
        data: [189, 222, 201, 158],
        borderColor: "#488cf2",
        backgroundColor: "#488cf2",
        fill: false
      }
    ]
  },
  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 + '\')">' +
          ds.label + '</span>' +
          '</li>';
      });
      return html + '</ul>';
    },
    scales: {
      yAxes: [{
        ticks: {
          beginAtZero: true,
          stepSize: 100
        }
      }]
    }
  }
});
document.getElementById("legend").innerHTML = chart.generateLegend();
#chart-wrapper {
  display: flex;
  width: 60%;
}

ul {
  list-style-type: none;
  margin: 0;
  padding: 0;
}

#legend {
  padding-left: 20px;
  padding-top: 10px;
}

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

#legend li span {
  white-space: nowrap; 
  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 id="chart-wrapper">  
  <canvas id="myChart" height="100"></canvas>
  <div id="legend"></div>
</div>

Upvotes: 2

Related Questions