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

Make legend appearance consistent with chart elements #5621

Merged
merged 6 commits into from May 9, 2019

Conversation

nagix
Copy link
Contributor

@nagix nagix commented Jul 6, 2018

Problems

Legend appearance is not consistent with chart elements. For example,

  1. In a bar chart, the border of the legend is rendered while bars have no border
  2. In a bar chart, the border width of the legend is 3 pixels while the width of bars is 6 pixels
  3. In a bar chart, the border width and color of the legend don't match any of bars
  4. In a line chart, the colors and border width of the legend don't match those of points when usePointStyle is true (legend.usePointStyle uses borderColor to fill everything #5375)
  5. In a bar chart, a dashed border is used in the legend while bars have no dashed border
  6. In a line chart, the rotation of the point in the legend doesn't match the one in the chart when usePointStyle is true and pointRotation is non-zero.
  7. In a line chart, the legend box is filled even if fill is false.

See https://jsfiddle.net/nagix/5ztb6hLc

screen shot 2018-07-07 at 4 48 27 am

screen shot 2019-02-13 at 12 11 26 am

Solutions

  1. The default value for line elements was always used. Use the default value for each element type if a property is not set.
  2. A border was rendered before a background was rendered. Stroke after fill to move borders to the front.
  3. The border width and color of the first element should be picked up. Support indexable and scriptable options.
  4. Use point's colors and border width when usePointStyle is true.
  5. Disable line styles (dash, cap and join) when usePointStyle is true or the dataset type is not 'line' or 'radar'.
  6. Use point's rotation when usePointStyle is true.
  7. The background color is set to transparent when fill is false.

See https://jsfiddle.net/nagix/negp2rLh

screen shot 2018-07-07 at 4 50 12 am

screen shot 2019-02-13 at 12 12 02 am

In addition to above, the existing tests are fixed and more tests are added.

Fixes #5375
Fixes #6135
Closes #2281

etimberg
etimberg previously approved these changes Jul 7, 2018
etimberg
etimberg previously approved these changes Jan 10, 2019
test/specs/plugin.legend.tests.js Outdated Show resolved Hide resolved
benmccann
benmccann previously approved these changes Jan 11, 2019
@kurkle
Copy link
Member

kurkle commented Jan 24, 2019

To me this seems ready to merge, @etimberg, @simonbrunel ?

@nagix
Copy link
Contributor Author

nagix commented Jan 24, 2019

Recently scriptable options have been added, so I will review the code.

@nagix
Copy link
Contributor Author

nagix commented Feb 12, 2019

Added support for scriptable options and pointRotation/rotation.

@simonbrunel
Copy link
Member

simonbrunel commented Feb 14, 2019

@nagix I think there is a deeper issue with the current implementation (master) because the legend needs to know about the dataset options logic, which is specific to the controller. I also don't think controllers should be responsible to override generateLabels, neither have the knowledge of the legend plugin (same issues with the tooltip labels).

Thinking out loud: what about introducing a new dataset API to generate a "style", so dataset controllers would be able to return a set of predefined style properties that should be used to represent the dataset.

For example (line controller):

// Part of the line dataset controller
// @params {string} type - "primary" / "secondary"
// @return {IStyleInterface}
getStyle: function(type) {
    var options = type === "primary"
       ? this._resolveLineOptions(...)
       : this._resolvePointOptions(...);

    return {
        backgroundColor: options.backgroundColor,
        borderColor: options.borderColor,
        // ...
    };
}

For backward compatibility, we will need a base implementation at the DatasetController level. Then the legend default generateLabels would be something like:

generateLabels: function(chart) {
    var options = chart.options.legend || {};
    var secondary = options.labels && legendOpts.labels.usePointStyle;
    var type = secondary ? 'secondary' : 'primary';

    return helpers.isArray(data.datasets) ? data.datasets.map(function(dataset, i) {
        var meta = chart.getDatasetMeta(i);
        var controller = meta.controller;
        var style = controller.getStyle(type);

        return {
            text: dataset.label,
            fillStyle: style.backgroundColor,
            // ...
        };
    } : [];
}

We could use getStyle() in the tooltip and certainly get rid of the custom generateLabels defaults in the doughnut and polar are controllers. Of course the suggested API is an example and would need to be discussed (getStyle, IStyleInterface, etc.) but you get the idea.

What do you think about this approach?

@nagix
Copy link
Contributor Author

nagix commented Feb 15, 2019

@simonbrunel I like this approach. getStyle could be used for other purposes like annotations and more. Let me write code to see how it works. Do you think the doughnut and polarArea controller still need to override generateLabels to support per-element labels?

@simonbrunel
Copy link
Member

@nagix I forgot about the per-element legend labels, so that means we need to support accessing style for the dataset or for a specific data. Maybe getStyle(index), with index the index of the data to retrieve the style or, if index: null/undefined, the style of the dataset (so no need of the type previously suggested).

I'm not sure we can remove the overrides in the doughnut and polar controllers yet. Maybe we could add a new legend options to switch between per-dataset / per-data legend items (e.g. source: 'dataset' | 'data'), but that would be part of another PR. Though, the current per-data approach is a bit strange in case of multiple datasets with different styles.

Copy link
Member

@kurkle kurkle left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just some minimization comments

src/controllers/controller.radar.js Outdated Show resolved Hide resolved
src/core/core.datasetController.js Outdated Show resolved Hide resolved
exwm pushed a commit to exwm/Chart.js that referenced this pull request Apr 30, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
6 participants