Search code examples
chartshighchartsdrilldown

Highmaps mappies with drilldown


I need to do a drilldown of mappies, from country to states: https://www.highcharts.com/maps/demo/map-pies

Actually I am using a custom map from Peru, but already with the example of USA would help me a lot showing me some solution. Is it possible to do this?


Solution

  • Thank you Wojciech Chmiel !

    I did my map with the help of your post.

    // New map-pie series type that also allows lat/lon as center option.
    // Also adds a sizeFormatter option to the series, to allow dynamic sizing
    // of the pies.
    Highcharts.seriesType('mappie', 'pie', {
      center: null, // Can't be array by default anymore
        clip: true, // For map navigation
        states: {
            hover: {
                halo: {
                    size: 5
                }
            }
        },
        dataLabels: {
            enabled: false
        }
    }, {
      getCenter: function() {
            var options = this.options,
                chart = this.chart,
                slicingRoom = 2 * (options.slicedOffset || 0);
            if (!options.center) {
                options.center = [null, null]; // Do the default here instead
            }
    		// Replace lat/lon with plotX/plotY
    		if (options.center.plotX !== undefined) {
    		  options.center = [options.center.plotX, options.center.plotY];
    		}
            // Handle dynamic size
            if (options.sizeFormatter) {
                options.size = options.sizeFormatter.call(this);
            }
            // Call parent function
            var result = Highcharts.seriesTypes.pie.prototype.getCenter.call(this);
            // Must correct for slicing room to get exact pixel pos
            result[0] -= slicingRoom;
            result[1] -= slicingRoom;
            return result;
        },
        translate: function (p) {
            this.options.center = this.userOptions.center;
            this.center = this.getCenter();
            return Highcharts.seriesTypes.pie.prototype.translate.call(this, p);
        }
    });
    
    
    var data = [
        // state, demVotes, repVotes, libVotes, grnVotes, sumVotes, winner, drilldown
            ['CAPLINA-OCONA', 729547, 1318255, 44467, 9391, 2101660, -1, 'aaa01'],
            ['CHAPARRA-CHINCHA', 116454, 163387, 18725, 5735, 304301, -1, 'aaa02'],
            ['CANETE-FORTALEZA', 1161167, 1252401, 106327, 34345, 2554240, -1, 'aaa03'],
            ['HUARMEY-CHICAMA', 380494, 684782, 29829, 9473, 1104578, -1, 'aaa04'],
            ['JEQUETEPEQUE-ZARUMILLA', 8577206, 4390272, 467370, 271047, 13705895, 1, 'aaa05'],
            ['MARANON', 1338870, 1202484, 144121, 38437, 2723912, 1, 'aaa06'],
            ['AMAZONAS', 897572, 673215, 48676, 22841, 1642304, 1, 'aaa07'],
            ['HUALLAGA', 235603, 185127, 14757, 6103, 441590, 1, 'aaa08'],
            ['UCAYALI', 282830, 12723, 4906, 4258, 304717, 1, 'aaa09'],
            ['MANTARO', 4504975, 4617886, 207043, 64399, 9394303, -1, 'aaa10'],
            ['PAMPAS-APURIMAC', 1877963, 2089104, 125306, 0, 4092373, -1, 'aaa11'],
            ['URUBAMBA-VILCANOTA', 266891, 128847, 15954, 12737, 424429, 1, 'aaa12'],
            ['MADRE DE DIOS', 189765, 409055, 28331, 8496, 635647, -1, 'aaa13'],
            ['TITICACA', 2977498, 2118179, 208682, 74112, 5378471, 1, 'aaa14']
      ],
      maxVotes = 0,
      demColor = 'rgba(74,131,240,0.80)',
      repColor = 'rgba(220,71,71,0.80)',
      libColor = 'rgba(240,190,50,0.80)',
      grnColor = 'rgba(90,200,90,0.80)';
    
    
    // Compute max votes to find relative sizes of bubbles
    Highcharts.each(data, function(row) {
      maxVotes = Math.max(maxVotes, row[5]);
    });
    
    // Build the chart
    var chart = Highcharts.mapChart('container', {
      chart: {
            animation: false, // Disable animation, especially for zooming
    		events: {
    		  load: function() {
    			addMapPie(this);
    		  },
    		  drilldown: function(e) {
    			if (!e.seriesOptions) {
    			  var chart = this,
    				//mapKey = 'countries/us/' + e.point.drilldown + '-all',
    				mapKey = 'paises/pe/' + e.point.drilldown,
    				ruta = e.point.drilldown,
    				// Handle error, the timeout is cleared on success
    				fail = setTimeout(function() {
    				  if (!Highcharts.maps[mapKey]) {
    					chart.showLoading('<i class="icon-frown"></i> Failed loading ' + e.point.name);
    					fail = setTimeout(function() {
    					  chart.hideLoading();
    					}, 1000);
    				  }
    				}, 3000);
    
    			  // Show the spinner
    			  chart.showLoading('<i class="icon-spinner icon-spin icon-3x"></i>'); // Font Awesome spinner
    
    			  // Load the drilldown map
    			  //$.getScript('https://code.highcharts.com/mapdata/' + mapKey + '.js', function() {
    			  //$.getScript('http://test1.ana.gob.pe/prueba-mappies/' + ruta + '.js', function () {
            $.getScript('https://aplicaciones01.ana.gob.pe/mappies/' + ruta + '.js', function () {
    
    				data = Highcharts.geojson(Highcharts.maps[mapKey]);
    
    				// Set a non-random bogus value
    				$.each(data, function(i) {
    				  this.value = i;
    				});
    
    				chart.series.forEach(function(s) {
    				  if (s.options.type === 'mappie') {
    					s.hide();
    				  }
    				});
    
    				// Hide loading and add series
    				chart.hideLoading();
    				clearTimeout(fail);
    				chart.addSeriesAsDrilldown(e.point, {
    				  name: e.point.name,
    				  data: data,
    				  dataLabels: {
    					enabled: true,
    					format: '{point.name}'
    				  }
    				});
    			  });
    			}
    
    			this.setTitle(null, {
    			  text: e.point.name
    			});
    		  },
    		  drillup: function() {
    			this.setTitle(null, {
    			  text: ''
    			});
    
    			this.series.forEach(function(s) {
    			  if (s.options.type === 'mappie') {
    				s.show();
    			  }
    			});
    		  }
    		}
        },
      title: {
            text: 'Resultados'
        },
    
        colorAxis: {
            dataClasses: [{
                from: -1,
                to: 0,
                color: 'rgba(244,91,91,0.5)',
                name: 'Republican'
            }, {
                from: 0,
                to: 1,
                color: 'rgba(124,181,236,0.5)',
                name: 'Democrat'
            }, {
                from: 2,
                to: 3,
                name: 'Libertarian',
                color: libColor
            }, {
                from: 3,
                to: 4,
                name: 'Green',
                color: grnColor
            }]
        },
    
      mapNavigation: {
            enabled: true	//Para el zoom (+ -)
        },
        // Limit zoom range
        yAxis: {
            minRange: 2300
        },
    
        tooltip: {
            useHTML: true
        },
    
        // Default options for the pies
        plotOptions: {
            mappie: {
                borderColor: 'rgba(255,255,255,0.4)',
                borderWidth: 1,
                tooltip: {
                    headerFormat: ''
                }
            }
        },
    
      series: [{
    		mapData: Highcharts.maps['paises/pe/aaa-all'],
            data: data,
            name: 'States',
            borderColor: '#FFF',
            showInLegend: false,
            joinBy: ['name', 'id'],
            //keys: ['id', 'demVotes', 'repVotes', 'libVotes', 'grnVotes',
            //    'sumVotes', 'value', 'pieOffset'],
    		keys: ['id', 'demVotes', 'repVotes', 'libVotes', 'grnVotes', 'sumVotes', 'value', 'drilldown'],
            tooltip: {
                headerFormat: '',
                pointFormatter: function () {
                    var hoverVotes = this.hoverVotes; // Used by pie only
                    return '<b>' + this.id + ' votes</b><br/>' +
                        Highcharts.map([
                            ['Democrats', this.demVotes, demColor],
                            ['Republicans', this.repVotes, repColor],
                            ['Libertarians', this.libVotes, libColor],
                            ['Green', this.grnVotes, grnColor]
                        ].sort(function (a, b) {
                            return b[1] - a[1]; // Sort tooltip by most votes
                        }), function (line) {
                            return '<span style="color:' + line[2] +
                                // Colorized bullet
                                '">\u25CF</span> ' +
                                // Party and votes
                                (line[0] === hoverVotes ? '<b>' : '') +
                                line[0] + ': ' +
                                Highcharts.numberFormat(line[1], 0) +
                                (line[0] === hoverVotes ? '</b>' : '') +
                                '<br/>';
                        }).join('') +
                        '<hr/>Total: ' + Highcharts.numberFormat(this.sumVotes, 0);
                }
            }
        }],
    
      drilldown: {
    		activeDataLabelStyle: {
    		  color: '#FFFFFF',
    		  textDecoration: 'none',
    		  textOutline: '1px #000000'
    		},
    		drillUpButton: {
    		  relativeTo: 'spacingBox',
    		  position: {
    			x: 0,
    			y: 60
    		  }
    		}
    	 }
    });
    
    
    function addMapPie(chart) {
      // Add the pies after chart load, optionally with offset and connectors
      Highcharts.each(chart.series[0].points, function(state) {
        //if (!state.id) {
    	if (!state.id || !state.properties) {
            return; // Skip points with no data, if any
        }
    
        var pieOffset = state.pieOffset || {},
            centerLat = parseFloat(state.properties.latitude),
            centerLon = parseFloat(state.properties.longitude);
    
        // Add the pie for this state
        chart.addSeries({
          type: 'mappie',
            name: state.id,
            zIndex: 6, // Keep pies above connector lines
            sizeFormatter: function () {
                var yAxis = this.chart.yAxis[0],
                    zoomFactor = (yAxis.dataMax - yAxis.dataMin) /
                        (yAxis.max - yAxis.min);
                return Math.max(
                    this.chart.chartWidth / 45 * zoomFactor, // Min size
                    this.chart.chartWidth / 11 * zoomFactor * state.sumVotes / maxVotes
                );
            },
          /*****/
          tooltip: {
                // Use the state tooltip for the pies as well
                pointFormatter: function () {
                    return state.series.tooltipOptions.pointFormatter.call({
                        id: state.id,
                        hoverVotes: this.name,
                        demVotes: state.demVotes,
                        repVotes: state.repVotes,
                        libVotes: state.libVotes,
                        grnVotes: state.grnVotes,
                        sumVotes: state.sumVotes
                    });
                }
            },
          data: [{
                name: 'Democrats',
                y: state.demVotes,
                color: demColor
            }, {
                name: 'Republicans',
                y: state.repVotes,
                color: repColor
            }, {
                name: 'Libertarians',
                y: state.libVotes,
                color: libColor
            }, {
                name: 'Green',
                y: state.grnVotes,
                color: grnColor
            }],
          center: {
                /*lat: centerLat + (pieOffset.lat || 0),
                lon: centerLon + (pieOffset.lon || 0)*/
    					plotX: state.plotX,
    				plotY: state.plotY
            }
        }, false);
    });
      // Only redraw once all pies and connectors have been added
      chart.redraw();
    }
    #container {
      min-width: 320px;
      max-width: 800px;
      height: 500px;
      margin: 1em auto;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/proj4js/2.3.15/proj4.js"></script>
    <script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
    <script src="https://code.highcharts.com/highcharts.js"></script>
    <script src="https://code.highcharts.com/maps/modules/map.js"></script>
    
    <script src="https://code.highcharts.com/modules/data.js"></script>
    <script src="https://code.highcharts.com/modules/drilldown.js"></script>
    
    <script src="https://code.highcharts.com/maps/modules/exporting.js"></script>
    <script src="https://code.highcharts.com/maps/modules/offline-exporting.js"></script>
    <script src="https://aplicaciones01.ana.gob.pe/mappies/AAA_psad56_simp.js"></script>
    
    <link href="https://netdna.bootstrapcdn.com/font-awesome/3.2.1/css/font-awesome.css" rel="stylesheet">
    
    <div id="container"></div>

    Here: - https://jsfiddle.net/JMarcia/w06k5zog/17/