I'm using high chart API in my angular project, my issue is when I get dynamic data I successfully generate highchart but when I click on any state my drilldown function not getting hit or not working. It's required in my scenario to use highchart with drilldown so after around 5 hours of searching and development, I don't get any solution yet not from google or highcharts own forum.
Here is my code:
generateMap() {
this.Highcharts = Highcharts;
const usMapData = require("@highcharts/map-collection/countries/us/us-all.geo.json");
const usMap = Highcharts.geojson(usMapData);
this.chartOptions = {
chart: {
height: (8 / 16) * 100 + "%",
},
events: {
drilldown: function (e) {
this.methodMap(e.point.splitName);
const chart = this as any;
const mapKey = "countries/us/" + e.point.drilldown + "-all";
const mapData = require(`@highcharts/map-collection/${mapKey}.geo.json`);
const provinceData = Highcharts.geojson(mapData);
chart.addSeriesAsDrilldown(e.point, {
name: e.point.name,
data: provinceData,
dataLabels: {
enabled: true,
format: '{point.name}'
}
});
chart.setTitle(null, { text: e.point.name });
},
drillup() {
const chart = this as any;
}
},
title: {
text: ""
},
colorAxis: {
min: 0,
minColor: "#E6E7E8",
maxColor: "#417BCC"
},
mapNavigation: {
enabled: true,
buttonOptions: {
verticalAlign: "bottom"
}
},
plotOptions: {
map: {
states: {
hover: {
color: "#F8BA03"
}
}
},
series: {
point: {
events: {
click: function (e) {
}
}
}
}
},
series: [
{
animation: {
duration: 1000
},
name: "United States",
data: null,
dataLabels: {
enabled: true,
color: '#FFFFFF',
format: `{point.splitName}`,
style: {
textTransform: 'uppercase',
}
},
}
],
drilldown: {}
};
this.CurrentVendorService.getAllVendorStates().pipe(
tap(result => {
this.chart.showLoading();
usMap.forEach((el: any, i) => {
el.splitName = el.properties["hc-key"].split('-')[1].toUpperCase();
el.drilldown = el.properties["hc-key"];
const getFirstMatchedVendor = result.data.find(vendorObj => vendorObj.State_Code == el.splitName);
if (getFirstMatchedVendor) {
el.value = getFirstMatchedVendor.Vendor_Count;
}
});
this.chartOptions.series = [
{
data: usMap
}
];
this.updateFromInput = true;
this.chart.hideLoading();
},
(error: any) => {
this.gifLoader = false
this.errorMessage = error.error.message;
this.snackBar.open(this.errorMessage, '', {
duration: 2000,
});
console.log(`error on retriving all vendors state list : ${error}`);
}
),
finalize(() => {})).subscribe();
}
Component.Html
<highcharts-chart
[Highcharts]="Highcharts"
[constructorType]="chartConstructor"
[callbackFunction]="chartCallback"
[options]="chartOptions"
style="width: 100%; height: 400px; display: block;"
[(update)]="updateFromInput"
></highcharts-chart>
generateMap()
call in ngOnInit()
. If I use static data instead of service. Its works like a charm but that's not the case here. I need to work drilldown with my dynamic data. Please help me with this what I'm doing wrong.
After some hours of struggling found my own question-answer. I'm still learning and improving my attention to detail on my programming problems.
Solution
Let me spoon feed you, so you just copy-paste it and get it done.
Some globally declarations:
Highcharts;
chartConstructor = "mapChart";
chartOptions: Highcharts.Options;
updateFromInput = false;
chart;
chartCallback;
Put the below code snippet in your component constructor
this.chartCallback = chart => {
this.chart = chart;
};
Put below code in ngOnInit()
this.generateMap();
Now the main part:
generateMap() {
const self = this;
self.Highcharts = Highcharts;
const usMapData = require("@highcharts/map-collection/countries/us/us-all.geo.json");
const usMap = Highcharts.geojson(usMapData);
self.chartOptions = {
chart: {
height: (8 / 16) * 100 + "%",
events: {
drilldown: function (e: any) {
setTimeout(() => {
self.methodMap(e.point.splitName);
const mapKey = "countries/us/" + e.point.drilldown + "-all";
const mapData = require(`@highcharts/map-collection/${mapKey}.geo.json`);
const provinceData = Highcharts.geojson(mapData);
self.chart.hideLoading();
self.chart.addSeriesAsDrilldown(e.point, {
name: e.point.name,
data: provinceData,
dataLabels: {
enabled: true,
format: '{point.name}'
}
} as Highcharts.SeriesOptionsType);
self.chart.setTitle(null, { text: e.point.name });
}, 100);
},
drillup() {
self.resetMethod();
}
}
},
title: {
text: ""
},
colorAxis: {
min: 0,
minColor: "#E6E7E8",
maxColor: "#417BCC"
},
mapNavigation: {
enabled: true,
buttonOptions: {
verticalAlign: "bottom"
}
},
plotOptions: {
map: {
states: {
hover: {
color: "#F8BA03"
}
}
}
},
series: [
{
type: "map",
name: "United States",
data: null,
dataLabels: {
enabled: true,
color: '#FFFFFF',
format: `{point.splitName}`,
style: {
textTransform: 'uppercase',
}
},
}
],
drilldown: {}
};
self.CurrentVendorService.getAllVendorStates().pipe(
tap(result => {
self.chart.showLoading();
usMap.forEach((el: any, i) => {
el.splitName = el.properties["hc-key"].split('-')[1].toUpperCase();
el.drilldown = el.properties["hc-key"];
const getFirstMatchedVendor = result.data.find(vendorObj => vendorObj.State_Code == el.splitName);
if (getFirstMatchedVendor) {
el.value = getFirstMatchedVendor.Vendor_Count;
}
});
self.chartOptions.series = [
{
type: "map",
data: usMap
}
];
self.updateFromInput = true;
self.chart.hideLoading();
},
(error: any) => {
self.gifLoader = false
self.errorMessage = error.error.message;
self.snackBar.open(self.errorMessage, '', {
duration: 2000,
});
console.log(`error on retriving all vendors state list : ${error}`);
}
),
finalize(() => { })).subscribe();
}
Yes, you will customize the above business logic as per your need. But that's what I want. I've done some modifications in self.chartOptions
object and add setTimeout
.
Cheers!