ECharts是一个基于 JavaScript 的开源可视化图表库,在很多大屏中都有使用到,但大多数情况都是用来制作图表,柱状图、折线图、饼图等等。地图也是它其中的一个模块,毕竟不像OpenLayer、Leaflet这样专业做地图的组件库,所以能实现的功能都十分基础,但它容易入手,配置项也很少,在使用时我们需要综合考虑需求来选择是否采用ECharts。
普通的引入JSON创建地图很常见也很简单,看文档应该是没问题的,并且很多官方的示例也都是用引入JSON文件的方式创建地图的。在这里我推荐几个我比较常用的网站吧。
阿里云DataV地理小工具
DataV.GeoAtlas地理小工具系列
GeoJSON
geojson.io | powered by Mapbox
这个功能类似与DataV的边界生成器,但这个我用起来更顺手,它可以直接编辑JSON文件并得到实时结果,在地图上看到变化。
高德和百度的地图坐标拾取器
拾取坐标系统
高德地图API
这两个功能相似,各有优劣
使用地理位置查坐标 | 精确度 | |
---|---|---|
百度 | 模糊搜索,会同时出现多个结果 | 精确到小数点后六位 |
高德 | 精确搜索,只有一个结果 | 精确到小数点后两位 |
这是我当时拿到的设计图,可以看到是三层地图图层,这个实现倒是简单,但是难就难在下方有个倒影,当时的我belike:
于是我开始尝试各种方法:
1
像之前做的地图一样用一层层叠加,最下面几层的填充使用渐变+透明度,边缘最深到中心透明度逐渐变为0。可以看到它是只有下方有颜色,最左边最右边和上面都是透明的,所以采用径向渐变,第一层没有任何问题,但做第二层的时候问题就来了,上面一层是透明的,那下一层颜色也会叠加上去,根本实现不了设计图里的效果,故pass。
2
从CSS入手,从根本入手,这效果不就是要倒影吗,CSS我印象中有倒影功能的,把上面的图层画好直接加上倒影和透明度就好,满怀欣喜写下代码之后得到的效果是这样的
3
UI提议要不直接把图当做背景,但这样的话就牺牲了交互性,而且之后还要在地图上加点,效果应该不会很理想,故也pass
4
这个时候我才注意到设计图上不只有倒影,还有第二、三层之间有竖条纹,这是3D地图的一个边缘纹理效果,所以我开始准备学习使用three.js来制作,或者ECharts GL来实现3D效果,但这次的地图所需具备的功能就只是在地图上展示一些点而已,并不要求有其他功能,所以我就想在这样一个地图上用WebGL是否有点杀鸡用牛刀,因为这就像我开始说的需要综合考虑需求来选取最合适的方案。所以经过一番考虑和尝试,也放弃了WebGL。
这时候我发现了ECharts可以支持以SVG图为底图来注册地图
它所用的方法其实上就是把一张SVG图作为底图,然后通过SVG图代码中一些属性来识别不同区域,最终达到和GeoJSON相同的效果。这样来说我是不是就可以把UI提供的图直接拿来用,加以改造使其具备地图的属性。看起来似乎是最优的解决方案,确定路线后就准备往前走了。但是SVG作为底图官方并没有画大篇幅进行讲解,搜索到的实例也十分有限,所以只能自己在摸索中前进。
在这个过程中也遇到了几个坑和难点,提供了几个我自己的解决方案,如果有更好的可以和我探讨,我踩过的坑也希望大家不要再踩了。
注册SVG地图
SVG底图的引入和JSON一样,可以使用import
方式引入,也支持require
方式引入,前一种方式适用于不变的文件引入,放在开头在编译时调用,后者是可以动态变化的,在运行过程中才加以调用。就例如我需要根据点击区域实现调用不同的SVG底图,这时就需要使用require
方式动态引入,如下所示:
const mapSVG = require('../../assets/images/map/' + this.cityName + '.svg')
但是注册地图就比JSON要麻烦一些了,它不能直接使用echarts.registerMap('map', mapJSON)
进行注册,这当时让我卡了好久,必须严格按照官网上的步骤一步步操作。
// 首先需要jquery方式获取刚才引入的SVG底图
$.get(mapSVG, function (mapSVG) {
// 然后才能进行地图注册
echarts.registerMap('cityMap', {svg: mapSVG});
// 下面就是常规的chart初始化配置操作
var chart = echarts.init(document.getElementById('map'))。
chart.setOption({
geo: [{
// 引用注册过的底图
map: 'cityMap',
...
}]
});
});
SVG编辑
如果引入的不是DataV里下载的SVG底图,而只是引入UI给的普通SVG图的话是没有交互效果的,它就只是一张图,和普通的背景没什么两样,在官网中有专门提到这类具名元素
如果要控制 SVG 中的某些元素,或者让某些元素能交互,我们首先要在 SVG 中标记这些元素:在这些元素上添加 name
属性(下文称此类添加过 name
属性的元素为:“具名元素”)。许多功能都依赖于对元素的命名。
所以我们需要编辑SVG文件,使其能够满足具名元素要求。SVG图片是一种矢量图形文件格式,可以直接用代码来描绘图像,可以用任何文字处理工具打开SVG图像,通过改变部分代码来使图像具有交互功能。
我在搜索之后找到了一个古早的软件SVGDeveloper,这个软件很难找(也很难用),上次更新还是在2014年,用的还是上个世纪的图形化界面,整体呈现一种复古感。
但使用起来没什么问题,功能也很多,从四面八方的工具栏就可以看出来,这次我采用的就是这个编辑器。将UI设计好的png图导入,用钢笔工具不用太细致地描出各个地市的边缘,当然别忘了在path
中加入name
使其成为具名元素。如下图所示:
然后不断重复,画出每个地市的每个区县,最后需要去掉边缘线添加填充色(画图时不加填充色是避免影响视觉,最后需要添加是因为不添加的画ECharts就当这块具名元素是透明的,但SVG里的颜色和最后ECharts所展示的颜色无关,可以随意设置),最后拿到的SVG图是这样的:
按上一步导入ECharts之后得到的效果就是这样:
交互、倒影,所有的要求都满足了,并且用的是最简单的实现方式。
之后我才发现SVG的在线编辑器也有很多,总体都大同小异,这里放一个吧。我所需要的功能它都有了,比起软件更加现代化,简单使用是没问题的。
svg在线编辑器_svg矢量图在线制作工具-易点在线矢量图形编辑器
需要补充一个点:将png图片导入SVGDeveloper之后它是可以正常显示的,但做好后的图导入ECharts就只显示每个区域而不显示png背景,这是因为引入的图片地址是存储在本地的,当上传服务器后他就找不到这个文件,如下图所示。
我的处理办法是将图片转为Base64编码,可以找到很多上传文件转Bese64编码的网站,在这里放上一个。
测试了上面这个在线的SVG编辑器之后发现,导入图片之后它就已经自动转换成Base64编码了,省去了这一次操作步骤。
因为遇到了另一个需求,需要多地图有多种操作,ECharts的地图已经不能满足,所以后来我们选择了使用OpenLayer来制作这部分的地图。
参考文章
OL是一个很庞大的体系,但入门起来也十分简单,只需要掌握Map、View、Source、Layer这几个核心类,就可以做出一个最基本的地图,需要在此基础上添加更多花样化定制化的GIS功能到时候再按需学习也可以。
一个大的容器Map,加上一个视角View,将来自数据源Source的图层Layer一层层叠加,就组合成了一个基本的地图。
Map
Map类是一个容器,接下来提到的其他类都是被包含在其中的,最重要的一个属性就是target了,target属性设置的是地图要挂载到哪个DOM节点上进行渲染。其他还有interactions
用来控制交互动作,controls
用来控制相关控件等,详细可以查看官方API文档。
View
View类是类似于相机,用于变化不同视角,里面一些比较常见的属性比如zoom
控制缩放,extent
控制视野范围,center
是地图中心点等。
Source
Source类是指的数据源,又被分为了很多子类:OSM、ImageSource**、**TileSources、VectorSource
等,根据实际情况选择不同类型数据源进行读取,本次项目使用较多的就是VectorSource
,因为大多都是读取的一些JSON文件,以及使用turfJS绘制的矢量图像。
Layer
Layer类是重点,地图正是一层一层图层叠加出来的,就如下图所示,这是放大地图后默认显示的四个图层,当地图缩小之后这四个图层将不可见,同时将另外的图层设为可见,另外点击地图上的点,还会出现对应时延圈,这也是三个图层。
将以上四个类有机结合起来,就可以组成一个完整的地图了,一个简易代码demo:
import Map from 'ol/Map';
import View from 'ol/View';
import OSM from 'ol/source/OSM';
import TileLayer from 'ol/layer/Tile';
new Map({
layers: [
new TileLayer({source: new OSM()})
],
view: new View({
center: [0, 0],
zoom: 2
}),
target: 'map'
});
我就接着补充两个可能会有用的part,以防不时之需。
tooltip是ECHarts一个很重要的部分,它独特的回调函数formatter属性
formatter(params: Object|Array, ticket: string, callback: (ticket: string, html: string)) => string | **HTMLElement** | **HTMLElement[]**
这是label、legend等其他配置项都不具有的功能(不用试了我已经试过一遍了),label最接近的一个解决方案是使用富文本rich,但仍有很大局限性,而在HTML标签中甚至可以再加入ECharts实现套娃~~,子子孙孙无穷尽也。~~
从上面官方给出的回调函数中可以看到有params、ticket、callback三个参数,具体是什么内容可以自己打印看看。
在函数中定义一个变量htmlStr,然后就可以在变量中书写HTML内容,写法和正常写HTML一样,标签内可以使用style参数定义样式,最后将htmlStr变量return就可以看到效果了。
⚠️ HTML内容需要包含在反引号 ( ` )中,而不是单、双引号中
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pf2UzIsk-1677567802010)(null)]
水球图‣是ECharts的一个社区扩展,提供了一种适合于展现单个百分比数据的图表,支持多条水波和动画。
水球图支持自定义的配置项很多,包括但不限于波浪条数、颜色、振幅、动画甚至外框的形状,具体配置项内容可以看这篇文章或查询官方文档。
⚠️ **注意:echarts-liquidfill@3
版本匹配echarts@5
版本,echarts-liquidfill@2
版本匹配echarts@4
版本,并且水球图是社区扩展,所以需要单独安装引入
很多插件是前端之光,减少了很多工作量,能使用轮子的地方就不用自己造了。
vue-seamless-scroll
vue-seamless-scroll
一个简单的基于vue.js的无缝滚动插件,可以支持上下左右无缝滚动,单步滚动,以及支持水平方向的手动切换功能,大屏里很常用。
⚠️ 注意:vue-seamless-scroll
仅支持Vue2,如果想在Vue3中使用,请使用此项目Issues中其他用户扩展的Vue3兼容版vue3-seamless-scroll
Swiper
Swiper中文网-轮播图幻灯片js插件,H5页面前端开发
一款滑动插件,效果类似于element的走马灯,不过这个插件效果更加强大,可定制化程度更高,效果也更好,同时支持电脑和移动端。