diff --git a/js/globe.js b/js/globe.js index ece7b41..9cc2aa1 100644 --- a/js/globe.js +++ b/js/globe.js @@ -65,6 +65,31 @@ { name: "San Francisco", lat: 37.8, lng: -122.4 } ]; + // 基于节点构造“飞行轨迹”连接数据(startLat/startLng -> endLat/endLng) + function buildArcsFromNodes(list) { + var arcs = []; + if (!Array.isArray(list) || list.length < 2) { + return arcs; + } + // 简单策略:每个节点连接到后面第 step 个节点,形成环状主干网络 + var step = Math.max(1, Math.floor(list.length / 3)); + list.forEach(function (src, idx) { + var dst = list[(idx + step) % list.length]; + if (!dst || (dst.lat === src.lat && dst.lng === src.lng)) { + return; + } + arcs.push({ + startLat: src.lat, + startLng: src.lng, + endLat: dst.lat, + endLng: dst.lng, + // 统一使用偏青色的轨迹,贴合云服务器 / CDN 的科技感 + color: "#38BDF8", + }); + }); + return arcs; + } + // three-globe 实例:使用空心陆地多边形(hollow globe 风格) var globe = new ThreeGlobe({ waitForGlobeReady: true, @@ -79,8 +104,40 @@ scene.add(globe); - // 存放自定义“闪烁节点” mesh,便于在动画循环中更新 - var nodeGlows = []; + // 构造并应用“节点连接 + 飞行轨迹”效果 + var arcs = buildArcsFromNodes(nodes); + if (typeof globe.arcsData === "function" && arcs.length) { + globe.arcsData(arcs); + if (typeof globe.arcColor === "function") { + globe.arcColor(function (d) { + return d.color || "#38BDF8"; + }); + } + if (typeof globe.arcAltitude === "function") { + globe.arcAltitude(0.2); + } + if (typeof globe.arcStroke === "function") { + globe.arcStroke(0.7); + } + // 使用虚线 + 动画时间制造“飞行”感 + if (typeof globe.arcDashLength === "function") { + globe.arcDashLength(0.35); + } + if (typeof globe.arcDashGap === "function") { + globe.arcDashGap(0.8); + } + if (typeof globe.arcDashInitialGap === "function") { + globe.arcDashInitialGap(function () { + return Math.random(); + }); + } + if (typeof globe.arcDashAnimateTime === "function") { + globe.arcDashAnimateTime(function () { + // 4~7 秒一圈,避免所有轨迹节奏完全一致 + return 4000 + Math.random() * 3000; + }); + } + } // 告诉 three-globe 当前渲染器的实际尺寸,避免默认按全窗口大小计算导致比例失真 if (typeof globe.rendererSize === "function") { @@ -95,6 +152,15 @@ var dist = r * 3.2; camera.position.set(0, 0.2, dist); camera.lookAt(0, 0, 0); + + // 在节点位置放置小型静态“节点点”,替代原来的绿色闪烁效果 + var nodeGeom = new THREE.SphereGeometry(r * 0.02, 16, 16); + var nodeMat = new THREE.MeshBasicMaterial({ + color: "#38BDF8", + transparent: true, + opacity: 0.9, + }); + // 通知 three-globe 当前视角,用于部分图层的内部计算 if (typeof globe.setPointOfView === "function") { globe.setPointOfView(camera); @@ -102,7 +168,7 @@ // 使用 globe 的工具方法,将经纬度转换为球面上的 3D 坐标 var hasGetCoords = typeof globe.getCoords === "function"; - nodes.forEach(function (n, idx) { + nodes.forEach(function (n) { var pos; if (hasGetCoords) { // altitude 略高于球面,避免被多边形遮挡 @@ -119,22 +185,9 @@ }; } - var glowGeom = new THREE.SphereGeometry(r * 0.03, 16, 16); - var glowMat = new THREE.MeshBasicMaterial({ - // 绿色闪烁点,和蓝色陆地形成冷暖对比 - color: "#22C55E", - transparent: true, - opacity: 0.7 - }); - var glowMesh = new THREE.Mesh(glowGeom, glowMat); - glowMesh.position.set(pos.x, pos.y, pos.z); - globe.add(glowMesh); - - nodeGlows.push({ - mesh: glowMesh, - // 随机相位,让节点闪烁不同步 - phase: Math.random() * Math.PI * 2 + idx - }); + var nodeMesh = new THREE.Mesh(nodeGeom, nodeMat); + nodeMesh.position.set(pos.x, pos.y, pos.z); + globe.add(nodeMesh); }); }); } @@ -219,14 +272,6 @@ // 地球自转 globe.rotation.y += delta * 0.25; - // 节点“呼吸式”闪烁 - var t = now / 1000; - nodeGlows.forEach(function (n) { - var s = 0.7 + 0.3 * Math.sin(t * 3 + n.phase); - n.mesh.scale.set(s, s, s); - n.mesh.material.opacity = 0.4 + 0.4 * Math.sin(t * 3 + n.phase); - }); - renderer.render(scene, camera); }