先看最终效果图。
该地图显示的是公司在各个市区的项目数量,然后统计其数量,并以热点的方式显示在地图上,使使用者能直观的看到公司项目分布及数量情况。
现将程序制作过程中的问题及注意情况分解如下:
1.数据格式。
看了echarts网站的示例可知,要展示数据,需要有2个数据字段,分别是data与geoCoordMap,geoCoordMap是一个地名+坐标的数据,为了获取坐标,我做了一个程序,用于自动化获取城市坐标,并写入到数据库里面。
#获取城市经纬度
def Get_Urt(address):
# 以get请求为例http://api.map.baidu.com/geocoder/v2/?address=百度大厦&output=json&ak=你的ak
queryStr = '/geocoding/v3/?address=%s&output=json&ak=你的ak' % address#你的ak指的是自己去百度申请的ak
#由于URL里面含有中文,所以需要用parse.quote进行处理,然后返回最终可调用的url
url = parse.quote("http://api.map.baidu.com"+queryStr, safe="/:=&?#+!$,;'@()*[]")
res = requests.get(url=url)
res_json = json.loads(res.text)
jwd_res = res_json['result']['location']
#print(jwd['lng'],'-',jwd['lat'])
return jwd_res
if __name__ == '__main__':
#print(jwd['lng'],'-',jwd['lat'])
city_list = City_Jwd_Sql()
#使用循环,查出城市的经纬度
for x in range(len(city_list)):
cityname = city_list[x][1]
cityno = city_list[x][0]
jwd = Get_Urt(cityname)
lng = jwd['lng']
lat = jwd['lat']
#print(cityno,cityname,jwd['lng'],'-',jwd['lat'])
#将查询到的城市经纬度插入到对应的记录行中
status = Update_City_Jwd(lng,lat,cityno,cityname)
print(cityname,status)
运行完程序后,我数据库表的字段内容如下。xmsl是数量,lng经度,lat纬度。这样就能把data与geoCoordMap要的数据都做到一张表里面了。
有了数据来源之后,需要对数据进行整理,按照echarts的要求,把数据整理成规定的格式。
后端脚本如下,数据返回的是一个字典格式。
#map地图首页
@server.route('/map',methods=['GET'])#
def map_web():
#print('map')
return render_template('map.html')
#地图数据
@server.route("/mdt",methods=['GET'])
def mdt():
city_sql = sql_echarts.City_Project_Shu_Sql()
print({'data':city_sql})
return jsonify({'data':city_sql})
print出来的字典数据格式如下:
2.前端使用后端返回的数据
后端返回了一个data字典,前端要怎么调整格式,使其满足echarts的格式要求呢?这里我参考了文哥在知乎的一个视频,地址是:使用flask加echarts5.x进行地图大屏显示,值得观看 - 知乎 有兴趣的可以看下。
$(function () {
$.ajax({
url:'/mdt',
type:'get',
success:function (cityres) {
var data = new Array();
var geoCoordMap = new Object();
for (var i = 0;i < cityres.data.length; i++){
data[i] = {
name : cityres.data[i].cityname,
value : cityres.data[i].xmsl
};
geoCoordMap[cityres.data[i].cityname] = [cityres.data[i].lng,cityres.data[i].lat];
};
const convertData = function (data) {
var res = [];
for (var i = 0; i < data.length; i++) {
var geoCoord = geoCoordMap[data[i].name];
if (geoCoord) {
res.push({
name: data[i].name,
value: geoCoord.concat(data[i].value),
visualMap: true
});
}
}
return res;
};
...//后续的脚本
}
其实在看文哥视频之前,我虽然能把data与geoCoordMap按照格式生成出来,通过console.log也能显示出合规的数据,但是地图上却一直无法把我的数据显示出来,看了文哥的视频后我发现,他把前端的网页脚本调整了一下顺序。
示例文件是先生成了data与geoCoordMap,然后在option中引用这2个变量。但是我在我的代码中同样的操作的时候,地图上就是显示不出数据,后来发现文哥的视频代码是把地图的一些样式设置脚本先显示出来,然后在get到数据后,再把后续的数据引用及整理脚本带出来(因此有2个myChart.setOption())。我把的前端代码全部贴出来,大家可以对照echarts的代码来看。
<!--
THIS EXAMPLE WAS DOWNLOADED FROM https://echarts.apache.org/examples/zh/editor.html?c=effectScatter-bmap
-->
<!DOCTYPE html>
<html style="height: 100%">
<head>
<meta charset="utf-8">
<!-- 去除百度logo -->
<style type="text/css">
.anchorBL{
display:none
}
</style>
</head>
<body style="height: 100%; margin: 0">
<div id="container" style="height: 100%"></div>
<script type="text/javascript" src="../static/js/echarts.js"></script>
<script type="text/javascript" src="../static/js/china.js"></script>
<script type="text/javascript" src="../static/js/vintage.js"></script>
<script type="text/javascript" src="../static/js/jquery.min.js"></script>
<script type="text/javascript" src="../static/js/bmap.js"></script>
<script src="http://api.map.baidu.com/api?v=2.0&ak=你的ak"></script>
<script type="text/javascript">
var dom = document.getElementById("container");
var myChart = echarts.init(dom);
var app = {};
var option,option_a,option_b;
//第一次进行myChart.setOption
myChart.setOption({
title: {
text: 'XX集团项目所在地热图',
//subtext: 'data from PM25.in',
//sublink: 'http://www.pm25.in',
left: 'center'
},
tooltip: {
trigger: 'item'
},
bmap: {
//center: [108.3734508258, 22.8226066012],//南宁市为中心
map: "china",
center: [108.9464655506, 37.2472688166],//西安市为中心
zoom: 5,
roam: true,
label: {
emphasis: {
show: false
}
},
itemStyle: {
normal: {
areaColor: "#0d0059",
borderColor: "#389dff",
borderWidth: 1, //设置外层边框
shadowBlur: 5,
shadowOffsetY: 8,
shadowOffsetX: 0,
shadowColor: "#01012a"
},
emphasis: {
areaColor: "#184cff",
shadowOffsetX: 0,
shadowOffsetY: 0,
shadowBlur: 5,
borderWidth: 0,
shadowColor: "rgba(0, 0, 0, 0.5)"
}
}
},
//设置散点圈颜色
visualMap: {
show:true,
type: 'piecewise',// 定义为分段型piecewise,如定义为连续型则 continuous ,
splitNumber:6,
pieces: [ //自定义『分段式视觉映射组件(visualMapPiecewise)』的每一段的范围,以及每一段的文字,以及每一段的特别的样式
//{min: 0, label: 'aaaa'}, // 不指定 max,表示 max 为无限大(Infinity)。
{min: 1, max: 10, label: '项目数:1-10个', color: '#006400'}, // 表示 value 1至10 的情况(即区间)。
{min: 11, max: 50, label: '项目数:11-50个', color: '#FF8C00'},
{min: 51, max: 100, label: '项目数:51-10个', color: '#b1a0c7'},
{min: 101, max: 200, label: '项目数:101-200个', color: '#538dd5'},
//{value: '50', label: '11-50', color: '#fa7d82'}, // 表示 value 等于 50 的情况(即单个数值)。
{min: 201 , label: '项目数:>=200个',color: '#ff0000'} // 不指定 min,表示 min 为无限大(-Infinity)。
],
min: 0,
max: 100,
minOpen:true, //界面上会额外多出一个『< min』的选块
maxOpen:true,
splitNumber: 5,
itemSymbol:"circle", //默认的图形。可选值为: 'circle', 'rect', 'roundRect', 'triangle', 'diamond', 'pin', 'arrow'
hoverLink:true,//鼠标悬浮到 visualMap 组件上时,鼠标位置对应的数值 在 图表中对应的图形元素,会高亮
inRange: {
color: ['#f02764'].reverse(),//设置散点圈颜色
symbolSize: [10, 50]
},
outOfRange:{ //定义 在选中范围外 的视觉元素。
color: ['#010101'].reverse(),
symbolSize: [10, 50]
},
left:'1%', //组件离容器左侧的距离,'left', 'center', 'right','20%'
backgroundColor:'#f9f8f7', //标题背景色
borderWidth:0,//边框线宽
textStyle: {
color: '#060606'
}
}
});
$(function () {
$.ajax({
url:'/mdt',
type:'get',
success:function (cityres) {
var data = new Array();
var geoCoordMap = new Object();
for (var i = 0;i < cityres.data.length; i++){
data[i] = {
name : cityres.data[i].cityname,
value : cityres.data[i].xmsl
};
geoCoordMap[cityres.data[i].cityname] = [cityres.data[i].lng,cityres.data[i].lat];
};
const convertData = function (data) {
var res = [];
for (var i = 0; i < data.length; i++) {
var geoCoord = geoCoordMap[data[i].name];
if (geoCoord) {
res.push({
name: data[i].name,
value: geoCoord.concat(data[i].value),
visualMap: true
});
}
}
return res;
};
//第二次进行myChart.setOption
myChart.setOption({
series: [
{
name: '项目数(个)',
type: 'scatter',
coordinateSystem: 'bmap',
data: convertData(data),
symbolSize: function (val) {
return val[2];
},
encode: {
value: 2
},
label: {
formatter: '{b}',
position: 'right',
show: false
},
emphasis: {
label: {
show: true
}
}
},
//显示前5数据名称
{
name: 'Top 5',
type: 'effectScatter',
coordinateSystem: 'bmap',
data: convertData(
data
.sort(function (a, b) {
return b.value - a.value;
})
.slice(0, 5)
),
symbolSize: function (val) {
return val[2] / 5;
},
encode: {
value: 2
},
showEffectOn: 'render',
rippleEffect: {
brushType: 'stroke'
},
label: {
formatter: '{b}',
position: 'right',
show: true
},
itemStyle: {
shadowBlur: 10,
shadowColor: '#333'
},
emphasis: {
scale: true
},
zlevel: 1
}
]
});/
//
}
});
});
//
/*
if (option && typeof option === 'object') {
myChart.setOption(option);
}
*/
</script>
</body>
</html>
另:为了方便大家使用js文件,我把js打包放网盘里了,大家可以下载使用。
链接:https://pan.baidu.com/s/1GGPlkLwUHtlWcyUtOVJTYA
提取码:nru8