Working with 3D globe in frontend
Tags: html, css, frontend, javascript
Published: 2024-01-16 10:20:10

## Under the Hood
Yesterday when I wrote this blog, I stumbled upon `react-globe.gl` library for maps in the front end.

This simple library provides a 3D globe using Three.js under the hood.

If you are new to three.js, a library that works on canva HTML elements to provide 3D object rendering in the front end.

Once I found this library I couldn’t wait to create something stunning using `react-glove.gl`.

## Project Idea
This makes sense, what does a globe show as the data?

The first idea that came to our mind was locating/marking the cities or countries.

So I collect the country's data along with latitude and longitude, we need latitude and longitude to mark the location on the map.

The Google Maps used by react-globe are rendered on an object known as a sphere using `sphereGeometry` mesh.

If you are new to these mesh and three.js objects, you can google out or watch the below YouTube playlist for a better understanding.
{% youtube https://youtu.be/y5CAuAZ7kKM?list=PLIRTsuB0iPJvxaYyg8MOrjffPPcYnccL0 %}

Go ahead and start your journey with 3d objects in front, this is so cool and fun 😄

Moving ahead, below is the sample list of props for markers on the google map.

```
const countries = [
 {
  latitude: "",
  longitude: "",
  country: "",
  name: ""
 }
]

```
## Rendering Globe
Once the data is collected, we will first render the globe or 3D map.

```
<Globe
    ref={globeEl}
    height={800}
    backgroundColor="rgba(0,0,0,0)"
    labelsData={COUNTRIES_DATA.map((item) => {
     return {
      lat: item.latitude,
      lng: item.longitude,
      name: item.name,
      country: item.country,
     };
    })}
    onLabelClick={({ lat, lng, name, country }) => {
     setActiveCountry({
      label: name,
      latitude: lat,
      longitude: lng,
      country,
     });
    }}
    atmosphereColor={colors.gray[800]}
    showAtmosphere={false}
    labelText={"name"}
    labelSize={1}
    labelColor={() => colors[labelTheme][200]}
    labelDotRadius={0.2}
    labelAltitude={0.05}
    arcColor={colors.orange[600]}
    hexPolygonsData={hex.features}
    hexPolygonResolution={3}
    hexPolygonMargin={0.62}
    hexPolygonColor={useCallback(() => colors.gray[800], [])}
   />
```
You can see so many props in one go, do not worry as I’ll explain them one by one.

- **width**: width of the globe
- **height**: height of the globe
- **backgroundColour**: The background colour of the globe
- **atmosphereColor**: the colour of the glove atmosphere
- **showAtmosphere**: boolean to show atmosphere or not
- **onLabelClick**: Event handler when the label is clicked
- **label styling**: such as label, text size, colour, dot radius and altitude
- **polygon styling**: CSS for styling polygons used to cover the continents
- **arc styling**: CSS for styling arc on the globe
- **path styling**: CSS for styling and adding paths on the globe
- **ring styling**: CSS for adding and styling rings on the globe

[npm module](https://www.npmjs.com/package/react-globe.gl?source=post_page-----84753398dff5--------------------------------)

React globe renders on canva element and it requires the browser window object, basically rendering on the client side, so importing the above globe component in next.js or server-side won’t work. But don’t worry next.js has a solution for side effects and that is using dynamic importing.

Importing the components without ssr or once the client-side rendering is over, stop the server-side rendering of the corresponding component imported dynamically using the next dynamic module.

```
import dynamic from "next/dynamic";

const Globe = dynamic(import("./customGlobe"), { ssr:false });
Once this is done, our Globe is ready to render in the front end.

```
Cool so far it looks good, you can extend the styling part via the props by using Tailwind CSS colours.

I prefer Tailwind every time and the main reason it’s because of its compatibility and it is accepted as the universal styling library.

## Select & Mark Countries
We have the country data along with latitude and longitude.

What extra we can do is add a select component mentioning all the countries in the select dropdown.

As soon as the user selects the country, we will rotate to the globe using a globe reference pointer to the active country position.

```
const [active, setActive] = useState();

<Select data={countries.map(item) => ({ value: item.country, lable: itme.country })} 
  onChange={val => setActive(countries.filter(item => item === val)[0])}
/>
```
In the custom globe components, we want to rotate the globe to the active country position and this can be done by passing the active country location object as the props and rotating the globe to the active country position.

 

```
const globeEl = useRef();

 useEffect(() => {
  const MAP_CENTER = { lat: 0, lng: 0, altitude: 1.5 };
  globeEl.current.pointOfView(MAP_CENTER, 0);
 }, [globeEl]);

 useEffect(() => {
  const countryLocation = {
   lat: activeCountry.latitude,
   lng: activeCountry.longitude,
   altitude: 1.5,
  };
  globeEl.current.pointOfView(countryLocation, 1000);
 }, [activeCountry]);
```
Easy, within 10 lines of code our 3D globe is ready to rotate to the centre and even have markers to all the countries we have provided as the data.

A total of 200 lines of code are added along

- Tailwind CSS styling
- Methods to rotate the globe to the active country
- Select the country from the dropdown
- Dropdown styling
- Dynamic importing of the custom globe
- Adding country's data along with latitude and longitude
and our 3D world map is ready!!

Feel free to subscribe to my newsletter, I share such interesting stories over email also along with news on Programming, Jobs, and AI that will be very helpful for you.

[Subscribe to my FREE Newsletter](ihatereading.in/subscribe)

Until next time, have a good day
Shrey