1
votes

This question is a possible duplicate of Show N/A in datalabels, when value is null - Highcharts

and dataLabels for bar chart in Highcharts not displaying for null values in 3.0.8

but workarounds suggested have stopped working in version 5.0.7 of highcharts.

formatter: function () {
    if (this.y == null) {
        var chart = this.series.chart,
            categoryWidth = chart.plotWidth / chart.xAxis[0].categories.length,
            offset = (this.point.x) * categoryWidth + categoryWidth / 2,
            text = chart.renderer.text('N/A', -999, -999).add();

        text.attr({
            x: chart.plotLeft + offset - text.getBBox().width / 2, //center label
            y: chart.plotTop + chart.plotHeight - 8 // padding
        });

    } else {
        return this.y;
    }
}

The issue seems to be still open on github: https://github.com/highcharts/highcharts/issues/2899

http://jsfiddle.net/90amxpc1/4/

Is there a possible workaround to show something like "N/A" using formatter function or chart.renderer method for null values in column charts?

1

1 Answers

4
votes

In new version of Highcharts formatter is not called for null points anymore.

A hacky way to make your code works as it worked before is to wrap drawDataLabels() method and temporary assign some value to null points, e.g. 0, and in formatter check if point.isNull is true.

var H = Highcharts;

H.wrap(H.Series.prototype, 'drawDataLabels', function (p) {
  this.points.forEach(point => {
    if (point.y === null) {
      point.y = 0;
    }
  });

  p.call(this);

  this.points.forEach(point => {
    if (point.isNull) {
      point.y = null;
    }
  });
});

In data labels config:

 dataLabels: {
            formatter: function () {
                if (this.point.isNull) {
                    var chart = this.series.chart,
                        categoryWidth = chart.plotWidth / chart.xAxis[0].categories.length,
                        offset = (this.point.x) * categoryWidth + categoryWidth / 2,
                        text = chart.renderer.text('N/A', -999, -999).add();

                    text.attr({
                        x: chart.plotLeft + offset - text.getBBox().width / 2, //center label
                        y: chart.plotTop + chart.plotHeight - 8 // padding
                    });

                    return false;
                } else {
                    return this.y;
                }
            },

example: http://jsfiddle.net/xnxpwt67/

It works, but it is not an elegant and efficient solution. Much better would be drawing labels for nulls, e.g. on load event.

    chart: {
  type: 'column',
  events: {
    load: function() {
      const categoryWidth = this.plotWidth / this.xAxis[0].categories.length;

      this.series[0].points.forEach(point => {
        if (point.y === null) {
          const offset = point.x * categoryWidth + categoryWidth / 2;
          const text = this.renderer.text('N/A', -999, -999).add();

          text.attr({
            x: this.plotLeft + offset - text.getBBox().width / 2,
            y: this.plotTop + this.plotHeight - 8
          });
        }
      })
    }
  }
},

example: http://jsfiddle.net/xnxpwt67/1/