Search code examples
reactjshighcharts

How to redraw a chart in render function avoiding eternal looping in Highcharts library


I'm adjusting some values for dataLabels in a render function, but I need to redraw a chart to apply these changes. Here's my render function:

render: function () {
  const points = this.series[0].points;
          
  for (var i = 0; i < points.length; i++) {

    if (i < points.length - 1) {
      const dataLabel1 = (points[i] as any).dataLabel
      const dataLabel2 = (points[i + 1] as any).dataLabel

      if ((dataLabel1.x + dataLabel1.width) >= dataLabel2.x) {

        dataLabel1.attr({
          y: dataLabel1.y - (dataLabel1.height + 2),
          fill: points[i].color
        });
 
      }
    }
  }
}

But nothing changes until, for example, the width of a chart is changed. So, I suppose that changes needs the chart to be rendered again to be applied.

I tried to redraw my chart like this:

render: function () {
  const points = this.series[0].points;
          
  for (var i = 0; i < points.length; i++) {

    if (i < points.length - 1) {
      const dataLabel1 = (points[i] as any).dataLabel
      const dataLabel2 = (points[i + 1] as any).dataLabel

      if ((dataLabel1.x + dataLabel1.width) >= dataLabel2.x) {

        dataLabel1.attr({
          y: dataLabel1.y - (dataLabel1.height + 2),
          fill: points[i].color
        });
 
      }
    }
  }

  this.redraw();
}

But this leads to the infinite render loop. How can I redraw a chart here or is there any other way to apply the changes?


Solution

  • You can conditionally redraw the chart, for example:

    let allowChartRedraw = true;
    
    Highcharts.chart('container', {
      chart: {
        events: {
          render: function() {
            if (allowChartRedraw) {
              allowChartRedraw = false;
    
              this.redraw();
    
              allowChartRedraw = true;
            }
          }
        }
      },
      ...
    });
    

    However, you probably don't need to do that. Using the attr method for data labels should be enough, please check this live example: https://jsfiddle.net/BlackLabel/tyL96pxd/