96SEO 2026-06-05 15:03 4
项目缘起:为什么要在 Three.js 里玩转地图贴图和热力图
说实话,我Zui近玩儿 Vue3 + Three.js 那叫一个爽。
咱就是说想把全国交通事故增长率这种灰蒙蒙的数据,直接砸到地图上变成彩色的热力山丘,听起来就像给枯燥的表格撒点魔法粉。

哈哈,光想象就Yi经激动得不行了。
但真正动手的时候,坑爹的地方一大堆——坐标系不对、UV 映射跑偏、纹理透明度怎么和高度挂钩,dou得慢慢捣鼓。
别担心,我把踩过的坑全dou记下来咱们一起从头到尾搬砖。
第一步:准备原始数据先把后台给的 JSON 拉下来里面每条记录dou有经纬度和一个数值。
我一般会把它们转成这样子:
const points = rawData.map(item=>({
lng: item.longitude,
lat: item.latitude,
value: item.count
}));
这个数组稍后会喂给 heatmap.js 去渲染 2D 热力画布。
生成 Canvas 热力图纹理先创建一个离屏 canvas,尺寸随地图视口而定。
然后用 heatmap.js 的 API 把点塞进去:
const hm = h337.create({
container: document.createElement,
width: size,
height: size,
gradient: {
'0': '#1fc2e1',
'0.5': '#f1e12a',
'1': '#ff0000'
},
radius: 30,
maxOpacity: 0.6,
blur: .85
});
hm.setData;
这时候 hm._renderer.canvas 就是一张灰度+彩色混合的热力图了。
第二步:坐标系对齐——从 WGS84 到 Three.js 世界坐标地图上常用的是 WGS84,而 Three.js 用的是右手笛卡尔坐标。
Zui直接的办法是投影——我选了 D3‑geo 的 mercator 投影。
const projection = d3.geoMercator
.center // 北京为中心,可改
.scale // 根据实际需求调节
.translate;
遍历 points,把经纬度算成 canvas 像素坐标,再喂回去:
points.forEach(p=>{
const = projection;
p.x = Math.floor;
p.y = Math.floor;
});
把像素坐标映射到平面几何体上
我们在 Three.js 场景里放一个 PlaneGeometry,宽高跟 canvas 一致。
const geometry = new THREE.PlaneGeometry;
const material = new THREE.MeshBasicMaterial;
const plane = new THREE.Mesh;
scene.add;
第三步:精准 UV 贴图,让纹理不走样
这一步hen关键,不然热力图会出现拉伸或错位。
思路hen简单:遍历几何体所有顶点,用包围盒算出每个顶点对应的 UV 比例。
geometry.computeBoundingBox;
const {min,max}=geometry.boundingBox;
const width=max.x-min.x;
const height=max.y-min.y;
const uv=;
for{
const x=geometry.attributes.position.getX;
const y=geometry.attributes.position.getY;
uv.push/width,/height);
}
geometry.setAttribute);
这段代码kan起来有点啰嗦,但只跑一次就Neng保证纹理像素对齐到模型表面。
把 Canvas 当作纹理塞进材质const tex = new THREE.CanvasTexture;
tex.needsUpdate=true;
material.map=tex;
material.transparent=true;
material.needsUpdate=true;
第四步:让热力“爬坡”——利用透明通道Zuo高度位移
普通的平面贴图只Nengkan到颜色,要想变成立体山丘,需要在顶点着色器里读取 alpha 值,然后把它当作高度因子乘以一个放大系数。
// vertex.glsl
varying vec2 vUv;
uniform sampler2D uHeatMap;
uniform float uScale;
void main{
vUv=uv;
vec4 tex=texture2D;
float height=tex.a*uScale;
vec3 pos=position+normal*height;
gl_Position=projectionMatrix*modelViewMatrix*vec4;
}
// fragment.glsl
varying vec2 vUv;
uniform sampler2D uHeatMap;
void main{
gl_FragColor=texture2D;
}
在 JavaScript 那边,把这些 shader 串进去:
const mat=new THREE.ShaderMaterial({
uniforms:{
uHeatMap:{value:tex},
uScale:{value:5} // 控制山丘高度,可动态调节
},
vertexShader:document.getElementById.textContent,
fragmentShader:document.getElementById.textContent,
transparent:true
});
plane.material=mat;
第五步:交互——点击热点弹出信息框
要让用户点中某个“山丘”,我们得先把鼠标屏幕坐标反算成三维射线,再跟平面的交叉点Zuo判断。
window.addEventListener('click',e=>{
const mouse=new THREE.Vector2(
*2-1,
-*2+1
);
raycaster.setFromCamera;
const intersects=raycaster.intersectObject;
if{
const pt=intersects.point;
// 把三维坐标再投影回像素空间取 alpha 值
const uv=new THREE.Vector2(
/size,
/size
);
const pixel=new Uint8Array;
renderer.readRenderTargetPixels(
renderTarget,
Math.floor,
Math.floor,
1,1,pixel
);
const alpha=pixel/255;
if{
alert}%`);
}
}
});
小技巧:使用离屏渲染目标提升读取效率
直接读默认帧缓冲太慢,建议开个 WebGLRenderTarget 专门渲染热力层,这样 readRenderTargetPixels Neng快好几倍。
第六步:性Neng优化小建议
#减小 Canvas 分辨率: Ru果只是展示概览,把 canvas 大小降到 512×512 再配合 mipmapping,基本kan不出差别,却省了不少显存。
#动态geng新局部区域: 每次新增几个点时只刷新对应的小块,而不是整张热力图重绘。heatmap.js 自带 setDataPoint 方法Ke以Zuo到增量geng新。
#使用 LOD: 远处只显示低分辨率纹理,近处才切换高分辨率。Three.js 的 texture.minFilter / magFilter 配合 anisotropy Neng帮忙搞定。
#限制顶点数: PlaneGeometry 本身Ke以细分hen多层,但细分太多会导致 CPU 顶点计算拖慢。通常 256×256 足够呈现细腻效果。
#开启实例化渲染散点: Ru果还想在同一张地图上叠加实时散点,InstancedMesh 是省显存又省算力的好选择。
*不对不对,上面那行代码忘记加 ; 实际写的时候记得补上啊~*
收官感言:从二维到三维,从颜色到高度,你学会了吗?说实话,这套流程听起来有点长,但每一步其实dou挺直白——准备数据、投影、生成纹理、算 UV、写 shader、加交互、调性Neng。
哈哈,Ru果你现在还Neng跟着我一起敲代码,那就说明Yi经掌握了核心要领;Ru果卡住了那也没事,多翻翻官方文档或者搜搜 Github 示例,一般dou有现成片段Ke以 copy-paste 改改参数就Neng跑通。
Coding 本来就是边写边调试的事儿,你懂的,多试几次总会找到Zui适合自己项目的那套组合拳。
再送你几个“老友提醒”⚡️
- 别忘了在开发环境打开 threejs 的 stats 插件,kan帧率飙不飙;卡的话第一时间检查 draw call 和 texture 大小!
- Ru果要在移动端跑,一定要把 Canvas 降采样,否则手机 GPU hen容易炸裂。
- 想让山丘geng真实?Ke以在 fragment 着色器里再叠加一层噪声贴图,让光照产生细微凹凸感。
- Zui后Ru果你觉得这篇文章帮到了你,记得给我点赞或者发个星星鼓励一下我可是不爱装逼的人哦 😆
作为专业的SEO优化服务提供商,我们致力于通过科学、系统的搜索引擎优化策略,帮助企业在百度、Google等搜索引擎中获得更高的排名和流量。我们的服务涵盖网站结构优化、内容优化、技术SEO和链接建设等多个维度。
| 服务项目 | 基础套餐 | 标准套餐 | 高级定制 |
|---|---|---|---|
| 关键词优化数量 | 10-20个核心词 | 30-50个核心词+长尾词 | 80-150个全方位覆盖 |
| 内容优化 | 基础页面优化 | 全站内容优化+每月5篇原创 | 个性化内容策略+每月15篇原创 |
| 技术SEO | 基本技术检查 | 全面技术优化+移动适配 | 深度技术重构+性能优化 |
| 外链建设 | 每月5-10条 | 每月20-30条高质量外链 | 每月50+条多渠道外链 |
| 数据报告 | 月度基础报告 | 双周详细报告+分析 | 每周深度报告+策略调整 |
| 效果保障 | 3-6个月见效 | 2-4个月见效 | 1-3个月快速见效 |
我们的SEO优化服务遵循科学严谨的流程,确保每一步都基于数据分析和行业最佳实践:
全面检测网站技术问题、内容质量、竞争对手情况,制定个性化优化方案。
基于用户搜索意图和商业目标,制定全面的关键词矩阵和布局策略。
解决网站技术问题,优化网站结构,提升页面速度和移动端体验。
创作高质量原创内容,优化现有页面,建立内容更新机制。
获取高质量外部链接,建立品牌在线影响力,提升网站权威度。
持续监控排名、流量和转化数据,根据效果调整优化策略。
基于我们服务的客户数据统计,平均优化效果如下:
我们坚信,真正的SEO优化不仅仅是追求排名,而是通过提供优质内容、优化用户体验、建立网站权威,最终实现可持续的业务增长。我们的目标是与客户建立长期合作关系,共同成长。
Demand feedback