• 【React】【react-globe.gl】3D Objects效果


    想要实现的效果

    示例地址

    在这里插入图片描述

    实现过程

    踩坑

    1. 示例是通过script引入的依赖,但本人需要在react项目中实现该效果。
    2. 按照react-globe.gl官方方法引入总是报错 Can't import the named export 'AmbientLight' from non EcmaScript module (only default export is available)
    3. 原因是通过import Globe from 'react-globe.gl';引入的是.mjs文件,react-globe.gl.mjs
    4. 尝试各种方法都失败,最终通过改为引入.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"
    
    • 1
    • 2
    • 3
    • 4
    • 5

    引入页面

    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; // km
      const SAT_SIZE = 80; // km
      const TIME_STEP = 3 * 1000; // per frame
    
      const globeEl = useRef();
      const [satData, setSatData] = useState();
      const [globeRadius, setGlobeRadius] = useState();
      const [time, setTime] = useState(new Date());
    
      useEffect(() => {
        // time ticker
        (function frameTicker() {
          requestAnimationFrame(frameTicker);
          setTime((time) => new Date(+time + TIME_STEP));
        })();
      }, []);
    
      useEffect(() => {
        // load satellite data
        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 /, ""),
              }))
              // exclude those that can't be propagated
              .filter((d) => !!satellite.propagate(d.satrec, new Date()).position)
              .slice(0, 1500);
    
            setSatData(satData);
          });
      }, []);
    
      const objectsData = useMemo(() => {
        if (!satData) return [];
    
        // Update satellite positions
        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
  • 相关阅读:
    第15届全国大学生知识竞赛场景实操 2022ciscn初赛 部分writeup
    MTK平台Metadata的加载(1)——Metadata介绍
    燕京啤酒何以至此?
    window11 设置 ubuntu2204 至最佳体验(安装/右键菜单/root用户/docker)
    k8s 自动扩缩容HPA原理及adapter配置详解
    【图像分类】Vision Transformer理论解读+实践测试
    M拷贝表行数据
    数据结构 - 链表详解(二)—— 带头双向循环链表
    CF1381D The Majestic Brown Tree Snake
    Eotalk Vol.04 : 如何安全开放 API 数据?
  • 原文地址:https://blog.csdn.net/lorogy/article/details/134205717