OpenLayers 热力图从原理到 Vue 组件一键接入

在 WebGIS 里,热力图很常见:人流密度、事件热点、设施覆盖、巡查频次......它把「一堆带权重的点」渲染成连续色带,一眼看出哪里「热」、哪里「冷」。

本文将按完整链路说明:

  1. 理解热力图:点 + 权重 + 模糊叠加

  2. 用 OpenLayers 原生 Heatmap 图层跑通最小示例

  3. 介绍 ym-giswidget-2d 已封装好的 Heatmap 组件

  4. 数据格式、控制面板参数、多数据源切换与定位

先看效果:地图上叠加可调半径、模糊度、色带的热力面。

*热力图效果*


一、思路先讲清楚

热力图不是画一堆圆点,而是:

  1. 每个热点是一个 Point,带上 weight(权重)

  2. 图层按半径、模糊度把点「摊开」成高斯状强度场

  3. 强度再映射到颜色渐变(低密度 → 高密度)

可以简单记成:

坐标点 + 权重 → HeatmapLayer → 色带渲染

业务侧通常只关心两件事:

  • 数据怎么组织(x / y / weight

  • 半径、模糊、透明度、色带怎么调

下面先用原生 OL 打通,再看组件封装。


二、引入 OpenLayers,准备地图与热力层

先安装依赖(Vue3 + Vite 示例):

bash 复制代码
// 终端执行:npm i ol

页面里放一个地图容器(例如 id 为 map 的 div),高度自行设置。然后创建底图 + 热力图层:

bash 复制代码
import Map from 'ol/Map'
import View from 'ol/View'
import TileLayer from 'ol/layer/Tile'
import OSM from 'ol/source/OSM'
import { Heatmap as HeatmapLayer } from 'ol/layer'
import { Vector as VectorSource } from 'ol/source'
import Feature from 'ol/Feature'
import Point from 'ol/geom/Point'
import { fromLonLat } from 'ol/proj'

const heatSource = new VectorSource()

// 示例点:经纬度 + 权重
[
  { lon: 117.21, lat: 31.81, weight: 20 },
  { lon: 117.22, lat: 31.815, weight: 45 },
  { lon: 117.23, lat: 31.82, weight: 70 },
  { lon: 117.24, lat: 31.825, weight: 35 },
  { lon: 117.25, lat: 31.83, weight: 90 },
].forEach((pt) => {
  heatSource.addFeature(
    new Feature({
      geometry: new Point(fromLonLat([pt.lon, pt.lat])),
      weight: pt.weight,
    }),
  )
})

const heatLayer = new HeatmapLayer({
  source: heatSource,
  blur: 15,
  radius: 15,
  opacity: 0.7,
  gradient: ['#000000', '#800000', '#FF0000', '#FF8000', '#FFFF00'],
  weight: (feature) => {
    // OL 默认读 feature 上的 weight,也可自定义归一化
    const w = feature.get('weight') || 0
    return Math.min(1, w / 100)
  },
})

const map = new Map({
  target: 'map',
  layers: [
    new TileLayer({ source: new OSM() }),
    heatLayer,
  ],
  view: new View({
    center: fromLonLat([117.23, 31.82]),
    zoom: 12,
  }),
})

常用可调参数:

  • radius:点半径,越大「摊」得越开

  • blur:模糊度,越大边界越柔和

  • opacity:图层不透明度

  • gradient:色带数组,从低到高

*OL 原生热力图效果*

到这里,原生链路已经跑通。工程里若还要面板拖动、多组数据切换、自动定位到点集范围,自己拼成本不低------组件库已封装好。


三、ym-giswidget-2d:Heatmap 组件已封装

译码二维组件库 ym-giswidget-2d 基于 OpenLayers Heatmap 图层,封装了:

  • 可拖动的「热力图控制」面板

  • 点半径 / 模糊度 / 色带 / 不透明度实时调节

  • 支持多组 data 切换数据源

  • 渲染后自动定位到当前点集范围

1. 安装

bash 复制代码
// 终端执行:npm i ym-giswidget-2d

// 或 pnpm / yarn 同理;monorepo 内可用 workspace 依赖

2. 引入样式(必做)

组件库样式不会自动注入 ,需在入口文件(如 main.js / main.ts)中显式引入:

bash 复制代码
import { createApp } from 'vue'
import App from './App.vue'
import 'ym-giswidget-2d/css/index.css' // 组件库样式,必引

createApp(App).mount('#app')

若项目已用 Element Plus,可与其样式一并放在入口:

bash 复制代码
import 'element-plus/dist/index.css'
import 'ym-giswidget-2d/css/index.css'

3. 最小用法

地图用 MapView,热力用 Heatmapdata 传入点集即可:

bash 复制代码
import { reactive } from 'vue'
import { MapView, Heatmap } from 'ym-giswidget-2d'

const reactiveValue = reactive({ map: null })

const heatData = [
  {
    title: '示例热力',
    points: [
      { x: 117.21, y: 31.81, weight: 20 },
      { x: 117.22, y: 31.815, weight: 45 },
      { x: 117.23, y: 31.82, weight: 70 },
      { x: 117.24, y: 31.825, weight: 35 },
      { x: 117.25, y: 31.83, weight: 90 },
    ],
  },
]

function onInitMap(mapView) {
  reactiveValue.map = mapView
  // 按需叠加底图......
}

// 模板示意:
// <div class="map-heatmap-shell" style="position:relative;height:30rem;">
//   <MapView @init="onInitMap" :center="[117.22718, 31.820386]" />
//   <Heatmap v-if="reactiveValue.map" :map="reactiveValue.map" :data="heatData" />
// </div>

要点:

  • 入口已引入 ym-giswidget-2d/css/index.css

  • HeatmapMapView 建议放在同一个 position: relative 容器内

  • 打开后会出现可拖动的控制面板;点「确认」仅收起面板,点「关闭」会移除热力图层

*组件控制面板*


四、数据格式说明

data 是数组,每一项是一组热力数据源:

bash 复制代码
const heatData = [
  {
    title: '示例热力', // 数据源名称(多组时出现在下拉框)
    points: [
      { x: 117.21, y: 31.81, weight: 20 },
      { x: 117.22, y: 31.815, weight: 45 },
    ],
  },
]

字段说明:

  • title:数据源标题

  • points:热点数组

  • points[].x / points[].y:与地图投影一致的坐标(示例为经纬度)

  • points[].weight:权重,数值越大该处越「热」

切换 data 中某一组时,组件会清空旧点、写入新点,并自动 locationGeometry 定位到当前点集范围。


五、控制面板能调什么

面板内置参数(打开即可拖动滑条 / 下拉):

  • 点半径:1 ~ 50,默认 15

  • 模糊度:1 ~ 50,默认 15

  • 不透明度:0 ~ 1,默认 0.7

  • 颜色渐变:内置多套色带

内置色带名称:

  • 喷流色带

  • 热力图色带(默认)

  • 冷色调色带

  • 大地色系

  • 紫翠玉色带

面板下方有「热力分布说明」色条预览:低密度 → 中密度 → 高密度。

*色带切换效果*


六、多数据源切换

data.length > 1 时,面板会出现「数据源」下拉框,可在多组点集之间切换:

bash 复制代码
const heatData = [
  {
    title: '区域甲',
    points: [
      { x: 117.20, y: 31.805, weight: 30 },
      { x: 117.21, y: 31.808, weight: 55 },
      { x: 117.215, y: 31.812, weight: 75 },
    ],
  },
  {
    title: '区域乙',
    points: [
      { x: 117.235, y: 31.825, weight: 25 },
      { x: 117.245, y: 31.828, weight: 60 },
      { x: 117.255, y: 31.832, weight: 95 },
    ],
  },
]

// 模板示意:
// <Heatmap v-if="map" :map="map" :data="heatData" />

切换后会自动定位到对应区域的点范围,适合「分片区 / 分时段」对比场景。

*多数据源切换*


七、和工具条一起用(可选)

若项目已使用 HorizontallyTopToolbar,也可把热力图挂成工具项,由工具条按需加载:

bash 复制代码
const heatmapTool = {
  id: 'heatmapTool',
  title: '热力图',
  classPath: '../heatmap/index.ts', // 以你项目工具条的加载约定为准
  icon: './img/tool/clear.png',
  isOnce: false,
  isRepels: false,
  data: heatData,
}

点击工具 → 打开面板与热力层;关闭面板时可移除图层,不影响其它工具。


八、小结

  1. 热力图本质:带权重的点 → 模糊叠加 → 色带映射

  2. 原生 OL:HeatmapLayer + VectorSource + Feature(Point, weight)

  3. 组件用法:入口引入 css/index.css,再写 <Heatmap :map="map" :data="heatData" />

  4. 面板可调半径 / 模糊 / 透明度 / 色带;多组 data 可切换并自动定位

自己实现适合理解原理、深度定制;日常业务更推荐组件封装------图层、面板、定位、多数据源都已打通。


获取 Demo 源码

关注译码设计 公众号,回复 gis2d-demo 获取ym-giswidget-2d组件使用 Demo 源码。

欢迎留言交流。


技术栈参考:OpenLayers 9.x · Vue 3组件:Heatmap(可拖动控制面板 + 多数据源热力渲染)

相关推荐
颜酱1 小时前
01 | 骨架搭建:FastAPI + Vue 跑通第一个 SSE 流式问答
前端·人工智能·后端
hoLzwEge1 小时前
解码 IDE 智能提示:jsconfig.json 辅助开发全攻略
前端·前端框架
leoZ2311 小时前
记忆系统与 Agent 定制完全指南(四):自定义 Agent 开发(一)
前端·chrome
慧一居士1 小时前
Element Plus 按需引入的配置使用说明和完整示例
前端·vue.js
程序员黑豆1 小时前
鸿蒙应用开发实战:从零学会自定义组件
前端·华为·harmonyos
leoZ2311 小时前
记忆系统与 Agent 定制完全指南(三):记忆的检索与使用
前端·chrome
遇乐的果园2 小时前
前端学习笔记-vue状态管理优化
前端·笔记·学习
GIS阵地3 小时前
QgsSingleBandPseudoColorRenderer 完整详解(QGIS 3.40.13 C++)
开发语言·前端·c++·qt·qgis
刘较瘦_3 小时前
AI 开发中的 Git Submodule 父子仓库模式:前后端分仓管理与协作实践
前端·github