9
votes

I was having some problem with chart.js legend. The legend with long text took up too much spaces which resulting in the reduce in the size of my pie chart:

Another example is this:

If I got more legend, the doughnut chart will eventually becomes smaller and smaller.

I tried to set maxWidth but to no avail.

var options = {
            layout: {
                padding: {
                  top: 5
                }
            },
            responsive: true,
            maintainAspectRatio: false,
            legend: {
                display: true,
                position: 'right',
                maxWidth: 100,
                onClick: null
            },
            animation: {
                animateScale: true,
                animateRotate: true
            },

        };

Any ideas?

I tried to follow this [solution][3] to create a html legend:

<div class="box-body" style="height:350px;">
<div class="float-left">
<div class="float-left" style="width:70%">

<canvas id="brandChart" style="position: relative; height: 350px;"></canvas>
</div>
<div class="float-left" style="width:30%">

<div id="js-legend" class="chart-legend">
</div>

</div>
</div>

It did restricted the width for legend, but then this lead to another problem which is after I collapsed and expanded the div, the canvas just went missing and I am only left with the legend div.

5
Have you tried changing legend position to bottom or top? - kastriotcunaku
Hmm I would like it to be at the right hand side as it is much neater - BlackMamba

5 Answers

7
votes

First off, set canvas­'s width and height using it­'s native attributes (do not use style attribute), like so :

<canvas id="brandChart" width="700" height="350"></canvas>

note: width should be twice the height

Then, set responsive property to false in your chart options, as such :

options: {
   responsive: false,
   ...
}

ᴅᴇᴍᴏ

var chart = new Chart(brandChart, {
   type: 'doughnut',
   data: {
      labels: ['Etronin Home Appliances Service & trading Pte Ltd', 'Giant'],
      datasets: [{
         data: [30, 70],
         backgroundColor: ['#2196f3', '#4caf50']
      }]
   },
   options: {
      responsive: false,
      legend: {
         display: true,
         position: 'right',
         onClick: null
      },
   }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.6.0/Chart.min.js"></script>
<canvas id="brandChart" width="700" height="350"></canvas>
3
votes

Long legend nowrap is a known issue check https://github.com/chartjs/Chart.js/issues/3641

May be they can cover it in next releases. For now the solution is to remove the native legend and draw your custom one

I've created this plunk as an example for doghnut chart with custom legend https://embed.plnkr.co/5nuGS2KEV6hvESwGrOse/

1
votes

I bumped into a similar issue while using a bar chart with several items in legend positioned at the bottom, I set responsive:true

 options: {
    responsive: true,
    legend: {
      display: true,
      position: "bottom",
      labels: {
        fontColor: "#3f5761"
      }
    },
    scales: {
      yAxes: [
        {
          ticks: {
            beginAtZero: true
          },
          scaleLabel: {
            display: true,
            labelString: "No. of tasks",
            fontSize: 10
          }
        }
      ]
    }
  }

and set the height to the canvas as I wanted the width to be responsive. It looks better now.

<canvas #taskCountsChart height="350"></canvas>
1
votes

There's no option that can be defined to easily achieve what you're looking for. An open feature request exists for such an option since 2016.

You'll have to generate custom HTML legend using legendCallback together with some CSS. The following code expects multi-line labels to be defined as arrays inside data.labels. It is aimed to be used for charts that have a unique dataset and where each legend label represents a value of its data (In case you need a solution for a chart with multiple datasets, please take a look at this answer).

legendCallback: chart => {
  let html = '<ul>';
  chart.data.labels.forEach((l, i) => {
    const ds = chart.data.datasets[0];
    const bgColor = ds.backgroundColor[i];
    const border = ds.borderWidth + 'px solid ' + ds.borderColor[i];
    html += '<li>' +
      '<span style="width: 36px; height: 14px; background-color:' + bgColor + '; border:' + border + '" onclick="onLegendClicked(event, \'' + i + '\')">&nbsp;</span>' +
      '<span id="legend-label-' + i + '" onclick="onLegendClicked(event, \'' + i + '\')">' +
      (Array.isArray(l) ? l.join('<br/>') : l) + '</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 doughnut slices and changes label text style between normal and strike-through.

function onLegendClicked(e, i) {
  let hidden = !chart.getDatasetMeta(0).data[i].hidden;
  chart.getDatasetMeta(0).data[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) {
  let hidden = !chart.getDatasetMeta(0).data[i].hidden;
  chart.getDatasetMeta(0).data[i].hidden = hidden;
  const legendLabelSpan = document.getElementById("legend-label-" + i);
  legendLabelSpan.style.textDecoration = hidden ? 'line-through' : '';
  chart.update();
};

const chart = new Chart('chart', {
  type: 'doughnut',
  data: {
    labels: [
      ['Label on', 'two lines'],     
      ['Legend label', 'spread over', 'three lines'],
       'A short label'
    ],
    datasets: [{
      data: [4, 5, 3],
      backgroundColor: ['rgba(255, 99, 132, 0.2)', 'rgba(255, 159, 64, 0.2)', 'rgba(54, 162, 235, 0.2)'],
      borderColor: ['rgb(255, 99, 132)', 'rgb(255, 159, 64)', 'rgb(54, 162, 235)'],
      borderWidth: 1
    }]
  },
  options: {
    legend: {
      display: false
    },
    tooltips: {
      callbacks: {
        title: (tooltipItems, data) => data.labels[tooltipItems[0].index],
        label: (tooltipItems, data) => 'Count: ' + data.datasets[0].data[tooltipItems.index]
      }
    },
    legendCallback: chart => {      
      let html = '<ul>';
      chart.data.labels.forEach((l, i) => {
        const ds = chart.data.datasets[0];
        const bgColor = ds.backgroundColor[i];
        const border = ds.borderWidth + 'px solid ' + ds.borderColor[i];
        html += '<li>' +
        '<span style="width: 36px; height: 14px; background-color:' + bgColor + '; border:' + border + '" onclick="onLegendClicked(event, \'' + i + '\')">&nbsp;</span>' +
        '<span id="legend-label-' + i + '" onclick="onLegendClicked(event, \'' + i + '\')">' +
        (Array.isArray(l) ? l.join('<br/>') : l) +'</span>' +
        '</li>';
      });
      return html + '</ul>';
    }
  }
});
document.getElementById("legend").innerHTML = chart.generateLegend();
#legend>ul {
  display: flex;
  justify-content: center;
}

#legend li {
  cursor: pointer;
  margin: 10px 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>
  <div id="legend"></div>
  <canvas id="chart" height="90"></canvas>
</div>
0
votes

This post is 9 months old but for the ones who are looking for a solution, use the following and this will make the pie/doughnut bigger in mobile/responsive view

Chart.defaults.global.maintainAspectRatio = false;