ECharts 区域地图可视化实战:以山东地图为例

0 阅读4分钟

引言

在数据可视化领域,地图可视化是展示地理相关数据的重要手段。本文将详细介绍如何使用 ECharts 结合 GeoJSON 数据实现区域地图的可视化,以山东省地图为例,带领大家从零开始构建一个精美的交互式地图应用。

效果预览

在这里插入图片描述

一、准备工作

1.1 环境要求

  • 浏览器:支持 HTML5 的现代浏览器(Chrome、Firefox、Edge 等)
  • 基础技术:HTML、JavaScript
  • 第三方库:ECharts 5.x

1.2 所需资源

  1. ECharts 库:用于地图渲染
  2. GeoJSON 数据:山东地图的地理边界数据
  3. 区域数据:各城市的统计数据

二、GeoJSON 数据解析

2.1 GeoJSON 结构说明

山东地图的 GeoJSON 文件结构如下:

{
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "properties": {
        "adcode": 370100,
        "name": "济南市",
        "center": [117.000923, 36.675807],
        "centroid": [117.221211, 36.3640013],
        "level": "city"
      },
      "geometry": {
        "type": "MultiPolygon",
        "coordinates": [...]
      }
    }
  ]
}

2.2 关键属性说明

属性说明
name城市名称,用于数据匹配
center城市中心点坐标 [经度, 纬度]
centroid城市几何中心坐标
adcode行政区划代码

三、封装 RegionMap 类

为了提高代码复用性,我们封装了一个通用的 RegionMap 类。

3.1 类的核心结构

class RegionMap {
  constructor(options = {}) {
    this.container = options.container || 'container';  // 容器ID
    this.mapName = options.mapName || 'region';         // 地图名称
    this.geoJSON = options.geoJSON || null;             // GeoJSON数据
    this.data = options.data || [];                     // 区域数据
    this.tooltipData = options.tooltipData || [];       // 提示数据
    this.title = options.title || '分布图';              // 标题
    this.layoutSize = options.layoutSize || '180%';     // 布局大小
    this.zoom = options.zoom || 0.65;                   // 缩放比例
    this.chart = null;
    this.geoCoordMap = {};
    this.init();
  }
}

3.2 坐标解析方法

关键在于正确解析 GeoJSON 中的坐标信息:

updateGeoCoordFromMap() {
  if (this.geoJSON && this.geoJSON.features) {
    this.geoJSON.features.forEach((feature) => {
      const name = feature.properties?.name;
      let coord = null;
      // 优先级:center > centroid > cp
      if (feature.properties?.center) {
        coord = feature.properties.center;
      } else if (feature.properties?.centroid) {
        coord = feature.properties.centroid;
      } else if (feature.properties?.cp) {
        coord = feature.properties.cp;
      }
      if (name && coord) {
        this.geoCoordMap[name] = coord;
      }
    });
  }
}

3.3 数据转换方法

将区域数据转换为 ECharts 所需格式:

convertData(data) {
  const res = [];
  for (let i = 0; i < data.length; i++) {
    const geoCoord = this.geoCoordMap[data[i].name];
    if (geoCoord) {
      res.push({
        name: data[i].name,
        value: geoCoord.concat(data[i].value)
      });
    }
  }
  return res;
}

四、实现山东地图

4.1 创建 HTML 页面

<!DOCTYPE html>
<html lang="zh-CN" style="height: 100%">
<head>
  <meta charset="utf-8">
  <title>山东地图数据可视化</title>
</head>
<body style="height: 100%; margin: 0">
  <div id="container" style="margin: 0 auto;width: 50%;height: 55%;"></div>
  
  <!-- 引入 ECharts 和封装类 -->
  <script src="https://registry.npmmirror.com/echarts/5.4.3/files/dist/echarts.min.js"></script>
  <script src="./region-map.js"></script>
  
  <script type="text/javascript">
    // 地图逻辑代码
  </script>
</body>
</html>

4.2 准备山东数据

// 山东省各城市数据
var shandongData = [
  { name: '济南市', value: 100 },
  { name: '青岛市', value: 150 },
  { name: '淄博市', value: 80 },
  { name: '枣庄市', value: 60 },
  { name: '东营市', value: 70 },
  { name: '烟台市', value: 120 },
  { name: '潍坊市', value: 90 },
  { name: '济宁市', value: 85 },
  { name: '泰安市', value: 75 },
  { name: '威海市', value: 95 },
  { name: '日照市', value: 65 },
  { name: '临沂市', value: 110 },
  { name: '德州市', value: 70 },
  { name: '聊城市', value: 80 },
  { name: '滨州市', value: 55 },
  { name: '菏泽市', value: 90 },
  { name: '莱芜市', value: 45 }
];

// Tooltip 详细数据
var tooltipData = [
  { name: '济南市', value: 100, areas: ['历下区', '市中区', '槐荫区', '天桥区', '历城区'] },
  { name: '青岛市', value: 150, areas: ['市南区', '市北区', '黄岛区', '崂山区'] },
  { name: '烟台市', value: 120, areas: ['芝罘区', '福山区', '牟平区', '莱山区'] },
  { name: '临沂市', value: 110, areas: ['兰山区', '罗庄区', '河东区'] },
  { name: '潍坊市', value: 90, areas: ['潍城区', '寒亭区', '坊子区', '奎文区'] }
];

4.3 加载 GeoJSON 并渲染地图

// 异步加载山东 GeoJSON 数据
fetch('./shandong.json')
  .then(response => response.json())
  .then(geoJSON => {
    // 创建地图实例
    var shandongMap = new RegionMap({
      container: 'container',      // 容器ID
      mapName: 'shandong',        // 地图名称(用于ECharts注册)
      geoJSON: geoJSON,           // GeoJSON数据
      data: shandongData,         // 区域数据
      tooltipData: tooltipData,   // Tooltip数据
      title: '山东地图数据可视化', // 标题
      layoutSize: '180%',         // 布局大小
      zoom: 0.65                  // 缩放比例
    });
    
    // 渲染地图
    shandongMap.render();
  })
  .catch(error => {
    console.error('加载GeoJSON失败:', error);
  });

五、地图配置详解

5.1 视觉效果配置

RegionMap 类提供了精美的视觉效果:

itemStyle: {
  normal: {
    areaColor: {
      type: 'linear',
      x: 1200, y: 0, x2: 0, y2: 0,
      colorStops: [
        { offset: 0, color: 'rgba(3,27,78,0.75)' },
        { offset: 1, color: 'rgba(58,149,253,0.75)' }
      ],
      global: true
    },
    borderColor: '#c0f3fb',
    borderWidth: 1,
    shadowColor: '#8cd3ef',
    shadowOffsetY: 10,
    shadowBlur: 120
  },
  emphasis: {
    areaColor: 'rgba(0,254,233,0.6)'
  }
}

5.2 多层次阴影效果

为了增强立体感,采用了多层地图叠加技术:

geo: [
  { zlevel: 0, layoutCenter: ['50%', '50%'] },      // 主地图
  { zlevel: -1, layoutCenter: ['50%', '51%'] },     // 第一层阴影
  { zlevel: -2, layoutCenter: ['50%', '52%'] },     // 第二层阴影
  { zlevel: -3, layoutCenter: ['50%', '53%'] },     // 第三层阴影
  { zlevel: -4, layoutCenter: ['50%', '54%'] }      // 第四层阴影
]

5.3 动态效果配置

// 涟漪散点效果
{
  type: 'effectScatter',
  data: convertData(tooltipData),
  showEffectOn: 'render',
  rippleEffect: {
    scale: 5,
    brushType: 'stroke'
  },
  itemStyle: {
    color: '#00FFFF',
    shadowBlur: 10,
    shadowColor: '#16ffff'
  }
}

六、功能扩展

6.1 数据更新

// 更新区域数据
shandongMap.setData(newData);

// 更新 Tooltip 数据
shandongMap.setTooltipData(newTooltipData);

// 重新渲染
shandongMap.render();

6.2 销毁地图

// 页面销毁时释放资源
shandongMap.dispose();

6.3 响应式布局

// 监听窗口大小变化
window.addEventListener('resize', () => {
  if (shandongMap.chart) {
    shandongMap.chart.resize();
  }
});

七、常见问题

7.1 GeoJSON 加载失败

问题现象:地图无法显示,控制台报错

解决方案

  1. 检查文件路径是否正确
  2. 确保服务器支持跨域访问
  3. 验证 GeoJSON 格式是否正确

7.2 数据不显示

问题现象:地图显示正常,但数据点不显示

解决方案

  1. 检查数据中的 name 字段是否与 GeoJSON 中的名称一致
  2. 确认坐标解析逻辑是否正确
  3. 使用 console.log 打印 geoCoordMap 检查坐标是否正确解析

7.3 地图显示不全

问题现象:地图只显示部分区域

解决方案

  1. 调整 layoutSize 参数(如 '200%'
  2. 修改 zoom 参数调整缩放比例
  3. 检查容器尺寸是否足够