Skip to main content
The Globe component renders an interactive 3D map that visualizes visited countries and provides navigation controls. It uses Mapbox GL and integrates with the application’s state management to highlight selected countries.

Overview

The Globe component:
  • Displays an interactive Mapbox GL map
  • Highlights visited countries with orange overlay
  • Supports dark/light theme based on system preferences
  • Provides map navigation controls
  • Responds to focus changes for zooming to specific countries
  • Uses forwardRef for imperative map operations

Type Definitions

export interface MapForwardedRef {
  isSourceLoaded: ForwardedRefFunction<MapRef['isSourceLoaded']>;
  querySourceFeatures: ForwardedRefFunction<MapRef['querySourceFeatures']>;
}

Component Signature

export const Globe = memo(
  forwardRef<MapForwardedRef>((_, ref) => {
    // Component implementation
  })
);
The component accepts no props but exposes map query methods through a ref.

Features

Theme Support

The globe automatically adapts to the user’s color scheme preference:
const prefersDark = useMatchMedia('(prefers-color-scheme: dark)');

<Map
  mapStyle={prefersDark ? darkThemeUrl : lightThemeUrl}
  // other props
/>
  • Light theme: mapbox://styles/mapbox/light-v11
  • Dark theme: mapbox://styles/mapbox/dark-v11

Country Highlighting

Visited countries are highlighted with an orange overlay:
const beenPaint: FillLayerSpecification['paint'] = {
  'fill-color': '#fd7e14',
  'fill-opacity': 0.6,
};

Building Extrusion

At high zoom levels (15+), buildings in visited countries are extruded:
<Layer
  id={MapboxLayerKeys.Buildings}
  type="fill-extrusion"
  source="composite"
  source-layer="building"
  minzoom={15}
  filter={buildingsFilter}
  paint={buildingsPaint}
/>

Auto-Focus

The map automatically focuses on countries when the focusAtom changes:
useEffect(() => {
  if (!focus?.bounds) {
    return;
  }
  const { current: map } = internalRef;
  map?.fitBounds(focus.bounds);
}, [focus]);

Map Configuration

minZoom
number
default:"1.8"
Minimum zoom level to prevent excessive zoom-out
mapboxAccessToken
string
Mapbox API token from environment variable VITE_API_KEY_MAPBOX
antialias
boolean
default:"true"
Enable antialiasing for smoother rendering
attributionControl
boolean
default:"false"
Hide default attribution control
logoPosition
string
default:"bottom-right"
Position of Mapbox logo

Usage Example

import { Globe } from './components/globe';
import type { MapForwardedRef } from './components/globe';
import { useRef } from 'react';

function App() {
  const globeRef = useRef<MapForwardedRef>(null);

  const checkSource = () => {
    const loaded = globeRef.current?.isSourceLoaded('countries');
    console.log('Source loaded:', loaded);
  };

  return (
    <div>
      <Globe ref={globeRef} />
      <button onClick={checkSource}>Check Source</button>
    </div>
  );
}

Layers

The globe uses multiple Mapbox layers:

1. Countries Layer

<Source
  id={MapboxSourceKeys.Countries}
  type="vector"
  url="mapbox://mapbox.country-boundaries-v1"
/>

<Layer
  id={MapboxLayerKeys.Been}
  type="fill"
  source={MapboxSourceKeys.Countries}
  source-layer="country_boundaries"
  beforeId="national-park"
  filter={beenFilter}
  paint={beenPaint}
/>

2. Buildings Layer

<Layer
  id={MapboxLayerKeys.Buildings}
  type="fill-extrusion"
  source="composite"
  source-layer="building"
  minzoom={15}
  filter={buildingsFilter}
  paint={buildingsPaint}
/>

State Integration

The Globe component integrates with Jotai atoms:
  • selectedCountriesAtom - Array of ISO 3166 country codes to highlight
  • focusAtom - Current focus bounds for auto-zooming
<NavigationControl showCompass={false} />
Provides zoom in/out buttons without the compass control.

Dependencies

  • mapbox-gl - Mapbox GL library
  • react-map-gl - React wrapper for Mapbox GL
  • jotai - State management
  • react - Core React functionality

Environment Variables

VITE_API_KEY_MAPBOX
string
required
Mapbox API access token for map tiles
MODE
string
Application mode (set to ‘test’ for test mode)

Source Code

Location: src/components/globe.tsx

Build docs developers (and LLMs) love