准备部分
// 下载 echarts "echarts": "^4.6.0",
// 下载 lodash "lodash": "^4.17.21",(地图自适应防抖)
// 在 main.js 文件中 引入/注册/声明使用
import echarts from 'echarts'
Vue.prototype.$echarts = echarts
import china from 'echarts/map/json/china.json'
echarts.registerMap('china', china)
HTML部分
<template>
<div>
<!-- 选择器 -->
<el-select v-model="selectVal" placeholder="请选择" @change="handleChange">
<el-option
v-for="item in ChineseProvinces"
:key="item.name"
:label="item.name"
:value="item.name"
>
</el-option>
</el-select>
<!-- 地图 -->
<div class="wrapper">
<div id="myEchart" ref="myEchart" class="map_container"></div>
</div>
</div>
</template>
JS部分(js引入部分在文末)
<script>
import { ChineseProvinces } from './mapData'
import { EleResize } from '../../utils/esresize'
import { debounce } from 'lodash'
export default {
data() {
return {
selectVal: '北京', // 下拉框选中值
toCoord: [116.4551, 40.2539], // 默认攻击点
ChineseProvinces: [], // 中国省份
// 地图配置
option: {
backgroundColor: 'rgba(0, 0, 0, 0.1)', // //设置地图外的背景颜色
// 标题配置
title: {
text: '中国地图数据',
subtext: '迁徙图', // 子标题
textStyle: {
color: '#e57373',
fontWeight: 'normal',
fontSize: 20,
lineHeight: 30,
},
subtextStyle: {
color: '#42a5f5',
fontSize: 15,
},
left: 'center', // 居中显示,可设置数值
},
// 地理坐标系组件。
geo: {
map: 'china', // 地图选择
roam: false, // 是否可缩放和平移
zoom: 1.2, // 当前视角的缩放比例。
// 缩放比例范围
scaleLimit: {
min: 1,
max: 2,
},
// 绑定文本的设置
label: {
// 静态的时候显示的默认样式
normal: {
color: 'inherit',
fontWeight: 'bold',
},
// 鼠标移入动态的时候显示的默认样式
emphasis: {
show: true,
fontWeight: 'bold',
},
},
// 选中板块配置
itemStyle: {
normal: {
color: 'red',
areaColor: '#142957', // 地图颜色
borderColor: '#0692a4', // 线条颜色
borderType: 'dotted', // 边框样式
opacity: '1',
},
emphasis: {
color: '#81acff', // 悬浮背景
areaColor: '#81acff', //
shadowColor: '#81acff', //
},
},
// 自定义地区的名称映射 'china': '中国'
nameMap: {
河南: '中原',
安徽: '安庆府',
},
selectedMode: 'single', // 点击板块会高亮选中板块,默认多选
// 在地图中对特定的区域配置样式,灵活操作
regions: [
{
name: '北京',
itemStyle: {
normal: { areaColor: '#f44336' },
},
},
{
name: '新疆',
itemStyle: {
emphasis: { areaColor: 'blue' },
},
},
],
},
// 提示框组件
tooltip: {},
// 数据配置
series: [],
},
}
},
created() {
this.ChineseProvinces = ChineseProvinces // 省份数据
},
mounted() {
// 处理线条数据
this.convertData(this.ChineseProvinces)
// 地图配置_提示框组件
this.option.tooltip = {
show: true, // 是否显示提升框
trigger: 'item', // 触发类型(item/axis/none)
backgroundColor: '#0052b4', // 提示框浮层的背景颜色。
borderColor: '#FFFFCC', // 提示框浮层的边框颜色
showDelay: 0, // 浮层显示的延迟,单位为 ms,默认没有延迟,也不建议设置。
hideDelay: 0, // 浮层隐藏的延迟,单位为 ms,在 alwaysShowContent 为 true 的时候无效。
enterable: true, // 鼠标是否可进入提示框浮层中,默认为false,如需详情内交互,如添加链接,按钮,可设置为 true。
transitionDuration: 0, // 提示框浮层的移动动画过渡时间,单位是 s,设置为 0 的时候会紧跟着鼠标移动。vvv
extraCssText: 'z-index:100', // 额外附加到浮层的 css 样式。如下为浮层添加阴影的示例:
// 提示框浮层内容格式器,支持字符串模板和回调函数两种形式 根据业务自己拓展要显示的内容
formatter: function (params, ticket, callback) {
var res = ''
var name = params.name
var value1 = params.value[params.seriesIndex - 1] || 0
var value2 = params.value[params.seriesIndex] || 0
res =
"<span style='color:#fff'>" +
name +
'</span>' +
'<br/>' +
'<i icon="el-icon-location-information"></i> 经度:' +
value1 +
'<br/>' +
'<i icon="el-icon-location-information"></i> 纬度:' +
value2
return res
},
}
// 地图配置_数据配置
this.option.series = [
// 线条数据
{
type: 'lines',
zlevel: 1,
// 线特效的配置
effect: {
show: true,
period: 4, // 箭头指向速度,值越小速度越快
trailLength: 0.3, // 特效尾迹长度[0,1]值越大,尾迹越长重
symbol: 'pin', // 箭头图标
symbolSize: 8, // 图标大小
color: '#2a6fd9',
},
lineStyle: {
normal: {
color: '#003262',
width: 1, // 尾迹线条宽度
opacity: 0.9, // 尾迹线条透明度
curveness: 0.3, // 尾迹线条曲直度
},
},
data: this.convertData(this.ChineseProvinces),
},
// 发光发数据
{
type: 'effectScatter',
coordinateSystem: 'geo',
zlevel: 2,
rippleEffect: {
// 涟漪特效
period: 1, // 动画时间,值越小速度越快
brushType: 'fill', // 波纹绘制方式 stroke, fill
scale: 6, // 波纹圆环最大限制,值越大波纹越大
color: '#003262', // 涟漪的颜色,默认为散点的颜色。
},
label: {
normal: {
show: true,
color: '#000046',
position: 'bottom', // 显示位置
offset: [1, 0], // 偏移设置
formatter: function (params) {
// 圆环显示文字
return params.data.name
},
fontSize: 14,
},
emphasis: {
show: false,
},
},
symbol: 'circle',
symbolSize: function (val) {
return 1 + val[2] * 5 // 圆环大小
},
itemStyle: {
color: '#2a6fd9',
shadowBlur: 4,
shadowColor: '#2a6fd9',
},
data: this.ChineseProvinces.map((dataItem) => {
return {
name: dataItem.name,
value: dataItem.log_lat,
itemStyle: {
color: '#2a6fd9',
shadowBlur: 4,
shadowColor: '#2a6fd9',
},
}
}),
},
// 被攻击点数据
{
type: 'scatter',
coordinateSystem: 'geo',
zlevel: 2,
label: {
normal: {
show: false,
position: 'right',
color: 'red',
formatter: '{b}',
textStyle: {
color: 'red',
},
},
emphasis: {
show: true,
color: 'red',
},
},
symbol: 'pin',
symbolSize: 0,
data: [],
},
]
// 渲染地图
this.RenderMap()
},
methods: {
// 处理线条数据
convertData(data) {
var res = []
for (var i = 0; i < data.length; i++) {
var Item = data[i]
// 出发点
var fromCoord = [
Item.log_lat[0], // 出发点经度
Item.log_lat[1], // 出发点纬度
]
if (fromCoord && this.toCoord) {
res.push([
// 线条出发点
{
coord: fromCoord,
value: Item.value, // ?
},
// 线条结束点
{
coord: this.toCoord,
},
])
}
}
return res
},
// 初次渲染地图
RenderMap() {
const Dom = document.getElementById('myEchart')
const MapEcharts = this.$echarts.init(Dom)
MapEcharts.setOption(this.option)
const listener = debounce(function () {
MapEcharts.resize()
}, 500)
EleResize.on(Dom, listener)
},
// 切换攻击点
handleChange(val) {
const PointItem = this.ChineseProvinces.find((item) => item.name === val)
this.toCoord = PointItem.log_lat.slice(0, 2) // 获取攻击点
this.convertData(this.ChineseProvinces) // 处理线条数据,修改攻击点
this.option.series[0].data = this.convertData(this.ChineseProvinces) // 修改地图配置项
this.RenderMap()
},
},
}
</script>
CSS部分
<style lang="scss" scoped>
.wrapper {
width: 100%;
height: 90vh;
.map_container {
width: 100%;
height: 90vh;
background-color: white;
}
}
</style>
JS 部分 引入文件数据 import { ChineseProvinces } from './mapData'(地图相关数据)
export const ChineseProvinces = [{
name: '北京',
log_lat: [116.4551, 40.2539, 1],
value: 2,
},
{
name: '黑龙江',
log_lat: [127.9688, 45.3686, 1],
value: 1
}, {
name: '内蒙古',
log_lat: [110.3467, 41.4899, 1],
value: 1,
}, {
name: '吉林',
log_lat: [125.8154, 44.2584, 1],
value: 1,
}, {
name: '辽宁',
log_lat: [123.1238, 42.1216, 1],
value: 1,
}, {
name: '河北',
log_lat: [114.4995, 38.1006, 1],
value: 1,
}, {
name: '天津',
log_lat: [117.4219, 39.4189, 1],
value: 1,
}, {
name: '山西',
log_lat: [112.3352, 37.9413, 1],
value: 1,
}, {
name: '陕西',
log_lat: [109.1162, 34.2004, 1],
value: 1,
}, {
name: '甘肃',
log_lat: [103.5901, 36.3043, 1],
value: 1,
}, {
name: '宁夏',
log_lat: [106.3586, 38.1775, 1],
value: 1,
}, {
name: '青海',
log_lat: [101.4038, 36.8207, 1],
value: 1,
}, {
name: '新疆',
log_lat: [87.9236, 43.5883, 1],
value: 1,
}, {
name: '西藏',
log_lat: [91.1661, 29.9667, 1],
value: 1,
}, {
name: '四川',
log_lat: [103.9526, 30.7617, 1],
value: 1,
}, {
name: '重庆',
log_lat: [108.3866, 30.4302, 1],
value: 1,
}, {
name: '山东',
log_lat: [117.1582, 36.8701, 1],
value: 1,
}, {
name: '河南',
log_lat: [113.4668, 34.6234, 1],
value: 1,
}, {
name: '江苏',
log_lat: [118.8062, 31.9208, 1],
value: 1,
}, {
name: '安徽',
log_lat: [117.2879, 32.0581, 1],
value: 1,
}, {
name: '湖北',
log_lat: [114.3896, 30.6628, 1],
value: 1,
}, {
name: '浙江',
log_lat: [119.5313, 29.8773, 1],
value: 1,
}, {
name: '福建',
log_lat: [119.4543, 25.9222, 1],
value: 1,
}, {
name: '江西',
log_lat: [116.0046, 28.6633, 1],
value: 1,
}, {
name: '湖南',
log_lat: [113.0823, 28.2568, 1],
value: 1,
}, {
name: '贵州',
log_lat: [106.6992, 26.7682, 1],
value: 1,
}, {
name: '广东',
log_lat: [113.1244, 23.0005, 1],
value: 1,
}, {
name: '广西',
log_lat: [108.4769, 23.1152, 1],
value: 1,
}, {
name: '云南',
log_lat: [102.9199, 25.4663, 1],
value: 1,
}, {
name: '海南',
log_lat: [110.3893, 19.8516, 1],
value: 1,
}, {
name: '上海',
log_lat: [121.4648, 31.2891, 1],
value: 1,
}, {
name: '台湾',
log_lat: [121.4068, 24.9763, 1],
value: 1,
}, {
name: '澳门',
log_lat: [113.3783, 22.11, 1],
value: 1,
}, {
name: '香港',
log_lat: [114.1545, 22.15, 1],
value: 1,
},
]
JS 部分 引入文件数据 import { EleResize } from '../../utils/esresize' (地图大小自适应)
var EleResize = {
_handleResize: function (e) {
var ele = e.target || e.srcElement
var trigger = ele.__resizeTrigger__
if (trigger) {
var handlers = trigger.__z_resizeListeners
if (handlers) {
var size = handlers.length
for (var i = 0; i < size; i++) {
var h = handlers[i]
var handler = h.handler
var context = h.context
handler.apply(context, [e])
}
}
}
},
_removeHandler: function (ele, handler, context) {
var handlers = ele.__z_resizeListeners
if (handlers) {
var size = handlers.length
for (var i = 0; i < size; i++) {
var h = handlers[i]
if (h.handler === handler && h.context === context) {
handlers.splice(i, 1)
return
}
}
}
},
_createResizeTrigger: function (ele) {
var obj = document.createElement('object')
obj.setAttribute('style',
'display: block; position: absolute; top: 0; left: 0; height: 100%; width: 100%; overflow: hidden;opacity: 0; pointer-events: none; z-index: -1;')
obj.onload = EleResize._handleObjectLoad
obj.type = 'text/html'
ele.appendChild(obj)
obj.data = 'about:blank'
return obj
},
_handleObjectLoad: function (evt) {
this.contentDocument.defaultView.__resizeTrigger__ = this.__resizeElement__
this.contentDocument.defaultView.addEventListener('resize', EleResize._handleResize)
}
}
if (document.attachEvent) { // ie9-10
EleResize.on = function (ele, handler, context) {
var handlers = ele.__z_resizeListeners
if (!handlers) {
handlers = []
ele.__z_resizeListeners = handlers
ele.__resizeTrigger__ = ele
ele.attachEvent('onresize', EleResize._handleResize)
}
handlers.push({
handler: handler,
context: context
})
}
EleResize.off = function (ele, handler, context) {
var handlers = ele.__z_resizeListeners
if (handlers) {
EleResize._removeHandler(ele, handler, context)
if (handlers.length === 0) {
ele.detachEvent('onresize', EleResize._handleResize)
delete ele.__z_resizeListeners
}
}
}
} else {
EleResize.on = function (ele, handler, context) {
var handlers = ele.__z_resizeListeners
if (!handlers) {
handlers = []
ele.__z_resizeListeners = handlers
if (getComputedStyle(ele, null).position === 'static') {
ele.style.position = 'relative'
}
var obj = EleResize._createResizeTrigger(ele)
ele.__resizeTrigger__ = obj
obj.__resizeElement__ = ele
}
handlers.push({
handler: handler,
context: context
})
}
EleResize.off = function (ele, handler, context) {
var handlers = ele.__z_resizeListeners
if (handlers) {
EleResize._removeHandler(ele, handler, context)
if (handlers.length === 0) {
var trigger = ele.__resizeTrigger__
if (trigger) {
trigger.contentDocument.defaultView.removeEventListener('resize', EleResize._handleResize)
ele.removeChild(trigger)
delete ele.__resizeTrigger__
}
delete ele.__z_resizeListeners
}
}
}
}
export {
EleResize
}