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;
@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:
After:
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
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 heightitemHeight * 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 incorrectI 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:
Edit: updated proposal,
pack
renamed toalign
,align
renamed tolabels.align
,labels.boxAlign
replaced bylabels.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;
To the following:
y += (ctx.canvas.clientHeight - (itemHeight * me.legendItems.length) - labelOpts.padding) / 2;
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>
Most helpful comment
Some additional thoughts: