ArcGIS for JavaScript 快速实现热力图渲染 🗺️
在 GIS 开发中,热力图是展示数据密度分布的常用方式,尤其适合地震、人口、交通、商品房流量等场景。本文适用于 ArcGIS Maps SDK for JavaScri pt 4.28~4.33 版本,手把手教你使用 CSVLayer、Legend、heatmap组件,实现一个可视化效果超赞的商品房热力图,小白也能轻松上手!🚀
文章目录
- [ArcGIS for JavaScript 快速实现热力图渲染 🗺️](#ArcGIS for JavaScript 快速实现热力图渲染 🗺️)
-
- [一、效果预览 & 核心功能](#一、效果预览 & 核心功能)
- [二、代码分步解析 🔍](#二、代码分步解析 🔍)
-
- [1. 基础 HTML 结构 & 样式](#1. 基础 HTML 结构 & 样式)
- [2. 核心 JS 逻辑(模块化写法)](#2. 核心 JS 逻辑(模块化写法))
-
- (1)导入必备模块
- [(2)配置数据来源 & 弹窗模板](#(2)配置数据来源 & 弹窗模板)
- [(3)关键配置:热力图渲染器 🎨](#(3)关键配置:热力图渲染器 🎨)
- [(4)创建 CSV 图层 & 标注配置](#(4)创建 CSV 图层 & 标注配置)
- [(5)组装地图 & 视图 & 图例](#(5)组装地图 & 视图 & 图例)
- [三、注意事项 ⚠️](#三、注意事项 ⚠️)
- 四、所有代码
| 工具 /插件/系统 名 | 版本 | 说明 |
|---|---|---|
| ArcGIS JS API | 4.28~4.33 | 地图核心能力(底图加载、视图渲染) |
| 天地图服务 | - | 提供街道、卫星、地形等底图数据源 |
一、效果预览 & 核心功能
先看最终实现的核心功能:
| 效果图1 | 效果图2 |
|---|---|
![]() |
![]() |
-
加载天地图底图(通过自定义
tiandituLoader.js工具) -
读取本地
商品房.csv数据,用热力图展示销售量分布 -
点击热力图区域,弹窗显示对应地区及销售量详情
-
自动标注高销量区域(文档中预留
mag>5过滤逻辑,可自定义调整) -
左下角添加图例控件,直观区分热力密度等级
二、代码分步解析 🔍
1. 基础 HTML 结构 & 样式
首先搭建页面骨架,引入 ArcGIS 依赖资源,设置地图容器占满屏幕:
HTML
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="utf-8" />
<!-- 移动端适配:禁止缩放,保持初始比例 -->
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
<title>商品房销售量热力图</title>
<!-- 引入ArcGIS官方样式(控制地图控件、弹窗等UI) -->
<link rel="stylesheet" href="https://js.arcgis.com/4.33/esri/themes/light/main.css" />
<style>
/* 关键:让地图容器铺满整个页面 */
html, body, #viewDiv {
padding: 0;
margin: 0;
height: 100%;
width: 100%;
}
</style>
<!-- 引入ArcGIS核心JS库(4.33版本,稳定兼容) -->
<script src="https://js.arcgis.com/4.33/"></script>
</head>
<body>
<!-- 地图渲染的核心容器,ID需与后续JS绑定 -->
<div id="viewDiv"></div>
</body>
</html>
2. 核心 JS 逻辑(模块化写法)
ArcGIS 4.x 推荐用module和$arcgis.import加载模块,避免全局变量冲突,代码结构更清晰,分 5 步实现:
(1)导入必备模块
先加载地图、CSV 数据层、视图、图例 4 个核心模块,以及天地图加载工具:
html
<script type="module">
// 1. 导入ArcGIS官方核心模块(按需加载,减少体积)
const [Map, CSVLayer, MapView, Legend] = await $arcgis.import([
"@arcgis/core/Map.js", // 地图实例(管理底图和图层)
"@arcgis/core/layers/CSVLayer.js", // CSV数据图层(加载商品房数据)
"@arcgis/core/views/MapView.js", // 2D视图(渲染地图到页面)
"@arcgis/core/widgets/Legend.js" // 图例控件(展示热力等级)
]);
// 2. 导入自定义天地图加载工具(需本地准备tiandituLoader.js,下文有说明)
import { loadTiandituBasemap } from './js/tiandituLoader.js';
const { tiandituBasemap } = await loadTiandituBasemap();
</script>
(2)配置数据来源 & 弹窗模板
-
数据来源:本地
商品房.csv(需确保路径正确,字段包含 "地区""销售量(套)") -
弹窗模板:点击热力图时显示详情,用
{字段名}直接关联 CSV 数据:
js
// 商品房CSV数据路径(本地文件,需与HTML同级或调整路径)
const url = "/商品房.csv";
// 弹窗模板(用户点击热力图时弹出的信息卡片)
const template = {
title: "{地区}", // 弹窗标题:显示对应地区
content: "销售量 {销售量(套)} 套", // 弹窗内容:显示具体销售量
};
(3)关键配置:热力图渲染器 🎨
热力图的视觉效果全靠renderer控制,核心是colorStops(渐变色阶)和maxDensity(最大密度):
js
const renderer = {
type: "heatmap", // 明确图层类型为热力图
colorStops: [ // 渐变色阶:从透明黄色到红棕色,共13个等级
{ color: "rgba(255, 255, 0, 0)", ratio: 0 }, // 0%:透明(无数据区域)
{ color: "#ffff00", ratio: 0.083 }, // 8.3%:亮黄色(低销量)
{ color: "#ffd700", ratio: 0.166 }, // 16.6%:金黄色
{ color: "#ffc107", ratio: 0.249 }, // 24.9%:琥珀色
{ color: "#ff9800", ratio: 0.332 }, // 33.2%:橙色
{ color: "#ff7043", ratio: 0.415 }, // 41.5%:深橙色
{ color: "#ff5722", ratio: 0.498 }, // 49.8%:橙红色
{ color: "#ff4500", ratio: 0.581 }, // 58.1%:橙红色(加深)
{ color: "#ff3a00", ratio: 0.664 }, // 66.4%:浅红色
{ color: "#ff2400", ratio: 0.747 }, // 74.7%:红色(加深)
{ color: "#e61900", ratio: 0.83 }, // 83%:深红色
{ color: "#cc1400", ratio: 0.913 }, // 91.3%:暗深红色
{ color: "#b30f00", ratio: 1 } // 100%:红棕色(高销量密集区)
],
maxDensity: 0.01, // 最大密度(关键参数!值越小,热力越集中;值越大越分散)
minDensity: 0, // 最小密度(默认0即可,代表无数据区域)
};
(4)创建 CSV 图层 & 标注配置
CSVLayer 是加载本地 CSV 数据的核心,同时可配置 "高销量区域标注"(文档中预留mag>5逻辑,需根据实际字段调整):
js
const layer = new CSVLayer({
url: url, // 绑定商品房CSV数据路径
title: "商品房销售量热力图", // 图层名称(将显示在图例上)
copyright: "模拟数据", // 版权信息(可替换为实际数据来源)
popupTemplate: template, // 绑定弹窗模板,点击显示详情
renderer: renderer, // 绑定热力图渲染器,控制视觉效果
labelsVisible: true, // 开启标注功能(显示高销量区域标识)
labelingInfo: [ // 标注具体配置(需根据CSV实际字段调整)
{
symbol: {
type: "text", // 标注类型:文本
color: "white", // 文字颜色:白色(醒目)
font: { family: "Noto Sans", size: 8 }, // 字体:无衬线字体,8号大小
haloColor: "#472b77", // 文字光晕:紫色(突出文字,避免被热力图覆盖)
haloSize: 0.75, // 光晕大小:0.75像素(适中)
},
labelPlacement: "center-center", // 标注位置:热力图中心点
labelExpressionInfo: {
// 标注内容:文档中用$feature.mag,需替换为CSV的"销售量(套)"字段
expression: "Text($feature.销售量(套), '#')",
},
// 过滤条件:文档中用mag>5,需替换为实际高销量阈值(如销售量>100)
where: "销售量(套) > 100",
},
],
});
(5)组装地图 & 视图 & 图例
最后将地图、图层、视图整合,设置初始显示位置,并添加图例控件:
js
// 1. 创建地图实例(绑定天地图底图 + 商品房热力图层)
const map = new Map({
basemap: tiandituBasemap, // 底图:天地图(需tiandituLoader.js支持)
layers: [layer], // 图层:添加商品房热力图层
});
// 2. 创建2D视图(绑定页面容器,设置初始显示参数)
const view = new MapView({
container: "viewDiv", // 绑定地图容器ID(与HTML中的div#viewDiv对应)
center: [116.4074, 39.9042], // 初始中心点:北京经纬度(可根据数据区域调整)
zoom: 2, // 初始缩放级别:2级(全球视角,可按需调大)
map: map, // 关联地图实例
});
// 3. 添加图例控件(放在左下角,方便查看热力等级)
view.ui.add(
new Legend({ view: view }), // 图例绑定当前视图
"bottom-left" // 图例位置:页面左下角
);
三、注意事项 ⚠️
-
天地图加载问题 :
tiandituLoader.js需要自己实现(需申请天地图 key,也可以直接在《天地图底图加载》)中直接复制,如果没有 key,可先用 ArcGIS 自带底图(如basemap: "streets")临时测试。 -
maxDensity 调整 :如果热力图太 "散",可减小
maxDensity(如 0.005);如果太 "集中",可增大(如 0.02),需根据数据量灵活调整。 -
跨域问题:如果本地打开 HTML 出现跨域报错,可部署到服务器(如 Nginx),或用 VSCode 的 "Live Server" 插件运行。
-
性能优化 :如果数据量过大(如超过 1 万条),可在 CSVLayer 中添加
definitionExpression过滤数据,减少渲染压力。
四、所有代码
index.html
html
<!DOCTYPE html>
<!doctype html>
<html lang="zh">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
<title>热力图</title>
<link rel="stylesheet" href="https://js.arcgis.com/4.33/esri/themes/light/main.css" />
<style>
html,
body,
#viewDiv {
padding: 0;
margin: 0;
height: 100%;
width: 100%;
}
</style>
<script src="https://js.arcgis.com/4.33/"></script>
<script type="module">
const [Map, CSVLayer, MapView, Legend] = await $arcgis.import([
"@arcgis/core/Map.js",
"@arcgis/core/layers/CSVLayer.js",
"@arcgis/core/views/MapView.js",
"@arcgis/core/widgets/Legend.js",
]);
import { loadTiandituBasemap } from './js/tiandituLoader.js';
const {
tiandituBasemap } = await loadTiandituBasemap();
const url = "/商品房.csv";
const template = {
title: "{地区}",
content: "销售量 {销售量(套)}.",
};
//最大像素强度用于指定颜色
//从colorStops属性中的连续颜色渐变
const renderer = {
type: "heatmap",
colorStops: [
{ color: "rgba(255, 255, 0, 0)", ratio: 0 }, // 透明黄色(起始)
{ color: "#ffff00", ratio: 0.083 }, // 亮黄色
{ color: "#ffd700", ratio: 0.166 }, // 金黄色
{ color: "#ffc107", ratio: 0.249 }, // 琥珀色
{ color: "#ff9800", ratio: 0.332 }, // 橙色
{ color: "#ff7043", ratio: 0.415 }, // 深橙色
{ color: "#ff5722", ratio: 0.498 }, // 橙红色
{ color: "#ff4500", ratio: 0.581 }, // 橙红色(加深)
{ color: "#ff3a00", ratio: 0.664 }, // 浅红色
{ color: "#ff2400", ratio: 0.747 }, // 红色(加深)
{ color: "#e61900", ratio: 0.83 }, // 深红色
{ color: "#cc1400", ratio: 0.913 }, // 暗深红色
{ color: "#b30f00", ratio: 1 } // 红棕色(终点)
],
maxDensity: 0.01,
minDensity: 0,
};
const layer = new CSVLayer({
url: url,
title: "热力显示",
copyright: "模拟数据",
popupTemplate: template,
renderer: renderer,
labelsVisible: true,
labelingInfo: [
{
symbol: {
type: "text",
color: "white",
font: {
family: "Noto Sans",
size: 8,
},
haloColor: "#472b77",
haloSize: 0.75,
},
labelPlacement: "center-center",
labelExpressionInfo: {
expression: "Text($feature.mag, '#.0')",
},
where: "mag > 5",
},
],
});
const map = new Map({
basemap: tiandituBasemap,
layers: [layer],
});
const view = new MapView({
container: "viewDiv",
center: [116.4074,39.9042],
zoom: 2,
map: map,
});
view.ui.add(
new Legend({
view: view,
}),
"bottom-left",
);
</script>
</head>
<body>
<div id="viewDiv"></div>
</body>
</html>
csv模拟数据
id,地区,latitude,longitude,销售量(套)
1,北京,39.9042,116.4074,50000
2,上海,31.2304,121.4737,60000
3,广州,23.1291,113.2644,45000
4,深圳,22.5437,114.0579,40000
5,杭州,30.2869,120.1583,35000
6,南京,32.0406,118.7677,30000
7,成都,30.5742,104.0631,48000
8,武汉,30.5928,114.3055,33000
9,西安,34.2647,108.9542,38000
10,重庆,29.5634,106.5504,55000

