数字孪生二维热力图制作,看这篇文章就够了!

核心价值与应用场景

三维场景中的热力图价值

在数据爆炸时代,三维可视化赋予我们透视城市脉搏的能力。热力图通过 "数据密度→色彩强度"映射原理,将复杂数据转化为直观的视觉语言,有效支撑决策场景,例如:

在DTS中,可使用heatmap类快速实现二维热力图效果。

核心概念与技术原理

三维热力图渲染流程

  1. 数据输入:接收三维坐标点数据
  2. 空间划分:定义热力点渲染范围
  3. 样式配置:设置数据点呈现样式
  4. 渲染输出:结合透明度和深度测试实现效果
热力数据定义

热力数据支持通过点位以及tif数据格式进行添加:
1. 数据点(data & range)

热力图中可通过如下数组结构描述热力图各个节点的内容细节:

csharp 复制代码
let range = [0, 100]; // 数据值范围
let data = [
  {
    coordinate: [x, y, z], // 三维坐标
    radius: 15, // 影响半径
    heatValue: 75 // 热力值(必须在range范围内)
  }
  ...
];

关键属性说明

1)coordinate: 标识点位位置。若使用 GPS 经纬度,需转换为场景坐标,具体可参考教程:《想掌握加载经纬度数据?可以试试这 3 类方法!》

2)radius:控制单个数据点在热力图中的扩散范围。数值越小,影响范围更集中,可保留更多细节差异;数值越大,热力点影响范围更广,多个点容易融合形成连续高温区。 3) heatValue:标识该节点的热力值,必须在range范围内

2. tif形式添加

json 复制代码
"tifFile": {
  "minHeight": -10,// 最小高度
  "maxHeight": 50,// 最大高度
  "file": HostConfig.Path + "/assets/tif/T2.tif" // tif文件路径
  }
空间范围(bbox)

针对点位添加热力需要定义热力图存在的三维边界,即三维空间的AABB轴对齐包围盒:

ini 复制代码
// 正确定义格式 [minX, minY, minZ, maxX, maxY, maxZ]
const bbox = [488670.75, 2488165, -10, 491659.59375, 2490987.5, 200]; // 指的是包含地下10米到地上200米

注意事项:

  • 坐标顺序:严格按 XYZmin-max 顺序排列,确保 minX < maxX,minY < maxY,minZ < maxZ
  • Z 轴范围:涉及地下数据时,z 值最小值需设为负值(如地下管网数据)
  • 边界覆盖:确保所有热力点坐标在 bbox 范围内,超出范围的点将无法呈现
样式参数配置指南
样式类型(style)

用于定义热力图的视觉表现样式,支持三种预设样式:

<<< 左右滑动见更多 >>>

注意:当 style= 0(自定义样式) / style = 1(波峰波谷)时,还可通过如下属性进一步定制样式细节,包括:

1)自定义颜色色值

支持自定义颜色色值。

bash 复制代码
let colors = {
    "gradient": true,
    "invalidColor": [0, 0, 0, 1],
    "colorStops": [
        {
            "value": 0,
            "color": [0, 0.968627, 0, 1]
        },
        {
            "value": 0.25,
            "color": [0.709804, 0.968627, 0, 1]
        },
        {
            "value": 0.5,
            "color": [1, 0.709804, 0, 1]
        },
        {
            "value": 0.75,
            "color": [0.868627, 0, 0, 1]
        },
        {
            "value": 1,
            "color": [1, 0, 0, 1]
        }
    ]
};

颜色配色参考:通用配色方案colors,解锁数字孪生"色彩自由"

关键注意点:

  1. 开启渐变功能后,颜色之间会自然过渡;关闭后,各颜色独立呈现,边界分明。

120e399f079284213faa59a48f2d3339

  1. colorStops中的value需要在range范围内
2) 可选配置参数

1

参数说明与使用建议

  1. opacityMode:控制透明度计算方式

    • 0:使用色卡自带的颜色色值 ,每个颜色的透明度固定不变,计算开销低,适合性能优先的场景。
    • 1:透明度随热力值变化,视觉效果更自然,可清晰呈现数据层次感。
  2. opacityRange:仅在 opacityMode = 1 时生效,可用于增强或减弱整体透明度效果,例如 [0.2, 0.8] 会让热力点更柔和。

  3. blur:控制热力点从中心到边缘的渐变模糊效果

    • 低 blur:边缘锐利,高温区集中,突出热点位置
    • 高 blur:边缘柔和,热力点融合平滑,适合展示整体趋势

64c33768cc6297d3634573ad13a9992d

  1. blendMode:设置颜色混合呈现方式
  • 0:正常模式,颜色覆盖关系明确。
  • 1:叠加模式,多个热力点的颜色相互融合,适合表现数据叠加密度。
纹理精度texture

纹理贴图像素尺寸,直接影响渲染质量和性能,值越大纹理越清晰但创建越耗时:

性能优化建议:当热力图导致帧率<30fps时,建议降低 textureSize。

其他参数

viewHeightRange可视距离:控制热力值在三维空间中的高度映射范围与可视化可见性,格式为 [最小可见高度,最大可见高度]。

热力运用实战

兴趣点时序年份热力变化

下面实现兴趣点时序年份热力点变化的完整流程:

  1. 数据读取与初始化
javascript 复制代码
const getNormalData = async () => {
    const loadPromises = []

    const years = []
    for (let year = 2016; year <= 2025; year += 1) {
      years.push(year)
    }

    years.forEach(year => {
      if (year === 2025) return

      marks[year] = `${year}年`
      const loadPromise = fetch(`./lib/data/${year}深圳市兴趣点位.geojson`)
        .then(res => res.json())
        .then(jsonData => {
          const geoJson = JSON.parse(JSON.stringify(jsonData))
          const yearPoints = []

          geoJson.features.forEach((feature, index) => {
            const [x, y] = feature.geometry.coordinates[0]

            // 创建数据点对象
            const point = {
              id: `${year}_${index}`,
              coordinate: [x, y, -200],
              radius: 200,
              heatValue: 0,
              year: year // 添加年份标识
            }

            // 添加到年份数据中
            yearPoints.push(point)
            allHeatMapPoints.push(point)
          })

          animationData.push({
            time: year.toString(),
            points: yearPoints
          })
        })
        .catch(err => {
          console.error(`加载${year}年热力图数据失败:`, err)
        })

      loadPromises.push(loadPromise)
    })

    await Promise.allSettled(loadPromises)

    // 找到数量最多的数据
    maxCount = Math.max(...animationData.map(item => item.points.length))
    console.log('最大热力点数量:', maxCount)
  }
  1. 热力图创建
javascript 复制代码
const addHeatMap = async () => {
  // 创建热力图
  await fdapi.heatmap.clear()

  // 初始化所有的热力点 - 与TypeScript类保持一致
  const data = []
  for (let index = 0; index < maxCount; index++) {
    data.push({
      id: index.toString(),
      coordinate: [0, 0, 0], // 热力点的坐标
      radius: 0, // 热力点影像半径范围
      heatValue: 0 // 热力值
    })
  }

  await createHeatmap('heatmap1', data)
}
  1. 年份数据更新
ini 复制代码
const updateHeatmapData = async year => {
  // 找到对应年份的数据
  const yearData = animationData.find(
    item => item.time === year.toString()
  )
  if (!yearData) return

  const data = []
  for (let index = 0; index < maxCount; index++) {
    const flag = index < yearData.points.length

    const heatPoint = {
      id: index.toString(),
      coordinate: flag
        ? [...yearData.points[index].coordinate]
        : [0, 0, 0],
      radius: flag ? 200 : 0,
      heatValue: flag ? 50 : 0
    }
    data.push(heatPoint)
  }

  // 构造更新参数对象
  const updateParams = {
    id: 'heatmap1',
    bbox: normalHeatMapOptions.bbox,
    data: data
  }

  // 使用实际数据更新热力图
  fdapi.heatmap.updateByHeatPoints(updateParams)
}
路网热力呈现

支持设置仅路网呈现热力效果,需使用fdapi.tileLayer.enableDecal()控制图层显示

php 复制代码
await fdapi.tileLayer.enableDecal([
  { 
    tileLayerId: roadLayerID, 
    supportAttach: true   // 开启路网热力
  },
  {
    tileLayerId: buildingLayerID,
    supportAttach: false  // 关闭建筑热力
  }
]);
相关推荐
Sokach3866 分钟前
vue3引入tailwindcss 4.1
前端·css
云水边17 分钟前
vue模版中.gitignore和.prettierrc功能区分
前端
尝尝你的优乐美20 分钟前
封装那些Vue3.0中好用的指令
前端·javascript·vue.js
敲代码的彭于晏23 分钟前
localStorage 不够用?试试 IndexedDB !
前端·javascript·浏览器
chxii25 分钟前
5.4 4pnpm 使用介绍
前端·javascript·vue.js
好好好明天会更好33 分钟前
Vue 中 slot 的常用场景有哪些
前端·vue.js
奔赴_向往1 小时前
【qiankun 踩坑】路由切换回来,子应用 Vuex Store 数据居然还在
前端
sorryhc1 小时前
【AI解读源码系列】ant design mobile——Image图片
前端·javascript·react.js
老猴_stephanie1 小时前
Sentry On-Premise 21.7 问题排查与处理总结
前端
sorryhc1 小时前
【AI解读源码系列】ant design mobile——Button按钮
前端·javascript·react.js