Echarts地图使用笔记

上周末Boss要求做一个全球疫情的项目,产品经理准备通过一个全球地图来展示疫情情况,我们考虑了下,选择了沿用之前全国疫情的技术选型,即ECharts来实现该地图。

这里记录下做的过程中的一些笔记,供今后类似需求做参考。

首先,好好读几遍ECharts地图相关的API

https://echarts.apache.org/zh/option.html#geo.zoom

这是重中之重。因为时间太紧迫(周末只有不到2天的开发时间,要尽快上线),我们一开始就埋头干,结果发现中间遇到问题时连蒙带猜,耗费了很多时间。而很多问题都是可以通过先通读一遍API就可以解决的。

工欲善其事,必先利其器;欲速则不达。

常用功能的实现方案

定位

https://www.echartsjs.com/zh/option.html#geo.layoutCenter

通过geo.layoutCenter+高亮的方式,变相定位

通过经纬度来计算:

http://tushuo.jk51.com/tushuo/3341728.html

这里我取了个巧:因为我们的用户绝大部分都是中国用户,所以定位功能我就先直接写死定位到中国地图,且大致能看完整个中国区域的范围。

这是中国位于中心,且展示全国地图的位置信息:

1
2
zoom=5.965524658471281, 
center=104.57885950810665,34.87372773233342

高亮红圈/五角星

这是通过单独的series实现的,这也符合程序设计的独立性。

series的typeeffectScatter,即动效波纹散点圆圈。

散点的大小,可以通过series中的symbolSize进行设置:

1
2
3
symbolSize: function (val) {
return val[2];
},

我们一般设计value[0]是经度,value[1]是维度,val[2]是需要显示的值,val[3]可以作为点的大小(我们这次是直接通过val[2]计算后得出其大小的,因此val[3]是没有用到的)。

注意要控制散点的最大值和最小值,比如我这里是这样控制的:

1
2
3
4
symbolSize: function (val) {
// minValue:数据的最小值,maxValue:数据的最大值;minSize:散点的最小尺寸;maxSize:散点的最大尺寸
return (val[2] - minValue) / (maxValue - minValue) * maxSize + minSize;
},

这是几个供参考的Demo:

闪点:

https://gallery.echartsjs.com/editor.html?c=xnmZ5X4gCz

飞线+闪点:

https://gallery.echartsjs.com/editor.html?c=xH2DfA0Olu

闪点+排名柱状图:

https://gallery.echartsjs.com/editor.html?c=x9dsJQiYl

飞线

飞线我们这次尚未用到,因此这里仅列出几个参考的Demo,后续用到了再实践:

AMap + echarts、google map + d3.js分别实现数据可视化中的飞线图(迁徙图):

https://blog.csdn.net/Ancecis/article/details/91914008

D3画地图与飞线:

https://www.jianshu.com/p/69dd56c28248

自定义形状

这是由于上面的散点不满足产品需求,需要我们画一些比较个性的形状。

这个用custom类型的seriez来画,可以参考:

https://www.jianshu.com/p/d6e889af6516

也可以用scatter来实现,其symbol可以定义为一个图片或者图片数据流(建议用图片,以减小打包后的JS大小):

https://gallery.echartsjs.com/editor.html?c=xntS7o_3ac

允许平移缩放

https://www.echartsjs.com/zh/option.html#geo.roam

通过将geo.roam设置为true来实现。

默认在地图上显示地名

通过geo.label进行设置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
label: {
normal: {
show: true, // 是否显示对应地名
textStyle: {
color: "#000",
// fontSize: '100%'
fontSize: getFontSize(16)
},
formatter: function(data) {
let name = data.name
if (!provinceEn) {
return name
}
let sname
sname = hideCity(provinceEn, name);
sname = replaceCity(sname);
sname = replaceCityT(provinceEn, sname);
return sname
}
}
},

给不同的数据设置不同的区域颜色

通过visualMap进行设置。

注意这里有一个坑:pieces里面设置的值,最终是会进行从小到大排序的,因此inRange.color中设置的颜色,必须按照从小到大的顺序罗列,否则就会对不上:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
visualMap: {
show: true,
type: "piecewise",
itemHeight: getPlatform() === 'iphone' ? 14 : getFontSize(10),
itemGap : getPlatform() === 'iphone' ? 8 : getFontSize(8),
pieces: [
{
min: 10000
},
{
min: 1000,
max: 9999
}, // 不指定 max,表示 max 为无限大(Infinity)。
{
min: 500,
max: 999
},
{
min: 100,
max: 499
},
{
min: 10,
max: 99
},
{
min: 1,
max: 9
}
],
showLabel: true,
itemSymbol: "circle",
seriesIndex: [0],
left: "2%",
bottom: "0",
hoverLink: false,
inRange: {
// 这里必须按照从小到大的顺序写颜色
color: [
"rgba(247,229,190,1)",
"rgba(237,183,111,1)",
"rgba(229,142,104,1)",
"rgba(207,82,78,1)",
"rgba(111,45,40,1)"
]
},
textStyle: {
color: "rgba(144,143,143,1)",
fontSize: getFontSize(16)
}
},

让颜色更加绚丽

可以参考这个,中心颜色和边缘颜色有区分,体现出了蔓延的效果:

https://gallery.echartsjs.com/editor.html?c=xVMQUYaV22

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
geo: {
map: 'world',
show: true,
roam: true,
label: {
emphasis: {
show: false
}
},
itemStyle: {
normal: {
areaColor: '#091632',
borderColor: '#1773c3',
shadowColor: '#1773c3',
shadowBlur: 20
}
}
},

让geo和series同步缩放

地图放大后自动显示名称

https://segmentfault.com/a/1190000018483921

这是通过重新setOption(),重绘地图实现的。目前我们尚未用到,但是感觉后面很可能会用到。

中国的省份直接画在世界地图上

https://blog.csdn.net/weixin_37930716/article/details/95046895

作图是基于地理信息数据的,因此我们只需要将中国各省份的数据,整合进世界数据即可。

注意整合后,要记得删除世界数据里面原来的中国数据,否则还可以点到整个中国区域。

另外数据要保持一致,因为不同来源的数据,可能规范不一致,会导致画出来的图和实际国界不符,引发政治风险问题。最好数据都用ECharts的。

不过ECharts的中国地理信息数据是做了压缩的,肉眼不可直接辨识,也不能直接合并到世界数据中,需要先转一次。具体转换算法详见这个文章:Echarts地图文件的压缩和解码

Vue发送通知

这个和地图技术无关,只是用户点击地图后,我们要通知页面上其他功能,将数据切换到用户点击的地域。

1
2
3
mixin.Event.$emit('locationSelect', data) // 地图点击全局通知
mixin.Event.$on('locationSelect', data => { // 监听地图点击的通知
})

工具

这里罗列一些开发过程中用到的工具。

调色板

http://www.ip138.com/yanse/index.htm

【精】各国geoJSON地图经纬度数据查询

highcharts官网:

https://code.highcharts.com.cn/mapdata/index.html

地图数据查询(仅限中国)

http://datav.aliyun.com/tools/atlas/#&lat=33.54139466898275&lng=104.32617187499999&zoom=4

其他国家地图查询

美国各州

https://stackoverflow.com/questions/19941975/d3-us-states-in-topojson-format-filesize-is-way-too-large

In addition to rysloan suggestions you can use Mapshaper and QGIS to extract the state boundaries. Both of these are also free. To get just the us-states follows these steps:

  • Upload the us.json file to Mapshaper;
  • Export it as a shape file;
  • Unpack the zip and you’ll notice the Mapshaper has already split your topojson into 3 shape files one of which is us-states;
  • Upload the us-states.shp and us-states.shx to Mapshaper (you’ll have to refresh Mapshaper to get rid of the orginal us.json file first); and
  • Save as topojson and you’ll have a file 58kb in size.

在地图上标记集合区域、打点

可以用这个网站来处理:http://geojson.io/

找icon:

https://www.iconfont.cn/search/index?searchType=icon&q=%E8%B5%9E

转base64数据流:

http://tool.chinaz.com/tools/imgtobase/

一些做得比较好的产品

国外的疫情地图

cov19,从谷歌商店下载

文章介绍:
https://baijiahao.baidu.com/s?id=1660659328481771660&wfr=spider&for=pc
效果:
https://www.arcgis.com/apps/opsdashboard/index.html#/bda7594740fd40299423467b48e9ecf6
移动版:
https://www.arcgis.com/apps/opsdashboard/index.html#/85320e2ea5424dfaaa75ae62e5c06e61

github:
https://github.com/CSSEGISandData/COVID-19

各国专利

https://gallery.echartsjs.com/editor.html?c=xr16-Eukt

艾滋病蔓延情况

https://gallery.echartsjs.com/editor.html?c=xVMQUYaV22

替换为百度地图存在的风险点

由于产品的部分交互用ECharts不大好实现,我们也思考了转用百度地图的可行性,虽然目前还没真正用起来,但是这里也记录下。

  1. 公司APP所独有的fontsize问题。【可以通过修改整个项目的字体解决】
  2. 百度地图没有提供tooltip。【百度地图默认没有,我们可以通过标记点实现】
  3. 百度地图默认会有道路、河流、楼等信息,理论上可以在百度控制台设置,但是,之前遇到过控制台设置之后,导出配置,换一个环境显示效果不一样。【可以要尝试配置很多次,非常耗时,百度地图自身问题】
  4. 地图加载可能会出现某些图层加载失败(出现白块),缩放时也会出现。【应该可以通过离线地图解决,但是没有官方的方法,需要尝试】
  5. 高亮区域:echarts各区域展示不同的颜色是通过配置visualMap实现,百度地图没有这个概念,需要获取各个区域的边界,遍历设置颜色。【可以通过标记热力点来解决,百度地图也不适合高亮区域,会遮住后面内容】
  6. 交互风险:比如点击触发某一块区域高亮,百度地图有click事件,但是这个是地图图层全局的,需要自己判断是否在某块区域内,然后设置颜色。【点击标记点来解决】
  7. 百度地图的zoom缩放是按一个数量级来的, 不能平滑缩放,不能微调。【可能影响用户体验,不过大家能接受目前百度地图的缩放交互,那应该问题不大】

综合分析后,发现应该是可以替换过来的。等后续有无法通过ECharts满足的需求时,我们再考虑下实际操作。