Vue3 + Echarts 5 绘制带有立体感流线中国地图,建议收藏
本文绘制的地图效果图如下:
一、Echarts 使用五部曲
1、下载并引入 echarts
Echarts 已更新到了 5.0 版本,安装完记得检查下自己的版本是否是 5.0 。
npm install echarts --save
下载地图的 json 数据
可以下载中国以及各个省份地图数据。免费的文件下载地址:
http://datav.aliyun.com/portal/school/atlas/area_selector#&lat=30.332329214580188&lng=106.72278672066881&zoom=3.5
记得收藏哦!免得浪费加班时间。
引入:
import * as echarts from "echarts"
import chinaJSON from '../../assets/json/china.json'
2、准备容器
给元素定义宽高确定的容器用来装地图。
<template> <div id="chinaMap"></div> </template>
3、实例化 echarts 对象
import * as echarts from 'echarts' import chinaJson from '../../assets/json/china.json' var myChart = echarts.init(document.getElementById('chinaMap')) // 创建了一个 myChart 对象
4、指定配置项和数据
var option = { // 存放需要绘制图片类型,以及样式设置 }
5、给 echarts 对象设置配置项
myChart.setOption(option)
就这么简单几步还用你告诉我吗?不瞒你说,官网也有这东东。虽然这些你都知道,但是并不影响你还是不知道流线图是怎么绘制出来的。下面我们看看是如何绘制的。
二、开始绘制流线中国地图
第一步:先绘制一个中国地图
import * as echarts from 'echarts' import chinaJson from '../../assets/json/china.json' import { onMounted, ref } from 'vue' const chinaMap = ref() onMounted(() => { drawChina() }) function drawChina() { var myChart = echarts.init(chinaMap.value) echarts.registerMap('china', chinaJson) //注册可用的地图 var option = { geo: { show: true, //设置中心点 center: [105.194115019531, 35.582111640625], map: 'china', roam: true, //是否允许缩放,拖拽 zoom: 1, //初始化大小 //缩放大小限制 scaleLimit: { min: 0.1, //最小 max: 12, //最大 }, //各个省份模块样式设置 itemStyle: { normal: { areaColor: '#3352c7',//背景色 color: 'red',//字体颜色 borderColor: '#5e84fd', borderWidth: 2, }, }, //高亮状态 emphasis: { itemStyle: { areaColor: '#ffc601', }, label: { show: true, color: '#fff', }, }, // 显示层级 z: 10, }, } myChart.setOption(option) }
一个简单的地图就绘制好了,继续研究如何添加流线。
第二步:添加流线
通过 series 属性来设置发色点的样式,接受点的样式,以及线条和线条上的动画。
设置 series 的值:
// 中国地理坐标图 var chinaGeoCoordMap: Object = { 西安: [108.906866, 34.162109], 拉萨: [91.140856, 29.645554], } //发射点 var chinaDatas = [ [ { name: '拉萨', value: 2, }, ], ] //投射点 const scatterPos = [108.906866, 34.162109] // 数据转换 var convertData = function (data: any) { var res = [] for (var i = 0; i < data.length; i++) { var dataItem = data[i] var fromCoord = chinaGeoCoordMap[dataItem[0].name] var toCoord = scatterPos if (fromCoord && toCoord) { res.push([ { coord: fromCoord, value: dataItem[0].value, }, { coord: toCoord, }, ]) } } return res } var series: Array<any> = [] ;[['西安', chinaDatas]].forEach(function (item, i) { series.push( //设置指向箭头信息 { type: 'lines', zlevel: 2, effect: { show: true, period: 4, //箭头指向速度,值越小速度越快 trailLength: 0.02, //特效尾迹长度[0,1]值越大,尾迹越长重 symbol: 'arrow', //箭头图标 symbolSize: 8, //图标大小 }, lineStyle: { normal: { color: '#adffd0', width: 1, //尾迹线条宽度 opacity: 1, //尾迹线条透明度 curveness: 0.3, //尾迹线条曲直度 }, }, data: convertData(item[1]), }, // 发射点位置涟漪等效果 { type: 'effectScatter', coordinateSystem: 'geo', zlevel: 2, rippleEffect: { //涟漪特效 period: 4, //动画时间,值越小速度越快 brushType: 'stroke', //波纹绘制方式 stroke, fill scale: 4, //波纹圆环最大限制,值越大波纹越大 }, label: { normal: { show: true, position: 'right', //显示位置 offset: [5, 0], //偏移设置 formatter: function (params) { //圆环显示文字 return params.data.name }, fontSize: 13, }, emphasis: { show: true, }, }, symbol: 'circle', symbolSize: function (val: Array<any>) { return 5 + val[2] * 5 //圆环大小 }, itemStyle: { normal: { show: false, color: '#f8f9f5', }, }, data: item[1].map(function (dataItem: any) { return { name: dataItem[0].name, value: chinaGeoCoordMap[dataItem[0].name].concat([dataItem[0].value]), } }), }, //被攻击点 { type: 'effectScatter', coordinateSystem: 'geo', zlevel: 2, rippleEffect: { //涟漪相关 period: 2, brushType: 'stroke', scale: 5, }, label: { normal: { show: true, position: 'right', color: '#0f0', formatter: '{b}', textStyle: { color: '#fff', fontSize: 12, }, }, emphasis: { show: true, color: '#f60', }, }, itemStyle: { normal: { color: '#f00', }, }, symbol: 'circle', symbolSize: 10, //圆圈大小 data: [ { name: item[0], value: chinaGeoCoordMap[item[0]].concat([10]), }, ], }, ) })
给上边的 option 添加 series 属性。
第三步:添加立体投影
添加立体投影的时候,由于并没有这样的属性,所以需要通过设置边框投影,再加一个偏移。
实现原理:绘制两个地图,设置中心点是一样的,然后一个设置边框投影+偏移,它的层级设置小一点,上边再绘制一个地图不设置投影,这样就能够实现上述效果。
// series 添加一个对象,绘制新地图 { //绘制一个新地图 type: 'map', map: 'china', zoom: 1, center: [105.194115019531, 35.582111640625], z: -1, aspectScale: 0.75, // itemStyle: { normal: { areaColor: '#f00', borderColor: '#090438', borderWidth: '2', shadowColor: '#090438', shadowOffsetX: 0, shadowOffsetY: 15, }, }, }
上述效果的完整源码:
<template> <div> 首页 <div ref="chinaMap" class="chinaMap" style=" height: 800px; border: solid 1px red; width: 100%; background: #0b0873; " > 地图1 </div> </div> </template> <style scoped> .chinaMap { transform: rotate3d(1, 0, 0, 35deg); } </style> <script lang="ts" setup> import * as echarts from 'echarts' import chinaJson from '../../assets/json/china.json' import { onMounted, ref } from 'vue' const chinaMap = ref() onMounted(() => { drawChina() }) /**************************** series start ************************************/ //中国地理坐标图 var chinaGeoCoordMap: Object = { 西安: [108.906866, 34.162109], 柯桥区: [120.476075, 30.078038], 拉萨: [91.140856, 29.645554], 沈阳: [123.431474, 41.805698], 新疆: [87.627704, 43.793026], 台湾: [121.508903, 25.044319], } var chinaDatas = [ [ { name: '柯桥区', value: 0, }, ], [ { name: '拉萨', value: 2, }, ], [ { name: '沈阳', value: 1, }, ], [ { name: '新疆', value: 1, }, ], [ { name: '台湾', value: 1, }, ], ] //设置投射点 const scatterPos = [108.906866, 34.162109] var convertData = function (data: any) { var res = [] for (var i = 0; i < data.length; i++) { var dataItem = data[i] var fromCoord = chinaGeoCoordMap[dataItem[0].name] var toCoord = scatterPos if (fromCoord && toCoord) { res.push([ { coord: fromCoord, value: dataItem[0].value, }, { coord: toCoord, }, ]) } } console.log('res', res) return res } var series: Array<any> = [] ;[['西安', chinaDatas]].forEach(function (item, i) { console.log(item, item[0]) series.push( { //绘制一个新地图 type: 'map', map: 'china', zoom: 1, center: [105.194115019531, 35.582111640625], z: -1, aspectScale: 0.75, // itemStyle: { normal: { areaColor: '#f00', borderColor: '#090438', borderWidth: '2', shadowColor: '#090438', shadowOffsetX: 0, shadowOffsetY: 15, }, }, }, //设置指向箭头信息 { type: 'lines', zlevel: 2, effect: { show: true, period: 4, //箭头指向速度,值越小速度越快 trailLength: 0.02, //特效尾迹长度[0,1]值越大,尾迹越长重 symbol: 'arrow', //箭头图标 symbolSize: 8, //图标大小 }, lineStyle: { normal: { color: '#adffd0', width: 1, //尾迹线条宽度 opacity: 1, //尾迹线条透明度 curveness: 0.3, //尾迹线条曲直度 }, }, data: convertData(item[1]), }, // 发射点位置涟漪等效果 { type: 'effectScatter', coordinateSystem: 'geo', zlevel: 2, rippleEffect: { //涟漪特效 period: 4, //动画时间,值越小速度越快 brushType: 'stroke', //波纹绘制方式 stroke, fill scale: 4, //波纹圆环最大限制,值越大波纹越大 }, label: { normal: { show: true, position: 'right', //显示位置 offset: [5, 0], //偏移设置 formatter: function (params) { //圆环显示文字 return params.data.name }, fontSize: 13, }, emphasis: { show: true, }, }, symbol: 'circle', symbolSize: function (val: Array<any>) { return 5 + val[2] * 5 //圆环大小 }, itemStyle: { normal: { show: false, color: '#f8f9f5', }, }, data: item[1].map(function (dataItem: any) { return { name: dataItem[0].name, value: chinaGeoCoordMap[dataItem[0].name].concat([dataItem[0].value]), } }), }, //被攻击点 { type: 'effectScatter', coordinateSystem: 'geo', zlevel: 2, rippleEffect: { //涟漪相关 period: 2, brushType: 'stroke', scale: 5, }, label: { normal: { show: true, position: 'right', // offset:[5, 0], color: '#0f0', formatter: '{b}', textStyle: { color: '#fff', fontSize: 12, }, }, emphasis: { show: true, color: '#f60', }, }, itemStyle: { normal: { color: '#f00', }, }, symbol: 'circle', symbolSize: 10, //圆圈大小 data: [ { name: item[0], value: chinaGeoCoordMap[item[0]].concat([10]), }, ], }, ) }) /****************************************************************/ function drawChina() { var myChart = echarts.init(chinaMap.value) echarts.registerMap('china', chinaJson) //注册可用的地图 var option = { tooltip: { trigger: 'item', backgroundColor: 'rgba(166, 200, 76, 0.82)', borderColor: '#FFFFCC', showDelay: 0, hideDelay: 0, enterable: true, transitionDuration: 0, extraCssText: 'z-index:100', formatter: function (params, ticket, callback) { //根据业务自己拓展要显示的内容 var res = '' var name = params.name var value = params.value[params.seriesIndex + 1] res = "<span style='color:#fff;'>" + name + '</span><br/>数据:' + value return res }, }, geo: { show: true, center: [105.194115019531, 35.582111640625], map: 'china', roam: true, //是否允许缩放,拖拽 zoom: 1, //初始化大小 //缩放大小限制 scaleLimit: { min: 0.1, //最小 max: 12, //最大 }, //设置中心点 //center: [95.97, 29.71], //省份地图添加背景 //regions: regions, itemStyle: { normal: { areaColor: '#3352c7', color: 'red', borderColor: '#5e84fd', borderWidth: 2, }, }, label: { color: 'rgba(255,255,255,0.5)', show: false, }, //高亮状态 emphasis: { itemStyle: { areaColor: '#ffc601', }, label: { show: true, color: '#fff', }, }, z: 10, }, //配置属性 series: series, } myChart.setOption(option) } </script>