【发布时间】:2019-09-23 08:30:58
【问题描述】:
我解释一下我的情况:
我正在使用 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 example
编辑 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 = 函数( _hold重绘, 类别, 原始事件 ) { var series = this.series, 图表 = series.chart, 向下钻取 = chart.options.drilldown, i = (drilldown.series || []).length, 系列选项;
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
}
});
}
});
【问题讨论】:
-
如果你能提供一些例子来说明所有变量是什么,那么阅读这段代码会很麻烦
-
@Gianmarco 没问题。我已经完成了这个代表我的问题的 JSFiddle:jsfiddle.net/bo9h0zxg/4。记住我不能修改
doDrilldown()函数。 -
我已经更新了 JSFiddle:jsfiddle.net/x7uzb85o
-
highcharts 文档中有一个关于异步钻取的部分:highcharts.com/docs/chart-concepts/drilldown 也许它可以帮助
-
谢谢,但这是为了添加动态钻取。在这个追逐中我无法帮助我:(。问题是我必须等待下钻(或任何其他操作)完成才能继续执行代码。在 JSFiddle 中可以看到真正的问题。
标签: javascript reactjs ecmascript-6 highcharts async-await