14

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.

ouflak
  • 2,458
  • 10
  • 44
  • 49
QWERTY
  • 2,303
  • 9
  • 44
  • 85

5 Answers5

12

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>
ɢʀᴜɴᴛ
  • 32,025
  • 15
  • 116
  • 110
4

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/

Mina paulis
  • 392
  • 3
  • 14
  • I created the HTML legend but this leads to another problem which is after I collapsed and expanded back the outer most div, the canvas went missing but not the legend div. Also, after I wrapped the canvas with div, the animation to plot the chart also went missing – QWERTY Aug 11 '17 at 09:09
  • The animation went because of the wrapper have float sot this markup should get the animation to work
    This is n't clear to me clarify it" after I collapsed and expanded back the outer most div, the canvas went missing but not the legend div"
    – Mina paulis Aug 11 '17 at 09:18
2

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>
Nagaraja JB
  • 729
  • 8
  • 18
2

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>
uminder
  • 23,831
  • 5
  • 37
  • 72
0

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;

Tanvir Gaus
  • 205
  • 1
  • 3
  • 10