1、用来干什么:该例子主要用来描述在react项目中,如何用echarts的绘制功能制作一个动态获取接口数据的地图
2、会收获什么:将会介绍百度API的使用与注意事项,echarts配合百度地图API绘制点图,点浮动时展示详细数据
3、示例
效果如图所示(关于具体的样式可以自行设计)
1)接入百度API
需要申请百度API开发者模式
https://lbsyun.baidu.com/index.php?title=jspopularGL
按步骤操作即可
在react的index.html中引入API
换成自己的ak,此时注意请求为https(http协议也行),查看一下setupProxy.js文件target网址的传输协议是否与百度api的相同,避免跨域。(以target里的为准,改动百度api的)
2)引入echarts绘制点
基于官网例子进行绘制
https://echarts.apache.org/examples/zh/editor.html?c=effectScatter-bmap
点的数据与位置从后台获取,在页面加载前完成绘制
let bReady = false;
let context = "";
let sLastDateInputofDoAjaxGetTooltip = "";
class Position extends React.Component {
state = {
data: [],
geoCoordMap: {},
}
componentDidMount() {
this.getPositionData()
}
render() {
return (
<div className="map">
<div id="main" style={{ width: '1800px', height: '1200px' }} />
</div>
)
}
}
export default Position;
//地图数据接口
getPositionData() {
mirrorService.getPosition().then(res => {
if (res.code === 200) {
console.log("返回的数据为", res);
//拼接相应的数组
let newArr = res.distributions
let data = []
newArr.map(item => {
data.push({name:item.district, value: item.nums, province: item.province, city: item.city})
})
let geoCoordMap = {}
newArr.map(item => {
geoCoordMap[item.district]=[item.lng, item.lat]
})
//数据与地理位置的准备
this.setState({
data, //数组,[省:,市: ,区: ,该区总数量: ]
geoCoordMap, //对象, {区: 区的经纬度数组}
})
//绘制地图
this.drawMap()
}
}).catch(error => {
error && message.error(error);
})
}
绘制地图函数
drawMap() {
var chartDom = document.getElementById('main');
var myChart = echarts.init(chartDom);
//let that = this
var option;
option = {
title: {
text: '全国主要城市',
subtext: '设备分布',
left: 'center'
},
tooltip: {
trigger: 'item',
//triggerOn: "click",
formatter: function (params, ticket, callback) {
//优化显示,防止闪烁
console.log(params.data);
if (sLastDateInputofDoAjaxGetTooltip === params.data.name) {
return context;
} else {
//鼠标触碰圆点时,调用接口查询该区的详细数据
mirrorService.getDetailPosition(params.data.province, params.data.city, params.data.name).then(res => {
bReady = false;//设置状态为不可用
if(sLastDateInputofDoAjaxGetTooltip === params.data.name){
bReady = true;
return;
}else {
sLastDateInputofDoAjaxGetTooltip = params.data.name;
}
if (res.code === 200) {
console.log("返回的详情数据", res);
context = `${params.data.name}的设备有</br>`
res.distributions.forEach(item => {
context += `位置:${item.address} 数量:${item.nums}</br>`;
});
let itv = setInterval(function () {
if(bReady === true){
callback(ticket, context);
window.clearInterval(itv);//停止检查
}
}, 100);
bReady = true;//不管有没有内容,状态都要改回去
}
})
}
return "数据查询中……";
},
},
bmap: {
center: [125.114129, 35.550339],
zoom: 5,
roam: true,
mapStyle: {
styleJson: [{
"featureType": "water",
"elementType": "geometry",
"stylers": {
"visibility": "on",
"color": "#ccd6d7ff"
}
}, {
"featureType": "green",
"elementType": "geometry",
"stylers": {
"visibility": "on",
"color": "#dee5e5ff"
}
},
//.....数据量太多,可以自行设计
//[百度地图个性化设计](https://lbsyun.baidu.com/customv2/editor/6e940a9e621efcb9cff05e4492936858)
]
}
},
series: [
{
name: '设备',
type: 'scatter',
coordinateSystem: 'bmap',
data: this.convertData(this.state.data),
symbolSize: function (val) {
return 15;
},
encode: {
value: 2
},
label: {
normal: {
show: true,
formatter: this.showNumber(this.state.data)
},
formatter: '{c}',
position: 'right',
show: false
},
emphasis: {
label: {
show: true
}
},
},
{
name: 'Top 5',
type: 'effectScatter',
coordinateSystem: 'bmap',
data: this.convertData(
this.state.data
.sort(function (a, b) {
return b.value - a.value;
})
.slice(0, 5)
),
symbolSize: function (val) {
return 20;
},
encode: {
value: 2
},
showEffectOn: 'render',
rippleEffect: {
brushType: 'stroke'
},
label: {
normal: {
show: true,
formatter: this.showNumber(this.state.data),
},
formatter: '{b}',
position: 'right',
show: true
},
itemStyle: {
shadowBlur: 10,
shadowColor: '#333'
},
emphasis: {
scale: true
},
zlevel: 1
}
]
};
option && myChart.setOption(option);
}
//显示圆点数字
showNumber(data) {
let numbers = []
if (data.length != 0) {
numbers = data.map(item => item.value)
}
return numbers
}
//数据的处理函数
convertData(data) {
var res = [];
for (var i = 0; i < data.length; i++) {
var geoCoord = this.state.geoCoordMap[data[i].name];
if (geoCoord) {
res.push({
name: data[i].name,
value: geoCoord.concat(data[i].value),
city: data[i].city,
province: data[i].province
});
}
}
return res;
};
问题汇总
1、tooltip中formatter的使用
此函数可以按照需要浮动展示数据,也可以在数据量较大或者降低耦合时,对相应数据的接口调用,此例中圆点展示区的总数,点浮动调用查询此区的详细数据。
建议使用回调函数function (params, ticket, callback) {}的格式,配合callback做到异步的效果
2、formatter内接口函数的调用
2.1 对于获取的数据直接与当前的数据进行字符拼接等操作,然后返回即可,所以请求数据不必保存到state
2.2 如果在formatter内直接实现接口函数,则不必考虑this指向问题,如果在外部实现再内部调用,可能会出现this丢失的问题,需要
在option外提前保存this,一般写为
let that = this
...
formatter: function (params, ticket, callback) {
...
that.函数(参数)
}
2.3 对于不同的请求方式,注意相应写法要求即可,实例中使用了fetch方式,jQuery Ajax,promise等异步请求方式都可以实现
3.在小圆圈内移动鼠标时,加载的内容会出现闪烁或再次加载
详细可参考https://blog.csdn.net/fanpeizhong/article/details/80274740?spm=1001.2014.3001.5502