Я объясняю свою ситуацию:
Я использую карты HighCharts. Код вызывает DrillDown (принудительно изменить карту) и после этого я должен искать во всех точках этой новой карты (следя за тем, чтобы DrillDown -doDrilldown () `- не была объявленной мной функцией, это функция собственность HighCharts)
Проблема в том, что я должен дождаться окончания DrillDown, прежде чем искать все точки этой недавно загруженной карты. Я решил это с помощью функции SetTimeOut:
var names = name.split(', ');
// Find point in countries map
this.internalChart.series[0].data.forEach(data => {
if (data.name === names[1]) {
data.doDrilldown() // FORCE DRILLDOWN. HERE I MUST WAIT
// WAITING WITH A TIMEOUT IS WORKING
setTimeout(() => {
// CODE THAT MUST BE EXECUTED ONCE MAP IS LOADED
this.state.loadedMaps.length > 0 && this.internalChart.options.drilldown.series[0].data.forEach(dataInside => {
if (dataInside.name === names[0]) {
this.setState({
province: dataInside['hc-key'],
loading: false
});
}
});
}, 1000)
}
});
Но это не правильный путь. Я не хочу всегда ждать одну секунду, я хочу, чтобы код выполнялся после завершения загрузки. Я пытался использовать async / await, но он не работает. Код, который я пробовал:
var names = name.split(', ');
// Find point in countries map
this.internalChart.series[0].data.forEach(data => {
if (data.name === names[1]) {
(async () => { await data.doDrilldown(); })() //HERE I MUST WAIT FOR DO THIS ACTION
.then(()=>{
// ONCE DONE BELOW ACTION, EXECUTE NEXT CODE:
this.internalChart.options.drilldown.series[0].data.forEach(dataInside => {
if (dataInside.name === names[0]) {
this.setState({
//country: country,
province: dataInside['hc-key'],
loading: false
});
}
});
});
}
});
Кто-нибудь знает, как я могу решить мою проблему?
Спасибо.
РЕДАКТИРОВАТЬ 1:
Я сделал пример, который представляет проблему. Его можно найти здесь: Пример JSFiddle
РЕДАКТИРОВАТЬ 2:
Мне нужно знать, когда .doDrilldown()
закончится. Эта функция загружает новую карту и ее данные, поэтому, когда новая карта и новые данные будут загружены, код должен продолжить выполнение. Я загружаю новую серию разверток, например:
// Import all map data
import(`./maps/${point['hc-key']}-all.geo`).then(mapData => {
// Set data of the map
var data = [];
mapData.default.features.forEach((element, i) => {
data.push({ 'hc-key': element.properties['hc-key'], 'name': element.properties.name, 'value': 0 });
});
// Create the new drilldown serie
try {
var drilldownSerie = {
id: point['hc-key'],
mapData: mapData.default,
data: data,
joinBy: 'hc-key',
name: mapData.default.title,
allowPointSelect: true,
borderColor: '#ffffff',
borderWidth: 1.2,
states: {
hover: {
color: this.props.geoColor
},
select: {
color: this.props.geoColor
}
},
dataLabels: {
enabled: true,
format: '{point.name}'
},
point: {
events: {
click: (event) => {
this.props.handleZoneChange(event.point);
this.setState({
selectedPoint: event.point
});
console.log("Click")
console.log(this.state.selectedPoint)
console.log("---")
}
}
}
};
// Add the new drilldown serie
this.internalChart.addSeriesAsDrilldown(point, drilldownSerie);
} catch (err) {
console.log(err.message)
}
}).catch((err) => {
console.log(err.message)
})
РЕДАКТИРОВАТЬ 3:
Вот полный код, если необходимо.
import React, { Component, Fragment } from 'react';
import PropTypes from 'prop-types';
import Highcharts from 'highcharts'
import HC_map from 'highcharts/modules/map'; //module
import HC_drilldown from 'highcharts/modules/drilldown'; //module
import HighchartsReact from 'highcharts-react-official';
import Button from '@material-ui/core/Button';
import worldMap, { dataWorldMap } from "./maps/worldMap.js";
HC_map(Highcharts); //init module
HC_drilldown(Highcharts) //init module
Highcharts.setOptions({
lang: {
drillUpText: '◁ Volver a: {series.name}'
}
});
class GeoZoneChart extends Component {
constructor(props) {
super(props);
this.state = {
loading: false,
selectedPoint: ''
};
}
geoZoneOptions = {
chart: {
map: worldMap,
events: {
drilldown: (event) => {
this.handleMapChange(event.point);
},
drillup: (event) => {
setTimeout(() => {
console.log("DU")
console.log(this.state.selectedPoint)
console.log("---")
}, 1000)
},
}
},
title: {
text: ""
},
mapNavigation: {
enabled: true,
buttonOptions: {
verticalAlign: 'bottom'
}
},
colorAxis: {
min: 0,
max: 0,
minColor: "#f7f7f7",
maxColor: "#e2e2e2"
},
tooltip: {
enabled: false
},
legend: {
enabled: false
},
exporting: { enabled: false },
series: [{
mapData: worldMap,
data: dataWorldMap,
joinBy: 'hc-key',
name: 'Mundo',
allowPointSelect: true,
borderColor: '#ffffff',
borderWidth: 1.2,
states: {
hover: {
color: this.props.geoColor
},
select: {
color: this.props.geoColor
}
},
dataLabels: {
enabled: true,
format: '{point.name}'
},
}, {
name: 'Separators',
type: 'mapline',
color: 'silver',
showInLegend: false,
enableMouseTracking: false
}],
drilldown: {
activeDataLabelStyle: {
textDecoration: 'none',
color: 'black'
},
series: []
}
}
internalChart = undefined;
handleMapChange = (point) => {
// Import all map data
import(`./maps/${point['hc-key']}-all.geo`).then(mapData => {
// Set data of the map
var data = [];
mapData.default.features.forEach((element, i) => {
data.push({ 'hc-key': element.properties['hc-key'], 'name': element.properties.name, 'value': 0 });
});
// Create the new drilldown serie
try {
var drilldownSerie = {
id: point['hc-key'],
mapData: mapData.default,
data: data,
joinBy: 'hc-key',
name: mapData.default.title,
allowPointSelect: true,
borderColor: '#ffffff',
borderWidth: 1.2,
states: {
hover: {
color: this.props.geoColor
},
select: {
color: this.props.geoColor
}
},
dataLabels: {
enabled: true,
format: '{point.name}'
},
point: {
events: {
click: (event) => {
this.props.handleZoneChange(event.point);
this.setState({
selectedPoint: event.point
});
console.log("Click")
console.log(this.state.selectedPoint)
console.log("---")
}
}
}
};
// Add the new drilldown serie
this.internalChart.addSeriesAsDrilldown(point, drilldownSerie);
// Select all map
//this.selectAll();
} catch (err) {
console.log(err.message)
}
}).catch((err) => {
console.log(err.message)
})
}
componentDidMount = () => {
// Recover and set selected zone if exist
this.props.defaultZone && this.selectRegionByName(this.props.defaultZone)
}
selectRegionByName = (name) => {
if (!name.includes(', ')) {
// Find point in global map
this.internalChart.series[0].data.forEach(data => {
if (data.name === name) {
// Select the point
data.select(true, true)
}
});
} else {
var names = name.split(', ');
// Find point in countries map
this.internalChart.series[0].data.forEach(data => {
if (data.name === names[1]) {
// Drilldown on the map
data.doDrilldown();
setTimeout(() => {
this.internalChart.series[0].data.forEach(dataInside => {
if (dataInside.name === names[0]) {
// Select the point
dataInside.select(true, true)
}
});
}, 100)
}
});
}
}
afterChartCreated = (chart) => {
this.internalChart = chart;
}
selectAll = () => {
this.internalChart.series[0].data.forEach(data => {
data.select(true, true);
});
this.props.handleSelectAllZones(this.internalChart.series[0].name);
}
componentWillUnmount = () => {
this.internalChart.series[0].data.forEach(data => {
data.select(false, false);
});
}
render() {
return (
<Fragment>
<HighchartsReact
highcharts={Highcharts}
constructorType={'mapChart'}
options={this.geoZoneOptions}
callback={this.afterChartCreated}
/>
<Button
variant="contained"
color="primary"
onClick={this.selectAll}
style={{
marginTop: -28,
padding: 0,
paddingLeft: 10,
paddingRight: 10,
float: "right",
backgroundColor: this.props.geoColor,
'&:hover': {
backgroundColor: this.props.geoDarkColor
}
}}
>
Seleccionar todo
</Button>
</Fragment >
);
}
}
GeoZoneChart.propTypes = {
handleZoneChange: PropTypes.func
};
export default GeoZoneChart;
РЕДАКТИРОВАТЬ 4:
Я хочу добиться, чтобы код выполнялся после doDrilldown()
. Моя проблема заключается в том, что когда я выполняю детализацию точки (point.doDrilldown()
), код загружает карту асинхронно, но код продолжает выполняться (карта еще не загружена) и завершается ошибкой (если я не использую setTimeout
). Поэтому мне нужно дождаться окончания doDrilldown()
, завершить загрузку асинхронной карты и продолжить выполнение кода.
Код @WojciechChmiel (модифицированный, я добавил асинхронную загрузку, но он не работает), я пытался добиться этого:
// Функция @WojciechChmiel изменена
(функция (H) {
H.Point.prototype.doDrilldown = function (
_holdRedraw,
категория,
originalEvent
) {
var series = this.series,
chart = series.chart,
Детализация = chart.options.drilldown,
i = (drilldown.series || []). длина,
seriesOptions;
if (!chart.ddDupes) {
chart.ddDupes = [];
}
while (i-- && !seriesOptions) {
if (
drilldown.series[i].id === this.drilldown &&
chart.ddDupes.indexOf(this.drilldown) === -1
) {
seriesOptions = drilldown.series[i];
chart.ddDupes.push(this.drilldown);
}
}
// Fire the event. If seriesOptions is undefined, the implementer can check
// for seriesOptions, and call addSeriesAsDrilldown async if necessary.
H.fireEvent(chart, 'drilldown', {
point: this,
seriesOptions: seriesOptions,
category: category,
originalEvent: originalEvent,
points: (
category !== undefined &&
this.series.xAxis.getDDPoints(category).slice(0)
)
}, function(e) {
var chart = e.point.series && e.point.series.chart,
seriesOptions = e.seriesOptions;
if (chart && seriesOptions) {
if (_holdRedraw) {
chart.addSingleSeriesAsDrilldown(e.point, seriesOptions);
} else {
chart.addSeriesAsDrilldown(e.point, seriesOptions);
}
}
// My code should go here?
else {
console.log(e.point)
// Import all map data
import(`./maps/${e.point['hc-key']}-all.geo`)
.then(mapData => {
// Set data of the map
var data = [];
mapData.default.features.forEach((element, i) => {
data.push({ 'hc-key': element.properties['hc-key'], 'name': element.properties.name, 'value': 0 });
});
// Create the new drilldown serie
try {
var drilldownSerie = {
id: e.point['hc-key'],
mapData: mapData.default,
data: data,
joinBy: 'hc-key',
name: mapData.default.title,
allowPointSelect: true,
borderColor: '#ffffff',
borderWidth: 1.2,
states: {
hover: {
color: this.props.geoColor
},
select: {
color: this.props.geoColor
}
},
dataLabels: {
enabled: true,
format: '{point.name}'
},
point: {
events: {
click: (event) => {
this.props.handleZoneChange(event.point);
this.setState({
selectedPoint: event.point['hc-key']
});
}
}
}
};
// Add the new drilldown serie
this.internalChart.addSeriesAsDrilldown(e.point, drilldownSerie);
// Select all map
//this.selectAll();
} catch (err) {
console.log(err.message)
}
}).catch((err) => {
console.log(err.message)
})
}
});
console.log('After drilldown');
}
})(Highcharts);
РЕДАКТИРОВАТЬ 5:
Это главная проблема:
this.internalChart.series[0].data.forEach(data => { // FIND A POINT IN ALL MAP
if (data.name === SelectedName1) { // IF A POINT IS FOUND...
data.doDrilldown() // DRILLDOWN TO CHILD MAP
// HERE I MUST WAIT. WHEN DODRILLDOWN ENDS, CONTINUE WITH BELOW CODE
// UNDERSTANDING "ENDS" WHEN NEW MAP AND ITS DATA IS LOADED AND READY
this.internalChart.options.drilldown.series[0].data.forEach(dataInside => { // FOR EACH POINT OF NEW MAP (DRILLDOWN/CHILD MAP)
if (dataInside.name === SelectedName2) { // IF A POINT IS FOUND
this.setState({ province: dataInside['hc-key'] }); // CHANGE STATE
}
});
}
});