You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

求助:如何在react-map-gl中实现热力图仅显示于建筑图层

解决热力图仅显示在建筑区域内的问题

针对你的需求,提供两种可行方案,适配react-map-gl 6.1.21(对应Mapbox GL JS v2+):


方案1:使用图层遮罩(推荐,无需修改数据源)

利用Mapbox的mask表达式,创建隐藏的建筑填充图层作为遮罩,让热力图仅在遮罩区域内显示:

步骤1:添加隐藏的建筑遮罩图层

在现有建筑3D图层的同一Source下,新增一个完全透明的填充图层,仅用作遮罩:

<Source id="building-source" type="vector" url="mapbox://mapbox.mapbox-streets-v8">
  {/* 隐藏的建筑填充遮罩层 */}
  <Layer
    id="building-mask"
    type="fill"
    source-layer="building"
    paint={{
      'fill-color': 'black',
      'fill-opacity': 0 // 完全透明,仅提供遮罩范围
    }}
  />
  {/* 原有的3D建筑图层 */}
  <Layer
    id="building-layer"
    type="fill-extrusion"
    source-layer="building"
    paint={{
      'fill-extrusion-color': 'black',
      'fill-extrusion-opacity': 0.6,
    }}
  />
</Source>

步骤2:修改热力图层的透明度规则

在热力图的paint属性中,新增基于遮罩的透明度控制,仅在建筑区域内显示热力图:

<Source
  id="heatmap-source"
  type="geojson"
  data={{
    type: 'FeatureCollection',
    features: heatmapData.map((point) => ({
      type: 'Feature',
      properties: {},
      geometry: {
        type: 'Point',
        coordinates: point,
      },
    })),
  }}
>
  <Layer
    id="heatmap-layer"
    type="heatmap"
    source="heatmap-source"
    paint={{
      // 保留原有热力图属性
      'heatmap-weight': {
        type: 'exponential',
        property: 'density',
        stops: [[0, 0], [6, 1]],
      },
      'heatmap-intensity': { stops: [[0, 0], [20, 1]] },
      'heatmap-color': [
        'interpolate',
        ['linear'],
        ['heatmap-density'],
        0, 'rgba(0, 0, 255, 0)',
        0.1, 'rgba(255, 0, 0, 0.5)',
        0.3, 'rgba(255, 255, 0, 0.7)',
        0.5, 'rgba(0, 255, 0, 0.9)',
        1, 'rgba(0, 255, 255, 1)',
      ],
      'heatmap-radius': { stops: [[0, 1], [20, 100]] },
      // 核心:仅在建筑遮罩内显示热力图
      'heatmap-opacity': [
        'case',
        ['mask', 'building-mask'],
        1, // 遮罩内完全显示
        0  // 遮罩外完全透明
      ]
    }}
  />
</Source>

方案2:预处理热力点数据(适合小数据量场景)

如果热力点数量不多,可通过turf.js前端过滤出落在建筑多边形内的点,仅渲染这些点的热力图:

步骤1:安装依赖

npm install @turf/turf

步骤2:过滤热力点数据

在地图加载完成后,获取建筑多边形并过滤热力点:

import * as turf from '@turf/turf';
import { useState } from 'react';

const YourMapComponent = () => {
  const [filteredHeatmapData, setFilteredHeatmapData] = useState([]);

  // 地图加载完成后执行数据过滤
  const handleMapLoad = (map) => {
    // 获取所有建筑多边形特征
    const buildingFeatures = map.querySourceFeatures('building-source', {
      sourceLayer: 'building'
    });
    // 过滤热力点:仅保留落在任意建筑内的点
    const filtered = heatmapData.filter(point => {
      const pointFeature = turf.point(point);
      return buildingFeatures.some(building => 
        turf.booleanPointInPolygon(pointFeature, building)
      );
    });
    setFilteredHeatmapData(filtered);
  };

  return (
    <Map
      onLoad={handleMapLoad}
      // 其他地图配置(如accessToken、viewport等)
    >
      {/* 使用过滤后的热力点数据 */}
      <Source
        id="heatmap-source"
        type="geojson"
        data={{
          type: 'FeatureCollection',
          features: filteredHeatmapData.map(point => ({
            type: 'Feature',
            properties: {},
            geometry: { type: 'Point', coordinates: point }
          }))
        }}
      >
        {/* 原热力图图层代码不变 */}
      </Source>
      
      {/* 原建筑图层代码不变 */}
    </Map>
  );
};

注意事项

  • 方案1依赖Mapbox GL JS v2+功能,react-map-gl 6.1.21已满足版本要求,确保你的Mapbox Token有权限使用v2特性。
  • 方案2若处理大量建筑或热力点,可能存在性能瓶颈,建议后端提前完成空间过滤,或使用空间索引优化前端计算。

内容的提问来源于stack exchange,提问作者Guillaume Munsch

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 17:14:57