Chart.js: Pie Graph legend on left or right is not vertically centered.

Created on 21 Aug 2016  Â·  28Comments  Â·  Source: chartjs/Chart.js

I have fixed this in my local copy by adding the following line into the draw function

y += (ctx.canvas.clientHeight - (itemHeight * me.legendItems.length)) / 2;

bug enhancement

Most helpful comment

Some additional thoughts:

image

Edit: updated proposal, pack renamed to align, align renamed to labels.align, labels.boxAlign replaced by labels.stretch

All 28 comments

@RZeni can you post screenshots of before and after your fix? I'd be happy to merge a PR fixing this

If not resolved yet, here is what he did:

var textWidth = ctx.measureText(legendItem.text).width,
width = boxWidth + (fontSize / 2) + textWidth,
x = cursor.x,
y = cursor.y;
y += (ctx.canvas.clientHeight - (itemHeight * me.legendItems.length)) / 2;

And the results:

Before:

sem-ajuste

After:
com-ajuste

Thanks btw, I was looking for it.

I added the following because it seems to bug the legend when it is not on the side of the chart.

if(me.options.position == 'left' || me.options.position == 'right')
y += (ctx.canvas.clientHeight - (itemHeight * me.legendItems.length)) / 2;

I took a look at this and noticed that the proposed solution would exhibit the following issues

  1. ctx.canvas.clientHeight is not guaranteed to be the render height of the canvas. When window.devicePixelRatio > 1 the canvas will have more pixels that it's CSS height
  2. itemHeight * me.legendItems.length will only give the legend height when there is one column of items. If there are enough data points, there will be multiple columns, and it will be incorrect

Proposed Solution

I think the better solution to this problem would be to update fit to store the height of each column. We already know it here. What we could do is save it into a new me._columnHeights array.

Then, we provide a new config option

legendOptions = {
  // options are 'start', 'end', 'center'. Default is 'start' which matches old behaviour
  align: 'start' 
}

During drawing, if the option is 'start' the legend draws at the top. If it's 'end' its at the bottom. 'center' does as expected. This option would apply to both horizontal and vertical legends and would need to be implemented accordingly for the horizontal case.

CC @chartjs/maintainers for input

I think that allowing legend location configuration options as specified by @etimberg would be the best route.

@etimberg sounds good, I prefer align, shorter and commonly used (e.g CSS box-align, text-align, vertical-align)?

@simonbrunel that works for me

Some additional thoughts:

image

Edit: updated proposal, pack renamed to align, align renamed to labels.align, labels.boxAlign replaced by labels.stretch

Interesting ideas @simonbrunel

I like the box align settings. I like the idea of reverse, but I'm not sure about the name. To me reverse could be confused with legendOpts.reverse which reverses the order of items in the legend.

In terms of the pack setting, I'm not sure how feasible that is for horizontal legends. Right now, each row is filled first before going to the next. That doesn't really play well with aligning columns

Initially, I pick legend.labels.direction (normal/reverse) to be consistent with the CSS box-direction. But finally chose legend.labels.reverse to be consistent with the legend.reverse option. Can be changed for direction if better.

legend.align is alignement inside the label (so always horizontal), so would not solve the reported issue (but solves #3367). align.pack is the solution for this ticket (the one you previously called alignment/align). I think pack is a better name since it really mimics the CSS box-pack feature.

Hmm, I think we'll have to see how reverse ends up in practice. I see what you mean about keeping them consistent.

I like the name pack as well. I was thinking about this more. I do like how the options for pack change the legend. Though I certainly see start, center, and end as being the most used.

+1

I'm looking for this exact behavior. Is the above hack still the only way to fix it?

Was this ever implemented?

+1

What is the resolution on this issue? 4577 and 3175 (this) were both marked as duplicates and closed.

@adammatthewsmith this issue has not been fixed

@adammatthewsmith : @etimberg meant that this issue is still open (not closed). Unfortunatelly there is nobody on it right now.

@simonbrunel the legend.align property has not been implemented yet right? are there any plans to when and if they will be implemented? is there any other oportunity to algin center a left/right legend?

Any news on this? Currently I'm turning off the built-in legend and using the legendCallback to build my own for this reason -- which works well, but there are certain contexts where I want to use the built-in version

is there any working model, like in JSfiddle or code pen

var textWidth = ctx.measureText(legendItem.text).width,
width = boxWidth + (fontSize / 2) + textWidth,
x = cursor.x,
y = cursor.y;
y += (ctx.canvas.clientHeight - (itemHeight * me.legendItems.length)) / 2;

like when i checked the chart.js docs for legend i found that default boxWidth is 40 and fontSize is 12 but from where are you getting the legendItem , x , y

and what is me for the below code ? also legendItems

if(me.options.position == 'left' || me.options.position == 'right')
y += (ctx.canvas.clientHeight - (itemHeight * me.legendItems.length)) / 2;

Any update on this guys? :)

If someone could explain chich part of the draw function to edit it would be nice

If someone could explain chich part of the draw function to edit it would be nice

line 11790

var itemHeight = fontSize + labelOpts.padding;
cursor = {
x: me.left + labelOpts.padding,
y: me.top + labelOpts.padding + (me.height - (itemHeight * me.legendItems.length)) / 2,
line: 0
};

Hello, I had the same problem.

I changed the contents of line 11792
y: me.top + labelOpts.padding,

per

y: me.top + labelOpts.padding + (me.height - ((fontSize + labelOpts.padding) * me.legendItems.length)) / 2,

I want to align legend items to the right centre. Any update on this?

I found that @guschnwg hack works a bit incorrectly when we have paddings

So I changed this code:

y += (ctx.canvas.clientHeight - (itemHeight * me.legendItems.length)) / 2;

image

To the following:

y += (ctx.canvas.clientHeight - (itemHeight * me.legendItems.length) - labelOpts.padding) / 2;

image

I need to align it left, any update???????

I have fixed this by using custom legend and bootstrap

<div class="row m-0">
        <div class="col-8 p-0">
            <canvas id="chart"></canvas>
        </div>
        <div class="col-4  p-0 my-auto">
              <div id="legend"></div>
         </div>
</div>

legend alignment to middle

Was this page helpful?
0 / 5 - 0 ratings