Legends for line charts in Chart.js
Asked Answered
M

6

14

I'd like to customize a legend for line data so that the legend graphic is a line (styled like the actually data line) rather than a box.

As far as I can tell from the source, the graphic can be a point or a box, and the height of the box is fixed to the font size. The 'generateLabels' option does not seem to allow for extending around these contraints.

Version 2.2.1.

Thanks for any help.

Maladminister answered 25/8, 2016 at 22:1 Comment(0)
P
18

NOTE: This solution only works if you have a local version of Chart.js since it needs to edit a function in the source code of the library, which can't be done if you import it form a CDN.

To achieve what you want, you will need to edit the drawLegendBox function (link to source here).

First, as if you wanted to do a pointStyle legend, add the useLineStyle and set it to true like this :

options: {
    legend: {
        labels : {
            useLineStyle: true
        }
    }
}

Then you need to go to your local version of Chart.js (obvisouly, you cannot edit it if you import it from a CDN) and search for the function drawLegendBox (on Chart.js v2.2.1, it is roughly line 6460; in Chart.js v2.9.4 search for labelOpts && labelOpts.usePointStyle).

Scroll down a little bit to see something like this :

if (opts.labels && opts.labels.usePointStyle) {
    // Recalulate x and y for drawPoint() because its expecting
    // x and y to be center of figure (instead of top left)
    var radius = fontSize * Math.SQRT2 / 2;
    var offSet = radius / Math.SQRT2;
    var centerX = x + offSet;
    var centerY = y + offSet;

    // Draw pointStyle as legend symbol
    Chart.canvasHelpers.drawPoint(ctx, legendItem.pointStyle, radius, centerX, centerY);
}
// --- NEW CONDITION GOES HERE ---
else {
    // Draw box as legend symbol
    ctx.strokeRect(x, y, boxWidth, fontSize);
    ctx.fillRect(x, y, boxWidth, fontSize);
}

And add this between the two conditions :

else if (opts.labels && opts.labels.useLineStyle) {
    ctx.beginPath();
    ctx.moveTo(x, y + fontSize * 0.45);
    ctx.lineTo(x + boxWidth, y + fontSize * 0.45);
    ctx.stroke();
}

With this edit, everytime you will set useLineStyle to true, legend boxes will be drawn as lines, as the following screenshot :

enter image description here

Partite answered 2/9, 2016 at 12:18 Comment(4)
Thanks Tektiv. I'd like to keep this open to see if there's a way to do it without forking the library. Appreciate this answer.Maladminister
Is there a way to do this if you are unable to edit the source? I have chartjs installed via npm in an angular application and this answer, while excellent, isnt an option for me.Manque
@Manque It has been a while since I have used Chart.js though I think there is still now way to do it without digging in the source code. You could host your own version of Chart.js on a server and import it later as you do with npmPartite
There is still no option in version 2.7.1, but tektiv's code still works. Thanks.Groomsman
S
14

I was able to use pointStyle: line, in the dataset and then under options use labels: {usePointStyle: true,},

Stridulous answered 21/5, 2018 at 14:5 Comment(3)
this is exactly what I was looking for, thank you so much! I don't know why this was so difficult to findSprue
Ok this works, but now the points are not shown as circles anymore ...Vitellus
THIS IS THE CORRECT ANSWER GUYS, Thanks dudeSunny
W
4

chart.js v3

For this version, none of the previously mentioned built-in configurations work. You can set boxHeight: 0 on the legend labels in order to get a line instead of a box:

{
  legend: {
    labels: {
      boxHeight: 0
    }
  }
}
Wolf answered 10/7, 2022 at 18:0 Comment(0)
Z
2

Just to improve on this solution from tektiv. If you want to show a dashed line too use this code in the same spot.

(chartJs 2.7.2 around Line 16289):

            if (opts.labels && opts.labels.usePointStyle) {
                // CHARTJS CODE
            } else if (opts.labels && opts.labels.useLineStyle) {
                if (legendItem.borderDash) {
                    ctx.setLineDash(legendItem.borderDash);
                }
                ctx.beginPath();
                ctx.moveTo(x, y + fontSize / 2);
                ctx.lineTo(x + boxWidth, y + fontSize / 2);
                ctx.stroke();
            } else {
                // CHARTJS CODE
            }
Zeph answered 31/8, 2018 at 13:5 Comment(0)
B
2

ChartJS v4

None of the previous answers worked for me. New to chartjs but I think at some point, the schema of their options changed from options.legend to options.plugins.legend.

According to their docs for legend labels configuration this should be achievable with the usePointStyle and pointStyle parameters in the legend labels configuration.

The following code produces this:

Resulting chart


    new Chart(ctx, {
        type: 'line',
        data: {
            labels: ['1', '2', '3', '4', '5', '6'],
            datasets: [{
                label: 'My Metric',
                data: [12, 19, 3, 5, 2, 3],
                pointStyle: 'line'
            }]
        },
        options: {
            plugins: {
                legend: {
                    labels: {
                        pointStyle: 'line', // Change to eg 'circle' or 'rect' to control legend independently of the plotted pointStyle
                        usePointStyle: true,
                    }
                }
            },
            scales: {
                y: {
                    beginAtZero: true
                }
            }
        }
    });
Bohs answered 27/7, 2023 at 15:16 Comment(0)
P
0

You can make line legend by changing width of legend box (for example 2px), it will be vertical line but it's looks nice too

plugins: {
   legend: {
       display: true,
       labels: {
           boxWidth: 2
       }
    }
}
Pleasing answered 7/10, 2021 at 15:21 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.