Skip to content

elhombre/projects-map

Repository files navigation

Projects Map

Interactive 3D map application for visualizing projects across Russia, built with Next.js and MapLibre GL JS.

Features

Core Mapping

  • Interactive 3D Map: Pan, zoom, tilt, and rotate with MapLibre GL JS
  • 3D Buildings: Extruded 3D buildings with customizable height and transparency
  • Interactive Camera Controls:
    • Ctrl + drag to adjust pitch (tilt)
    • Right-click + drag to rotate map (bearing)
    • 2D/3D toggle button with smooth animations
    • Auto-sync button state with interactive pitch changes
  • Dual Basemap: Toggle between light (OpenStreetMap) and dark (CartoDB) styles
  • Distance Measurement Tool:
    • Click to add measurement points
    • Real-time distance calculation using Haversine formula
    • Shows segment and total distances
    • Keyboard shortcuts (Backspace to undo, Esc to clear)
  • Interactive Minimap:
    • Overview map in bottom-left corner
    • Resizable (150-400px) with +/- buttons
    • Drag to navigate main map
    • Click to jump to location
    • Shows viewport rectangle and project markers
    • Theme synchronization (dark/light)
    • Size persists across all interactions

Data Visualization

  • 200+ Mock Projects: Realistic dataset across 33+ Russian cities
  • Smart Clustering: Automatically groups nearby projects at lower zoom levels
  • Site Outlines: Octagonal polygons (1 hectare) around projects
  • 3D Buildings: Rectangular footprints (2000 m²) extruded to 17m height
  • Adaptive Labels: Independent label control with contrast optimization
  • Status/Type Colors: Visual coding by project status and type

Search & Filtering

  • Advanced Filtering: Filter by status, type, dates, and viewport
  • Project Search: Search by name or ID with instant results
  • Dual-Mode Geocoding:
    • Local Mode: Offline search in 40+ Russian cities (MiniSearch)
    • External Mode: Global search via Photon API with typo-tolerance
  • Viewport Filter: Show only projects visible in current map view

UX Features

  • Virtual List: Efficiently displays large project lists with react-window
  • Permalink Support: Share map views via URL (center, zoom, filters, selection)
  • Floating Legend: Semi-transparent widget with configurable opacity
  • Language Switcher: Toggle between English and Russian (saved in cookie)
  • Responsive Layout: Sidebar with filters, legend, and project list
  • Interactive Selection: Synchronized highlighting between map and list

Tech Stack

  • Framework: Next.js 15 (App Router)
  • Language: TypeScript
  • Styling: Tailwind CSS
  • Mapping: MapLibre GL JS (with 3D support)
  • Search: MiniSearch (local geocoding)
  • Virtualization: react-window
  • I18n: next-intl
  • Code Quality: Biome (linting & formatting)

Getting Started

Prerequisites

  • Node.js 18+ and npm

Installation

# Install dependencies
npm install

# Prepare geocoder index (generates mock Russian cities data)
npm run prepare:geocoder

# Run development server
npm run dev

Open http://localhost:3000 (redirects to /map)

Build for Production

# Build the application
npm run build

# Start production server
npm start

Project Structure

projects-map/
├── app/
│   ├── actions.ts           # Server actions (language switching)
│   ├── contexts/            # React contexts (MapContext)
│   ├── hooks/               # Custom hooks (useMapProjects, useSearchMapProjects, etc.)
│   ├── map/                 # Main map page
│   └── layout.tsx           # Root layout with i18n
├── components/
│   ├── map/
│   │   └── hooks/
│   │       ├── useMinimap.ts      # Minimap control hook
│   │       ├── useMapInteraction.ts
│   │       ├── useMapLayers.ts
│   │       └── ...                # Other map hooks
│   ├── MapView.tsx          # Main map component with 3D support
│   ├── FloatingLegend.tsx   # Floating legend widget
│   ├── LocaleSwitcher.tsx   # Language switcher
│   ├── LayerToggles.tsx     # Layer visibility controls
│   ├── SearchBar.tsx        # Project/address search
│   ├── FiltersPanel.tsx     # Filtering controls
│   └── ...                  # Other UI components
├── lib/
│   ├── config.ts            # App configuration
│   ├── styleConfig.ts       # Map styling configuration
│   ├── types.ts             # TypeScript type definitions
│   ├── mockData.ts          # Mock project generator (200 projects)
│   ├── buildingGeometry.ts  # 3D geometry coordinate transformations
│   ├── buildingGenerators.ts # Complex building generation with collision detection
│   ├── measurementUtils.ts  # Distance measurement utilities
│   ├── localGeocoder.ts     # MiniSearch-based local geocoding
│   └── useSmartTranslations.ts  # Type-safe i18n hook
├── i18n/
│   ├── messages/            # Translation files (en.json, ru.json)
│   └── request.ts           # next-intl configuration
├── scripts/
│   └── prepare-geocoder.ts  # Script to generate geocoder index
└── public/
    └── data/
        └── geocoder-index.json  # Pre-generated geocoder data

Scripts

# Development
npm run dev              # Start dev server with Turbopack

# Build
npm run build            # Build for production
npm run start            # Start production server

# Data Preparation
npm run prepare:geocoder # Generate geocoder index

# Code Quality
npm run lint             # Check code with Biome
npm run lint:fix         # Auto-fix code issues
npm run format           # Format code

Configuration

Map Settings

Edit lib/config.ts to customize:

  • Map basemaps (light/dark tile sources)
  • Initial center and zoom
  • Total mock projects count
  • Geocoder settings (local/external mode)
  • 3D buildings settings (min zoom, height, footprint area)
  • UI settings (legend opacity)

Styling

Edit lib/styleConfig.ts to customize:

  • Status colors (planning, inProgress, completed, etc.)
  • Project type colors
  • Cluster colors
  • MapLibre style expressions

Features in Detail

3D Visualization

  • Complex 3D Buildings: Each project features a unique multi-building complex (3-6 buildings)
  • Randomized Architecture: Buildings are procedurally generated with type-specific characteristics:
    • Housing: 8-14 × 18-30 m, heights 15-30 m (residential blocks)
    • Commercial: 10-20 × 12-25 m, heights 10-25 m (retail/office)
    • Infrastructure: 12-24 × 12-26 m, heights 12-28 m (utilities)
    • Social: 12-24 × 12-24 m, heights 20-40 m (schools, hospitals)
    • Transport: 14-28 × 10-18 m, heights 8-18 m (stations, terminals)
  • Smart Constraints:
    • All buildings contained within octagonal site boundaries (1 hectare)
    • No overlapping buildings (2 meter minimum gaps)
    • All buildings axis-aligned (90-degree angles only)
    • Height variation (minimum 15% difference between buildings)
  • Deterministic Generation: Buildings generated from project ID seed for consistency
  • Instant Switching: Zero-delay transition between points and 3D buildings
  • Independent Controls: Separate toggles for points, buildings, and labels

Interactive Camera

  • Pitch Control: Tilt map from 0° (top-down) to 60° (perspective)
  • Bearing Control: Rotate map to any angle
  • Smooth Animations: 1-second transitions for programmatic changes
  • Auto-sync UI: Button state automatically reflects current view mode

Distance Measurement

  • Haversine Formula: Accurate distance calculation on sphere
  • Visual Feedback: Line and point markers for measurement path
  • Distance Format: Meters (< 1km) or kilometers (≥ 1km)
  • Keyboard Shortcuts:
    • Backspace: Remove last point
    • Esc: Clear all measurements

Interactive Minimap

  • Custom IControl: Native MapLibre control implementation
  • Dynamic Sizing: Resize between 150-400px using +/- buttons
  • Drag Navigation: Click and drag to move main map instantly
  • Click to Jump: Single click to fly to any location
  • Viewport Visualization: Semi-transparent blue rectangle shows current view
  • Project Markers: Red dots indicate all project locations
  • Theme Sync: Automatically switches between dark/light basemaps
  • Size Persistence: Maintains size across theme changes and map interactions
  • Smart Updates: Updates theme and data without recreating control

Map Interaction

  • Clustering: Automatically groups nearby projects at lower zoom levels
  • Hover Effects: Highlights projects using MapLibre feature-state
  • Click Actions: Opens project details in popup modal
  • Cluster Expansion: Click clusters to zoom to bounds

Filtering

  • Status: Planning, In Progress, Completed, On Hold, Cancelled
  • Type: Infrastructure, Housing, Commercial, Industrial, Social, Transport
  • Date Range: Filter by start and end dates
  • Viewport Only: Show only projects visible in current map view

Search

  • Projects: Search by name or ID with instant results
  • Addresses (Local Mode):
    • Offline search in 40+ major Russian cities
    • MiniSearch-powered fuzzy search
    • Supports transliteration (ru↔lat)
  • Addresses (External Mode):
    • Global search via Photon API
    • Search-as-you-type with debounce
    • Typo-tolerant

Data Management

  • Mock Data: 200 deterministic projects across Russia
  • 50% Polygons: Half of projects include boundary polygons
  • Realistic Distribution: Projects centered around 33 major Russian cities
  • Complex Building Geometry: Each project has unique 3D building complex (3-6 buildings) generated at creation time
  • Dynamic Site Outlines: 1 hectare octagonal boundaries generated on-the-fly

Internationalization

The application supports two languages with cookie-based persistence:

  • English (default)
  • Russian

Language detection order:

  1. NEXT_LOCALE cookie (set via language switcher)
  2. Browser's Accept-Language header
  3. Default: English

Switch languages using the EN/RU button in the page header. Selection is saved to cookie and persists across sessions.

Mock Data

The application includes 200 mock projects with:

  • Locations: Distributed across 33 major Russian cities
  • Statuses: Planning, In Progress, Completed, On Hold, Cancelled
  • Types: Infrastructure, Housing, Commercial, Industrial, Social, Transport
  • Budgets: Range from 1M to 500M RUB
  • Dates: Project timelines from 2020-2024

Note: Mock data is deterministic (seeded) for consistency. Change the SEED constant in lib/mockData.ts to generate a different dataset.

Performance Optimizations

  • Differential Updates: Only changed GeoJSON sources are updated
  • Feature State: Hover highlighting without GeoJSON rebuild
  • Virtual List: Efficient rendering of large project lists
  • Debounced Loading: 300ms debounce for viewport-based data loading
  • Request Cancellation: Outdated requests cancelled automatically
  • Zero-Delay 3D: Direct event handlers with refs for instant 3D switching

Development Notes

Critical Technical Patterns

  1. 3D Switching Without Delays: Use direct map event handlers with refs instead of useEffect to avoid React render delays
  2. Infinite Loop Prevention: Use programmatic change flags (refs) when syncing UI state with map events
  3. Dark Mode Colors: Use pure Tailwind classes for semi-transparent backgrounds, NOT inline styles with opacity
  4. Type-Safe i18n: useSmartTranslations provides autocomplete for all translation keys
  5. Cookie-based Locale: Language preference stored in cookie, NOT in URL routing
  6. Minimap Size Persistence: Use refs to store state across control recreation, separate useEffect for initial setup vs updates
  7. Drag & Drop Without Glitches: Block sync during drag, use jumpTo for instant movement, add global mouseup handler

Biome Linting

The project uses Biome for code quality. Key rules:

  • No non-null assertions (use local variables instead)
  • No array index keys (use compound keys)
  • Exhaustive dependencies (don't add unnecessary deps)
  • SVG accessibility (title elements required)

Run npm run lint to check and npm run lint:fix to auto-fix issues.

License

MIT

Credits

  • Map tiles: © OpenStreetMap contributors
  • Dark basemap: CartoDB Dark Matter
  • Geocoding data: GeoNames (cities1000, Russia)
  • Distance calculations: Haversine formula

About

Interactive 3D map application for visualizing projects, built with Next.js and MapLibre GL JS.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages