Search code examples
highchartshighmaps

Combine PieChart with Map


I'm trying to plot PieCharts over a map using Highcharts and Highmaps. I didn't find anything specific on this on the documentation neither I found examples on Web. I'm following this demo where I can draw mapbubles over the map. I would like to do exactly the same but with pie charts instead of map bubbles.

So far what I have is:

   $('.map').slideDown().highcharts('Map', {
        title: {
            text: null
        },
        mapNavigation: {
            enabled: true
        },
        series: [{ // First series, plot the map
            mapData: result,
            name: 'Random data'             
        }, { // Second serie, plot a pie chart on specific coordinates
            type: 'pie',
            dataLabels: {
                enabled: true
            },
            name: 'Cities',
            data: [{
                lat: -21.194476, 
                lon: -43.794456,
                y: 100,
                name: 'Barbacena'
            }, {
                lat: -21.194476, 
                lon: -43.794456,
                y: 50,
                name: 'Barbacena'
            }],
            maxSize: '12%'
        }],
        legend: {
            layout: 'vertical',
            align: 'left',
            verticalAlign: 'bottom'
        },
    });

The pie chart is plotted but it totally ignores the map. It is not draged around when I drag the map.

So, is there a built-in way in Highcharts of doing that?

Thanks in advance


Solution

  • I've written a wrapper which allows to draw a pie chart according to lat/lon. More information on lat/lon on the website here.

    The first step is to parse lat/lon to x/y which can be achieved by chart.fromLatLonToPoint(). After that it is needed to set a center of a pie chart. Center accepts pixels, so x/y values should be translate to pixels - it can be achieved with axis.toPixels() method.

    Highcharts.wrap(Highcharts.seriesTypes.pie.prototype, 'getCenter', function(p) {
    var centerOptions = this.options.center,
      centerLatLonOptions = this.options.centerLatLon,
      chart = this.chart,
      slicedOffset = this.options.slicedOffset,
      pos,
      lat,
      lon;
    
    if (centerLatLonOptions && chart.fromLatLonToPoint) {
      pos = chart.fromLatLonToPoint({
        lat: centerLatLonOptions[0],
        lon: centerLatLonOptions[1]
      });
    
      centerOptions[0] = chart.xAxis[0].toPixels(pos.x, true) - 2 * slicedOffset;
      centerOptions[1] = chart.yAxis[0].toPixels(pos.y, true) - 2 * slicedOffset;
    }
    
    return p.call(this);
    });
    

    Re-center pie charts needs to be called on redraw, it allows a pie chart to stay in the correct position.

    redraw: function() {
          if (!this.centeringPies) {
            this.centeringPies = true;
    
            this.series.forEach(function(serie) {
              if (serie.type === 'pie' && serie.options.centerLatLon) {
                serie.update({
                  center: serie.getCenter()
                }, false);
              }
            });
    
            this.redraw(false);
            this.centeringPies = false;
          }
        },
    

    Example: https://jsfiddle.net/qqyLb7qx/1/

    A thing to do is to check if a pie chart is inside a plot area - and if it's not, hide it.