Search code examples
sortinghighchartsstacked-chart

Highcharts sorted stacked columns : position of labels


I need to sort a categorized stacked columns in Highcharts (sorting categories by totals and in each column, sorting series to ascending/descending).

I found the topic Highcharts: Sort column stack order to ascending that seems to be a great solution to achieve that.

The result is visible here : https://jsfiddle.net/vegaelce/0ye9objs/

The two things I would like to conclude are:

1/ place correctly the value labels (they don't follow the series sorting). I tried to change the datalabel y position with : stackedPoint.dataLabel.y = plotY; without success

2/ make functional the click on legend (when you clic on Jane for instance it does not result the expected behaviour). If it's not possible : just disable the click and let available the hover

Thanks


Solution

  • I've updated the example a bit. There is an additional sortStacks function, which is called on chart load. Moreover, data-labels positions are corrected by using attr method and hidden series are ignored in the sortSeries function.

    function sortStacks(chart) {
      const series = chart.series;
      const newSeries = [];
      let sortedPoints;
    
      series.forEach(s => {
        sortedPoints = [...s.points].sort((p1, p2) => p2.total - p1.total);
        s.setData(sortedPoints.map(p => p.y), false);
      });
    
      chart.xAxis[0].setCategories(sortedPoints.map(p => p.category));
    }
    
    function sortSeries(chart) {
      const series = chart.series;
      const yStart = chart.plotHeight;
    
      series[0].points.forEach((point, index) => {
        const points = series.map(s => s.points[index]);
        points.sort((p1, p2) => p2.y - p1.y);
        let lastY = 0;
    
        points.forEach((p, i) => {
          if (!p.series || !p.series.visible) {
            return false;
          }
    
          const newY = lastY ?
            lastY - p.shapeArgs.height :
            yStart - p.shapeArgs.height;
    
          lastY = newY;
    
          p.graphic.attr({
            y: newY
          });
    
          p.dataLabel.attr({
            y: newY + p.shapeArgs.height / 2 - p.dataLabel.height / 2
          });
          p.tooltipPos[1] = newY;
        });
      });
    }
    
    Highcharts.chart('container', {
      chart: {
        ...,
        events: {
          load: function() {
            sortStacks(this);
          },
          render: function() {
            sortSeries(this);
          }
        }
      },
      ...
    });
    

    Live demo: http://jsfiddle.net/BlackLabel/8fp96u1r/

    API Reference: https://api.highcharts.com/class-reference/Highcharts.Series#setData