实现效果
1、基本配置
首先需要配置基本场景、相机、渲染器
import * as THREE from 'three'
// 场景
this.scene = new THREE.Scene();
// 正交相机
this.camera = new THREE.OrthographicCamera(-1, 1, 1, -1, 1, 10000000);
this.camera.position.set(0, 0, 5.5);
// 渲染器
this.renderer = new THREE.WebGLRenderer();
this.renderer.setSize(width, height);
this.renderer.setClearColor('#383838', 1);
dom.appendChild(this.renderer.domElement);
//配置环境光
this.ambientLight(this.scene)
// 开始渲染
const animate = () => {
requestAnimationFrame(animate);
this.controls.update();
// 渲染主场景
this.renderer.clear();
this.renderer.render(this.scene, this.camera);
// 渲染坐标轴场景
this.renderer.autoClear = false; // 不清除颜色缓存
this.renderer.clearDepth(); // 清除深度缓存
// 设置坐标轴的渲染区域
this.renderer.setViewport(0, 0, width / 4, height / 4);
this.renderer.render(this.Helper.axesScene, this.Helper.axesCamera);
// 复原视口
this.renderer.setViewport(0, 0, width, height);
this.renderer.autoClear = true; // 恢复 autoClear
}
animate()
2、数据结构解析
points- 点的x、y、z轴坐标
properties- 点的热力值
{
"points": [
[5.6,0,0],
[0,5.6,0],
[0,0,5.6],
[0,0,0]
],
"properties": [
"3.83E+07",
"4.99E+07",
"3.79E+07",
"4.92E+07"
]
}
3、代码部分
引入准备好的json文件
import data from 'data.json'
核心部分
热力的核心部分是min_color和max_color需要定义两个颜色对应热力的最大值和最小值,然后根据每个点下标对应的properties对应的数字进行计算得出。
rgb_convert 用于提取数字
rgb_diff 计算两个RGB颜色之间的差异
点图需要很大的数据支撑。我最上面方的图点的数量大概是8w多个
drawScatter(data){
let geometry = new THREE.BufferGeometry();
let vertices = [];
let colors = [];
let aps = data.properties.map(at => parseFloat(at))
let min_color = this.rgb_convert('rgb(0,0,0)')
let max_color = this.rgb_convert('rgb(255,255,255)')
let seg_colors = []
let diff = this.rgb_diff(min_color, max_color)
let aps_max = aps[0]
let aps_min = aps[0]
for (let i = 0; i < aps.length; i++) {
if (aps[i] < aps_min) {
aps_min = aps[i]
}
if (aps[i] > aps_max) {
aps_max = aps[i]
}
}
let aps_diff = aps_max - aps_min
for (let i = 0; i < aps.length; i++) {
if (i === 1) {
console.log('aps[i]:' + aps[i])
console.log('(aps[i] - aps_min) / aps_diff * diff[0] + min_color[0]:' + ((aps[i] - aps_min) / aps_diff * diff[0] + min_color[0]))
}
seg_colors.push([
parseInt((aps[i] - aps_min) / aps_diff * diff[0] + min_color[0]),
parseInt((aps[i] - aps_min) / aps_diff * diff[1] + min_color[1]),
parseInt((aps[i] - aps_min) / aps_diff * diff[2] + min_color[2]),
])
}
data.points.forEach((in_it, in_index) => {
let x = in_it[0];
let y = in_it[1] * 5;
let z = in_it[2];
vertices.push(x, y, z);
// 随机颜色
let color = new THREE.Color("rgb("+seg_colors[in_index][0]+","+
seg_colors[in_index][1]+","+ seg_colors[in_index][2]+")");
colors.push(color.r, color.g, color.b);
})
geometry.setAttribute('position', new THREE.Float32BufferAttribute(vertices, 3));
geometry.setAttribute('color', new THREE.Float32BufferAttribute(colors, 3)); // 设置颜色属性
// 定义点的材质
let material = new THREE.PointsMaterial({vertexColors: true, size: 10});
// 创建粒子系统对象
let particleSystem = new THREE.Points(geometry, material);
return particleSystem
}
rgb_convert(rgb_str) {
let rgb = rgb_str.substring(5, rgb_str.length - 1).replace(/ /g, '').split(',').map(Number);
return rgb
}
rgb_diff(min, max) {
return [max[0] - min[0], max[1] - min[1], max[2] - min[2]]
}
绘制部分
调用上述代码,将所有的内容放到atomGroup 中,将atomGroup 添加到场景即可实现完整逻辑
const particleSystem = this.drawScatter(data)
// 将粒子系统对象添加到场景中
this.scatterGroup.add(particleSystem);
// 放入场景
scene.add(this.scatterGroup)