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

[BUG] Chart invisible when Legend too large #3761

Closed
Queenferno opened this issue Jan 3, 2017 · 22 comments · Fixed by #8193
Closed

[BUG] Chart invisible when Legend too large #3761

Queenferno opened this issue Jan 3, 2017 · 22 comments · Fixed by #8193

Comments

@Queenferno
Copy link

Queenferno commented Jan 3, 2017

Expected Behavior

Imagine a Pie/Doughnut Chart with the following requirements:

  1. It has a Dataset of 100 Products
  2. Each Product is represented by a Legend Label (thus, 100 labels)
  3. The Chart resides within a medium div (say "col-lg-4" of Bootstrap)

It can be obvious that both the 6 generated columns with the Labels cannot fit to the div with the Chart. In my opinion, they should not.

Image presenting the Chart in a full-screen mode:
largechart

Current Behavior

When working with a Chart following the aforementioned requirements:

  1. The div of the chart (canvas) shows some of the Legend Labels (say the 60 last ones)
  2. The other Labels are hidden, rendered outside the canvas
  3. The Chart is nowhere to be seen, probably thrown out by the Labels

Image presenting the Chart in a smaller Div. Most elements are gone. All that is left are some of the Legend Labels:
smallchart

Possible Solution

Add a scrollable overflow to the "box" that hosts the Legends?

Steps to Reproduce

  1. Create a medium div (any size will do, as long as it's not a full-screen one)
    <div class="row">
    <div class="col-lg-4">
    <div>
    <div>
  2. In the "col-lg-4" div, place a canvas for your Chart. Make it :
  • Type = Pie/Doughnut
  • Responsive = true
  • Fullwidth = true (although "false" has the exact same behavior)
  • Dataset = any array holding 100+ elements (e.g. array of {name, value})
  • Labels = the "name" values of your array (so that you will have 100 labels)
    Options Example:
    options="{ 'responsive': true,'maintainAspectRatio':true,'transparencyEffects':true,'dataSetBorderWidth': 2, 'legend':{ 'display': true, 'fullWidth':true, 'position': 'right', 'labels':{'boxWidth':40, 'fontSize':12, 'fontStyle':'normal', 'fontColor':'#666', 'usePointStyle':false}}, 'pallette': ['#a694ff','#a59891','#98a7ad','#ea7d7d','#80d27a','#99b4f4','#fed444','#3f3f3f','#b6696c','#417d83','#ff9750']}"

When you run it, you will see that your div will only present some of the Legend Labels. All other Labels and the Chart will be cone.

Environment

  • Chart.js version:2.2.1
  • Browser name and version: Chrome & Mozilla
@etimberg
Copy link
Member

etimberg commented Jan 3, 2017

Hmmm, I'm not sure what the best solution is here. I almost think an HTML legend would be the way to go in this case.

@chartjs/maintainers any thoughts?

@panzarino
Copy link
Contributor

@etimberg I agree that an HTML legend would be the best approach, and it covers that "scrollable overflow." I don't think that most users will have this many legend options, so an enhancement to the core library doesn't seem necessary.

@Queenferno
Copy link
Author

I agree as well and that is something I was trying to accomplish, namely:

  • Hide the Legend from the Original chart
  • Use the legendCallback to display the Legend in another div
  • Copy all the properties and events of the original Legend into the new one, so as to avoid code duplication

However, no matter how much I tried, I could not copy the styles and events from the Chart component into my generated legend. I saw that a previous version had a legendTemplate as well, that could maybe solve my problem (regarding the code duplication), but it is not available any more.

Maybe if the legendCallback could return a list of properties with their styles and events, rather than a plain HTML list? (Which was what I was trying to do and maybe would accomplish if I had more extensive Javascript and HTML Canvas knowledge..). Would that be hard or undoable?

@etimberg
Copy link
Member

etimberg commented Jan 4, 2017

It would be almost impossible to directly copy over the styles from the canvas since they aren't in CSS. It is possible to update the default legendCallback to produce something that look much more like canvas one. That shouldn't actually be that hard since it would be in the string generation. To reduce code duplication, we could move the generateLegend implementation into the actual chart legend. That way, the legend could run all the normal stuff to generate labels, click handling, etc, then all we have to do is bind it all together and return something that gets put into the DOM tree (would probably need to return the <div> at the top of the tree rather than a string to attach functions correctly. This would be a major change though and I would not want to break any existing HTML legends.

The legendTemplate was used in v1 to generate the legend but it was just a shorthand for building the legend HTML string so it didn't end up getting much use.

You could change the legendCallback in your chart to return something else. Then, when you call chart.generateLegend() you will get whatever is returned from legendCallback.

@itsmelion
Copy link

itsmelion commented Jan 19, 2017

I like the html idea @zachpanz88, but this is a real issue.
there are a couple of problems which this 'layout bug' can interfere.

i use this lib on a real application, with angular-chart.
screen shot 2017-01-18 at 19 06 05

  1. as the legends grow, the graphs become smaller, this is merely aesthetic, but each graph depending on the size of the legend is a mess. especially when they are on the same row. gives the impression of a poor design/alignment. luckly, the last chart didnt had a 4th legend, but if it had we were going to see 3 different pie chart sizes on that row. ( eww! 😖 )

  2. @Queenferno mentioned a 100items list.. but on my CRM app, i dont have this many items, still i get the same problem. as in the image, i have a row, with 3 charts. Campaigns, Responsibles, and Deal Status. The campaign's legend array, have just a couple of.. less than 10 items. And the graph is already gone. 😞

@simonbrunel
Copy link
Member

@itsmelion what should be the expected layout/design of these charts at this size (let's say the last one "Status" have an extra legend item)?

@kykocamp
Copy link

@itsmelion Anyway, this chart is created dynamically. If the user chooses "All time chart" in the filters, he could have 1k Campaigns, and it will generate 1k legend's items.

Maybe the best solution for this is what @Queenferno proposed, if we could take the legendCallback properties for styles and events to interact with the chart.

@PabloMCampos
Copy link

I think that is important to have an option for this in the bundle of chart.js, not as outside solution. If we have a "wrap" option for the text in the legend and "max-width", the text will be automatically ajust to the width.

@daniel-shuy
Copy link

daniel-shuy commented Jul 8, 2017

I have an idea. What if Chart.js' constructor took in 2 canvases, 1 for the Chart itself, and the other for the Legend?

That way, one could control the sizing and positioning of each canvas separately.

For example, to solve the above problem, one could simply increase the height of the Legend canvas and wrap it with a scrollable <div> (with overflow: scroll;), without affecting the Chart canvas.

This would also solve issue #1959 (size of Chart will not change if the height/width of the Legend changes).

@JHenighan
Copy link

JHenighan commented Jul 28, 2017

Did anyone find a solution to this as I am having the exact problem.

Thanks

@bahiamartins
Copy link

I'm not expert but we could be possible to show only top 5 legends to avoid an invisible chart

@etimberg
Copy link
Member

@bahiamartins yes, this can be done. A custom label generation function that returns the first 5 will work

@timbauwens
Copy link

Using a legendCallback function works to create the html legend, but does anyone have a working example that also handles clicks on legend items with the same behavior as the default legend?

@renielsalvador
Copy link

I am experiencing the same problem. Any good solution for this that includes the legend's events?

@timbauwens
Copy link

timbauwens commented Nov 15, 2018

@renielDev Here is the solution I wrote:
Fiddle

But fair warning
This is a hacky solution, that probably won't work if you have multiple datasets. I have stripped the fiddle down to the minimum, but it's taken from production code, so there's probably still some "noise" in it. If anything is unclear, let me know and I will try my best to explain the madness.

@renielsalvador
Copy link

renielsalvador commented Nov 27, 2018

Will look into it @timbauwens. Thanks

@JohnArcher
Copy link

The solution of @timbauwens looks nice, but as he mentioned it is a bit hacky (still much appreciated). Still, a more "official" solution would be nice. Like if the core could be altered in the way that @daniel-shuy proposed.

@sjdemoor
Copy link

Any updates on a solution to this issue? Custom responsive legends, (including piping in information for localization and canvas size), get very messy very quickly. These types of coding gymnastics are not generally necessary with most charting libraries.

I believe solution described by @PabloMCampos would be the easiest to use, although not necessarily the easiest to develop.

@andrewdurkiewicz
Copy link

I am also having the issue, but it is much more evident for mobile devices. Any solution to this?

@Anyoks
Copy link

Anyoks commented Oct 30, 2019

Didn't think that this would be an issue for me, till my data set enlarged! The chart becomes a tiny spec on the canvas while the legend takes center stage, which beats the point of having a chart! @daniel-shuy solutions seems practical.

@adriglib
Copy link

How is this issue still opened? Is there no way to add a 'min-height' to the graph so it doesn't shrink? That way the container will grow.

@emilsgulbis
Copy link

emilsgulbis commented Nov 10, 2020

How are you guys handling this problem?
There is toBase64Image method available, but maintainers recommend to use HTML legend instead. This doesn't make any sense.

  • If i want to save chart with title, data and legend i can't really do it, because chart looks tiny for large datasets.
  • If i use HTML legends then this image will not contain that

Is there any chance to modify canvas height by height of legend for horizontal layout?

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.