Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pie Graph legend on left or right is not vertically centered. #3175

Closed
RZeni opened this issue Aug 20, 2016 · 28 comments · Fixed by #6141
Closed

Pie Graph legend on left or right is not vertically centered. #3175

RZeni opened this issue Aug 20, 2016 · 28 comments · Fixed by #6141

Comments

@RZeni
Copy link

RZeni commented Aug 20, 2016

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;

@etimberg
Copy link
Member

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

@guschnwg
Copy link

guschnwg commented Dec 23, 2016

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;

@etimberg
Copy link
Member

etimberg commented Jan 11, 2017

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

@panzarino
Copy link
Contributor

panzarino commented Jan 11, 2017

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

@simonbrunel
Copy link
Member

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

@etimberg
Copy link
Member

@simonbrunel that works for me

@simonbrunel
Copy link
Member

simonbrunel commented Jan 14, 2017

Some additional thoughts:

image

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

@etimberg
Copy link
Member

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

@simonbrunel
Copy link
Member

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.

@etimberg
Copy link
Member

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.

@rightisleft
Copy link

+1

@zerox1212
Copy link

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

@barrychapman
Copy link

Was this ever implemented?

@jakeboyles
Copy link

+1

@etimberg etimberg marked this as a duplicate of #4577 Jul 27, 2017
@adammatthewsmith
Copy link

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

@etimberg
Copy link
Member

@adammatthewsmith this issue has not been fixed

@Tatranskymedved
Copy link

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

@EMFHDinf
Copy link

@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?

@bathyscaaf
Copy link

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

@mmdileepthomas
Copy link

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;

@Math3v
Copy link

Math3v commented Jun 1, 2018

Any update on this guys? :)

@Fr33maan
Copy link

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

@jvaldezn
Copy link

jvaldezn commented Oct 3, 2018

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
};

@c3bola
Copy link

c3bola commented Oct 5, 2018

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,

@manifoldhiker
Copy link

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

@manifoldhiker
Copy link

manifoldhiker commented Oct 19, 2018

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

@FelipeFelizardo
Copy link

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

dkichler pushed a commit to dkichler/Chart.js that referenced this issue Mar 18, 2019
… for controlling alignment of legend blocks in horizontal/vertical legends.

Maintains backward compatibility for legends positioned on the left/right by defaulting to 'start'.
dkichler pushed a commit to dkichler/Chart.js that referenced this issue Mar 18, 2019
dkichler pushed a commit to dkichler/Chart.js that referenced this issue Mar 18, 2019
- New config parameter options.legened.align, for controlling alignment of legend blocks in horizontal/vertical legends.
- Maintains backward compatibility for legends positioned on the left/right by defaulting to 'start'.
- Replacing nearby pixel unit tests for legend with image based tests
- Documentation for options.legend.align
dkichler pushed a commit to dkichler/Chart.js that referenced this issue Mar 18, 2019
- New config parameter options.legened.align, for controlling alignment of legend blocks in horizontal/vertical legends.
- Maintains backward compatibility for legends positioned on the left/right by defaulting to 'start'.
- Replacing nearby pixel unit tests for legend with image based tests
- Documentation for options.legend.align
dkichler pushed a commit to dkichler/Chart.js that referenced this issue Mar 18, 2019
- New config parameter options.legend.align, for controlling alignment of legend blocks in horizontal/vertical legends.
- Maintains backward compatibility for legends positioned on the left/right by defaulting to 'start'.
- Replacing nearby pixel unit tests for legend with image based tests
- Documentation for options.legend.align
@simonbrunel simonbrunel added this to the Version 2.9 milestone Mar 23, 2019
@HariKumarValluru
Copy link

HariKumarValluru commented Jun 28, 2019

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.