简述
本节讲述热力图,讲解的案例用的是官方示例,主要讲解热力图的这几个配置项
热力图,是以特殊的高亮形式(渐变色带)对数据的聚合状态进行表达。这或许表达的并不准确。举一个场景例子,我们有全球地震发生的地点和级别,以点的形式标记在地图上,为了更直观的表现地震发生的频率,可以采用热力图表达。
在GIS学科里,有一类方法叫做插值,如克里金插值等,他们会根据不同的算法进行插值,形成的结果其实和热力图类似(或者说一样),而影响插值结果的有很多,简单来讲有距离(半径)和权重。
距离
权重
是本文需要注意的两点
示例
代码
function addHeatMap(map) {
// 本示例为官方示例改动而成
map.addSource("earthquakes", {
type: "geojson",
// 数据为mapbox官方数据
// 可能访问不到或者跨域,本地测试时可以直接下下来
data: "https://docs.mapbox.com/mapbox-gl-js/assets/earthquakes.geojson",
});
map.addLayer(
{
id: "earthquakes-heat",
type: "heatmap",
source: "earthquakes",
maxzoom: 9,
paint: {
// 根据频率和属性大小增加热力图权重
"heatmap-weight": [
"interpolate",
["linear"],
["get", "mag"],
0,
0,
6,
1,
],
// 根据缩放级别增加热力图权重
// heatmap-intensity 是热力图权重的乘数
"heatmap-intensity": ["interpolate", ["linear"], ["zoom"], 0, 1, 9, 3],
// 色带
"heatmap-color": [
"interpolate",
["linear"],
["heatmap-density"],
0,
"rgba(33,102,172,0)",
0.2,
"rgb(103,169,207)",
0.4,
"rgb(209,229,240)",
0.6,
"rgb(253,219,199)",
0.8,
"rgb(239,138,98)",
1,
"rgb(178,24,43)",
],
// 根据缩放级别调整热力图半径
"heatmap-radius": ["interpolate", ["linear"], ["zoom"], 0, 2, 9, 20],
// 透明度
"heatmap-opacity": ["interpolate", ["linear"], ["zoom"], 7, 1, 9, 0],
},
},
"waterway-label"
);
// 添加圆图层,叠加效果更好
map.addLayer(
{
id: "earthquakes-point",
type: "circle",
source: "earthquakes",
minzoom: 7,
paint: {
"circle-radius": [
"interpolate",
["linear"],
["zoom"],
7,
["interpolate", ["linear"], ["get", "mag"], 1, 1, 6, 4],
16,
["interpolate", ["linear"], ["get", "mag"], 1, 5, 6, 50],
],
"circle-color": [
"interpolate",
["linear"],
["get", "mag"],
1,
"rgba(33,102,172,0)",
2,
"rgb(103,169,207)",
3,
"rgb(209,229,240)",
4,
"rgb(253,219,199)",
5,
"rgb(239,138,98)",
6,
"rgb(178,24,43)",
],
"circle-stroke-color": "white",
"circle-stroke-width": 1,
"circle-opacity": ["interpolate", ["linear"], ["zoom"], 7, 0, 8, 1],
},
},
"waterway-label"
);
map.flyTo({
center: [-120, 50],
zoom: 2,
});
}
示例逻辑
- 请求地震数据并添加为source
- 添加热力图(heatmap)
- 添加圆图(circle)
第一步为addSource,第三步是圆图层,这两步不做讲解,重点关注热力图这段
示例代码解析
map.addLayer(
{
id: "earthquakes-heat",
type: "heatmap",
source: "earthquakes",
maxzoom: 9,
paint: {
// 根据频率和属性大小增加热力图权重
"heatmap-weight": [
"interpolate",
["linear"],
["get", "mag"],
0,
0,
6,
1,
],
// 根据缩放级别增加热力图权重
// heatmap-intensity 是热力图权重的乘数
"heatmap-intensity": ["interpolate", ["linear"], ["zoom"], 0, 1, 9, 3],
// 色带
"heatmap-color": [
"interpolate",
["linear"],
["heatmap-density"],
0,
"rgba(33,102,172,0)",
0.2,
"rgb(103,169,207)",
0.4,
"rgb(209,229,240)",
0.6,
"rgb(253,219,199)",
0.8,
"rgb(239,138,98)",
1,
"rgb(178,24,43)",
],
// 根据缩放级别调整热力图半径
"heatmap-radius": ["interpolate", ["linear"], ["zoom"], 0, 2, 9, 20],
// 透明度
"heatmap-opacity": ["interpolate", ["linear"], ["zoom"], 7, 1, 9, 0],
},
},
"waterway-label"
);
heatmap-weight
热力图权重,默认为1,这个属性更多是要和字段联系起来,最后将字段值归一化(变成0~1),这是上文所说的权重
,
如果不设置这个属性,就会让热力图只和距离相关。
"heatmap-weight": [
"interpolate",
["linear"],
["get", "mag"],
0,
0,
6,
1,
],
这里有一个之前没讲过的表达式 interpolate
, 是插值的意思,而后面的 [‘linear’] 是插值的方式,整体为线性插值,还有另外几种方式,这里不作详解(作为入门,学会这个就可以应对绝大部分业务场景)
[`interpolate`,['linear'],["get",属性字段],值1,效果值1,值2,效果值2,·····]
在我们的示例中,先获取为mag
字段的值(这份地震数据中,mag字段值的范围是06),以06归一化,为了方便理解,我将它转化为js代码(下面代码不能代表真实的底层逻辑)
属性值 /(值2 - 值1) * ( 效果值2 - 效果值1 )+ 效果值1
// 假如 mag 字段值为 2
2 / (6-0) + (1 - 0) + 0 // 0.333
// 假如 mag 字段值为 3
3 / (6-0) + (1 - 0) + 0 // 0.5
heatmap-intensity
与heatmap-weight
类似,也是对权重的控制,但我更愿意叫它为权重系数
"heatmap-intensity": ["interpolate", ["linear"], ["zoom"], 0, 1, 9, 3],
可以看到这个字段的设置也使用了线性渐变的表达式,但和之前不同的是,这里并没有用[“get”,属性字段]的方式获取Feature属性,因为这里的zoom
是mapbox自身的属性,不需要通过get形式获取,get是获取Feature的写法。
这里有一个之前没接触的概念,mapbox(map)自身属性,zoom
值的是地图当前的缩放级别,我们可以利用它实现一些动态效果,比如之前的例子中,我们绘制了不同颜色的面,但并不会随着地图缩放产生变化,如果我们用线性渐变和zoom对颜色进行控制,那么就会实现随着缩放变化面的颜色。
在这个例子中,使用线性渐变和zoom变化权重系数,这会让一个数据在不同缩放级别下有不同的权重,从而达到美观的效果
heatmap-color
热力图颜色,热力图颜色需要一个色带,所以至少需要两种颜色,然后通过线性插值供程序使用。
"heatmap-color": [
"interpolate",
["linear"],
["heatmap-density"],
0,
"rgba(33,102,172,0)",
0.2,
"rgb(103,169,207)",
0.4,
"rgb(209,229,240)",
0.6,
"rgb(253,219,199)",
0.8,
"rgb(239,138,98)",
1,
"rgb(178,24,43)",
],
这里同样使用了线性插值,并且用了另一个mapbox(map)自带的属性,heatmap-density
,指热力图密度,即热力图图层插值计算后的结果(每一个像素点,值域0~1),示例中渐变用了六种颜色。注意,插值表达式写法没有默认值(case,match都有默认值)
heatmap-radius
热力图半径(距离),这是开头说的距离
,每一个数据点与指定半径内其他数据点进行计算,单位是像素。
"heatmap-radius": ["interpolate", ["linear"], ["zoom"], 0, 2, 9, 20],
同样用了线性渐变,此处不作解释。
heatmap-opacity
热力图透明度,当透明度为0时便隐藏了
"heatmap-opacity": ["interpolate", ["linear"], ["zoom"], 7, 1, 9, 0],
同样用了线性渐变,此处不作解释。
示例总结
heatmap-weight
连接数据字段mag作为权重,heatmap-color
设置热力图色带,再以heatmap-radius
设置热力图半径,heatmap-intensity
设置热力图系数,heatmap-opacity
设置热力图透明度。通过对zoom线性插值的使用让热力图在不同级别有不同的表现。
总结
本节讲述了热力图几个重要的属性及其效果,同时对interpolate
线性插值表达式进行了讲解,下节讲fill-extrusion
的应用