Files
BlackFruit-UI/js/globe.js
yiqiu d743029e0d
All checks were successful
continuous-integration/drone/push Build is passing
1
2025-11-21 21:59:21 +08:00

194 lines
5.9 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// 3D 地球效果(首页 banner 右侧)基于 three-globe
// 依赖:全局 THREE 和 ThreeGlobe在 index.html 中通过 CDN 引入)
(function () {
function initGlobe() {
var container = document.getElementById("bannerGlobe");
if (!container) {
console.warn("[Globe] bannerGlobe container not found");
return;
}
if (typeof THREE === "undefined") {
console.warn(
"[Globe] THREE is undefined, please ensure three.min.js is loaded"
);
return;
}
if (typeof ThreeGlobe === "undefined") {
console.warn(
"[Globe] ThreeGlobe is undefined, please ensure three-globe.min.js is loaded"
);
return;
}
var width = container.clientWidth || 400;
var height = container.clientHeight || 400;
// 基础 Three.js 场景
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(45, width / height, 0.1, 1000);
// 稍微偏右俯视一点
camera.position.set(0, 0.4, 4.0);
camera.lookAt(0, 0, 0);
var renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
renderer.setPixelRatio(Math.min(window.devicePixelRatio || 1, 2));
renderer.setSize(width, height);
renderer.setClearColor(0x000000, 0); // 透明背景
container.appendChild(renderer.domElement);
// 柔和光照
var ambient = new THREE.AmbientLight(0xffffff, 0.65);
scene.add(ambient);
var dirLight = new THREE.DirectionalLight(0xffffff, 0.9);
dirLight.position.set(5, 3, 5);
scene.add(dirLight);
// 示例节点数据(可后续替换为真实机房经纬度)
var nodes = [
{ name: "Beijing", lat: 39.9, lng: 116.4 },
{ name: "Shanghai", lat: 31.2, lng: 121.5 },
{ name: "Hong Kong", lat: 22.5, lng: 114.1 },
{ name: "Singapore", lat: 1.3, lng: 103.8 },
{ name: "San Francisco", lat: 37.8, lng: -122.4 },
{ name: "Berlin", lat: 52.5, lng: 13.4 },
{ name: "Tokyo", lat: 35.7, lng: 139.7 },
];
// 示例 arcs从北京发出到其他节点
var arcs = nodes
.filter(function (n) {
return n.name !== "Beijing";
})
.map(function (n) {
return {
startLat: 39.9,
startLng: 116.4,
endLat: n.lat,
endLng: n.lng,
};
});
// three-globe 实例(仅使用其数据层,大气层和坐标系)
var globe = new ThreeGlobe({
waitForGlobeReady: true,
animateIn: true,
})
// 隐藏 three-globe 默认球体,我们自己画一个实心地球
.showGlobe(false)
.showAtmosphere(true)
.atmosphereColor("#2b9fff")
.atmosphereAltitude(0.18)
.showGraticules(false)
// 节点柱状体
.pointsData(nodes)
.pointColor(function () {
return "#5ad8ff";
})
.pointAltitude(0.06)
.pointRadius(0.32)
.pointsTransitionDuration(1000)
// 弧线
.arcsData(arcs)
.arcColor(function () {
return ["#5ad8ff", "#ffffff"];
})
.arcAltitude(0.35)
.arcStroke(0.45)
.arcDashLength(0.6)
.arcDashGap(0.25)
.arcDashAnimateTime(2600);
scene.add(globe);
// 自绘一个实心地球球体,避免默认球体材质透明或贴图问题
try {
var earthRadius = 1; // three-globe 使用的半径单位
var earthGeometry = new THREE.SphereGeometry(earthRadius, 64, 64);
var earthMaterial = new THREE.MeshPhongMaterial({
color: new THREE.Color("#163a5f"), // 基础色:深蓝
emissive: new THREE.Color("#040915"), // 自发光:微亮
specular: new THREE.Color("#3aaefc"), // 高光:亮蓝
shininess: 40,
transparent: false,
opacity: 1,
});
var earthMesh = new THREE.Mesh(earthGeometry, earthMaterial);
// 将地球球体挂到 three-globe 对象上,保证与节点/弧线共用坐标系
globe.add(earthMesh);
} catch (e) {
console.warn("[Globe] failed to create custom earth sphere:", e);
}
// 暴露给调试用
if (typeof window !== "undefined") {
window.__globe = globe;
}
// 星辰背景(简单加一点点空间感)
var starGeometry = new THREE.BufferGeometry();
var starCount = 600;
var starPositions = new Float32Array(starCount * 3);
for (var i = 0; i < starCount; i++) {
var sr = 10 + Math.random() * 5;
var theta = Math.random() * Math.PI * 2;
var phi = Math.acos(2 * Math.random() - 1);
var sx = sr * Math.sin(phi) * Math.cos(theta);
var sy = sr * Math.sin(phi) * Math.sin(theta);
var sz = sr * Math.cos(phi);
starPositions[i * 3] = sx;
starPositions[i * 3 + 1] = sy;
starPositions[i * 3 + 2] = sz;
}
starGeometry.setAttribute(
"position",
new THREE.BufferAttribute(starPositions, 3)
);
var starMaterial = new THREE.PointsMaterial({
color: 0x3f76ff,
size: 0.08,
transparent: true,
opacity: 0.7,
});
var stars = new THREE.Points(starGeometry, starMaterial);
scene.add(stars);
// 自适应窗口大小
function onResize() {
if (!container) return;
var w = container.clientWidth || width;
var h = container.clientHeight || height;
camera.aspect = w / h;
camera.updateProjectionMatrix();
renderer.setSize(w, h);
}
window.addEventListener("resize", onResize);
// 动画循环
var lastTime = performance.now();
function animate() {
requestAnimationFrame(animate);
var now = performance.now();
var delta = (now - lastTime) / 1000;
lastTime = now;
// 地球自转
globe.rotation.y += delta * 0.25;
// 星空轻微旋转
stars.rotation.y -= delta * 0.03;
renderer.render(scene, camera);
}
animate();
}
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", initGlobe);
} else {
initGlobe();
}
})();