🗾3分钟学会Echart地图下钻

🗺️ 什么是地图下钻?

地图下钻就是深入层级,比如你当前地图上面显示了全国范围的行政区,这时候点击了一个行政区,地图就变成这个行政区的样子.

就像下面

💡 实现思路

  1. 初始化地图
    • 页面加载时,初始化 ECharts 实例,默认显示全国地图
  2. 获取地图数据
    • 根据对应的行政区编码获取地图数据
  3. 渲染地图
    • 使用 echarts.registerMap 注册当前区域地图。
  4. 编写下钻逻辑
    • 监听地图点击事件,获取被点击区域的行政区代码和名称。
  5. 获取到geojson后重新注册地图和更新Echarts

📊 数据来源

DataV地址 :DataV.GeoAtlas地理小工具系列

地图的geo数据是从dataV里面获取的

这串数字就是我们的行政区代码,我只要修改行政区代码,就可以获取到不同行政区的geojson数据

通过观察请求回来的json数据可以发现,每个行政区都会带它的编码,这样就很方便了,只要每次点击地图的时候,把对应地块的行政区代码获取到,再重新请求即可.

✨ 最终效果

💻 完整代码

html 复制代码
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>地图下钻</title>
    <style>
      :root {
        --primary: #1890ff;
        --primary-hover: #40a9ff;
        --bg: #f4f8fb;
        --radius: 18px;
        --shadow: 0 4px 24px 0 rgba(24, 144, 255, 0.08);
      }
      body {
        margin: 0;
        padding: 0;
        font-family: Arial, sans-serif;
        background: var(--bg);
        min-height: 100vh;
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
      }
      .center-box {
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        width: 100vw;
        height: 100vh;
      }
      .map-container {
        width: 80vw;
        max-width: 1200px;
        height: 80vh;
        min-height: 400px;
        background: #fff;
        border-radius: var(--radius);
        box-shadow: var(--shadow);
        position: relative;
        overflow: hidden;
        display: flex;
        align-items: center;
        justify-content: center;
        transition: box-shadow 0.3s;
      }
      #main {
        width: 100%;
        height: 70%;
        border-radius: var(--radius);
      }
      .btn {
        position: absolute;
        top: 32px;
        left: 32px;
        padding: 10px 28px;
        background-color: var(--primary);
        color: #fff;
        border: none;
        border-radius: 6px;
        cursor: pointer;
        font-size: 16px;
        font-weight: 500;
        box-shadow: 0 2px 8px 0 rgba(24, 144, 255, 0.12);
        transition: background 0.2s, transform 0.2s, box-shadow 0.2s;
        z-index: 10;
      }
      .btn:hover {
        background-color: var(--primary-hover);
        transform: translateY(-2px) scale(1.04);
        box-shadow: 0 4px 16px 0 rgba(24, 144, 255, 0.18);
      }
      @media (max-width: 900px) {
        .map-container {
          width: 98vw;
          height: 70vh;
        }
        .btn {
          top: 16px;
          left: 16px;
          padding: 8px 18px;
          font-size: 14px;
        }
      }
      @media (max-width: 600px) {
        .map-container {
          width: 100vw;
          height: 60vh;
          min-height: 220px;
        }
        .btn {
          top: 8px;
          left: 8px;
          padding: 6px 10px;
          font-size: 13px;
        }
      }
    </style>
    <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
    <script
      src="https://cdnjs.cloudflare.com/ajax/libs/echarts/5.6.0/echarts.min.js"
      integrity="sha512-XSmbX3mhrD2ix5fXPTRQb2FwK22sRMVQTpBP2ac8hX7Dh/605hA2QDegVWiAvZPiXIxOV0CbkmUjGionDpbCmw=="
      crossorigin="anonymous"
      referrerpolicy="no-referrer"
    ></script>
  </head>
  <body>
    <div class="center-box">
      <div class="map-container">
        <div id="main"></div>
        <input
          type="button"
          class="btn"
          onClick="reutrnUp()"
          value="返回上一级"
        />
      </div>
    </div>
    <script>
      // 获取echartsDOM元素
      const echartDOM = document.getElementById('main')
      const chart = echarts.init(echartDOM)
      let menus = [
        {
          adcode: 100000,
          name: '全国'
        }
      ]
      /**
       *  @function 获取地区数据
       *  @param {number} adcode - 地区编码,默认为100000(全国)
       * */
      const getGeoJson = async (adcode = 100000) => {
        try {
          const url = `https://geo.datav.aliyun.com/areas_v2/bound/${adcode}_full.json`
          const result = await axios.get(url)
          return result.data
        } catch (err) {
          return void 0
        }
      }
      const updateEcharts = async (adcode, name) => {
        // 默认获取全国行政区数据
        const geoJson = await getGeoJson(adcode)
        if (!geoJson) {
          throw new Error('已经是最后一级了')
        }
        // 注册地图
        echarts.registerMap(name, geoJson)
        // 设置地图配置项
        const option = {
          title: {
            text: name,
            left: 'center'
          },
          series: [
            {
              type: 'map',
              map: name,
              itemStyle: {
                areaColor: '#1890ff'
              },
              data: geoJson['features'].map((item) => {
                return {
                  name: item.properties.name,
                  value: item.properties.adcode
                }
              })
            }
          ]
        }
        // 设置图表配置项
        chart.setOption(option)
      }
      updateEcharts(100000, '全国')
      // 点击行政区的时候,重新加载这个行政区的数据
      chart.on('click', async (params) => {
        const { value, name } = params.data
        if (value) {
          try {
            await updateEcharts(value, name)
            menus.push({
              adcode: value,
              name
            })
          } catch (err) {
            alert(err.message)
          }
        }
      })
      // 返回上一级
      const reutrnUp = async () => {
        if (menus.length > 1) {
          menus.pop()
          const { adcode, name } = menus[menus.length - 1]
          await updateEcharts(adcode, name)
        } else {
          menus = [
            {
              adcode: 100000,
              name: '全国'
            }
          ]
          await updateEcharts(100000, '全国')
          alert('已经是最开始一级了。')
        }
      }
    </script>
  </body>
</html>
相关推荐
小公主5 分钟前
还在等后端接口?vite-plugin-mock 教你前端自造接口跑起来!
前端
Ryan今天学习了吗5 分钟前
💥总结你需要知道有关 JSON 的一切
前端·javascript
1024小神6 分钟前
cocos控制角色玩家飞机只可以在一定范围内移动,不能越界
前端·javascript
晴殇i7 分钟前
Ultracite:告别 ESLint 和 Prettier,迎接 AI 时代的代码格式化新标准
前端·程序员·前端框架
拾光拾趣录7 分钟前
组合总和:深度解析电商促销系统的核心算法实践
前端·算法
三年三月7 分钟前
022-自定义顶点颜色实现渐变
前端·three.js
1024小神10 分钟前
cocos开发2d游戏的时候,模拟背景无限循环移动的思路和实现方法
前端·javascript
我想说一句11 分钟前
React性能优化:深入理解useMemo、useCallback与memo
前端·前端框架
顾辰呀20 分钟前
css flex 一行2个元素 不能挤压空间
前端·css·css3
潜心专研的小张同学21 分钟前
vue3实现高性能pdf预览器功能可行性方案及实践(pdfjs-dist5.x插件使用及自定义修改)
前端·vue.js