Echarts --- 中国地图(2D)

0. 环境搭建

1. 所需数据集

echarts ---- 生成中国地图所需的所有数据集

2. 包下载

npm i echarts
npm i mathjs

1. 处理数据并传给子组件

map/index.vue

<template>
    <div class="mapview">
        <!-- 左侧图表 -->
        <div class="c-left">
            <!-- 设备统计 -->
            <div class="total">
                <div class="title">产品统计</div>
                <div class="card">
                    <!--                    <div class="list" v-for="(item, index) in totalList" :key="index">-->
                    <!--                        <span class="list-num">{{ item.value + '' || '&#45;&#45;' }}</span>-->
                    <!--                        <span class="list-name">{{ item.title || '' }}</span>-->
                    <!--                    </div>-->
                </div>
            </div>
        </div>

        <mapChina :pointData="pointData" :filterPointArr="filterPointArr"/>
    </div>
</template>

<script>
    import mapChina from "@/views/map/config/mapChina";
    import {subtract} from 'mathjs';

    export default {
        name: "balerMap",
        components: {
            mapChina,
        },
        data() {
            return {
                originalData: [    // 原始数据
                    {
                        "id": 3,
                        "longitude": "120.335777",
                        "latitude": "29.744551"
                    },
                    {
                        "id": 4,
                        "longitude": "108.449715",
                        "latitude": "21.575615"
                    },
                    {
                        "id": 5,
                        "longitude": "120.360321",
                        "latitude": "31.903963"
                    },
                    {
                        "id": 7,
                        "longitude": "118.490368",
                        "latitude": "34.929584"
                    },
                    {
                        "id": 8,
                        "longitude": "118.577217",
                        "latitude": "31.176367"
                    },
                    {
                        "id": 11,
                        "longitude": "119.257591",
                        "latitude": "31.542629"
                    },
                    {
                        "id": 13,
                        "longitude": "111.371857",
                        "latitude": "35.587124"
                    },
                    {
                        "id": 19,
                        "longitude": "121.20354",
                        "latitude": "30.215174"
                    },
                    {
                        "id": 27,
                        "longitude": "112.315285",
                        "latitude": "30.299171"
                    },
                    {
                        "id": 29,
                        "longitude": "119.725922",
                        "latitude": "32.518761"
                    },
                    {
                        "id": 33,
                        "longitude": "112.247955",
                        "latitude": "37.601864"
                    }
                ],
                pointData: [],
                filterPointArr: [], // 处理后的数据
            }
        },
        mounted() {
            this.getPositionData()
        },
        methods: {
            getPositionData() {
                // 经纬度整数部分数据相同, 合并散点  地图层级较低时, 利用此数据展示该位置有多少机器数量
                const filterPointArr = []
                // 经纬度相同的坐标合并 (合并id)
                const mergedIDArray = [];
                // // 利用集合处理数据
                const processedIds = new Set();

                this.originalData.forEach((item, index) => {
                    item.id = item.id + ''

                    // 经纬度有可能会错位,矫正经纬度
                    if (Number(item.latitude) > Number(item.longitude)) {
                        const lgd = item.longitude;
                        item.longitude = item.latitude;
                        item.latitude = lgd;
                    }
                    if (index === 0) {
                        filterPointArr.push(item);
                    } else {
                        // 经纬度相同的坐标优先级 > 合并ID相同的数据
                        for (let k = 0; k < filterPointArr.length; k++) {
                            const subtractLatitude = subtract(item.latitude, filterPointArr[k].latitude);
                            const subtractLongitude = subtract(item.longitude, filterPointArr[k].longitude);
                            if (Math.abs(subtractLatitude) < 1 && Math.abs(subtractLongitude) < 1) {
                                // 查找已处理数据中是否有相同 ID 的数据
                                const flagg = filterPointArr.filter((fitem) => fitem.id.split(',').includes(item.id));
                                if (!flagg.length) {
                                    filterPointArr[k].id += `,${item.id}`;
                                }
                            }
                        }
                        // 等for结束后, 如果此item.id没被捕获, 直接push这条数据
                        const flag = filterPointArr.filter((fitem) => fitem.id.split(',').includes(item.id));
                        if (!flag.length) {
                            filterPointArr.push(item);
                        }
                    }
                    if (!processedIds.has(item.longitude) && !processedIds.has(item.latitude)) {
                        const matchingItems = mergedIDArray.filter(
                            (otherItem) => otherItem.longitude === item.longitude && otherItem.latitude === item.latitude
                        );

                        if (matchingItems.length > 0) {
                            const mergedIds = matchingItems.map((matchingItem) => matchingItem.id).join(', ');
                            mergedIDArray.push({
                                id: mergedIds,
                                longitude: item.longitude,
                                latitude: item.latitude,
                            });

                            matchingItems.forEach((matchingItem) => {
                                processedIds.add(matchingItem.longitude + matchingItem.latitude);
                            });
                        } else {
                            mergedIDArray.push(item);
                        }
                    }
                })

                for (let k of mergedIDArray) {
                    this.pointData.push({
                        name: k.id,
                        value: [k.longitude, k.latitude, k.longitude + ', ' + k.latitude],
                    });
                }

                for (let k of filterPointArr) {
                    this.filterPointArr.push({
                        name: k.id,
                        value: [k.longitude, k.latitude, k.longitude + ', ' + k.latitude],
                    });
                }
            }
        }

    }
</script>

<style lang="less" scoped>
    .mapview {
        width: 100%;
        height: calc(100vh - 55px);
        background: linear-gradient(to bottom, #122d56 0%, #113d7b 80%, #1d4583 100%);
        overflow: hidden;
        position: relative;

        .c-left {
            width: 370px;
            height: auto;
            padding: 10px 10px;
            color: #c7dbfa;
            position: absolute;
            left: 0;
            display: flex;
            flex-direction: column;
            justify-content: space-between;
            z-index: 2;

            .total {
                width: 100%;
                height: 220px;
                border: 1px solid #5993ea;
                border-radius: 4px;
                box-shadow: inset 0px 0px 20px #25679f;

                .title {
                    width: 50%;
                    height: 30px;
                    line-height: 30px;
                    margin: 8px auto;
                    text-align: center;
                    font-size: 16px;
                    border-radius: 5px;
                    background: #1f5193;
                    overflow: hidden;
                    white-space: nowrap;
                    text-overflow: ellipsis;
                    -o-text-overflow: ellipsis;
                }

                .card {
                    width: 99%;
                    height: 78%;
                    padding: 2px 2px;
                    display: flex;
                    flex-wrap: wrap;
                    justify-content: space-around;
                    align-items: center;
                    overflow: hidden;

                    .list {
                        width: 31%;
                        height: 44%;
                        border-radius: 2px;
                        background-color: #1f5193;
                        display: flex;
                        flex-direction: column;
                        justify-content: space-evenly;
                        align-items: center;
                        white-space: nowrap;

                        span {
                            white-space: nowrap;
                        }

                        .list-num {
                            font-size: 20px;
                            font-weight: bold;
                        }

                        .list-name {
                            font-size: 13px;
                        }
                    }
                }
            }
        }
    }
</style>

map/config/mapChina.vue

<template>
    <div style="width: 100%; height: 1080%">
        <div id="scatter"></div>
    </div>
</template>

<script>
    import * as chinaMap from '@/static/map/china.json'
    import * as echarts from 'echarts';

    export default {
        name: "mapChina",
       	// 接收父组件传递的数据
        props: {
            pointData: Array,
            filterPointArr: Array,
        },
    }
</script>

<style lang="less" scoped>
</style>

2. 初始化地图

map/config/mapChina.vue

<template>
    <div style="width: 100%; height: 1080%">
        <div id="scatter"></div>
    </div>
</template>

<script>
    import * as chinaMap from '@/static/map/china.json'
    import * as echarts from 'echarts';

    export default {
        name: "mapChina",

        data() {
            return {
                option: {
                    animation: false,
                    tooltip: {},
                    geo: {
                        map: 'china', // 地图类型, 这里是中国地图
                        zoom: 1.5,   // 地图默认缩放等级
                        center: [98, 34.5],  // 地图中心经纬度
                        roam: true, //是否允许缩放 - 拖拽
                        // selectedMode: "single", //点击省份高亮 single / multiple
                        animationDurationUpdate: 0, //地图移动的时候,渲染的点跟着移动,但是会有延迟,值为0,则无需延迟
                        scaleLimit: {
                            min: 0.7,
                            // max: 8.0,
                        },
                        label: {
                            show: true, // 显示省份
                            color: '#eaeaea',
                            fontSize: 16,
                        },
                        itemStyle: {
                            areaColor: '#2971c3', //#2971c3  #228fba  #3a7fd5
                            borderColor: '#0299e2', //#0e335e  #0299e2
                            borderWidth: 2,
                            // shadowBlur: 10,
                            // shadowOffsetX: 2,
                            // shadowOffsetY: 2,
                            // shadowColor: '#0e335e',
                        },
                        //hover状态下的多边形和标签样式
                        emphasis: {
                            // disabled: true, //是否关闭高亮状态
                            focus: 'none', //是否淡出其它数据的图形 'self' / 'none'
                            label: {
                                show: true,
                                color: '#eaeaea',
                            },
                            itemStyle: {
                                areaColor: '#39c5cf',
                                color: '#0066CC',
                            },
                        },
                        tooltip: {
                            show: false,
                        },
                        data: [],
                    }
                },
            }
        },
        mounted() {
            // 1. 注册中国地图
            echarts.registerMap('china', chinaMap)
            // 2. 初始化地图
            this.initMap('china')
        },
        methods: {
            /**
             * echarts 初始化地图
             * @param mapType
             */
            initMap(mapType) {
                this.mapReset()
                this.mapChart = echarts.init(document.getElementById('scatter'))
                this.option.geo.map = mapType
                // 配置中国地图 或 世界地图的配置
                if (mapType === 'china') {
                    this.option.geo.zoom = 1.5;
                    this.option.geo.center = ['98', '35'];
                    this.option.geo.label.show = true;
                } else {
                    this.option.geo.zoom = 1;
                    this.option.geo.center = '';
                    this.option.geo.label.show = true;
                }
                this.mapChart.setOption(this.option, true)
            },

            /**
             * echarts 重置地图配置
             */
            mapReset() {
                this.mapChart && this.mapChart.dispose()
                this.mapChart = null
            }
        }
    }
</script>

<style lang="less" scoped>
    #scatter {
        width: 1920px;
        height: 1080px;
    }

    .mapBack {
        padding: 8px 14px;
        font-size: 15px;
        color: #bdddfd;
        background-color: #1c4c7c;
        position: absolute;
        left: 425px;
        margin-top: 20px;
        z-index: 9;
        white-space: nowrap;
    }
</style>

3. 根据坐标在地图打点

map/config/mapChina.vue

<template>
    <div style="width: 100%; height: 1080%">
        <div id="scatter"></div>
    </div>
</template>

<script>
    import * as chinaMap from '@/static/map/china.json'
    import * as echarts from 'echarts';

    export default {
        name: "mapChina",

        data() {
            return {
                isHighLevel: false,
                option: {
                    animation: false,
                    tooltip: {},
                    geo: {
                        map: 'china', // 地图类型, 这里是中国地图
                        zoom: 1.5,   // 地图默认缩放等级
                        center: [98, 34.5],  // 地图中心经纬度
                        roam: true, //是否允许缩放 - 拖拽
                        // selectedMode: "single", //点击省份高亮 single / multiple
                        animationDurationUpdate: 0, //地图移动的时候,渲染的点跟着移动,但是会有延迟,值为0,则无需延迟
                        scaleLimit: {
                            min: 0.7,
                            // max: 8.0,
                        },
                        label: {
                            show: true, // 显示省份
                            color: '#eaeaea',
                            fontSize: 16,
                        },
                        itemStyle: {
                            areaColor: '#2971c3', //#2971c3  #228fba  #3a7fd5
                            borderColor: '#0299e2', //#0e335e  #0299e2
                            borderWidth: 2,
                            // shadowBlur: 10,
                            // shadowOffsetX: 2,
                            // shadowOffsetY: 2,
                            // shadowColor: '#0e335e',
                        },
                        //hover状态下的多边形和标签样式
                        emphasis: {
                            // disabled: true, //是否关闭高亮状态
                            focus: 'none', //是否淡出其它数据的图形 'self' / 'none'
                            label: {
                                show: true,
                                color: '#eaeaea',
                            },
                            itemStyle: {
                                areaColor: '#39c5cf',
                                color: '#0066CC',
                            },
                        },
                        tooltip: {
                            show: false,
                        },
                        data: [],
                    },
                    // 3. 添加地图数据的配置项
                    series: [
                        {
                            type: 'scatter', //scatter, effectScatter(涟漪)
                            coordinateSystem: 'geo',
                            // zlevel: 2,
                            // rippleEffect: {
                            // 	//涟漪特效
                            // 	number: 3, //环数
                            // 	period: 4, //动画时间,值越小速度越快
                            // 	brushType: 'stroke', //波纹绘制方式 stroke, fill
                            // 	scale: 8, //波纹圆环最大限制,值越大波纹越大
                            // 	color: '#ffaa00',
                            // },
                            symbol: 'circle', //标记的图形
                            symbolSize: 8,
                            itemStyle: {
                                show: false,
                                color: '#ffaa00',
                            },
                            emphasis: {
                                disabled: true,
                            },
                            data: [],
                        },
                        {
                            name: 'pin',
                            type: 'scatter',
                            coordinateSystem: 'geo',
                            symbol: 'pin',
                            // symbolOffset: [0, '-10%'],
                            symbolSize: 40,
                            tooltip: {
                                show: true,
                                trigger: 'item',
                                formatter: function (e) {
                                    // return `设备id:  ${e.name}\n经纬度:  ${e.value[2]}`
                                    if (e.name.length === 1) {
                                        return `设备数量: 1`;
                                    } else if (e.name.length > 1) {
                                        return `设备数量: ${e.name.split(',').length}`;
                                    }
                                },
                                borderColor: '#ffaa00',
                                backgroundColor: '#fefefe',
                            },
                            label: {
                                show: true,
                                color: '#fff',
                                fontSize: 17,
                                formatter: (e) => {
                                    if (e.name.length === 1) {
                                        return e.name.length;
                                    } else if (e.name.length > 1) {
                                        return e.name.split(',').length;
                                    } else {
                                        return '';
                                    }
                                },
                            },
                            itemStyle: {
                                color: '#eb9d00', //标志颜色
                                borderColor: '#fff',
                                // borderWidth: 2,
                                opacity: 1,
                            },
                            zlevel: 3,
                            data: [],
                        },
                    ],
                },
            }
        },
        // 2. 监听数据的变化
        watch:{
            // 当数据发生变化时, 重新在地图上打点
            pointData:{
                handler(){
                    if (this.isHighLevel) {
                        // 地图缩放层级高, 展示精细定位数据
                        this.option.series[0].data = this.pointData;
                        this.option.series[1].data = this.pointData;
                    } else {
                        this.option.series[0].data = this.filterPointArr;
                        this.option.series[1].data = this.filterPointArr;
                    }
                    this.mapChart.setOption(this.option, true);
                },
                deep:true
            }
        },
        mounted() {
            // 1. 必须使用 $nextTick 获取最新更新的dom
            this.$nextTick(() => {
                echarts.registerMap('china', chinaMap)
                this.initMap('china')
            });

        },
        methods: {
            /**
             * echarts 初始化地图
             * @param mapType
             */
            initMap(mapType) {
                this.mapReset()
                this.mapChart = echarts.init(document.getElementById('scatter'))
                this.option.geo.map = mapType
                // 配置中国地图 或 世界地图的配置
                if (mapType === 'china') {
                    this.option.geo.zoom = 1.5;
                    this.option.geo.center = ['98', '35'];
                    this.option.geo.label.show = true;
                } else {
                    this.option.geo.zoom = 1;
                    this.option.geo.center = '';
                    this.option.geo.label.show = true;
                }
                this.mapChart.setOption(this.option, true)
            },

            /**
             * echarts 重置地图配置
             */
            mapReset() {
                this.mapChart && this.mapChart.dispose()
                this.mapChart = null
            }
        },
        props: {
            pointData: Array,
            filterPointArr: Array,
        },
    }
</script>

<style lang="less" scoped>
    #scatter {
        width: 1920px;
        height: 1080px;
    }

    .mapBack {
        padding: 8px 14px;
        font-size: 15px;
        color: #bdddfd;
        background-color: #1c4c7c;
        position: absolute;
        left: 425px;
        margin-top: 20px;
        z-index: 9;
        white-space: nowrap;
    }
</style>

4. 地图缩放、拖拽

``

<template>
    <div style="width: 100%; height: 1080%">
        <div id="scatter"></div>
    </div>
</template>

<script>
    import * as chinaMap from '@/static/map/china.json'
    import * as echarts from 'echarts';

    export default {
        name: "mapChina",

        data() {
            return {
                levelData: [],
                mapChart: null,
                isHighLevel: false,
                option: {
                    animation: false,
                    tooltip: {},
                    geo: {
                        map: 'china', // 地图类型, 这里是中国地图
                        zoom: 1.5,   // 地图默认缩放等级
                        center: [98, 34.5],  // 地图中心经纬度
                        roam: true, //是否允许缩放 - 拖拽
                        // selectedMode: "single", //点击省份高亮 single / multiple
                        animationDurationUpdate: 0, //地图移动的时候,渲染的点跟着移动,但是会有延迟,值为0,则无需延迟
                        scaleLimit: {
                            min: 0.7,
                            // max: 8.0,
                        },
                        label: {
                            show: true, // 显示省份
                            color: '#eaeaea',
                            fontSize: 16,
                        },
                        itemStyle: {
                            areaColor: '#2971c3', //#2971c3  #228fba  #3a7fd5
                            borderColor: '#0299e2', //#0e335e  #0299e2
                            borderWidth: 2,
                            // shadowBlur: 10,
                            // shadowOffsetX: 2,
                            // shadowOffsetY: 2,
                            // shadowColor: '#0e335e',
                        },
                        //hover状态下的多边形和标签样式
                        emphasis: {
                            // disabled: true, //是否关闭高亮状态
                            focus: 'none', //是否淡出其它数据的图形 'self' / 'none'
                            label: {
                                show: true,
                                color: '#eaeaea',
                            },
                            itemStyle: {
                                areaColor: '#39c5cf',
                                color: '#0066CC',
                            },
                        },
                        tooltip: {
                            show: false,
                        },
                        data: [],
                    },
                    // 3. 添加地图数据的配置项
                    series: [
                        {
                            type: 'scatter', //scatter, effectScatter(涟漪)
                            coordinateSystem: 'geo',
                            // zlevel: 2,
                            // rippleEffect: {
                            // 	//涟漪特效
                            // 	number: 3, //环数
                            // 	period: 4, //动画时间,值越小速度越快
                            // 	brushType: 'stroke', //波纹绘制方式 stroke, fill
                            // 	scale: 8, //波纹圆环最大限制,值越大波纹越大
                            // 	color: '#ffaa00',
                            // },
                            symbol: 'circle', //标记的图形
                            symbolSize: 8,
                            itemStyle: {
                                show: false,
                                color: '#ffaa00',
                            },
                            emphasis: {
                                disabled: true,
                            },
                            data: [],
                        },
                        {
                            name: 'pin',
                            type: 'scatter',
                            coordinateSystem: 'geo',
                            symbol: 'pin',
                            // symbolOffset: [0, '-10%'],
                            symbolSize: 40,
                            tooltip: {
                                show: true,
                                trigger: 'item',
                                formatter: function (e) {
                                    // return `设备id:  ${e.name}\n经纬度:  ${e.value[2]}`
                                    if (e.name.length === 1) {
                                        return `设备数量: 1`;
                                    } else if (e.name.length > 1) {
                                        return `设备数量: ${e.name.split(',').length}`;
                                    }
                                },
                                borderColor: '#ffaa00',
                                backgroundColor: '#fefefe',
                            },
                            label: {
                                show: true,
                                color: '#fff',
                                fontSize: 17,
                                formatter: (e) => {
                                    if (e.name.length === 1) {
                                        return e.name.length;
                                    } else if (e.name.length > 1) {
                                        return e.name.split(',').length;
                                    } else {
                                        return '';
                                    }
                                },
                            },
                            itemStyle: {
                                color: '#eb9d00', //标志颜色
                                borderColor: '#fff',
                                // borderWidth: 2,
                                opacity: 1,
                            },
                            zlevel: 3,
                            data: [],
                        },
                    ],
                },
            }
        },


        methods: {
            /**
             * echarts 初始化地图
             * @param mapType
             */
            initMap(mapType) {
                // ......

                // 1. 注册地图拖拽、缩放事件
                this.listenerGeoRoam()
            },
            
            // 2. 地图拖拽、缩放事件的回调函数
            listenerGeoRoam() {
                // 注册地图的缩放、拖拽事件及其回调函数
                this.mapChart.on('geoRoam', (params) => {
                    if (params.dy || params.dx) return

                    const _option = this.mapChart.getOption()
                    if (params.zoom != null && params.zoom != undefined) {
                        if (this.levelData.length === 1) {
                            // 缩放等级大于 1.5
                            if (_option.geo[0].zoom > 1.5) {
                                if (this.roamFlag > 1.5 && _option.geo[0].zoom > this.roamFlag) {
                                    return;
                                }
                                // 重置数据
                                this.isHighLevel = true;
                                this.option.series[0].data = this.pointData;
                                this.option.series[1].data = this.pointData;
                                this.option.geo.zoom = _option.geo[0].zoom;
                                this.mapChart.setOption(this.option, true);
                                this.roamFlag = _option.geo[0].zoom;
                            } else {
                                if (_option.geo[0].zoom <= 1) return;
                                this.isHighLevel = false;
                                this.option.series[0].data = this.pointData;
                                this.option.series[1].data = this.pointData;
                                this.option.geo.zoom = _option.geo[0].zoom;
                                this.mapChart.setOption(this.option, true);
                                this.roamFlag = _option.geo[0].zoom;
                            }
                        }
                    }
                })
            }

        },
        props: {
            pointData: Array,
            filterPointArr: Array,
        },
    }
</script>

<style lang="less" scoped>
    #scatter {
        width: 1920px;
        height: 1080px;
    }

    .mapBack {
        padding: 8px 14px;
        font-size: 15px;
        color: #bdddfd;
        background-color: #1c4c7c;
        position: absolute;
        left: 425px;
        margin-top: 20px;
        z-index: 9;
        white-space: nowrap;
    }
</style>

5. 地图点击

npm i lodash
<template>
    <div style="width: 100%; height: 1080%">
        <div id="scatter"></div>
    </div>
</template>

<script>
    import * as chinaMap from '@/static/map/china.json'
    import * as echarts from 'echarts';
    import {city, county, province} from '@/utils/map/mapNameList';
    import {throttle} from 'lodash'

    export default {
        name: "mapChina",

        data() {
            return {
                levelData: [],
                mapChart: null,
                isHighLevel: false,
                roamFlag: 0,
                option: {
                    animation: false,
                    tooltip: {},
                    geo: {
                        map: 'china', // 地图类型, 这里是中国地图
                        zoom: 1.5,   // 地图默认缩放等级
                        center: [98, 34.5],  // 地图中心经纬度
                        roam: true, //是否允许缩放 - 拖拽
                        // selectedMode: "single", //点击省份高亮 single / multiple
                        animationDurationUpdate: 0, //地图移动的时候,渲染的点跟着移动,但是会有延迟,值为0,则无需延迟
                        scaleLimit: {
                            min: 0.7,
                            // max: 8.0,
                        },
                        label: {
                            show: true, // 显示省份
                            color: '#eaeaea',
                            fontSize: 16,
                        },
                        itemStyle: {
                            areaColor: '#2971c3', //#2971c3  #228fba  #3a7fd5
                            borderColor: '#0299e2', //#0e335e  #0299e2
                            borderWidth: 2,
                            // shadowBlur: 10,
                            // shadowOffsetX: 2,
                            // shadowOffsetY: 2,
                            // shadowColor: '#0e335e',
                        },
                        //hover状态下的多边形和标签样式
                        emphasis: {
                            // disabled: true, //是否关闭高亮状态
                            focus: 'none', //是否淡出其它数据的图形 'self' / 'none'
                            label: {
                                show: true,
                                color: '#eaeaea',
                            },
                            itemStyle: {
                                areaColor: '#39c5cf',
                                color: '#0066CC',
                            },
                        },
                        tooltip: {
                            show: false,
                        },
                        data: [],
                    },
                    // 3. 添加地图数据的配置项
                    series: [
                        {
                            type: 'scatter', //scatter, effectScatter(涟漪)
                            coordinateSystem: 'geo',
                            // zlevel: 2,
                            // rippleEffect: {
                            // 	//涟漪特效
                            // 	number: 3, //环数
                            // 	period: 4, //动画时间,值越小速度越快
                            // 	brushType: 'stroke', //波纹绘制方式 stroke, fill
                            // 	scale: 8, //波纹圆环最大限制,值越大波纹越大
                            // 	color: '#ffaa00',
                            // },
                            symbol: 'circle', //标记的图形
                            symbolSize: 8,
                            itemStyle: {
                                show: false,
                                color: '#ffaa00',
                            },
                            emphasis: {
                                disabled: true,
                            },
                            data: [],
                        },
                        {
                            name: 'pin',
                            type: 'scatter',
                            coordinateSystem: 'geo',
                            symbol: 'pin',
                            // symbolOffset: [0, '-10%'],
                            symbolSize: 40,
                            tooltip: {
                                show: true,
                                trigger: 'item',
                                formatter: function (e) {
                                    // return `设备id:  ${e.name}\n经纬度:  ${e.value[2]}`
                                    if (e.name.length === 1) {
                                        return `设备数量: 1`;
                                    } else if (e.name.length > 1) {
                                        return `设备数量: ${e.name.split(',').length}`;
                                    }
                                },
                                borderColor: '#ffaa00',
                                backgroundColor: '#fefefe',
                            },
                            label: {
                                show: true,
                                color: '#fff',
                                fontSize: 17,
                                formatter: (e) => {
                                    if (e.name.length === 1) {
                                        return e.name.length;
                                    } else if (e.name.length > 1) {
                                        return e.name.split(',').length;
                                    } else {
                                        return '';
                                    }
                                },
                            },
                            itemStyle: {
                                color: '#eb9d00', //标志颜色
                                borderColor: '#fff',
                                // borderWidth: 2,
                                opacity: 1,
                            },
                            zlevel: 3,
                            data: [],
                        },
                    ],
                },
            }
        },
        methods: {
            /**
             * echarts 初始化地图
             * @param mapType
             */
            initMap(mapType) {
                this.mapReset()
                this.mapChart = echarts.init(document.getElementById('scatter'))
                this.option.geo.map = mapType
                // 配置中国地图 或 世界地图的配置
                if (mapType === 'china') {
                    this.option.geo.zoom = 1.5;
                    this.option.geo.center = ['98', '35'];
                    this.option.geo.label.show = true;
                } else {
                    this.option.geo.zoom = 1;
                    this.option.geo.center = '';
                    this.option.geo.label.show = true;
                }
                this.mapChart.setOption(this.option, true)

                // 注册事件
                this.listenerClick()
            },

            /**
             * echarts 重置地图配置
             */
            mapReset() {
                this.mapChart && this.mapChart.dispose()
                this.mapChart = null
            },

            // 地图点击回调函数 ( 使用 lodash 库中的 throttle 来做节流处理)
            listenerClick: throttle(
                function () {
                    this.mapChart.on('click', (param) => {
                        // 如果点击的是地图中的省份, 则展示对应省份的地图
                        if (param.name in province) {
                            this.option.series[0].data = this.pointData;
                            this.option.series[1].data = this.pointData;
                            this.roamFlag = 0;
                            let names = param.name
                            for (let key in province) {
                                if (names === key) {
                                    this.showProvince(province[key], key)
                                    break
                                }
                            }
                        } else if (param.name in city) {  // 如果点击的是地图中的市, 则展示对应市的地图
                            this.option.series[0].data = this.pointData;
                            this.option.series[1].data = this.pointData;
                            this.roamFlag = 0;

                            // 点击市
                            let names = param.name;
                            for (let key in city) {
                                if (names === key) {
                                    this.showCity(city[key], key);
                                    break;
                                }
                            }
                        } else if (param.name in county) {
                            // 点击区
                            this.option.series[0].data = this.filterPointArr;
                            this.option.series[1].data = this.filterPointArr;
                            this.roamFlag = 0;

                            let names = param.name;
                            for (let key in county) {
                                if (names === key) {
                                    this.showCounty(county[key], key);
                                    break;
                                }
                            }
                        }
                    })
                },
                1000, {
                    leading: false,
                    trailing: true
                }
            ),
            // 地图中展示对应的省的地图
            showProvince(pName) {
                let cityJSON = require('@/static/map/province/' + pName + '.json');
                this.mapReset()
                echarts.registerMap(pName, cityJSON)  // 重新注册地图, 地图类型为省级地图, 城市 JSON 文件
                this.initMap(pName)
                this.levelData = []
                this.addLevelData('province', pName);
            },

            // 地图中展示对应的市的地图
            showCity(cName) {
                let cityJSON = require('@/static/map/city/' + cName + '.json');
                this.mapReset()
                echarts.registerMap(cName, cityJSON)  // 重新注册地图, 地图类型为省级地图, 城市 JSON 文件
                this.initMap(cName)
                this.levelData = []
                this.addLevelData('city', cName);
            },

            // 地图中展示对应的区/县的地图
            showCounty(cName) {
                if (cName === '330205' && this.levelData.length < 2) return; //重庆 - 浙江省宁波市 都有江北区
                let cityJSON = require('@/static/map/county/' + cName + '.json');
                this.mapReset();
                echarts.registerMap(cName, cityJSON);
                this.initMap(cName);
            },

            // 缓存下个层级的地图
            addLevelData(level, name) {
                if (this.levelData.length === 0) {
                    this.levelData.push({
                        level: level,
                        name: name
                    })
                    return
                }

                let flag = false;
                for (let k = 0; k < this.levelData.length; k++) {
                    if (this.levelData[k].name !== name) {
                        flag = true;
                    }
                }

                if (flag) {
                    this.levelData.push({
                        level: level,
                        name: name,
                    });
                    flag = false;
                    return;
                }
            }

        },
        props: {
            pointData: Array,
            filterPointArr: Array,
        },
    }
</script>

<style lang="less" scoped>
    #scatter {
        width: 1920px;
        height: 1080px;
    }

    .mapBack {
        padding: 8px 14px;
        font-size: 15px;
        color: #bdddfd;
        background-color: #1c4c7c;
        position: absolute;
        left: 425px;
        margin-top: 20px;
        z-index: 9;
        white-space: nowrap;
    }
</style>

6. 鼠标右键返回上一级地图

<template>
    <div style="width: 100%; height: 1080%">
        <div id="scatter"></div>
    </div>
</template>

<script>
    import * as chinaMap from '@/static/map/china.json'
    import * as echarts from 'echarts';
    import {city, county, province} from '@/utils/map/mapNameList';
    import {throttle} from 'lodash'

    export default {
        name: "mapChina",

        data() {
            return {
                levelData: [],
                mapChart: null,
                isHighLevel: false,
                roamFlag: 0,
                option: {
                    animation: false,
                    tooltip: {},
                    geo: {
                        map: 'china', // 地图类型, 这里是中国地图
                        zoom: 1.5,   // 地图默认缩放等级
                        center: [98, 34.5],  // 地图中心经纬度
                        roam: true, //是否允许缩放 - 拖拽
                        // selectedMode: "single", //点击省份高亮 single / multiple
                        animationDurationUpdate: 0, //地图移动的时候,渲染的点跟着移动,但是会有延迟,值为0,则无需延迟
                        scaleLimit: {
                            min: 0.7,
                            // max: 8.0,
                        },
                        label: {
                            show: true, // 显示省份
                            color: '#eaeaea',
                            fontSize: 16,
                        },
                        itemStyle: {
                            areaColor: '#2971c3', //#2971c3  #228fba  #3a7fd5
                            borderColor: '#0299e2', //#0e335e  #0299e2
                            borderWidth: 2,
                            // shadowBlur: 10,
                            // shadowOffsetX: 2,
                            // shadowOffsetY: 2,
                            // shadowColor: '#0e335e',
                        },
                        //hover状态下的多边形和标签样式
                        emphasis: {
                            // disabled: true, //是否关闭高亮状态
                            focus: 'none', //是否淡出其它数据的图形 'self' / 'none'
                            label: {
                                show: true,
                                color: '#eaeaea',
                            },
                            itemStyle: {
                                areaColor: '#39c5cf',
                                color: '#0066CC',
                            },
                        },
                        tooltip: {
                            show: false,
                        },
                        data: [],
                    },
                    // 3. 添加地图数据的配置项
                    series: [
                        {
                            type: 'scatter', //scatter, effectScatter(涟漪)
                            coordinateSystem: 'geo',
                            // zlevel: 2,
                            // rippleEffect: {
                            // 	//涟漪特效
                            // 	number: 3, //环数
                            // 	period: 4, //动画时间,值越小速度越快
                            // 	brushType: 'stroke', //波纹绘制方式 stroke, fill
                            // 	scale: 8, //波纹圆环最大限制,值越大波纹越大
                            // 	color: '#ffaa00',
                            // },
                            symbol: 'circle', //标记的图形
                            symbolSize: 8,
                            itemStyle: {
                                show: false,
                                color: '#ffaa00',
                            },
                            emphasis: {
                                disabled: true,
                            },
                            data: [],
                        },
                        {
                            name: 'pin',
                            type: 'scatter',
                            coordinateSystem: 'geo',
                            symbol: 'pin',
                            // symbolOffset: [0, '-10%'],
                            symbolSize: 40,
                            tooltip: {
                                show: true,
                                trigger: 'item',
                                formatter: function (e) {
                                    // return `设备id:  ${e.name}\n经纬度:  ${e.value[2]}`
                                    if (e.name.length === 1) {
                                        return `设备数量: 1`;
                                    } else if (e.name.length > 1) {
                                        return `设备数量: ${e.name.split(',').length}`;
                                    }
                                },
                                borderColor: '#ffaa00',
                                backgroundColor: '#fefefe',
                            },
                            label: {
                                show: true,
                                color: '#fff',
                                fontSize: 17,
                                formatter: (e) => {
                                    if (e.name.length === 1) {
                                        return e.name.length;
                                    } else if (e.name.length > 1) {
                                        return e.name.split(',').length;
                                    } else {
                                        return '';
                                    }
                                },
                            },
                            itemStyle: {
                                color: '#eb9d00', //标志颜色
                                borderColor: '#fff',
                                // borderWidth: 2,
                                opacity: 1,
                            },
                            zlevel: 3,
                            data: [],
                        },
                    ],
                },
            }
        },
        // 2. 监听数据的变化
        watch: {
            // 当数据发生变化时, 重新在地图上打点
            pointData: {
                handler() {
                    if (this.isHighLevel) {
                        // 地图缩放层级高, 展示精细定位数据
                        this.option.series[0].data = this.pointData;
                        this.option.series[1].data = this.pointData;
                    } else {
                        this.option.series[0].data = this.filterPointArr;
                        this.option.series[1].data = this.filterPointArr;
                    }
                    this.mapChart.setOption(this.option, true);
                },
                deep: true
            }
        },
        mounted() {
            // 1. 必须使用 $nextTick 获取最新更新的dom
            this.$nextTick(() => {
                echarts.registerMap('china', chinaMap)
                this.initMap('china')
            });

        },
        methods: {
            /**
             * echarts 初始化地图
             * @param mapType
             */
            initMap(mapType) {
                this.mapReset()
                this.mapChart = echarts.init(document.getElementById('scatter'))
                this.option.geo.map = mapType
                // 配置中国地图 或 世界地图的配置
                if (mapType === 'china') {
                    this.option.geo.zoom = 1.5;
                    this.option.geo.center = ['98', '35'];
                    this.option.geo.label.show = true;
                } else {
                    this.option.geo.zoom = 1;
                    this.option.geo.center = '';
                    this.option.geo.label.show = true;
                }
                this.mapChart.setOption(this.option, true)

                // 注册事件
                this.listenerContextmenu(); //监听鼠标右键 (返回中国地图页)
            },

            /**
             * echarts 重置地图配置
             */
            mapReset() {
                this.mapChart && this.mapChart.dispose()
                this.mapChart = null
            },
			
            // 监听鼠标右键点击事件, 返回中国地图页
            listenerContextmenu() {
                // 取消右键单机默认事件
                let mapRight = document.querySelector('#scatter');
                mapRight.oncontextmenu = function () {
                    return false;
                };

                //右键单击返回上一级地图
                this.mapChart.on('contextmenu', () => {
                    this.mapBack();
                });
            },
            
            // 地图返回中国地图页的回调函数
            mapBack() {
                this.isHighLevel = false;
                this.option.series[0].data = this.filterPointArr;
                this.option.series[1].data = this.filterPointArr;
                this.roamFlag = 0;

                // 当 缓存的地图层级-数组 为空时 => 中国地图, 不再执行返回
                if (!this.levelData.length) {
                    echarts.registerMap('china', chinaMap);
                    this.initMap('china');
                }

                if (this.levelData.length === 0 || this.levelData.length === 1) {
                    this.levelData = [];
                    this.mapReset();

                    echarts.registerMap('china', chinaMap);
                    this.initMap('china');
                    return;
                }

                let thisLevelData = this.levelData.pop();
                thisLevelData = this.levelData.pop();
                let jSON = require('@/static/map/' + thisLevelData.level + '/' + thisLevelData.name + '.json');
                this.mapReset();

                echarts.registerMap(thisLevelData.name, jSON);
                this.initMap(thisLevelData.name);
                this.levelData.push(thisLevelData);
            },

        },
        props: {
            pointData: Array,
            filterPointArr: Array,
        },
    }
</script>

<style lang="less" scoped>
    #scatter {
        width: 1920px;
        height: 1080px;
    }

    .mapBack {
        padding: 8px 14px;
        font-size: 15px;
        color: #bdddfd;
        background-color: #1c4c7c;
        position: absolute;
        left: 425px;
        margin-top: 20px;
        z-index: 9;
        white-space: nowrap;
    }
</style>

9. 参考博客

https://blog.csdn.net/m0_52539553/article/details/138074255
posted @ 2024-09-13 15:56  河图s  阅读(336)  评论(0)    收藏  举报