想要实现的效果
示例地址
实现过程
踩坑
- 示例是通过script引入的依赖,但本人需要在react项目中实现该效果。
- 按照react-globe.gl官方方法引入总是报错
Can't import the named export 'AmbientLight' from non EcmaScript module (only default export is available)
。 - 原因是通过
import Globe from 'react-globe.gl';
引入的是.mjs文件,react-globe.gl.mjs
。 - 尝试各种方法都失败,最终通过改为引入.js文件
import Globe from "../../node_modules/react-globe.gl/dist/react-globe.gl.min";
成功。
安装依赖
package.json版本
"react-globe.gl": "^2.27.0",
"satellite.js": "^5.0.0",
"three": "^0.157.0",
"three-globe": "^2.30.0",
"web-vitals": "^2.1.4"
引入页面
import React, { Component, useState, useEffect, useRef, useMemo } from "react";
import Globe from "../../node_modules/react-globe.gl/dist/react-globe.gl.min";
import * as THREE from "three";
import * as satellite from "satellite.js";
function World() {
const w = window.screen.width * 0.5;
const h = (window.screen.height - 80) * 0.7;
const EARTH_RADIUS_KM = 6371;
const SAT_SIZE = 80;
const TIME_STEP = 3 * 1000;
const globeEl = useRef();
const [satData, setSatData] = useState();
const [globeRadius, setGlobeRadius] = useState();
const [time, setTime] = useState(new Date());
useEffect(() => {
(function frameTicker() {
requestAnimationFrame(frameTicker);
setTime((time) => new Date(+time + TIME_STEP));
})();
}, []);
useEffect(() => {
fetch("//unpkg.com/globe.gl/example/datasets/space-track-leo.txt")
.then((r) => r.text())
.then((rawData) => {
const tleData = rawData
.replace(/\r/g, "")
.split(/\n(?=[^12])/)
.filter((d) => d)
.map((tle) => tle.split("\n"));
const satData = tleData
.map(([name, ...tle]) => ({
satrec: satellite.twoline2satrec(...tle),
name: name.trim().replace(/^0 /, ""),
}))
.filter((d) => !!satellite.propagate(d.satrec, new Date()).position)
.slice(0, 1500);
setSatData(satData);
});
}, []);
const objectsData = useMemo(() => {
if (!satData) return [];
const gmst = satellite.gstime(time);
return satData.map((d) => {
const eci = satellite.propagate(d.satrec, time);
if (eci.position) {
const gdPos = satellite.eciToGeodetic(eci.position, gmst);
const lat = satellite.radiansToDegrees(gdPos.latitude);
const lng = satellite.radiansToDegrees(gdPos.longitude);
const alt = gdPos.height / EARTH_RADIUS_KM;
return { ...d, lat, lng, alt };
}
return d;
});
}, [satData, time]);
const satObject = useMemo(() => {
if (!globeRadius) return undefined;
const satGeometry = new THREE.OctahedronGeometry(
(SAT_SIZE * globeRadius) / EARTH_RADIUS_KM / 2,
0
);
const satMaterial = new THREE.MeshLambertMaterial({
color: "palegreen",
transparent: true,
opacity: 0.7,
});
return new THREE.Mesh(satGeometry, satMaterial);
}, [globeRadius]);
useEffect(() => {
setGlobeRadius(globeEl.current.getGlobeRadius());
globeEl.current.pointOfView({ altitude: 3.5 });
}, []);
return (
<div id="globeViz" className="map_bg">
<Globe
width={w}
height={h}
backgroundColor="rgba(0,0,0,0)"
ref={globeEl}
globeImageUrl="//unpkg.com/three-globe/example/img/earth-blue-marble.jpg"
objectsData={objectsData}
objectLabel="name"
objectLat="lat"
objectLng="lng"
objectAltitude="alt"
objectFacesSurface={false}
objectThreeObject={satObject}
/>
</div>
);
}
class App extends Component {
...
render() {
return (
...
<World />
...
)
}
}
export default App;
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117