0
votes

I am working with a pair of PIE charts. Each cover the same theme of data and can have the same slice items. However, not all legend items appear in both PIEs all the time. I have looked at several solutions to this (this one being the closest). However, it breaks when one of the PIEs does not have all the slices that the other has.

Test case jsFiddle shows that the first PIE does not have the 'Engineering' slice while the second PIE does. But, this means that the item does not show up in the legend. How can I get all unique entries in each PIE's legend in one single legend?

This is the current callback function (notice it is based on series[0]):

  $(chart.series[0].data).each(function(i, e) {
    e.legendItem.on('click', function(event) {
      var legendItem = e.name;

      event.stopPropagation();

      $(chart.series).each(function(j, f) {
        $(this.data).each(function(k, z) {
          if (z.name == legendItem) {
            if (z.visible) {
              z.setVisible(false);
            } else {
              z.setVisible(true);
            }
          }
        });
      });

    });
  });
1

1 Answers

1
votes

You need to get an array which contains unique points' names (this will be a legend), then iterate through the items in the legend and set appropriate events.

My proposition below is sufficient for your test case (e.g. it does not take into the consideration linked series).

Here's a wrapper on getAllItems() method which delivers items for a legend, I get the unique points' names here (the loop looking for a unique name might be optimised but for this case the difference would rather be negligible) :

Highcharts.wrap(Highcharts.Legend.prototype, 'getAllItems', function (p) {              
            if (!this.options.mergedPieItems) {
                return p.call(this);
            }

            var allItems = [],
                uniquePieNames = [];

            this.chart.series.forEach(function (series) {
                var i,
                    len,
                    point;

                if (series.type === 'pie') {
                    for (i = 0, len = series.data.length; i < len; i++) {
                        point = series.data[i];

                        if (uniquePieNames.indexOf(point.name) === -1) {
                            uniquePieNames.push(point.name);
                            allItems.push(point);
                        }
                    }
                } else {
                    allItems.push(series);
                }
            });

            return allItems;
        });

Here I set events, this is almost the copy of the code you attached

load: function () {
                    if (this.options.legend.mergedPieItems) {
                        var series = this.series;

                        this.legend.allItems.forEach(function (item) {
                            if (item.series) {
                                item.legendItem.element.onclick = function (e) {
                                    e.stopPropagation();

                                    series.forEach(function (series) {
                                        series.data.forEach(function (point) {
                                            if (point.name === item.name) {
                                                point.setVisible(!point.visible);
                                            }
                                        });
                                    });
                                };
                            }
                        }); 
                    }
                }

Enabling wrappers and callback, in case if the legend should behave as is not wrapped.

legend: {
            enabled: true,
            mergedPieItems: true
        },

Your example: http://jsfiddle.net/fjLao4nr/2/

Example with series different than pie: http://jsfiddle.net/fjLao4nr/

Color of slices will not match for such pies - but this can be achieved by setting the same color for the points. Also, when the item in the legend is hovered, only the point in one series is highlighted - this can be achieved by setting state of the a point on a mouseouver/mouseout event (similar as it is done in the load callback).