- 需求: 用echarts构建中国地图展示数据并点击下钻展示各省市地图
-
- 安装echarts并在main.js中引入
npm install echarts
import * as echarts from 'echarts';
Vue.prototype.$echarts = echarts;
-
- 创建div图表容器(html + css)
<template>
<div class="container">
<!-- 返回按钮 -->
<img
@click="toBack()"
v-if="paramsList.length > 1"
:src="require('@/assets/img/landTransport/return.png')"
alt=""
/>
<!-- 数据加载中 -->
<div v-if="showLoading" class="loading">
<div><i class="el-icon-loading"></i></div>
<div class="loading-label">数据加载中...</div>
</div>
<!-- 地图容器 -->
<div class="china-map" ref="mapRef"></div>
</div>
</template>
<style>
.container {
width: 100%;
height: 100%;
padding: 20px;
position: relative;
img {
width: 25px;
height: 22px;
cursor: pointer;
position: absolute;
top: 20px;
right: 20px;
z-index: 999;
}
.loading {
position: absolute;
top: 38%;
left: 45%;
z-index: 999;
div {
width: 100px;
display: flex;
justify-content: center;
}
i {
font-size: 30px;
color: white;
}
.loading-label {
font-size: 30px;
color: #fff;
}
}
// echarts容器必须定义宽高!!
.china-map {
width: 100%;
height: 100%;
}
}
</style>
-3 初始化echarts配置项
export const mailRouteMapOption = {
geo: {
map: 'china',
roam: 'scale', // 闭拖拽
aspectScale: 0.8,
layoutCenter: ['50%', '50%'], // 地图位置
layoutSize: '100%',
zoom: 1.25, // 当前视角的缩放比例
roam: false,
animationDurationUpdate: 0,
// 鼠标放上去的样式
emphasis: {
show: false,
},
itemStyle: {
shadowColor: '#054569',
areaColor: '#021132',
borderColor: '#00B2FF',
borderWidth: 3, // 边界
shadowOffsetX: 0,
shadowOffsetY: 10,
opacity: 0.9,
},
regions: [
{
name: '南海诸岛',
itemStyle: {
opacity: 0,
label: {
show: true,
},
},
},
],
// "center": "POINT(124.9 22)",
},
series: [
// 常规地图
{
type: 'map',
silent: true,
map: 'china',
mapType: 'china',
aspectScale: 0.8,
layoutCenter: ['50%', '50%'], // 地图位置
layoutSize: '100%',
zoom: 1.25, // 当前视角的缩放比例
roam: false, // 是否开启平游或缩放
label: {
// 通常状态下的样式
show: true, // 省份名展示
color: '#fff',
},
// 鼠标放上去的样式
emphasis: {
show: false,
disabled: true,
},
itemStyle: {
areaColor: '#021132',
borderColor: '#305E76',
borderWidth: 1, //边界
},
},
// 气泡
{
type: 'scatter',
coordinateSystem: 'geo',
symbolSize: [12, 12],
symbolOffset: [0, 0],
symbol: circleImg,
zlevel: 9999,
data: [],
},
// 线路
{
type: 'lines',
coordinateSystem: 'geo',
emphasis: {
show: false,
},
zlevel: 99999,
// symbol: 'arrow',
effect: {
show: true,
period: 6, // 箭头指向速度,值越小速度越快
trailLength: 0, // 特效尾迹长度[0,1]值越大,尾迹越长重
symbol: 'arrow', // 箭头图标
symbolSize: 10, // 图标大小
// color: '#fff',
},
lineStyle: {
width: 1,
opacity: 1, // 尾迹线条透明度
curveness: 0.4, // 曲线的弯曲程度
color: '#00FDFF',
},
data: [],
},
],
};
-4 初始化echarts(js)
<script>
import { mailRouteMapOption } from './config'; // echarts配置项
export default {
data() {
return {
paramsList: [], // 参数列表
showLoading: false, // 是否显示loading按钮
};
},
created() {
this.chart = null;
this.mapData = []; // 地图名称和code码的映射关系
this.mapJson = {}; // 地图json数据
this.mapLineData = []; // 地图线
this.mapScatterData = []; // 地图点
this.chartOption = JSON.parse(JSON.stringify(mailRouteMapOption));
},
methods: {
createChart(){
// 初始化echarts实例
if(!this.chart){
this.chart = this.$echarts.init(this.$refs.mapRef);
}else {
this.chart &&this.chart.clear();
};
// 更改配置项
this.initChinaData(mapName);
// 注册地图
this.$echarts.registerMap(
mapName, // 地图名称
this.mapJson, // 地图json数据
{}
);
// 设置配置项
this.chart.setOption(this.chartOption);
},
initChinaData(mapName = 'china'){}
}
}
</script>
-5 初始化请求并在mounted中调用该请求
queryMapsInfo() {
this.showLoading = true;
let { mapCode, mapType, mapName } =
this.paramsList[this.paramsList.length - 1];
this.mapLineData = [];
this.mapScatterData = [];
this.mapJson = {};
// 地图json数据传参
const params = {
code: mapCode,
type: mapType,
};
Promise.allSettled([
this.$api.queryMapsInfo(params),
this.$api.queryMailPostalRoute(params),
]).then((res) => {
// 地图json数据处理
if (
res[0].status !== 'rejected' &&
res[0].value.data &&
res[0].value.data.length
) {
if (this.chinaMap) this.chinaMap.clear();
this.mapJson = this.handleGeojson(res[0].value);
} else {
this.$message.warning('暂无数据');
}
// 地图数据处理
if (
res[1].status !== 'rejected' &&
res[1].value.length &&
Array.isArray(res[1].value)
) {
let { dataLine, dataScatter } = this.getDataLineAndScatter(
res[1].value
);
this.mapLineData = dataLine;
this.mapScatterData = dataScatter;
} else {
this.mapLineData = [];
this.mapScatterData = [];
}
this.createChart(mapName);
this.showLoading = false;
}).catch((err) => {
this.mapLineData = [];
this.mapScatterData = [];
this.mapJson = {};
this.createChart(mapName);
this.showLoading = false;
console.log(err);
});
},
mounted(){
this.paramsList.push({ mapCode: '000000', mapType: '0', mapName: 'china' });
this.queryMapsInfo();
}
-6 将接口返回的地图数据返回成echarts地图渲染所需要的格式数据
接口返回格式
echarts所需要的格式
handleGeojson(param, str = 'data') {
this.mapData = [];
let geojson = {
type: 'FeatureCollection',
features: param[str].map((item) => {
let geo = {};
let properties = {
name: item.name,
adcode: Number(item.code),
};
this.mapData.push({
name: item.name,
value: item.code.slice(0, -6),
});
geo = {
type: 'Feature',
geometry: item.geom,
properties: properties,
};
return geo;
}),
};
return geojson;
},
-7 处理地图scatter和lines数据处理成需要的格式
// 点需要的格式 - 点的经纬度
[{value: [longitude, latitude]}]
// 线所需要的格式 - 起始和结束两个点的经纬度
[
{
coords:
[ [start.longitude, start.latitude], [end.longitude, nd.latitude]]
}
]
//获取地图线路及标注的圆点
getDataLineAndScatter(data) {
if (!data.length) return;
let dataLine = [];
let dataScatter = [];
data.forEach((item, index) => {
if (item.stationList.length && Array.isArray(item.stationList)) {
item.stationList.forEach((smallItem, smallIndex) => {
let start = smallItem;
let end = item.stationList[smallIndex + 1];
if (!end) return;
if (
start.longitude &&
start.latitude &&
end.longitude &&
end.latitude
) {
dataLine.push({
fromCode: start.stationOrgCode,
toCode: end.stationOrgCode,
coords: [
[start.longitude, start.latitude],
[end.longitude, end.latitude],
],
});
dataScatter.push(
{
name: start.stationOrgName,
value: [start.longitude, start.latitude],
},
{
name: end.stationOrgName,
value: [end.longitude, end.latitude],
}
);
}
});
} else {
return;
}
});
return { dataLine, dataScatter };
},
-8 处理echarts数据并添加点击事件
initChinaData(mapName = 'china') {
// 地图名称
this.chartOption.geo.map = mapName;
this.chartOption.series[0].map = mapName;
// 地图数据
if (this.mapLineData.length && this.mapScatterData.length) {
// 接口有数据
this.chartOption.series[1].data = this.mapScatterData || [];
this.chartOption.series[2].data = this.mapLineData || [];
this.chartOption.series[2].lineStyle.color = '#00FDFF';
} else {
this.chartOption.series[1].data = [];
this.chartOption.series[2].data = [];
}
// 添加点击事件
// 地图双击
this.chart.off('click');
this.chart.on('click', (param) => {
let { name, value } = this.findAreacode(param.name);
// 下钻到省
if (param.componentType == 'geo' && this.paramsList.length < 3) {
this.chart.clear();
// 获取下钻信息
this.paramsList.push({ mapCode: value, mapType: '2', mapName: name });
this.queryMapsInfo();
}
});
},
-9 添加返回上一层事件
// 返回上一层
toBack() {
this.paramsList.pop();
this.queryMapsInfo();
},
-10 地图响应式
mounted(){
window.addEventListener('resize', this.chartResize);
},
methods:{
// 地图自适应
chartResize() {
this.chart && this.chart.resize();
},
},
beforeDestroy() {
window.removeEventListener('resize', this.chartResize);
},
- 健康地活着,平静地过着 -
- 开心地笑着,适当地忙着 -
- 就很好了 -