嘿,朋友!我是 Agnes。今天咱们不聊虚的,直接来硬核实战。
我知道你看到 “GeoJSON” 和 “可视化” 这几个词可能有点头大,别怕。我教过无数零基础的同学,地图这东西,其实就像玩拼图——你手里有一张底图(GeoJSON),再盖上一层漂亮的颜色(热力分布),它就活了。
这篇教程我会陪你一步步把这件事啃下来。我会把那些晦涩的专业术语翻译成大白话,确保你不仅能把代码跑起来,还能真正理解背后的逻辑。准备好你的编辑器了吗?咱们开始。
第一步:搞清楚我们要做什么
在写任何代码之前,我们先画个草图。我们的目标是用 Apache ECharts(一个非常强大的开源可视化库)做一个效果:
- 加载一张自定义地图:比如你们市的行政区划图,或者某个特定区域的地图。
- 注册到 ECharts:让 ECharts 知道这张地图长什么样,有哪些区域(比如哪些是区,哪些是街道)。
- 映射数据:把一组数值数据(比如人流密度、房价、销售额)和地图上的区域对应起来。
- 渲染热力效果:让数值高的地方颜色深,数值低的地方颜色浅,形成热力分布图。
是不是听起来也没那么复杂?对吧!
第二步:准备地图数据 (GeoJSON)
这是最关键,也是新手最容易卡住的地方。GeoJSON 是什么?简单说,它就是一种用来描述地理形状的标准格式,本质上是一堆 JSON 数据。
2.1 哪里找地图数据?
对于国内项目,最方便的是去 高德开放平台 或者 阿里云 DataV.GeoAtlas 下载。
- 推荐工具:DataV.GeoAtlas。你可以选择省、市、甚至区县级别的地图。
- 操作:选好你想要的区域,点击“获取代码”,然后下载 GeoJSON 文件。
假设我们下载了一个叫 haidian.geojson 的文件,内容大概长这样(我简化展示,实际文件会很大):
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {
"adcode": 110108,
"name": "海淀区",
"center": [116.298218, 39.969393],
"childrenNum": 17
},
"geometry": {
"type": "Polygon",
"coordinates": [[[[116.2, 39.9], [116.3, 39.9], [116.3, 40.0], [116.2, 40.0], [116.2, 39.9]]]]
}
},
{
"type": "Feature",
"properties": {
"adcode": 110109,
"name": "门头沟区",
"center": [116.1, 39.93],
"childrenNum": 11
},
"geometry": { ... }
}
// ... 还有很多区域
]
}
重点看 properties 里的 name 和 adcode。name 是区域的名称(比如“海淀区”),adcode 是行政区划代码。后面我们写数据的时候,就要用这个 name 或者 adcode 来匹配。
2.2 本地部署小建议
因为浏览器安全策略(CORS),直接双击打开 HTML 文件去请求本地的 GeoJSON 可能会失败。建议你用 VS Code 装一个 Live Server 插件,右键 HTML 文件选择 “Open with Live Server”,这样你就能本地运行服务了。
第三步:搭建基础 HTML 骨架
我们不需要复杂的框架,一个普通的 HTML 文件就够了。先把 ECharts 的 CDN 引入进来,这样你不用本地安装任何东西就能跑起来。
创建一个 index.html,填入以下内容:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>自定义地图热力图实战</title>
<!-- 引入 ECharts -->
<script src="https://cdn.jsdelivr.net/npm/echarts@5.4.3/dist/echarts.min.js"></script>
<style>
/* 让图表容器占满整个屏幕 */
#mapChart {
width: 100vw;
height: 100vh;
}
</style>
</head>
<body>
<!-- 图表挂载点 -->
<div id="mapChart"></div>
<script>
// 这里稍后会填入我们的核心代码
initMap();
</script>
</body>
</html>
现在,打开浏览器,你应该能看到一个空白的大屏幕。别急,好戏在后头。
第四步:加载并注册 GeoJSON
这是 ECharts 地图可视化的核心。我们需要用 echarts.registerMap 方法,把我们下载的 GeoJSON 注册进去。
我会把这段代码加在 <script> 标签里。这里涉及到一个异步请求,我用现代 JavaScript 的 fetch API 来写,既简洁又易懂。
// 假设你的 GeoJSON 文件就在同级目录下,名叫 haidian.geojson
const GEOJSON_URL = 'haidian.geojson';
const MAP_NAME = 'haidianMap'; // 你给这张地图起的名字,后面要用
async function initMap() {
try {
// 1. 发送请求获取 GeoJSON 数据
const response = await fetch(GEOJSON_URL);
// 2. 检查请求是否成功
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
// 3. 解析 JSON 数据
const geoJsonData = await response.json();
// 4. 【关键步骤】注册地图到 ECharts
// 第一个参数是地图名字,第二个参数是 GeoJSON 数据
echarts.registerMap(MAP_NAME, geoJsonData);
// 注册成功后,我们再初始化图表
renderChart();
} catch (error) {
console.error('地图加载失败:', error);
alert('地图加载失败,请检查控制台错误或确保 GeoJSON 文件路径正确');
}
}
// 5. 渲染图表的函数,我们后面再详细写
function renderChart() {
// ... 暂时留空
}
这里有个小知识点:echarts.registerMap 是 ECharts 提供的一个全局方法。一旦你注册了,以后在任何 ECharts 实例中,只要配置里写了 map: 'haidianMap',它就会去找这张图。这就像是在图书馆给一本书编目,以后你就能随时找到它了。
第五步:构建热力分布图表
现在地图已经注册好了,我们只需要告诉 ECharts:“嘿,用这张地图,再给我配上这些数据,用热力图的方式显示出来。”
热力分布在 ECharts 里属于 VisualMap(视觉映射)组件配合 Map 系列 图表来实现的。
我们把 renderChart 函数补全:
function renderChart() {
// 1. 初始化 ECharts 实例,绑定到 div
const myChart = echarts.init(document.getElementById('mapChart'));
// 2. 准备数据
// 这是一个数组,每个对象代表一个区域的数据
// value 是热力值,比如人流、热度等
const mapData = [
{ name: '海淀区', value: 9500 },
{ name: '东城区', value: 8200 },
{ name: '西城区', value: 7600 },
{ name: '朝阳区', value: 8800 },
{ name: '丰台区', value: 6500 },
{ name: '石景山区', value: 4300 },
{ name: '门头沟区', value: 2100 },
{ name: '房山区', value: 3500 },
{ name: '通州区', value: 5600 },
{ name: '顺义区', value: 4200 },
{ name: '昌平区', value: 3800 },
{ name: '大兴区', value: 4100 },
{ name: '怀柔区', value: 1500 },
{ name: '平谷区', value: 1200 },
{ name: '密云区', value: 800 },
{ name: '延庆区', value: 600 }
];
// 3. 配置项
const option = {
// 标题
title: {
text: '北京市各区热度分布图',
left: 'center',
textStyle: {
fontSize: 24,
fontWeight: 'bold'
}
},
// 提示框:鼠标悬停时显示详细信息
tooltip: {
trigger: 'item',
formatter: function(params) {
// params.data 就是我们的数据对象
// params.value 是数值
return `${params.name}<br/>热度指数:${params.value}`;
}
},
// 视觉映射组件:这是实现“热力”效果的关键!
visualMap: {
min: 0, // 数据最小值
max: 10000, // 数据最大值
left: 'left',
top: 'bottom',
text: ['高', '低'], // 两端的文字
calculable: true, // 是否显示拖拽用的手柄
inRange: {
// 颜色渐变范围,从浅到深
color: ['#e0f3f8', '#abd9e9', '#74add1', '#4575b4', '#313695']
},
textStyle: {
color: '#333'
}
},
// 地图配置
series: [
{
name: '热度分布',
type: 'map', // 告诉 ECharts 这是地图类型
map: MAP_NAME, // 必须和 registerMap 时的名字一致!
roam: true, // 允许缩放和拖动
zoom: 1.2, // 初始缩放比例
label: {
show: true, // 显示区域名称
color: '#333'
},
emphasis: { // 鼠标悬停时的样式
label: {
color: '#fff',
fontWeight: 'bold'
},
itemStyle: {
areaColor: '#f4d03f', // 悬停时的高亮颜色
shadowBlur: 10,
shadowColor: 'rgba(0,0,0,0.5)'
}
},
data: mapData // 填入我们的数据
}
]
};
// 4. 设置配置项,渲染图表
myChart.setOption(option);
// 5. 监听窗口大小变化,自适应调整图表大小
window.addEventListener('resize', function() {
myChart.resize();
});
}
重点解析:visualMap 是魔法发生的地方
很多新手只关注 series 里的配置,却忽略了 visualMap。其实,热力效果的本质就是颜色映射。
min和max:定义了数据的范围。ECharts 会根据这个范围,把数据值映射到颜色上。inRange.color:这是一个颜色数组。ECharts 会自动进行插值。你给它 5 个颜色,它就会根据数据大小,在这 5 个颜色之间平滑过渡。数据越小,越靠近第一个颜色(浅蓝);数据越大,越靠近最后一个颜色(深蓝)。
你可以自己试着修改 inRange.color 里的颜色,比如改成 ['#fff', '#ff0000'],看看效果是不是变成了白色到红色的渐变。
第六步:常见问题排查(避坑指南)
按照上面的步骤做,理论上应该能跑起来了。但如果遇到报错,别慌,看看是不是这几个问题:
问题 1:地图显示空白,或者提示 “map not found”
- 原因:
map: MAP_NAME里的名字和你registerMap时用的名字不一致。 - 检查:确保字符串完全匹配,包括大小写。
问题 2:区域名称对不上,数据显示不出来
- 原因:你的 GeoJSON 里区域的
name和你数据里的name不一致。 - 例子:GeoJSON 里叫 “海淀区”,你数据里写的是 “海淀”,这就匹配不上,该区域就会显示为默认色或灰色。
- 解决:打开 GeoJSON 文件,检查一下
properties.name的真实值是什么,然后修正你的mapData数据。
问题 3:本地打开 HTML 报错 CORS
- 原因:直接用
file://协议打开浏览器,禁止了跨域请求本地文件。 - 解决:使用 VS Code 的 Live Server 插件,或者在命令行运行
python -m http.server 8000,然后访问http://localhost:8000。
第七步:进阶——让地图更漂亮
现在的地图已经能用了,但如果想让它看起来更专业、更有“高级感”,我们可以加一点修饰。
7.1 添加省份/城市边界线
有时候我们只想看某个特定的市,周围的其他区域可能会干扰视线。我们可以通过配置 regions 来高亮显示我们关心的区域,并淡化其他区域。
在 series 配置中加入:
regions: [
{
name: '其他区域', // 这里填入你不关心的区域名称,或者通过 regex 匹配
itemStyle: {
areaColor: '#eee', // 灰色背景
borderColor: '#ccc'
},
emphasis: { // 悬停时也保持灰色
itemStyle: {
areaColor: '#eee'
}
}
}
]
注意:这种方式比较暴力。更优雅的方式是只保留目标区域的 GeoJSON 数据,比如只下载“海淀区”的 GeoJSON,这样地图上就只有这一个区,干净利落。
7.2 添加涟漪散点效果
除了面状的热力图,我们有时也想在地图上标出几个具体的点(比如热门商圈)。这可以用 effectScatter 系列。
如果你想在一个地图系列里同时显示 面状热力 和 点状涟漪,可以这样配置 series 数组:
series: [
// 第一个系列:面状热力图
{
name: '区域热度',
type: 'map',
map: MAP_NAME,
data: mapData,
// ... 其他 map 配置
},
// 第二个系列:点状涟漪图
{
name: '热点位置',
type: 'effectScatter',
coordinateSystem: 'geo', // 注意:effectScatter 要用 geo 坐标系,而不是 map
// 这里需要把地图注册为 geo 坐标系才能用
data: convertData([ // 假设有这样一个转换函数,将经纬度数据转换
{ name: '中关村', value: [116.31, 39.96, 1000] },
{ name: '三里屯', value: [116.46, 39.93, 800] }
]),
symbolSize: function(val) {
return val[2] / 100; // 根据数值大小动态设置点的大小
},
showEffectOn: 'render',
rippleEffect: {
brushType: 'stroke'
},
hoverAnimation: true,
label: {
formatter: '{b}',
position: 'right',
show: true
},
itemStyle: {
color: '#f44336',
shadowBlur: 10,
shadowColor: '#333'
},
zlevel: 1
}
]
注意:effectScatter 使用 coordinateSystem: 'geo',这意味着你需要把地图同时注册为一个 geo 组件,而不仅仅是 series 里的 map。这稍微复杂一点,但对于初学者,先把基础的热力图做出来更重要。
第八步:完整代码汇总
为了方便你复制运行,我把整个 index.html 的内容整合在一起。你只需要准备好一个 haidian.geojson 文件放在旁边,然后替换成你下载的 GeoJSON 路径即可。
”`html <!DOCTYPE html>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ECharts 自定义地图热力图实战</title>
<script src="https://cdn.jsdelivr.net/npm/echarts@5.4.3/dist/echarts.min.js"></script>
<style>
body { margin: 0; padding: 0; overflow: hidden; }
#mapChart { width: 100vw; height: 100vh; }
</style>
<div id="mapChart"></div>
<script
