This commit is contained in:
@@ -5,11 +5,10 @@
|
|||||||
|
|
||||||
<!-- 首页脚本 -->
|
<!-- 首页脚本 -->
|
||||||
<script src="/web/BlackFruit-web/js/index.js"></script>
|
<script src="/web/BlackFruit-web/js/index.js"></script>
|
||||||
<!-- 3D 地球依赖:Three.js
|
<!-- 3D 地球依赖:Three.js 和 three-globe(使用 CDN 版本方便预览效果) -->
|
||||||
如需本地部署,请将 three.min.js 放到 /web/BlackFruit-web/vender/three/three.min.js
|
|
||||||
这里默认使用 CDN,方便快速预览效果 -->
|
|
||||||
<script src="https://unpkg.com/three@0.155.0/build/three.min.js"></script>
|
<script src="https://unpkg.com/three@0.155.0/build/three.min.js"></script>
|
||||||
<!-- 3D 地球效果脚本 -->
|
<script src="https://unpkg.com/three-globe@2.45.0/dist/three-globe.min.js"></script>
|
||||||
|
<!-- 3D 地球效果脚本(基于 three-globe) -->
|
||||||
<script src="/web/BlackFruit-web/js/globe.js"></script>
|
<script src="/web/BlackFruit-web/js/globe.js"></script>
|
||||||
<script src="/web/BlackFruit-web/js/viewer.min.js"></script>
|
<script src="/web/BlackFruit-web/js/viewer.min.js"></script>
|
||||||
|
|
||||||
|
|||||||
181
js/globe.js
181
js/globe.js
@@ -1,5 +1,5 @@
|
|||||||
// 3D 地球效果(首页 banner 右侧)
|
// 3D 地球效果(首页 banner 右侧)基于 three-globe
|
||||||
// 依赖:Three.js(全局 THREE 对象),脚本路径建议:/web/BlackFruit-web/vender/three/three.min.js
|
// 依赖:全局 THREE 和 ThreeGlobe(在 index.html 中通过 CDN 引入)
|
||||||
|
|
||||||
(function () {
|
(function () {
|
||||||
function initGlobe() {
|
function initGlobe() {
|
||||||
@@ -9,114 +9,110 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (typeof THREE === "undefined") {
|
if (typeof THREE === "undefined") {
|
||||||
// Three.js 未加载时直接跳过,不影响其它功能
|
console.warn(
|
||||||
console.warn("[Globe] THREE is undefined, please ensure three.min.js is loaded");
|
"[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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var width = container.clientWidth || 400;
|
var width = container.clientWidth || 400;
|
||||||
var height = container.clientHeight || 400;
|
var height = container.clientHeight || 400;
|
||||||
|
|
||||||
|
// 基础 Three.js 场景
|
||||||
var scene = new THREE.Scene();
|
var scene = new THREE.Scene();
|
||||||
|
|
||||||
var camera = new THREE.PerspectiveCamera(45, width / height, 0.1, 1000);
|
var camera = new THREE.PerspectiveCamera(45, width / height, 0.1, 1000);
|
||||||
var radius = 1.2;
|
// 稍微偏右俯视一点
|
||||||
camera.position.set(0, 0, radius * 3.2);
|
camera.position.set(0, 0.4, 4.0);
|
||||||
camera.lookAt(0, 0, 0);
|
camera.lookAt(0, 0, 0);
|
||||||
|
|
||||||
var renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
|
var renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
|
||||||
renderer.setPixelRatio(Math.min(window.devicePixelRatio || 1, 2));
|
renderer.setPixelRatio(Math.min(window.devicePixelRatio || 1, 2));
|
||||||
renderer.setSize(width, height);
|
renderer.setSize(width, height);
|
||||||
renderer.setClearColor(0x000000, 0); // 透明背景,融入页面
|
renderer.setClearColor(0x000000, 0); // 透明背景
|
||||||
container.appendChild(renderer.domElement);
|
container.appendChild(renderer.domElement);
|
||||||
|
|
||||||
// 光照:柔和的环境光 + 方向光
|
// 柔和光照
|
||||||
scene.add(new THREE.AmbientLight(0xffffff, 0.5));
|
var ambient = new THREE.AmbientLight(0xffffff, 0.65);
|
||||||
|
scene.add(ambient);
|
||||||
var dirLight = new THREE.DirectionalLight(0xffffff, 0.9);
|
var dirLight = new THREE.DirectionalLight(0xffffff, 0.9);
|
||||||
dirLight.position.set(5, 3, 5);
|
dirLight.position.set(5, 3, 5);
|
||||||
scene.add(dirLight);
|
scene.add(dirLight);
|
||||||
|
|
||||||
var globeGroup = new THREE.Group();
|
// 示例节点数据(可后续替换为真实机房经纬度)
|
||||||
scene.add(globeGroup);
|
var nodes = [
|
||||||
|
{ name: "Beijing", lat: 39.9, lng: 116.4 },
|
||||||
// 地球球体
|
{ name: "Shanghai", lat: 31.2, lng: 121.5 },
|
||||||
var earthGeometry = new THREE.SphereGeometry(radius, 64, 64);
|
{ name: "Hong Kong", lat: 22.5, lng: 114.1 },
|
||||||
|
{ name: "Singapore", lat: 1.3, lng: 103.8 },
|
||||||
// 纯色高光材质,若后续有贴图可替换为 MeshPhongMaterial + map
|
{ name: "San Francisco", lat: 37.8, lng: -122.4 },
|
||||||
var earthMaterial = new THREE.MeshPhongMaterial({
|
{ name: "Berlin", lat: 52.5, lng: 13.4 },
|
||||||
color: 0x163a5f,
|
{ name: "Tokyo", lat: 35.7, lng: 139.7 },
|
||||||
emissive: 0x061727,
|
|
||||||
shininess: 35,
|
|
||||||
specular: 0x3aaefc,
|
|
||||||
});
|
|
||||||
|
|
||||||
var earthMesh = new THREE.Mesh(earthGeometry, earthMaterial);
|
|
||||||
globeGroup.add(earthMesh);
|
|
||||||
|
|
||||||
// 大气层发光效果
|
|
||||||
var atmosphereGeometry = new THREE.SphereGeometry(radius * 1.06, 64, 64);
|
|
||||||
var atmosphereMaterial = new THREE.MeshBasicMaterial({
|
|
||||||
color: 0x2b9fff,
|
|
||||||
transparent: true,
|
|
||||||
opacity: 0.25,
|
|
||||||
side: THREE.BackSide,
|
|
||||||
});
|
|
||||||
var atmosphereMesh = new THREE.Mesh(
|
|
||||||
atmosphereGeometry,
|
|
||||||
atmosphereMaterial
|
|
||||||
);
|
|
||||||
globeGroup.add(atmosphereMesh);
|
|
||||||
|
|
||||||
// 将经纬度转换为球面坐标
|
|
||||||
function latLngToVector3(lat, lng, r) {
|
|
||||||
var phi = (90 - lat) * (Math.PI / 180);
|
|
||||||
var theta = (lng + 180) * (Math.PI / 180);
|
|
||||||
var x = -r * Math.sin(phi) * Math.cos(theta);
|
|
||||||
var z = r * Math.sin(phi) * Math.sin(theta);
|
|
||||||
var y = r * Math.cos(phi);
|
|
||||||
return new THREE.Vector3(x, y, z);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 一些示例节点(可以根据业务改为真实机房经纬度)
|
|
||||||
var nodeConfigs = [
|
|
||||||
{ lat: 39.9, lng: 116.4 }, // 北京
|
|
||||||
{ lat: 31.2, lng: 121.5 }, // 上海
|
|
||||||
{ lat: 22.5, lng: 114.1 }, // 香港
|
|
||||||
{ lat: 1.3, lng: 103.8 }, // 新加坡
|
|
||||||
{ lat: 37.8, lng: -122.4 }, // 旧金山
|
|
||||||
{ lat: 52.5, lng: 13.4 }, // 柏林
|
|
||||||
{ lat: 35.7, lng: 139.7 }, // 东京
|
|
||||||
];
|
];
|
||||||
|
|
||||||
var nodeGroup = new THREE.Group();
|
// 示例 arcs:从北京发出到其他节点
|
||||||
globeGroup.add(nodeGroup);
|
var arcs = nodes
|
||||||
|
.filter(function (n) {
|
||||||
var nodeMaterial = new THREE.MeshBasicMaterial({
|
return n.name !== "Beijing";
|
||||||
color: 0x5ad8ff,
|
})
|
||||||
});
|
.map(function (n) {
|
||||||
|
return {
|
||||||
var nodes = [];
|
startLat: 39.9,
|
||||||
var nodeRadius = radius * 0.03;
|
startLng: 116.4,
|
||||||
nodeConfigs.forEach(function (cfg, index) {
|
endLat: n.lat,
|
||||||
var pos = latLngToVector3(cfg.lat, cfg.lng, radius * 1.02);
|
endLng: n.lng,
|
||||||
var geom = new THREE.SphereGeometry(nodeRadius, 16, 16);
|
};
|
||||||
var mesh = new THREE.Mesh(geom, nodeMaterial);
|
|
||||||
mesh.position.copy(pos);
|
|
||||||
nodeGroup.add(mesh);
|
|
||||||
|
|
||||||
nodes.push({
|
|
||||||
mesh: mesh,
|
|
||||||
baseScale: 1,
|
|
||||||
phase: Math.random() * Math.PI * 2 + index,
|
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
|
||||||
// 通过 Points 实现星空点阵背景
|
// three-globe 实例
|
||||||
|
var globe = new ThreeGlobe({
|
||||||
|
waitForGlobeReady: true,
|
||||||
|
animateIn: true,
|
||||||
|
})
|
||||||
|
// 夜间地球 + 地形凹凸贴图(使用 three-globe 示例贴图)
|
||||||
|
.globeImageUrl(
|
||||||
|
"https://unpkg.com/three-globe/example/img/earth-night.jpg"
|
||||||
|
)
|
||||||
|
.bumpImageUrl(
|
||||||
|
"https://unpkg.com/three-globe/example/img/earth-topology.png"
|
||||||
|
)
|
||||||
|
.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);
|
||||||
|
|
||||||
|
// 星辰背景(简单加一点点空间感)
|
||||||
var starGeometry = new THREE.BufferGeometry();
|
var starGeometry = new THREE.BufferGeometry();
|
||||||
var starCount = 600;
|
var starCount = 600;
|
||||||
var starPositions = new Float32Array(starCount * 3);
|
var starPositions = new Float32Array(starCount * 3);
|
||||||
for (var i = 0; i < starCount; i++) {
|
for (var i = 0; i < starCount; i++) {
|
||||||
var sr = radius * 4 + Math.random() * radius * 2;
|
var sr = 10 + Math.random() * 5;
|
||||||
var theta = Math.random() * Math.PI * 2;
|
var theta = Math.random() * Math.PI * 2;
|
||||||
var phi = Math.acos(2 * Math.random() - 1);
|
var phi = Math.acos(2 * Math.random() - 1);
|
||||||
var sx = sr * Math.sin(phi) * Math.cos(theta);
|
var sx = sr * Math.sin(phi) * Math.cos(theta);
|
||||||
@@ -132,9 +128,9 @@
|
|||||||
);
|
);
|
||||||
var starMaterial = new THREE.PointsMaterial({
|
var starMaterial = new THREE.PointsMaterial({
|
||||||
color: 0x3f76ff,
|
color: 0x3f76ff,
|
||||||
size: 0.02,
|
size: 0.08,
|
||||||
transparent: true,
|
transparent: true,
|
||||||
opacity: 0.8,
|
opacity: 0.7,
|
||||||
});
|
});
|
||||||
var stars = new THREE.Points(starGeometry, starMaterial);
|
var stars = new THREE.Points(starGeometry, starMaterial);
|
||||||
scene.add(stars);
|
scene.add(stars);
|
||||||
@@ -152,7 +148,6 @@
|
|||||||
|
|
||||||
// 动画循环
|
// 动画循环
|
||||||
var lastTime = performance.now();
|
var lastTime = performance.now();
|
||||||
|
|
||||||
function animate() {
|
function animate() {
|
||||||
requestAnimationFrame(animate);
|
requestAnimationFrame(animate);
|
||||||
|
|
||||||
@@ -160,18 +155,10 @@
|
|||||||
var delta = (now - lastTime) / 1000;
|
var delta = (now - lastTime) / 1000;
|
||||||
lastTime = now;
|
lastTime = now;
|
||||||
|
|
||||||
// 地球缓慢自转
|
// 地球自转
|
||||||
globeGroup.rotation.y += delta * 0.25;
|
globe.rotation.y += delta * 0.25;
|
||||||
|
// 星空轻微旋转
|
||||||
// 星辰慢速旋转,增强空间感
|
stars.rotation.y -= delta * 0.03;
|
||||||
stars.rotation.y -= delta * 0.05;
|
|
||||||
|
|
||||||
// 节点呼吸效果
|
|
||||||
var t = now / 1000;
|
|
||||||
nodes.forEach(function (n) {
|
|
||||||
var s = n.baseScale * (1 + 0.6 * Math.sin(t * 2.5 + n.phase));
|
|
||||||
n.mesh.scale.set(s, s, s);
|
|
||||||
});
|
|
||||||
|
|
||||||
renderer.render(scene, camera);
|
renderer.render(scene, camera);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user