【初学者笔记】echarts中国地图

1,133 阅读2分钟
  • 需求: 用echarts构建中国地图展示数据并点击下钻展示各省市地图

image.png

    1. 安装echarts并在main.js中引入
npm install echarts

import * as echarts from 'echarts';
Vue.prototype.$echarts = echarts;
    1. 创建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地图渲染所需要的格式数据

接口返回格式 image.png echarts所需要的格式 image.png

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);
},

- 健康地活着,平静地过着 -

- 开心地笑着,适当地忙着 -

- 就很好了 -