Chartjs-plugin-datalabels: Align Automatic data label in line chart or line type in bar chart

Created on 21 May 2018  路  2Comments  路  Source: chartjs/chartjs-plugin-datalabels

Hello everyone! I'm encountering a small problem called 'align', it's giving me a headache to resolve and I would like the help of the guys or a possible improvement.

Well, my situation is as follows, I have a set of values, but some of them are close values and one stands on top of the other, so my idea was to align one for 'start' and the other the opposite and vice versa, and by default the center.

But I am not able to do this calculation, it follows my code attempt:

    this.options.plugins.datalabels.align = function (context) {
      self.lastDataLabel.pos = 'center'
      if (context.dataIndex === self.lastDataLabel.dtIndex ||
        (context.dataset.data[context.dataIndex] - 10 > context.dataset.data[self.lastDataLabel.dtIndex])
      ) {
        self.lastDataLabel.pos = 'start'
      } else if (context.dataset.data[context.dataIndex] - 10 < context.dataset.data[self.lastDataLabel.dtIndex]) {
        self.lastDataLabel.pos = 'end'
      }
      self.lastDataLabel.value = context.dataset.data[context.dataIndex]
      self.lastDataLabel.dtIndex = context.dataIndex
      self.lastDataLabel.dtsIndex = context.datasetIndex
      return self.lastDataLabel.pos
    }

My dataset:

"datasets": [
    {
        "label": "CAND. A",
        "backgroundColor": "rgb(8, 81, 156)",
        "borderColor": "rgb(8, 81, 156)",
        "type": "line",
        "pointRadius": "5",
        "pointHoverRadius": "5",
        "fill": false,
        "hidden": false,
        "data": [
            "10",
            "20",
            "30",
            "40"
        ]
    },
    {
        "label": "CAND. B",
        "backgroundColor": "rgb(166, 54, 3)",
        "borderColor": "rgb(166, 54, 3)",
        "type": "line",
        "pointRadius": "5",
        "pointHoverRadius": "5",
        "fill": false,
        "hidden": false,
        "data": [
            "20",
            "20",
            "25",
            "18"
        ]
    },
    {
        "label": "CAND. C",
        "backgroundColor": "rgb(0, 109, 44)",
        "borderColor": "rgb(0, 109, 44)",
        "type": "line",
        "pointRadius": "5",
        "pointHoverRadius": "5",
        "fill": false,
        "hidden": false,
        "data": [
            "70",
            "60",
            "45",
            "42"
        ]
    }
],
"labels": [
    "AGO",
    "SET",
    "OUT",
    "NOV"
]

Here's a print of how it's getting:
image

And how I wish it were:
image

My config:
"chart.js": "2.7.2",
"chartjs-plugin-datalabels": "0.3.0",

support

Most helpful comment

@renatodolce sorry for the late reply: unfortunately there is nothing built-in to prevent label to overlap. I'm currently looking how to implement this feature, but that's not trivial.

As a (very limited) workaround (and if you don't have more that 3 datasets), you can still script the align option to detect where the label should be positioned. Something similar to what I did in this example:

align: function(ctx) {
    var idx = ctx.dataIndex;
    var val = ctx.dataset.data[idx];
    var datasets = ctx.chart.data.datasets;
    var min, max, i, ilen, ival;

    min = max = val;

    for (i = 0, ilen = datasets.length; i < ilen; ++i) {
        if (i === ctx.datasetIndex) {
            continue;
        }

        ival = datasets[i].data[idx];
        min = Math.min(min, ival);
        max = Math.max(max, ival);

        if (val > min && val < max) {
            return 'center';
        }
    }

    return val <= min ? 'start' : 'end';
}

you can see it in action in this jsfiddle. It's not ideal, but I think it works in most use cases where the number of datasets is <= 3.

All 2 comments

@renatodolce sorry for the late reply: unfortunately there is nothing built-in to prevent label to overlap. I'm currently looking how to implement this feature, but that's not trivial.

As a (very limited) workaround (and if you don't have more that 3 datasets), you can still script the align option to detect where the label should be positioned. Something similar to what I did in this example:

align: function(ctx) {
    var idx = ctx.dataIndex;
    var val = ctx.dataset.data[idx];
    var datasets = ctx.chart.data.datasets;
    var min, max, i, ilen, ival;

    min = max = val;

    for (i = 0, ilen = datasets.length; i < ilen; ++i) {
        if (i === ctx.datasetIndex) {
            continue;
        }

        ival = datasets[i].data[idx];
        min = Math.min(min, ival);
        max = Math.max(max, ival);

        if (val > min && val < max) {
            return 'center';
        }
    }

    return val <= min ? 'start' : 'end';
}

you can see it in action in this jsfiddle. It's not ideal, but I think it works in most use cases where the number of datasets is <= 3.

I'm not sure that tweaking the align option to prevent labels to overlap would work in many cases, especially if there is more than 3 datasets. Prevent overlap by moving the label position is already reported in #72 (and a few others), so I'm closing this issue.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

danielwstrimpel picture danielwstrimpel  路  4Comments

ericsvendsen picture ericsvendsen  路  15Comments

stockiNail picture stockiNail  路  12Comments

erenesto picture erenesto  路  8Comments

boriskogan81 picture boriskogan81  路  4Comments