diff --git a/index.html b/index.html index 5cc32bf..7f69caf 100644 --- a/index.html +++ b/index.html @@ -5,11 +5,10 @@ - + - + + diff --git a/js/globe.js b/js/globe.js index 3ef3989..4d58295 100644 --- a/js/globe.js +++ b/js/globe.js @@ -1,5 +1,5 @@ -// 3D 地球效果(首页 banner 右侧) -// 依赖:Three.js(全局 THREE 对象),脚本路径建议:/web/BlackFruit-web/vender/three/three.min.js +// 3D 地球效果(首页 banner 右侧)基于 three-globe +// 依赖:全局 THREE 和 ThreeGlobe(在 index.html 中通过 CDN 引入) (function () { function initGlobe() { @@ -9,114 +9,110 @@ return; } if (typeof THREE === "undefined") { - // Three.js 未加载时直接跳过,不影响其它功能 - console.warn("[Globe] THREE is undefined, please ensure three.min.js is loaded"); + 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); - 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); 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); // 透明背景,融入页面 + renderer.setClearColor(0x000000, 0); // 透明背景 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); dirLight.position.set(5, 3, 5); scene.add(dirLight); - var globeGroup = new THREE.Group(); - scene.add(globeGroup); - - // 地球球体 - var earthGeometry = new THREE.SphereGeometry(radius, 64, 64); - - // 纯色高光材质,若后续有贴图可替换为 MeshPhongMaterial + map - var earthMaterial = new THREE.MeshPhongMaterial({ - color: 0x163a5f, - 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 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 }, ]; - var nodeGroup = new THREE.Group(); - globeGroup.add(nodeGroup); - - var nodeMaterial = new THREE.MeshBasicMaterial({ - color: 0x5ad8ff, - }); - - var nodes = []; - var nodeRadius = radius * 0.03; - nodeConfigs.forEach(function (cfg, index) { - var pos = latLngToVector3(cfg.lat, cfg.lng, radius * 1.02); - 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, + // 示例 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, + }; }); - }); - // 通过 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 starCount = 600; var starPositions = new Float32Array(starCount * 3); 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 phi = Math.acos(2 * Math.random() - 1); var sx = sr * Math.sin(phi) * Math.cos(theta); @@ -132,9 +128,9 @@ ); var starMaterial = new THREE.PointsMaterial({ color: 0x3f76ff, - size: 0.02, + size: 0.08, transparent: true, - opacity: 0.8, + opacity: 0.7, }); var stars = new THREE.Points(starGeometry, starMaterial); scene.add(stars); @@ -152,7 +148,6 @@ // 动画循环 var lastTime = performance.now(); - function animate() { requestAnimationFrame(animate); @@ -160,18 +155,10 @@ var delta = (now - lastTime) / 1000; lastTime = now; - // 地球缓慢自转 - globeGroup.rotation.y += delta * 0.25; - - // 星辰慢速旋转,增强空间感 - 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); - }); + // 地球自转 + globe.rotation.y += delta * 0.25; + // 星空轻微旋转 + stars.rotation.y -= delta * 0.03; renderer.render(scene, camera); }