首页 前端知识 如何在 Vue3 中结合 ECharts 实现交互式的中国地图钻取功能

如何在 Vue3 中结合 ECharts 实现交互式的中国地图钻取功能

2024-08-18 22:08:52 前端知识 前端哥 128 513 我要收藏

在许多业务场景中,我们需要展示与地理位置相关的数据。本文将详细介绍如何在 Vue3 中结合 ECharts 库来实现一个可交互的中国地图,并支持用户通过点击地图上的省份来查看更详细的地区数据。

实现效果

29fe8a114050403d8748ac7ac513681d.png807a9f33b6fc433d92411cb4193681d6.png

 

最终的效果是:用户可以点击中国地图上的任意省份,然后页面会展示该省份的详细信息;同时提供一个“返回”按钮,用户可以点击它回到初始的中国地图视图。

技术栈

  • Vue.js 3:用于构建前端应用程序。
  • ECharts:用于数据可视化。
  • Fetch:用于请求本地JSON文件。

步骤详解

1. 模板定义

在 Vue3 组件的模板中定义一个用于显示地图的容器和一个返回按钮。

<template>
  <div style="position: relative; width: 100%; height: 100%">
    <div id="map" ref="mapRef" style="width: 100%; height: 400px" />
    <span v-if="isBack" class="go-back" @click="gotoParent">返回</span>
  </div>
</template>

2. 请求省份 JSON 数据

使用Fetch加载中国省份的地图数据(GeoJSON 格式)。

async function fetchMapJson(adcode) {
  // 使用 fetch 加载 JSON 文件
  const response = await fetch("/json/map/" + adcode + ".json");
  mapJsonData.value = await response.json();
}

3. 注册地图数据

使用 ECharts 的 registerMap 方法来注册地图数据。

// 注册地图数据
function handleRegisterMap(regionName) {
  mapChart.value = echarts.init(mapRef.value); // 初始化地图
  echarts.registerMap(regionName, mapJsonData.value);
  const option = {
    geo: {
      map: regionName,
      roam: true,
      label: {
        normal: { show: false },
        emphasis: { show: true },
      },
      itemStyle: {
        normal: {
          areaColor: "#2B91B7",
          borderColor: "#111",
        },
        emphasis: {
          areaColor: "#0489d6",
        },
      },
    },
    series: [
      {
        type: "scatter",
        coordinateSystem: "geo",
        map: regionName,
        data: [], // 这里可以填充省份数据
        label: {
          normal: {
            show: false,
          },
          emphasis: {
            show: true,
            textStyle: {
              color: "#fff",
            },
          },
        },
        itemStyle: {
          normal: {
            areaColor: "#2B91B7",
            borderColor: "#aaa",
          },
          emphasis: {
            areaColor: "#0489d6",
          },
        },
      },
    ],
  };

  mapChart.value.setOption(option);
}

4. 添加省份点击事件

// 添加省份点击事件
let returnArray = ref([]);
const handleClickMap = async (params) => {
  if (params.componentType === "geo" && params.name !== "") {
    // 查找地理编码
    let adcode = null;
    const features = mapJsonData.value.features;
    const filterArray = features.filter((item) => {
      return item.properties.name === params.name;
    });
    if (filterArray && filterArray.length > 0) {
      adcode = filterArray[0].id;
    }
    const regionName = params.name;
    if (adcode) {
      isBack.value = true;
      await fetchMapJson(adcode);
      returnArray.value.push({
        adcode: adcode,
        regionName: regionName,
        mapJsonData: JSON.stringify(mapJsonData.value),
      });
      // 清除当前地图选项
      mapChart.value.clear();
      // 刷新地图实例
      mapChart.value.resize();

      handleRegisterMap(regionName);
    }
  } else if (params.componentType === "series") {
    // 点击的数据
    const data = params.data;
    console.log("data", data);
  }
};

5. 初始化中国地图

设置 ECharts 实例,并配置地图的基本选项。

let chinaJsonData = ref({}); // 中国地图数据
onMounted(async () => {
  // 使用 fetch 加载 JSON 文件
  await fetchMapJson(100000);
  chinaJsonData.value = mapJsonData.value; // 先保留中国地图json
  handleRegisterMap("china");
  isBack.value = false;
  returnArray.value.push({
    adcode: 100000,
    regionName: "china",
    mapJsonData: JSON.stringify(chinaJsonData.value),
  });
  mapChart.value.on("click", handleClickMap);
  window.addEventListener("resize", () => {
    mapChart.value.resize();
  });
});

6. 返回上级

实现返回按钮的功能,当点击返回时可以返回它的上一级,直至中国地图。

// 返回上级
async function gotoParent() {
  if (isBack.value) {
    if (returnArray.value.length > 0) {
      returnArray.value.pop();
      let backMap = returnArray.value.slice(-1);
      if (backMap && backMap.length > 0) {
        mapJsonData.value = JSON.parse(backMap[0].mapJsonData);
        // 清除当前地图选项
        mapChart.value.clear();
        // 刷新地图实例
        mapChart.value.resize();
        handleRegisterMap(backMap[0].regionName);
        if (backMap[0].adcode == 100000) {
          isBack.value = false;
          returnArray.value = [
            {
              adcode: 100000,
              regionName: "china",
              mapJsonData: JSON.stringify(chinaJsonData.value),
            },
          ];
        }
      }
    } else {
      isBack.value = false;
    }
  }
}

完整代码

为了便于理解,以下是完整的组件代码示例:

<template>
  <div style="position: relative; width: 100%; height: 100%">
    <div id="map" ref="mapRef" style="width: 100%; height: 400px" />
    <span v-if="isBack" class="go-back" @click="gotoParent">返回</span>
  </div>
</template>

<script setup>
import * as echarts from "echarts";
import { ref, onMounted, onBeforeUnmount } from "vue";

const mapRef = ref(null);
let mapJsonData = ref({});
let mapChart = ref(null);
let isBack = ref(false); // 加标记,是否返回上一级

// 根据地理编号请求json数据
async function fetchMapJson(adcode) {
  // 使用 fetch 加载 JSON 文件
  const response = await fetch("/json/map/" + adcode + ".json");
  mapJsonData.value = await response.json();
}

// 注册地图数据
function handleRegisterMap(regionName) {
  mapChart.value = echarts.init(mapRef.value); // 初始化地图
  echarts.registerMap(regionName, mapJsonData.value);
  const option = {
    geo: {
      map: regionName,
      roam: true,
      label: {
        normal: { show: false },
        emphasis: { show: true },
      },
      itemStyle: {
        normal: {
          areaColor: "#2B91B7",
          borderColor: "#111",
        },
        emphasis: {
          areaColor: "#0489d6",
        },
      },
    },
    series: [
      {
        type: "scatter",
        coordinateSystem: "geo",
        map: regionName,
        data: [], // 这里可以填充省份数据
        label: {
          normal: {
            show: false,
          },
          emphasis: {
            show: true,
            textStyle: {
              color: "#fff",
            },
          },
        },
        itemStyle: {
          normal: {
            areaColor: "#2B91B7",
            borderColor: "#aaa",
          },
          emphasis: {
            areaColor: "#0489d6",
          },
        },
      },
    ],
  };

  mapChart.value.setOption(option);
}

// 添加省份点击事件
let returnArray = ref([]);
const handleClickMap = async (params) => {
  if (params.componentType === "geo" && params.name !== "") {
    // 查找地理编码
    let adcode = null;
    const features = mapJsonData.value.features;
    const filterArray = features.filter((item) => {
      return item.properties.name === params.name;
    });
    if (filterArray && filterArray.length > 0) {
      adcode = filterArray[0].id;
    }
    const regionName = params.name;
    if (adcode) {
      isBack.value = true;
      await fetchMapJson(adcode);
      returnArray.value.push({
        adcode: adcode,
        regionName: regionName,
        mapJsonData: JSON.stringify(mapJsonData.value),
      });
      // 清除当前地图选项
      mapChart.value.clear();
      // 刷新地图实例
      mapChart.value.resize();

      handleRegisterMap(regionName);
    }
  } else if (params.componentType === "series") {
    // 点击的数据
    const data = params.data;
    console.log("data", data);
  }
};

// 返回上级
async function gotoParent() {
  if (isBack.value) {
    if (returnArray.value.length > 0) {
      returnArray.value.pop();
      let backMap = returnArray.value.slice(-1);
      if (backMap && backMap.length > 0) {
        mapJsonData.value = JSON.parse(backMap[0].mapJsonData);
        // 清除当前地图选项
        mapChart.value.clear();
        // 刷新地图实例
        mapChart.value.resize();
        handleRegisterMap(backMap[0].regionName);
        if (backMap[0].adcode == 100000) {
          isBack.value = false;
          returnArray.value = [
            {
              adcode: 100000,
              regionName: "china",
              mapJsonData: JSON.stringify(chinaJsonData.value),
            },
          ];
        }
      }
    } else {
      isBack.value = false;
    }
  }
}

let chinaJsonData = ref({}); // 中国地图数据
onMounted(async () => {
  // 使用 fetch 加载 JSON 文件
  await fetchMapJson(100000);
  chinaJsonData.value = mapJsonData.value; // 先保留中国地图json
  handleRegisterMap("china");
  isBack.value = false;
  returnArray.value.push({
    adcode: 100000,
    regionName: "china",
    mapJsonData: JSON.stringify(chinaJsonData.value),
  });
  mapChart.value.on("click", handleClickMap);
  window.addEventListener("resize", () => {
    mapChart.value.resize();
  });
});
onBeforeUnmount(() => {
  // 移除地图点击事件监听器
  mapChart.value.off("click", handleClickMap);
});
</script>

<style scoped>
#map {
  width: 100%;
  height: 400px;
}
.go-back {
  display: inline-block;
  position: absolute;
  right: 20px;
  top: 20px;
  z-index: 9999;
  cursor: pointer;
  color: #36cfff;
}
</style>

总结

通过上述步骤,您可以在 Vue3 应用中实现一个交互式的中国地图,支持省份点击和返回功能。

 

转载请注明出处或者链接地址:https://www.qianduange.cn//article/16123.html
标签
评论
发布的文章

无涯教程-HTML5 - MathML

2024-08-25 23:08:46

大家推荐的文章
会员中心 联系我 留言建议 回顶部
复制成功!