Skip to content

Commit

Permalink
Add particles layer and satellites example
Browse files Browse the repository at this point in the history
  • Loading branch information
vasturiano committed Jan 19, 2025
1 parent 0d16c54 commit 5fcea63
Show file tree
Hide file tree
Showing 9 changed files with 10,442 additions and 247 deletions.
17 changes: 16 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ React-Three-Fiber Globe Visualization
#### Check out the examples:
* [Basic](https://vasturiano.github.io/r3f-globe/example/basic/) ([source](https://github.com/vasturiano/r3f-globe/blob/master/example/basic/index.html))
* [Scene with multiple globe styles](https://vasturiano.github.io/r3f-globe/example/multiple-globes/) ([source](https://github.com/vasturiano/r3f-globe/blob/master/example/multiple-globes/index.html))
* [Satellites](https://vasturiano.github.io/r3f-globe/example/satellites/) ([source](https://github.com/vasturiano/r3f-globe/blob/master/example/satellites/index.html))

## Quick start

Expand Down Expand Up @@ -44,6 +45,7 @@ then
* [Hex Bin Layer](#hex-bin-layer)
* [Hexed Polygons Layer](#hexed-polygons-layer)
* [Tiles Layer](#tiles-layer)
* [Particles Layer](#particles-layer)
* [Rings Layer](#rings-layer)
* [Labels Layer](#labels-layer)
* [HTML Elements Layer](#html-elements-layer)
Expand Down Expand Up @@ -205,6 +207,20 @@ then
| <b>tileCurvatureResolution</b> | <i>number</i>, <i>string</i> or <i>func</i> | 5 | Tile object accessor function, attribute or a numeric constant for the resolution (in angular degrees) of the surface curvature. The finer the resolution, the more the tile geometry is fragmented into smaller faces to approximate the spheric surface, at the cost of performance. |
| <b>tilesTransitionDuration</b> | <i>number</i> | 1000 | Duration (ms) of the transition to animate tile changes involving geometry modifications. A value of `0` will move the tiles immediately to their final position. New tiles are animated by scaling them from the centroid outwards. |

### Particles Layer

| Prop | Type | Default | Description |
| --- | :--: | :--: | --- |
| <b>particlesData</b> | <i>array</i> | `[]` | List of particle sets to represent in the particles map layer. Each particle set is displayed as a group of [Points](https://threejs.org/docs/#api/en/objects/Points). Each point in the group is a geometry vertex and can be individually positioned anywhere relative to the globe. |
| <b>particlesList</b> | <i>string</i> or <i>func</i> | `d => d` | Particle set accessor function or attribute for the list of particles in the set. By default, the data structure is expected to be an array of arrays of individual particle objects. |
| <b>particleLat</b> | <i>number</i>, <i>string</i> or <i>func</i> | `lat` | Particle object accessor function, attribute or a numeric constant for the latitude coordinate. |
| <b>particleLng</b> | <i>number</i>, <i>string</i> or <i>func</i> | `lng` | Particle object accessor function, attribute or a numeric constant for the longitude coordinate. |
| <b>particleAltitude</b> | <i>number</i>, <i>string</i> or <i>func</i> | 0.01 | Particle object accessor function, attribute or a numeric constant for the altitude in terms of globe radius units. |
| <b>particlesSize</b> | <i>number</i>, <i>string</i> or <i>func</i> | 0.5 | Particle set accessor function, attribute or a numeric constant for the size of all the particles in the group. |
| <b>particlesSizeAttenuation</b> | <i>bool</i>, <i>string</i> or <i>func</i> | `true` | Particle set accessor function, attribute or a boolean constant for whether the size of each particle on the screen should be attenuated according to the distance to the camera. |
| <b>particlesColor</b> | <i>string</i> or <i>func</i> | `white` | Particle set accessor function or attribute for the color of all the particles in the group. This setting will be ignored if `particlesTexture` is defined. |
| <b>particlesTexture</b> | <i>string</i> or <i>func</i> | - | Particle set accessor function or attribute for the [Texture](https://threejs.org/docs/#api/en/textures/Texture) to be applied to all the particles in the group. |

### Rings Layer

| Prop | Type | Default | Description |
Expand Down Expand Up @@ -279,7 +295,6 @@ then
| <b>onClick</b> | <i>func</i> | *-* | Callback function for globe element clicks. The type of layer, the associated data object (if exists) and the event object are included as arguments: `onClick(layer, elementData, event)`. |
| <b>onHover</b> | <i>func</i> | *-* | Callback function for globe element mouse over events. The type of layer (or `undefined` if it's hovering off the globe) and the associated data object (if exists) are included as arguments: `onHover(layer, elementData)`. |


### Render Control

| Prop | Type | Default | Description |
Expand Down
115 changes: 115 additions & 0 deletions example/satellites/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
<head>
<style> body { margin: 0; } </style>

<script type="importmap">{ "imports": {
"three": "https://esm.sh/three",
"three/": "https://esm.sh/three/",
"three/addons/": "https://esm.sh/three/examples/jsm/",
"react": "https://esm.sh/react@18",
"react/": "https://esm.sh/react@18/",
"react-dom": "https://esm.sh/react-dom@18",
"react-dom/": "https://esm.sh/react-dom@18/",
"@react-three/fiber": "https://esm.sh/@react-three/fiber?external=react,react-dom,three",
"@react-three/drei": "https://esm.sh/@react-three/drei?external=@react-three/fiber,react,react-dom,three"
}}</script>

<!-- <script type="module">import * as THREE from 'three'; import * as React from 'react'; window.THREE = THREE; window.React = React;</script>-->
<!-- <script src="../../dist/r3f-globe.js" defer></script>-->
</head>

<body>
<div id="r3fScene"></div>

<script src="//unpkg.com/@babel/standalone"></script>
<script type="text/jsx" data-type="module">
import R3fGlobe from 'https://esm.sh/r3f-globe?external=three,react';
import React, { useMemo, useCallback, useEffect, useState } from "react";
import ReactDOM from "react-dom";
import { Canvas } from '@react-three/fiber';
import { OrbitControls } from '@react-three/drei';
import * as satellite from 'https://esm.sh/satellite.js';

const EARTH_RADIUS_KM = 6371; // km
const TIME_STEP = 3 * 1000; // per frame

const GlobeViz = () => {
const [satData, setSatData] = 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);

setSatData(satData);
});
}, []);

const particlesData = 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;
}).filter(d => !isNaN(d.lat) && !isNaN(d.lng) && !isNaN(d.alt))
];
}, [satData, time]);

return <R3fGlobe
globeImageUrl="//unpkg.com/three-globe/example/img/earth-blue-marble.jpg"
particlesData={particlesData}
particleLabel="name"
particleLat="lat"
particleLng="lng"
particleAltitude="alt"
particlesColor={useCallback(() => 'palegreen', [])}
onHover={console.log}
/>;
}

const Scene = () => {
return <div style={{ height: window.innerHeight }}>
<Canvas
camera={useMemo(() => ({position: [0, 0, 250]}), [])}
raycaster={useMemo(() => ({ params: { Points: { threshold: 0.2 } } }), [])}
>
<OrbitControls minDistance={101} maxDistance={1e4} dampingFactor={0.1} zoomSpeed={0.3} rotateSpeed={0.3} />
<color attach="background" args={[0, 0, 0]}/>
<ambientLight intensity={Math.PI}/>
<directionalLight intensity={0.6 * Math.PI}/>
<GlobeViz />
</Canvas>
</div>;
};

ReactDOM.createRoot(document.getElementById('r3fScene'))
.render(<Scene />);
</script>
</body>
Binary file added example/satellites/preview.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 5fcea63

Please sign in to comment.