3D球体树状结构的实现
1.场景
const createScene = () => {
return new THREE.Scene();
};
2.相机
const createPerspectiveCamera = ({ fov, aspect, near, far }) => {
return new THREE.PerspectiveCamera(fov, aspect, near, far);
};
3.渲染器
const createWebGLRenderer = ({ dom, width, height }) => {
if (width === undefined) {
width = dom.clientWidth;
}
if (height === undefined) {
height = dom.clientHeight;
}
const renderer = new THREE.WebGLRenderer();
renderer.setSize(width, height);
dom.appendChild(renderer.domElement);
return renderer;
};
4.辅助线
const createAxesHelper = (length) => {
return new THREE.AxesHelper(length);
};
5.环境光
const createAmbientLight = ({ color, intensity }) => {
return new THREE.AmbientLight(color, intensity);
};
6.电光
const createPointLight = ({ color, intensity, distance, decay }) => {
return new THREE.PointLight(color, intensity, distance, decay);
};
7.球形几何体
const createSphereGeometry = ({
radius,
widthSegments,
heightSegments,
phiStart,
phiLength,
thetaStart,
thetaLength,
}) => {
return new THREE.SphereGeometry(
radius,
widthSegments,
heightSegments,
phiStart,
phiLength,
thetaStart,
thetaLength
);
};
8.球形几何体的材质
const createMeshLambertMaterial = (data) => {
return new THREE.MeshLambertMaterial(data);
};
9.球形背景几何体的材质
const createMeshPhongMaterialTexture = (data) => {
let materialData = {
map: new THREE.TextureLoader().load(data.url)
}
if(data.side){
materialData.side = THREE.DoubleSide
}
return new THREE.MeshPhysicalMaterial(materialData);
}
10.// 线几何体
const createLineGeometry = (points) => {
const pointsVector3 = [];
for (let i = 0; i < points.length; i++) {
pointsVector3.push(
new THREE.Vector3(points[i].x, points[i].y, points[i].z)
);
}
const geometry = new THREE.BufferGeometry().setFromPoints(pointsVector3);
const line = new MeshLine();
line.setGeometry(geometry);
return line;
};
11.线几何体的材质
const createMeshLineMaterial = (data) => {
return new MeshLineMaterial({
lineWidth: data.linewidth,
color: data.color || "white",
dashArray: data.dashArray || 0,
transparent: true,
});
};
12.物体
const createMesh = (geometry, materialBasic) => {
return new THREE.Mesh(geometry, materialBasic);
};
13.文本
const createText = ({ text, size, color }) => {
let textClass = new SpriteText(text, size);
textClass.color = color;
return textClass;
};
14.轨道控制
const createControl = (camera, dom) => {
return new THREE.OrbitControls(camera, dom);
};
15.完整代码
const createScene = () => {
return new THREE.Scene();
};
const createPerspectiveCamera = ({ fov, aspect, near, far }) => {
return new THREE.PerspectiveCamera(fov, aspect, near, far);
};
const createWebGLRenderer = ({ dom, width, height }) => {
if (width === undefined) {
width = dom.clientWidth;
}
if (height === undefined) {
height = dom.clientHeight;
}
const renderer = new THREE.WebGLRenderer();
renderer.setSize(width, height);
dom.appendChild(renderer.domElement);
return renderer;
};
const createAxesHelper = (length) => {
return new THREE.AxesHelper(length);
};
const createAmbientLight = ({ color, intensity }) => {
return new THREE.AmbientLight(color, intensity);
};
const createPointLight = ({ color, intensity, distance, decay }) => {
return new THREE.PointLight(color, intensity, distance, decay);
};
const createSphereBufferGeometry = ({
radius,
widthSegments,
heightSegments,
phiStart,
phiLength,
thetaStart,
thetaLength,
}) => {
return new THREE.SphereBufferGeometry(
radius,
widthSegments,
heightSegments,
phiStart,
phiLength,
thetaStart,
thetaLength
);
};
const createSphereGeometry = ({
radius,
widthSegments,
heightSegments,
phiStart,
phiLength,
thetaStart,
thetaLength,
}) => {
return new THREE.SphereGeometry(
radius,
widthSegments,
heightSegments,
phiStart,
phiLength,
thetaStart,
thetaLength
);
};
const createMeshLambertMaterial = (data) => {
return new THREE.MeshLambertMaterial(data);
};
const createMeshPhongMaterialTexture = (data) => {
let materialData = {
map: new THREE.TextureLoader().load(data.url)
}
if(data.side){
materialData.side = THREE.DoubleSide
}
return new THREE.MeshPhysicalMaterial(materialData);
}
const createLineGeometry = (points) => {
const pointsVector3 = [];
for (let i = 0; i < points.length; i++) {
pointsVector3.push(
new THREE.Vector3(points[i].x, points[i].y, points[i].z)
);
}
const geometry = new THREE.BufferGeometry().setFromPoints(pointsVector3);
const line = new MeshLine();
line.setGeometry(geometry);
return line;
};
const createMeshLineMaterial = (data) => {
return new MeshLineMaterial({
lineWidth: data.linewidth,
color: data.color || "white",
dashArray: data.dashArray || 0,
transparent: true,
});
};
const createMesh = (geometry, materialBasic) => {
return new THREE.Mesh(geometry, materialBasic);
};
const createText = ({ text, size, color }) => {
let textClass = new SpriteText(text, size);
textClass.color = color;
return textClass;
};
const createControl = (camera, dom) => {
return new THREE.OrbitControls(camera, dom);
};
const computedDataWeight = (data) => {
let weight = 0;
for (let i = 0; i < data.length; i++) {
let item = data[i];
if (item ?.children ?.length) {
item.weight = computedDataWeight(item.children);
weight += item.weight;
} else {
item.weight = 1;
weight += 1;
}
}
return weight;
};
const computedArcRArr = (data, pointInterval) => {
let ArcRArr = [];
let ArcData = [];
let ArcWeight = [];
formatTreeToArcData(data, ArcData);
for (let i = 0; i < ArcData.length; i++) {
let item = ArcData[i];
let weight = 0;
for (let j = 0; j < item.length; j++) {
weight += item[j].weight;
}
ArcWeight.push(weight);
}
let R = computedArcR(pointInterval, ArcWeight[0]);
for (let i = 0; i < ArcData.length; i++) {
let item = ArcData[i];
if (ArcWeight[i] < ArcWeight[0]) {
ArcRArr.push(R);
} else {
if (item.length > 1) {
let DValue = 0;
item.forEach((weight) => {
DValue += Math.floor(weight.weight / 2);
});
ArcRArr.push(((ArcWeight[i] - DValue) / ArcWeight[i]) * R);
} else {
ArcRArr.push(0);
}
}
}
return { ArcRArr, R };
};
const formatTreeToArcData = (data, ArcData, deep = 0) => {
data.forEach((element) => {
if (!ArcData[deep]) {
ArcData[deep] = [];
}
ArcData[deep].push({
label: element.label,
point_uuid: element.point_uuid,
weight: element.weight,
});
if (element?.children?.length) {
formatTreeToArcData(element?.children, ArcData, deep + 1);
}
});
};
const computedArcR = (pointInterval, points) => {
if (points === 1) {
return pointInterval * 2;
}
let arcR =
pointInterval /
2 /
Math.cos((Math.PI / 180) * (((points - 2) * 180) / points / 2));
if (arcR < pointInterval) {
arcR = pointInterval * 2;
}
return arcR;
};
const computedTreeStyleAuto = (style, ArcRArr, R) => {
if (style.yr === "auto") {
style.yr = ArcRArr.length === 1 ? R : R / (ArcRArr.length - 1);
}
style.startPositionY =
((ArcRArr.length - 1) / 2) * style.yr + style.centerXYZ[1];
};
const computedPointPosition = (
data,
style,
ArcRArr,
startAngle = 0,
endAngle = Math.PI * 2,
deep = 0
) => {
let totalWight = 0;
for (let i = 0; i < data.length; i++) {
totalWight += data[i].weight;
}
let AngleScope = endAngle - startAngle;
let curAngle = startAngle;
let randTranslate = ArcRArr[deep] * 10 || 1000
for (let i = 0; i < data.length; i++) {
let item = data[i];
let ratioAngle = (item.weight / totalWight) * AngleScope;
item.targetPostion = {
x: Math.sin(curAngle + ratioAngle / 2) * ArcRArr[deep] + style.centerXYZ[0],
y: style.startPositionY - deep * (style.yr || 0) + style.centerXYZ[1],
z: Math.cos(curAngle + ratioAngle / 2) * ArcRArr[deep] + style.centerXYZ[2]
}
item.translatePostion = {
y: rand(-randTranslate, randTranslate),
x: rand(-randTranslate, randTranslate),
z: rand(-randTranslate, ArcRArr[deep])
}
if (item ?.children ?.length) {
computedPointPosition(
item ?.children,
style,
ArcRArr,
curAngle,
curAngle + ratioAngle,
deep + 1
);
}
curAngle += ratioAngle;
}
};
const computedCameraStyle = (style, dom, treeStyle, R) => {
if (style.position === "auto") {
style.position = {
x: 0,
y: treeStyle.yr * 1.5,
z: R * 3,
};
}
if (style.data === "auto") {
style.data = {
fov: 45,
aspect: dom.clientWidth / dom.clientHeight,
near: 0.1,
far: R * 1000,
};
}
if (style.lookAt === "auto") {
style.lookAt = JSON.parse(JSON.stringify(treeStyle.centerXYZ));
}
};
const computedBjMeshStyleAuto = (style, R) => {
style.geometry.radius = R
}
const rand = (n, m) => {
const c = m - n + 1
return Math.floor(Math.random() * c + n)
}
const randTree = (deep = 0, maxDeep = 3, parentName) => {
let tree = []
let length = rand(1,3)
for(let i = 0; i < length; i++){
let data = {
name: parentName ? parentName + '-' + i : i + ''
}
if(rand(0,2) && deep < maxDeep){
data.children = randTree(deep + 1, maxDeep, data.name)
}
tree.push(data)
}
return tree
}
const originTreeStyle = {
centerXYZ: [0, 0, 0],
yr: "auto",
pointInterval: 10,
};
let treeStyle = null
const originCameraStyle = {
position: "auto",
data: "auto",
lookAt: "auto",
};
let cameraStyle = null
const bjMeshStyle = {
geometry: {
radius: 'auto',
widthSegments: 320,
heightSegments: 160
},
material: {
url: "./sphere-bg2.jpg",
side: true
}
}
const sphereMeshStyle = {
geometry: {
radius: 1,
widthSegments: 320,
heightSegments: 160,
},
material: {
color: "#ffffff",
wireframe: false,
},
};
const lineMeshStyle = {
material: {
color: "#ffffff",
linewidth: 0.3,
},
};
const textMeshStyle = {
material: {
size: 0.5,
color: "#0080ff",
},
};
let scene = null;
let camera = null;
let renderer = null;
let control = null;
let bjMesh = null;
let axes = null;
let ambientLight = null;
let pointLight = null;
let animationIndex = 0
let targetAnimationIndex = 50
let sphereGeometrys = [];
let textGeometrys = [];
let lineGeometrys = [];
let old_sphereGeometrys = [];
let old_textGeometrys = [];
let cameraAnimationIndex = 0
let targetCameraAnimationIndex = 50
const init = (rendererDom, data) => {
treeStyle = JSON.parse(JSON.stringify(originTreeStyle))
cameraStyle = JSON.parse(JSON.stringify(originCameraStyle))
computedDataWeight(data);
let { ArcRArr, R } = computedArcRArr(data, treeStyle.pointInterval);
computedTreeStyleAuto(treeStyle, ArcRArr, R);
computedPointPosition(data, treeStyle, ArcRArr);
computedCameraStyle(cameraStyle, rendererDom, treeStyle, R);
if(!scene){
scene = createScene();
}
if(!camera){
camera = createPerspectiveCamera(cameraStyle.data);
camera.position.set(
cameraStyle.position.x,
cameraStyle.position.y,
cameraStyle.position.z
);
}
camera.translate_camera_position = {
x: camera.position.x - cameraStyle.position.x,
y: camera.position.y - cameraStyle.position.y,
z: camera.position.z - cameraStyle.position.z,
}
camera.camera_position = cameraStyle.position
camera.init_camera_position = JSON.parse(JSON.stringify(cameraStyle.position))
if(!renderer){
renderer = createWebGLRenderer({
dom: rendererDom,
});
}
if(!control){
control = createControl(camera, rendererDom);
}
if(!axes){
axes = createAxesHelper(R);
}
if(!ambientLight){
ambientLight = createAmbientLight({ color: "#fff", intensity: 0.2 });
scene.add(ambientLight);
}
if(!pointLight){
pointLight = createPointLight({ color: "#fff", intensity: 1 });
let pointLightL = R * 10
pointLight.rotateSpeed = Math.PI / 100;
pointLight.lightAngle = Math.atan(1);
pointLight.arcR = Math.sqrt(pointLightL * pointLightL * 2);
pointLight.init_position = {
x: pointLightL,
y: pointLightL,
z: pointLightL,
}
pointLight.position.set(pointLightL, pointLightL, pointLightL);
scene.add(pointLight);
}
animationIndex = 0
cameraAnimationIndex = 0
old_sphereGeometrys = [...sphereGeometrys];
old_textGeometrys = [...textGeometrys];
lineGeometrys.forEach(item => {
scene.remove(item);
})
sphereGeometrys = [];
textGeometrys = [];
lineGeometrys = [];
let geometry = createSphereGeometry(sphereMeshStyle.geometry);
let material = createMeshLambertMaterial(sphereMeshStyle.material);
initGeometrys(data, geometry, material, sphereGeometrys, textGeometrys, lineGeometrys);
geometry.dispose();
material.dispose();
scene.add(...sphereGeometrys);
scene.add(...textGeometrys);
render();
};
const initGeometrys = (data, geometry, material, sphereGeometrys, textGeometrys, lineGeometrys, parentPosition) => {
for (let i = 0; i < data.length; i++) {
let item = data[i];
const mesh = createMesh(geometry, material);
mesh.position.set(item.targetPostion.x + item.translatePostion.x, item.targetPostion.y + item.translatePostion.y, item.targetPostion.z + item.translatePostion.z);
mesh.originData = item
mesh.scale.set(1.3, 1.3, 1.3);
sphereGeometrys.push(mesh);
const text = createText({
text: item.name,
size: textMeshStyle.material.size,
color: textMeshStyle.material.color,
});
text.position.x = item.targetPostion.x + item.translatePostion.x;
text.position.y = item.targetPostion.y + item.translatePostion.y + sphereMeshStyle.geometry.radius * 2;
text.position.z = item.targetPostion.z + item.translatePostion.z;
textGeometrys.push(text);
if (parentPosition) {
const lineGeometry = createLineGeometry([
parentPosition,
{ x: item.targetPostion.x, y: item.targetPostion.y, z: item.targetPostion.z },
]);
const lineMaterial = createMeshLineMaterial(lineMeshStyle.material);
const lineMesh = createMesh(lineGeometry, lineMaterial);
lineGeometrys.push(lineMesh);
lineGeometry.dispose();
lineMaterial.dispose();
}
if (item?.children?.length) {
initGeometrys(
item.children,
geometry,
material,
sphereGeometrys,
textGeometrys,
lineGeometrys,
{ x: item.targetPostion.x, y: item.targetPostion.y, z: item.targetPostion.z }
);
}
}
};
const render = () => {
stats.update()
rotate()
pointAnimation()
cameraAnimation()
requestAnimationFrame(render);
renderer.render(scene, camera);
};
const resetPointLightPosition = () => {
pointLight.position.set(pointLight.init_position.x, pointLight.init_position.y, pointLight.init_position.z);
pointLight.lightAngle = Math.atan(1);
}
const rotate = (angle) => {
if(pointLight.rotateFlag){
return
}
pointLight.lightAngle += angle || pointLight.rotateSpeed
pointLight.lightAngle = pointLight.lightAngle % (Math.PI * 2)
pointLight.position.set(Math.sin(pointLight.lightAngle) * pointLight.arcR, pointLight.position.y, Math.cos(pointLight.lightAngle) * pointLight.arcR);
}
const pointAnimation = () => {
if(animationIndex === targetAnimationIndex){
return
}
animationIndex++
let scale = (targetAnimationIndex - animationIndex) / targetAnimationIndex
let scale2 = animationIndex / targetAnimationIndex
sphereGeometrys.forEach((item, index) => {
let data = {
x: item.originData.targetPostion.x + item.originData.targetPostion.x * scale,
y: item.originData.targetPostion.y + item.originData.targetPostion.y * scale,
z: item.originData.targetPostion.z + item.originData.targetPostion.z * scale
}
item.position.set(data.x, data.y, data.z);
textGeometrys[index].position.set(data.x, data.y + sphereMeshStyle.geometry.radius * 2, data.z)
})
old_sphereGeometrys.forEach((item, index) => {
let data = {
x: item.originData.targetPostion.x + item.originData.targetPostion.x * scale2,
y: item.originData.targetPostion.y + item.originData.targetPostion.y * scale2,
z: item.originData.targetPostion.z + item.originData.targetPostion.z * scale2
}
item.position.set(data.x, data.y, data.z);
old_textGeometrys[index].position.set(data.x, data.y + sphereMeshStyle.geometry.radius * 2, data.z)
})
if(animationIndex === targetAnimationIndex){
old_sphereGeometrys.forEach((item,index) => {
scene.remove(item);
scene.remove(old_textGeometrys[index]);
})
old_sphereGeometrys = []
old_textGeometrys = []
if(lineGeometrys.length){
scene.add(...lineGeometrys);
}
}
}
const cameraAnimation = () => {
if(cameraAnimationIndex === targetCameraAnimationIndex){
return
}
cameraAnimationIndex++
let scale = (targetCameraAnimationIndex - cameraAnimationIndex) / targetCameraAnimationIndex
camera.position.set(
camera.camera_position.x + camera.translate_camera_position.x * scale,
camera.camera_position.y + camera.translate_camera_position.y * scale,
camera.camera_position.z + camera.translate_camera_position.z * scale,
);
camera.lookAt(
cameraStyle.lookAt[0],
cameraStyle.lookAt[1],
cameraStyle.lookAt[2]
);
}
const visualAngleChange = (mesh) => {
let dx = mesh.position.x - cameraStyle.lookAt[0]
let dy = mesh.position.y - cameraStyle.lookAt[1]
let dz = mesh.position.z - cameraStyle.lookAt[2]
if (Math.abs(dx) < 0.001) {
dx = 0
}
if (Math.abs(dy) < 0.001) {
dy = 0
}
if (Math.abs(dz) < 0.001) {
dz = 0
}
let targetPositon = {}
if (dx === 0 && dy === 0 && dz === 0) {
targetPositon = {
x: mesh.position.x + treeStyle.pointInterval,
y: mesh.position.y + treeStyle.pointInterval,
z: mesh.position.z + treeStyle.pointInterval,
}
} else if (dx === 0 && dy === 0) {
let dzPointInterval = dz / Math.abs(dz) * treeStyle.pointInterval * 2
targetPositon = {
x: mesh.position.x + dzPointInterval,
y: mesh.position.y + dzPointInterval,
z: mesh.position.z + dzPointInterval,
}
} else if (dy === 0 && dz === 0) {
let dxPointInterval = dx / Math.abs(dx) * treeStyle.pointInterval * 2
targetPositon = {
x: mesh.position.x + dxPointInterval,
y: mesh.position.y + dxPointInterval,
z: mesh.position.z + dxPointInterval,
}
} else if (dx === 0 && dz === 0) {
let dyPointInterval = dy / Math.abs(dy) * treeStyle.pointInterval * 2
targetPositon = {
x: mesh.position.x + dyPointInterval,
y: mesh.position.y + dyPointInterval,
z: mesh.position.z + dyPointInterval,
}
} else {
let dd = null
if (dx !== 0) {
dd = dx
} else if (dy !== 0) {
dd = dy
} else if (dz !== 0) {
dd = dz
}
let translateL = treeStyle.pointInterval * dd / Math.abs(dd)
let dxdd = dx / dd
let dydd = dy / dd
let dzdd = dz / dd
let maxdd = dxdd > dydd ? dxdd : dydd
maxdd = maxdd > dzdd ? maxdd : dzdd
if (Math.abs(maxdd) > 1) {
let scale = Math.abs(maxdd) / 1
dxdd = dxdd / scale
dydd = dydd / scale
dzdd = dzdd / scale
}
targetPositon = {
x: mesh.position.x + translateL * dxdd,
y: mesh.position.y + translateL * dydd,
z: mesh.position.z + translateL * dzdd,
}
}
camera.translate_camera_position = {
x: camera.position.x - targetPositon.x,
y: camera.position.y - targetPositon.y,
z: camera.position.z - targetPositon.z,
}
camera.camera_position = JSON.parse(JSON.stringify(targetPositon))
let length = Math.sqrt(Math.pow(camera.translate_camera_position.x, 2) + Math.pow(camera.translate_camera_position.y, 2) + Math.pow(camera.translate_camera_position.z, 2))
cameraAnimationIndex = length > treeStyle.pointInterval ? 0 : Math.floor(length / treeStyle.pointInterval * targetCameraAnimationIndex)
}
16.init部分——优化前
const init = (rendererDom, data) => {
treeStyle = JSON.parse(JSON.stringify(originTreeStyle))
cameraStyle = JSON.parse(JSON.stringify(originCameraStyle))
computedDataWeight(data);
let { ArcRArr, R } = computedArcRArr(data, treeStyle.pointInterval);
computedTreeStyleAuto(treeStyle, ArcRArr, R);
computedPointPosition(data, treeStyle, ArcRArr);
computedCameraStyle(cameraStyle, rendererDom, treeStyle, R);
if(!scene){
scene = createScene();
}
if(!camera){
camera = createPerspectiveCamera(cameraStyle.data);
camera.position.set(
cameraStyle.position.x,
cameraStyle.position.y,
cameraStyle.position.z
);
}
camera.translate_camera_position = {
x: camera.position.x - cameraStyle.position.x,
y: camera.position.y - cameraStyle.position.y,
z: camera.position.z - cameraStyle.position.z,
}
camera.camera_position = cameraStyle.position
camera.init_camera_position = JSON.parse(JSON.stringify(cameraStyle.position))
if(!renderer){
renderer = createWebGLRenderer({
dom: rendererDom,
});
}
if(!control){
control = createControl(camera, rendererDom);
}
if(!axes){
axes = createAxesHelper(R);
}
if(!ambientLight){
ambientLight = createAmbientLight({ color: "#fff", intensity: 0.2 });
scene.add(ambientLight);
}
if(!pointLight){
pointLight = createPointLight({ color: "#fff", intensity: 1 });
let pointLightL = R * 10
pointLight.rotateSpeed = Math.PI / 100;
pointLight.lightAngle = Math.atan(1);
pointLight.arcR = Math.sqrt(pointLightL * pointLightL * 2);
pointLight.init_position = {
x: pointLightL,
y: pointLightL,
z: pointLightL,
}
pointLight.position.set(pointLightL, pointLightL, pointLightL);
scene.add(pointLight);
}
animationIndex = 0
cameraAnimationIndex = 0
old_sphereGeometrys = [...sphereGeometrys];
old_textGeometrys = [...textGeometrys];
lineGeometrys.forEach(item => {
scene.remove(item);
})
sphereGeometrys = [];
textGeometrys = [];
lineGeometrys = [];
initGeometrys(data, sphereGeometrys, textGeometrys, lineGeometrys);
scene.add(...sphereGeometrys);
scene.add(...textGeometrys);
render();
};
const initGeometrys = (data, sphereGeometrys, textGeometrys, lineGeometrys, parentPosition) => {
for (let i = 0; i < data.length; i++) {
let item = data[i];
const geometry = createSphereGeometry(sphereMeshStyle.geometry);
const material = createMeshLambertMaterial(sphereMeshStyle.material);
const mesh = createMesh(geometry, material);
mesh.position.set(item.targetPostion.x + item.translatePostion.x, item.targetPostion.y + item.translatePostion.y, item.targetPostion.z + item.translatePostion.z);
mesh.originData = item
mesh.scale.set(1.3, 1.3, 1.3);
sphereGeometrys.push(mesh);
geometry.dispose();
material.dispose();
const text = createText({
text: item.name,
size: textMeshStyle.material.size,
color: textMeshStyle.material.color,
});
text.position.x = item.targetPostion.x + item.translatePostion.x;
text.position.y = item.targetPostion.y + item.translatePostion.y + sphereMeshStyle.geometry.radius * 2;
text.position.z = item.targetPostion.z + item.translatePostion.z;
textGeometrys.push(text);
if (parentPosition) {
const lineGeometry = createLineGeometry([
parentPosition,
{ x: item.targetPostion.x, y: item.targetPostion.y, z: item.targetPostion.z },
]);
const lineMaterial = createMeshLineMaterial(lineMeshStyle.material);
const lineMesh = createMesh(lineGeometry, lineMaterial);
lineGeometrys.push(lineMesh);
lineGeometry.dispose();
lineMaterial.dispose();
}
if (item ?.children ?.length) {
initGeometrys(
item.children,
sphereGeometrys,
textGeometrys,
lineGeometrys,
{ x: item.targetPostion.x, y: item.targetPostion.y, z: item.targetPostion.z }
);
}
}
};
17.init——优化后
const init = (rendererDom, data) => {
treeStyle = JSON.parse(JSON.stringify(originTreeStyle))
cameraStyle = JSON.parse(JSON.stringify(originCameraStyle))
computedDataWeight(data);
let { ArcRArr, R } = computedArcRArr(data, treeStyle.pointInterval);
computedTreeStyleAuto(treeStyle, ArcRArr, R);
computedPointPosition(data, treeStyle, ArcRArr);
computedCameraStyle(cameraStyle, rendererDom, treeStyle, R);
if(!scene){
scene = createScene();
}
if(!camera){
camera = createPerspectiveCamera(cameraStyle.data);
camera.position.set(
cameraStyle.position.x,
cameraStyle.position.y,
cameraStyle.position.z
);
}
camera.translate_camera_position = {
x: camera.position.x - cameraStyle.position.x,
y: camera.position.y - cameraStyle.position.y,
z: camera.position.z - cameraStyle.position.z,
}
camera.camera_position = cameraStyle.position
camera.init_camera_position = JSON.parse(JSON.stringify(cameraStyle.position))
if(!renderer){
renderer = createWebGLRenderer({
dom: rendererDom,
});
}
if(!control){
control = createControl(camera, rendererDom);
}
if(!axes){
axes = createAxesHelper(R);
}
if(!ambientLight){
ambientLight = createAmbientLight({ color: "#fff", intensity: 0.2 });
scene.add(ambientLight);
}
if(!pointLight){
pointLight = createPointLight({ color: "#fff", intensity: 1 });
let pointLightL = R * 10
pointLight.rotateSpeed = Math.PI / 100;
pointLight.lightAngle = Math.atan(1);
pointLight.arcR = Math.sqrt(pointLightL * pointLightL * 2);
pointLight.init_position = {
x: pointLightL,
y: pointLightL,
z: pointLightL,
}
pointLight.position.set(pointLightL, pointLightL, pointLightL);
scene.add(pointLight);
}
animationIndex = 0
cameraAnimationIndex = 0
old_sphereGeometrys = [...sphereGeometrys];
old_textGeometrys = [...textGeometrys];
lineGeometrys.forEach(item => {
scene.remove(item);
})
sphereGeometrys = [];
textGeometrys = [];
lineGeometrys = [];
let geometry = createSphereGeometry(sphereMeshStyle.geometry);
let material = createMeshLambertMaterial(sphereMeshStyle.material);
initGeometrys(data, geometry, material, sphereGeometrys, textGeometrys, lineGeometrys);
geometry.dispose();
material.dispose();
scene.add(...sphereGeometrys);
scene.add(...textGeometrys);
render();
};
const initGeometrys = (data, geometry, material, sphereGeometrys, textGeometrys, lineGeometrys, parentPosition) => {
for (let i = 0; i < data.length; i++) {
let item = data[i];
const mesh = createMesh(geometry, material);
mesh.position.set(item.targetPostion.x + item.translatePostion.x, item.targetPostion.y + item.translatePostion.y, item.targetPostion.z + item.translatePostion.z);
mesh.originData = item
mesh.scale.set(1.3, 1.3, 1.3);
sphereGeometrys.push(mesh);
const text = createText({
text: item.name,
size: textMeshStyle.material.size,
color: textMeshStyle.material.color,
});
text.position.x = item.targetPostion.x + item.translatePostion.x;
text.position.y = item.targetPostion.y + item.translatePostion.y + sphereMeshStyle.geometry.radius * 2;
text.position.z = item.targetPostion.z + item.translatePostion.z;
textGeometrys.push(text);
if (parentPosition) {
const lineGeometry = createLineGeometry([
parentPosition,
{ x: item.targetPostion.x, y: item.targetPostion.y, z: item.targetPostion.z },
]);
const lineMaterial = createMeshLineMaterial(lineMeshStyle.material);
const lineMesh = createMesh(lineGeometry, lineMaterial);
lineGeometrys.push(lineMesh);
lineGeometry.dispose();
lineMaterial.dispose();
}
if (item?.children?.length) {
initGeometrys(
item.children,
geometry,
material,
sphereGeometrys,
textGeometrys,
lineGeometrys,
{ x: item.targetPostion.x, y: item.targetPostion.y, z: item.targetPostion.z }
);
}
}
};
18.点击捕获
const meshOnClick = (event) => {
const pointer = new THREE.Vector2();
pointer.x = (event.clientX / renderer.domElement.clientWidth) * 2 - 1;
pointer.y = - (event.clientY / renderer.domElement.clientHeight) * 2 + 1;
let intersects = [];
let raycaster = new THREE.Raycaster();
raycaster.setFromCamera(pointer, camera);
intersects = raycaster.intersectObjects(sphereGeometrys, true);
if (intersects.length > 0) {
meshOnClickCb(intersects[0].object)
}
}
const meshOnClickCb =(mesh)=> {
console.log("mesh.originData.name:" + mesh.originData.name);
console.log("mesh.originData.ID:" + mesh.originData.ID);
document.getElementById('selectedID').value = mesh.originData.ID;
console.log("test:" + document.getElementById('selectedID').value);
visualAngleChange(mesh);
}