ECHARTS 地图使用

2,533 阅读7分钟

- 地图JSON数据下载

点击直达

- 注册地图

echarts.registerMap

  1. 使用该函数注册地图
  • type: echarts 方法(不是实例的方法)
  • 参数
    • name (string): 注册地图的名字
    • object:
      • geoJson: 注册地图的geoJson数据
  1. 注册完成后,便可使用该地图

- 使用地图

使用地图有两种方式:

  • 使用 geo 组件注册 地理坐标系组件,绘制散点图线集时需要使用到该组件

  • 参数

    • object:
      • map (string): 注册地图的名字
      • show (boolean): 是否显示地理坐标系组件
      • roam (boolean):缩放、平移
      • .....
  • 使用 serires 注册 地图主要用于地理区域数据的可视化,配合 visualMap 组件用于展示不同区域的人口分布密度等数据

  • 参数

    • object
      • type (string): 'map' 地图组件
      • map (string): 注册的地图的名字
      • ......

- 地图上下钻

思路: 监听 echarts 的点击事件,获取点击的地点名与geojson,之后再使用registerMap方法重新注册地图

  1. 自动获取所有geoJson数据(vite)
// 自动导入geoJson数据
const modules = import.meta.glob("@/geoJson/*.json", { eager: true });
const pattern = /(?<=geoJson\/).*(?=\.json)/;
const geoJson = {};

Object.keys(modules).forEach(async (item) => {
    const name = item.match(pattern)[0];
    const data = modules[item];
    geoJson[name] = data.default;
});

export default geoJson;

数据如下形式:

geoJson = {
	全国: {
			geoJson: [... ],
			info: {
					name: ' ... ',
					level: '...',
					adcode: ...
				}
		},
	江西省:{
		geoJson: {...},
		info: {...}
	}
	...
}
  1. 初始化地图 我们使用 historyList 存储每个层级的数据,index存储地图层级,如初始进入 index 为 0,historyList存入 全国数据:
// 历史列表
const historyList = reactive([]);
// 层级
const index = ref();
onMounted(() => {
	myEchart.value = useEcharts(main.value, null, {
        width: "auto",
        height: "auto",
    });
    pushHistory(historyList, mapData.info);
    index.value = 0
    })

向 historyList 添加记录: 当 info 的 level 为同一级则不添加到历史列表中,如两次都点击为 省,表明没有下钻,则不需要添加至记录中

export const pushHistory = (list, info) => {
    if (list.length === 0) {
        list.push(info);
        return;
    }

    const index = list.length - 1;
    if (list[index].level === info.level) {
        list[index] = info;
    } else {
        list.push(info);
    }
};

注册 map 组件: 我们使用 watch 监听层级 index 的变化,当层级变化就说明进行了下钻回或上钻,此时我们只需要重新注册地图,并且我们将 index 初始值赋值为空,初始化地图时我们 赋予 index 为 0,也会触发 watch,进行地图的初始化注册

watch(index, (newv) => {
    let name = historyList[newv].name;
    const geoJson = map.value[name].geoJson;
    registerMap(name, { geoJson });
    myEchart.value.setOption({
        // 标题组件,包含主标题和副标题。
        title: {
            show: true,
            // 主题文字内容
            text: "全国经济情况(假)",
            // 主标题文字样式
            textStyle: {
                color: "red",
                fontStyle: "italic",
                textBorderColor: "#000",
                textBorderWidth: 1,
                width: 100,
                textShadowColor: "red",
                textShadowBlur: 3,
                textShadowOffsetY: 3,
            },
            subtext: "2022-10-11(数据随机)",
            subtextStyle: {
                color: "red",
                fontStyle: "italic",
            },
            left: "center",
        },
        // 地理坐标系组件用于地图的绘制,支持在地理坐标系上绘制散点图,线集
        geo: {
            map: name,
            show: false,
        },
        //  提示框组件。
        tooltip: {
            show: true,
            trigger: "item",
            // 提示框浮层内容格式器,支持字符串模板和回调函数两种形式。
            formatter(params) {
                return `${params.name}: ${params.value}`;
            },
            backgroundColor: "rgba(0, 0, 0, 0.7)",
            textStyle: {
                color: "#fff",
            },
        },
        series: [
            // 地图组件
            {
                name: "经济",
                type: "map",
                // 使用 registerMap 注册的地图名称。
                map: name,
                // 是否显示地理坐标系组件。
                show: true,
                // 是否开启鼠标缩放和平移漫游。默认不开启。如果只想要开启缩放或者平移,可以设置成 'scale' 或者 'move'。设置成 true 为都开启
                roam: true,
                label: {
                    show: true,
                    color: "#fff",
                },
                itemStyle: {
                    // 地图整体颜色
                    areaColor: "#fff",
                    // 地图线条颜色
                    borderColor: "#1773c3",
                    // 阴影颜色
                    shadowColor: "#1773c3",
                    // 阴影大小
                    shadowBlur: 4,
                    shadowOffsetY: 1,
                    // 图形颜色,与areaColor颜色一致,优先级若于areaColor
                    color: "#000",
                    //描边线宽
                    borderWidth: 0,
                    //描边类型。
                    borderType: [5, 10],
                    borderDashOffset: 130,
                },
                //高亮状态下的多边形和标签样式。
                emphasis: {
                    disabled: false,
                    focus: "none",
                    label: {
                        color: "red",
                        fontWeight: "bolder",
                    },
                    // 地图区域的多边形 图形样式。
                    itemStyle: {
                        areaColor: "#1773c3",
                    },
                },
                //选中状态下的多边形和标签样式。
                select: {
                    label: {
                        fontWeight: "bolder",
                        color: "#fff",
                    },
                    itemStyle: {
                        areaColor: "#000",
                    },
                },
                // regions: [
                //     {
                //         name: "江西省",
                //         itemStyle: {
                //             areaColor: "red",
                //             color: "red",
                //         },
                //     },
                // ],
            },
        ],
    });
});
  1. 监听 echarts 点击事件 实现地图上下钻

地图下钻 点击地图时,监听 ecarts 点击事件,可以获取到 地图名称,我们只需要将层级 index 加一 ,并且将地图的info添加至记录(historyList),触发 watch 进行地图的重新注册,实现地图下钻

myEchart.value.on("click", (params) => {
        console.log("params", params.name);
        const name = params.name;
        if (!map.value[name]) return;
        index.value = index.value + 1;
        pushHistory(historyList, map.value[name].info);
    });

地图上钻 当点击空白处,没有点击地图时,我们将层级 index 减一,将记录(historyList)最后的info删除,index 变化会触发 watch 进行地图重新注册

// 点击空白处时,返回地图的上一级
    myEchart.value.getZr().on("click", async (event) => {
        if (!event.target) {
            console.log("点击了空白处");
            popHistiry(historyList)
                .then(() => {
                    index.value = index.value - 1;
                })
                .catch((err) => {
                    console.log("不能再返回了");
                });
        }
    });

监听“空白处”的事件 直达: 有时候,开发者需要监听画布的“空白处”所触发的事件。比如,当需要在用户点击“空白处”的时候重置图表时。

在讨论这个功能之前,我们需要先明确两种事件。zrender 事件和 echarts 事件。

myChart.getZr().on('click', function(event) {
  // 该监听器正在监听一个`zrender 事件`。
});
myChart.on('click', function(event) {
  // 该监听器正在监听一个`echarts 事件`。
});

zrender 事件与 echarts 事件不同。前者是当鼠标在任何地方都会被触发,而后者是只有当鼠标在图形元素上时才能被触发。事实上,echarts 事件是在 zrender 事件的基础上实现的,也就是说,当一个 zrender 事件在图形元素上被触发时,echarts 将触发一个 echarts 事件给开发者。

有了 zrender 事件,我们就可以实现监听空白处的事件,具体如下:

myChart.getZr().on('click', function(event) {
  // 没有 target 意味着鼠标/指针不在任何一个图形元素上,它是从“空白处”触发的。
  if (!event.target) {
    // 点击在了空白处,做些什么。
  }
});

完整代码

<script setup>
import mapGeoJson from "../geoJson";
import { ref, shallowRef, onMounted, watch, reactive, watchEffect } from "vue";
import { registerMap, useEcharts } from "../utils/echarts";
import { pushHistory, popHistiry } from "../utils/mapHistory.js";
import mapData from "../geoJson/全国.json";

const map = shallowRef(mapGeoJson);
const main = ref(null);
const myEchart = shallowRef(null);
const historyList = reactive([]);
const index = ref();

onMounted(() => {
    myEchart.value = useEcharts(main.value, null, {
        width: "auto",
        height: "auto",
    });
    pushHistory(historyList, mapData.info);
    index.value = 0;
    // 点击地图下钻
    myEchart.value.on("click", (params) => {
        console.log("params", params.name);
        const name = params.name;
        if (!map.value[name]) return;
        index.value = index.value + 1;
        pushHistory(historyList, map.value[name].info);
    });

    // 点击空白处时,返回地图的上一级
    myEchart.value.getZr().on("click", async (event) => {
        if (!event.target) {
            console.log("点击了空白处");
            popHistiry(historyList)
                .then(() => {
                    index.value = index.value - 1;
                })
                .catch((err) => {
                    console.log("不能再返回了");
                });
        }
    });
});

watch(index, (newv) => {
    // 清空当前实例,会移除实例中所有的组件和图表。
    let name = historyList[newv].name;
    const geoJson = map.value[name].geoJson;
    registerMap(name, { geoJson });
    myEchart.value.setOption({
        // 标题组件,包含主标题和副标题。
        title: {
            show: true,
            // 主题文字内容
            text: "全国经济情况(假)",
            // 主标题文字样式
            textStyle: {
                color: "red",
                fontStyle: "italic",
                textBorderColor: "#000",
                textBorderWidth: 1,
                width: 100,
                textShadowColor: "red",
                textShadowBlur: 3,
                textShadowOffsetY: 3,
            },
            subtext: "2022-10-11(数据随机)",
            subtextStyle: {
                color: "red",
                fontStyle: "italic",
            },
            left: "center",
        },
        // 地理坐标系组件用于地图的绘制,支持在地理坐标系上绘制散点图,线集
        geo: {
            map: name,
            // 不显示组件,如果 series 注册了地图,geo也注册可,会显示两个地图组件(重叠)
            show: false,
        },
        //  提示框组件。
        tooltip: {
            show: true,
            trigger: "item",
            // 提示框浮层内容格式器,支持字符串模板和回调函数两种形式。
            formatter(params) {
                return `${params.name}: ${params.value}`;
            },
            backgroundColor: "rgba(0, 0, 0, 0.7)",
            textStyle: {
                color: "#fff",
            },
        },

        series: [
            {
                name: "经济",
                type: "map",
                // 使用 registerMap 注册的地图名称。
                map: name,
                // 是否显示地理坐标系组件。
                show: true,
                // 是否开启鼠标缩放和平移漫游。默认不开启。如果只想要开启缩放或者平移,可以设置成 'scale' 或者 'move'。设置成 true 为都开启
                roam: true,
                label: {
                    show: true,
                    color: "#fff",
                },
                itemStyle: {
                    // 地图整体颜色
                    areaColor: "#fff",
                    // 地图线条颜色
                    borderColor: "#1773c3",
                    // 阴影颜色
                    shadowColor: "#1773c3",
                    // 阴影大小
                    shadowBlur: 4,
                    shadowOffsetY: 1,
                    // 图形颜色,与areaColor颜色一致,优先级若于areaColor
                    color: "#000",
                    //描边线宽
                    borderWidth: 0,
                    //描边类型。
                    borderType: [5, 10],
                    borderDashOffset: 130,
                },
                //高亮状态下的多边形和标签样式。
                emphasis: {
                    disabled: false,
                    focus: "none",
                    label: {
                        color: "red",
                        fontWeight: "bolder",
                    },
                    // 地图区域的多边形 图形样式。
                    itemStyle: {
                        areaColor: "#1773c3",
                    },
                },
                //选中状态下的多边形和标签样式。
                select: {
                    label: {
                        fontWeight: "bolder",
                        color: "#fff",
                    },
                    itemStyle: {
                        areaColor: "#000",
                    },
                },
                // regions: [
                //     {
                //         name: "江西省",
                //         itemStyle: {
                //             areaColor: "red",
                //             color: "red",
                //         },
                //     },
                // ],
            },
        ],
    });
});
</script>
<template>
    <div class="main" ref="main"></div>
</template>
<style lang="scss" scoped>
.main {
    width: 1400px;
    height: 900px;
}
</style>