首页 > 解决方案 > 在 React 中旋转 Globe.gl 地球仪(使用 react-three-fiber 或其他方式)

问题描述

我正在遵循 Globe.gl 中的这个示例来实现以下输出。我想使用 react-three-fiber 旋转这个地球,即使用这个例子中的方法。

这是我的Globe.js

import React from "react";
import * as d3 from "d3-dsv";
import indexBy from "index-array-by";
import Globe from "react-globe.gl";

import earth from "../../public/images/earth-dark.png";
import background from "../../public/images/globeBackground.png";

function GlobeHome() {
  const { useState, useEffect, useRef } = React;
  const globeEl = useRef();
  const [airports, setAirports] = useState([]);
  const [routes, setRoutes] = useState([]);
  
  const COUNTRY = "United States";
  const OPACITY = 0.125;
  const airportParse = ([
    airportId,
    name,
    city,
    country,
    iata,
    icao,
    lat,
    lng,
    alt,
    timezone,
    dst,
    tz,
    type,
    source,
  ]) => ({
    airportId,
    name,
    city,
    country,
    iata,
    icao,
    lat,
    lng,
    alt,
    timezone,
    dst,
    tz,
    type,
    source,
  });
  const routeParse = ([
    airline,
    airlineId,
    srcIata,
    srcAirportId,
    dstIata,
    dstAirportId,
    codeshare,
    stops,
    equipment,
  ]) => ({
    airline,
    airlineId,
    srcIata,
    srcAirportId,
    dstIata,
    dstAirportId,
    codeshare,
    stops,
    equipment,
  });

  useEffect(() => {
    Promise.all([
      fetch(
        "https://raw.githubusercontent.com/jpatokal/openflights/master/data/airports.dat"
      )
        .then((res) => res.text())
        .then((d) => d3.csvParseRows(d, airportParse)),
      fetch(
        "https://raw.githubusercontent.com/jpatokal/openflights/master/data/routes.dat"
      )
        .then((res) => res.text())
        .then((d) => d3.csvParseRows(d, routeParse)),
    ]).then(([airports, routes]) => {
      const byIata = indexBy(airports, "iata", false);

      const filteredRoutes = routes
        .filter(
          (d) =>
            byIata.hasOwnProperty(d.srcIata) && byIata.hasOwnProperty(d.dstIata)
        )
        .filter((d) => d.stops === "0")
        .map((d) =>
          Object.assign(d, {
            srcAirport: byIata[d.srcIata],
            dstAirport: byIata[d.dstIata],
          })
        )
        .filter(
          (d) =>
            d.srcAirport.country === COUNTRY && d.dstAirport.country !== COUNTRY
        );

      setAirports(airports);
      setRoutes(filteredRoutes);
    });
  }, []);

  useEffect(() => {
    globeEl.current.pointOfView({ lat: 42, lng: -71, altitude: 2 });
  }, []);

  return (
    <Globe
      ref={globeEl}
      width={1000}
      height={1000}
      showGlobe={true}
      globeImageUrl={earth}
      backgroundImageUrl={background}
      arcsData={routes}
      arcStartLat={(d) => +d.srcAirport.lat}
      arcStartLng={(d) => +d.srcAirport.lng}
      arcEndLat={(d) => +d.dstAirport.lat}
      arcEndLng={(d) => +d.dstAirport.lng}
      arcDashLength={0.25}
      arcDashGap={1}
      arcDashInitialGap={() => Math.random()}
      arcDashAnimateTime={4000}
      arcColor={(d) => [
        `rgba(48, 64, 77, ${OPACITY})`,
        `rgba(191, 204, 214, ${OPACITY})`,
      ]}
      arcsTransitionDuration={0}
      pointsData={airports}
      pointColor={() => "white"}
      pointAltitude={0}
      pointRadius={0.03}
      pointsMerge={true}
    />
  );
}

export default GlobeHome;

然后我将其导入Boxes.js

import React, { useRef, useState } from "react";
import { Canvas, useFrame } from "react-three-fiber";
import Globe from './Globe'

function Box(props) {
  // This reference will give us direct access to the mesh
  const mesh = useRef();
  // Set up state for the hovered and active state
  const [hovered, setHover] = useState(false);
  const [active, setActive] = useState(false);
  // Rotate mesh every frame, this is outside of React without overhead
  useFrame(() => {
    mesh.current.rotation.x = mesh.current.rotation.y += 0.01;
  });
  return (
    <mesh
      {...props}
      ref={mesh}
    >
      <Globe />
    </mesh>
  );
}

export default function App() {
  return (
    <Canvas>
      <ambientLight intensity={0.5} />
      <spotLight position={[10, 10, 10]} angle={0.15} penumbra={1} />
      <pointLight position={[-10, -10, -10]} />
      <Box />
    </Canvas>
  );
}

使用这种方法会给我以下错误:

Uncaught "Div" is not part of the THREE namespace! Did you forget to extend it?

关于调试的想法?有没有更好的方法来旋转这个 Globe.gl 地球仪?

标签: reactjsthree.js3dreact-three-fiberwebgl-globe

解决方案


我也遇到了这个问题。问题是您将 Globe 组件作为 Box 组件的属性传递,该组件是一个网格。然后 Box 组件位于 Canvas 组件中。该库要求您将 Globe 组件作为标准 React 组件放置在 Canvas 组件之外。通过将 App 组件更改为仅返回 <Globe ...> 及其属性,我能够解决我的逻辑中的问题。


推荐阅读