引言
在数据可视化领域,地图可视化是展示地理相关数据的重要手段。本文将详细介绍如何使用 ECharts 结合 GeoJSON 数据实现区域地图的可视化,以山东省地图为例,带领大家从零开始构建一个精美的交互式地图应用。
效果预览
一、准备工作
1.1 环境要求
- 浏览器:支持 HTML5 的现代浏览器(Chrome、Firefox、Edge 等)
- 基础技术:HTML、JavaScript
- 第三方库:ECharts 5.x
1.2 所需资源
- ECharts 库:用于地图渲染
- GeoJSON 数据:山东地图的地理边界数据
- 区域数据:各城市的统计数据
二、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 加载失败
问题现象:地图无法显示,控制台报错
解决方案:
- 检查文件路径是否正确
- 确保服务器支持跨域访问
- 验证 GeoJSON 格式是否正确
7.2 数据不显示
问题现象:地图显示正常,但数据点不显示
解决方案:
- 检查数据中的
name字段是否与 GeoJSON 中的名称一致 - 确认坐标解析逻辑是否正确
- 使用
console.log打印geoCoordMap检查坐标是否正确解析
7.3 地图显示不全
问题现象:地图只显示部分区域
解决方案:
- 调整
layoutSize参数(如'200%') - 修改
zoom参数调整缩放比例 - 检查容器尺寸是否足够