# Project Hints - dees-catalog-geo

## Overview
Geospatial web components library using MapLibre GL JS for map rendering and terra-draw for drawing capabilities.

## Key Dependencies
- **maplibre-gl** (v5.x): WebGL-based vector map library
- **terra-draw** (v1.24.0): Modern drawing library with support for multiple map libraries
- **terra-draw-maplibre-gl-adapter** (v1.x): Adapter connecting terra-draw with MapLibre

## Component: dees-geo-map

### Properties
| Property | Type | Default | Description |
|----------|------|---------|-------------|
| `center` | `[number, number]` | `[0, 0]` | Map center as [lng, lat] |
| `zoom` | `number` | `2` | Initial zoom level |
| `mapStyle` | `string` | `'osm'` | Map style ('osm' or custom URL) |
| `activeTool` | `TDrawTool` | `'static'` | Active drawing tool |
| `geoJson` | `GeoJSON.FeatureCollection` | `{...}` | Initial features |
| `showToolbar` | `boolean` | `true` | Show/hide drawing toolbar |
| `projection` | `'mercator' \| 'globe'` | `'mercator'` | Map projection type |
| `showSearch` | `boolean` | `false` | Show address search input |
| `showNavigation` | `boolean` | `false` | Show A-to-B navigation panel |
| `navigationMode` | `'driving' \| 'walking' \| 'cycling'` | `'driving'` | Transport mode for routing |
| `showTraffic` | `boolean` | `false` | Enable traffic layer visualization |
| `trafficApiKey` | `string` | `''` | HERE API key for traffic data |
| `trafficProvider` | `ITrafficProvider` | `null` | Custom traffic data provider |

### Drawing Tools (TDrawTool)
- `point` - Draw points
- `linestring` - Draw lines
- `polygon` - Draw polygons
- `rectangle` - Draw rectangles
- `circle` - Draw circles
- `freehand` - Freehand drawing
- `select` - Select and edit features
- `static` - Pan/zoom only (no drawing)

### Events
- `map-ready` - Fired when map is initialized
- `map-move` - Fired on pan/zoom with center and zoom
- `draw-change` - Fired on any feature change
- `draw-finish` - Fired when a shape is completed
- `address-selected` - Fired when a search result is selected
- `route-calculated` - Fired when a navigation route is calculated (includes route, startPoint, endPoint, mode)
- `traffic-updated` - Fired when traffic data is refreshed

### Public Methods
- `getFeatures()` - Get all drawn features
- `getGeoJson()` - Get features as FeatureCollection
- `loadGeoJson(geojson)` - Load features from GeoJSON
- `clearAllFeatures()` - Remove all features
- `setTool(tool)` - Set active drawing tool
- `flyTo(center, zoom?)` - Animate to location
- `fitToFeatures(padding?)` - Fit view to all features
- `setProjection(projection)` - Set map projection ('mercator' or 'globe')
- `getMap()` - Get underlying MapLibre instance
- `getTerraDraw()` - Get TerraDraw instance
- `calculateRoute()` - Calculate route between start and end points
- `setNavigationStart(coords, address?)` - Set navigation start point
- `setNavigationEnd(coords, address?)` - Set navigation end point
- `clearNavigation()` - Clear all navigation state
- `enableTraffic()` - Enable traffic visualization
- `disableTraffic()` - Disable traffic visualization
- `toggleTraffic()` - Toggle traffic visualization
- `refreshTraffic()` - Refresh traffic data
- `setTrafficProvider(provider)` - Set custom traffic provider
- `supportsTrafficRouting()` - Check if traffic-aware routing is available
- `getTrafficController()` - Get the TrafficController instance

### Context Menu
Right-click on the map to access a context menu with the following options:
- **Drag to Draw** - Toggle between drag mode (click-drag for circles/rectangles) and two-click mode
- **Globe View** - Toggle between globe (3D sphere) and Mercator (flat) projection
- **Show Traffic** - Toggle traffic layer (requires configured traffic provider)
- **Clear All Features** - Remove all drawn features from the map
- **Fit to Features** - Zoom and pan to show all drawn features

### Navigation Feature
The navigation panel (`showNavigation={true}`) provides A-to-B routing using OSRM (Open Source Routing Machine):
- **Transport modes**: Driving, Walking, Cycling
- **Point selection**: Type an address or click on the map
- **Route display**: Blue line overlay with turn-by-turn directions
- **API**: Uses free OSRM API (https://router.project-osrm.org) with fair-use rate limit
- **Traffic-aware routing**: When a traffic provider is configured, shows duration with/without traffic

### Traffic Feature
Live traffic visualization with pluggable provider architecture:

#### HERE Traffic Provider (Recommended)
```typescript
// Using API key property
<dees-geo-map trafficApiKey="YOUR_HERE_API_KEY" showTraffic></dees-geo-map>

// Or programmatically
import { HereTrafficProvider } from '@design.estate/dees-catalog-geo';
const map = document.querySelector('dees-geo-map');
const provider = new HereTrafficProvider();
provider.configure({ apiKey: 'YOUR_HERE_API_KEY' });
map.setTrafficProvider(provider);
map.enableTraffic();
```

**Free Tier**: 250,000 transactions/month (no credit card required)
Sign up at: https://developer.here.com

#### Valhalla Traffic Provider (Self-Hosted)
```typescript
import { ValhallaTrafficProvider } from '@design.estate/dees-catalog-geo';
const provider = new ValhallaTrafficProvider();
provider.configure({
  serverUrl: 'https://your-valhalla-server.com',
  trafficDataUrl: 'https://your-traffic-data-endpoint.com' // optional
});
map.setTrafficProvider(provider);
```

#### Traffic Color Legend
- 🟢 Green - Free flow
- 🟡 Yellow - Light congestion
- 🟠 Orange - Moderate congestion
- 🔴 Red - Heavy congestion
- 🔴 Dark Red - Severe/stopped

## Development
- `pnpm install` - Install dependencies
- `pnpm watch` - Start development server (port 3002)
- `pnpm build` - Build for production

## File Structure
```
ts_web/
├── index.ts                           # Main exports
├── 00_commitinfo_data.ts              # Auto-generated
└── elements/
    ├── index.ts                       # Elements barrel
    ├── 00colors.ts                    # Color definitions
    ├── 00componentstyles.ts           # Shared styles
    └── 00group-map/
        ├── index.ts
        └── dees-geo-map/
            ├── index.ts               # Exports main + modules
            ├── dees-geo-map.ts        # Main component
            ├── dees-geo-map.demo.ts   # Demo function
            ├── geo-map.icons.ts       # Icon SVG definitions
            ├── geo-map.search.ts      # SearchController class
            ├── geo-map.navigation.ts  # NavigationController class
            ├── geo-map.traffic.ts     # TrafficController class
            └── geo-map.traffic.providers.ts # Traffic provider implementations
```

## Modular Architecture
The component was refactored for better maintainability:

### geo-map.icons.ts
Contains all SVG icon definitions as a `GEO_MAP_ICONS` record and a `renderIcon(name)` helper function.

### geo-map.search.ts
`SearchController` class encapsulating Nominatim geocoding search:
- Reusable for standalone search or within navigation
- Debounced API calls
- Keyboard navigation support
- Customizable via `ISearchControllerConfig`

### geo-map.navigation.ts
`NavigationController` class for A-to-B routing:
- OSRM routing API integration
- Start/end point management with markers
- Map click mode for point selection
- Turn-by-turn directions rendering
- Route overlay on map
- Traffic-aware routing integration (shows congestion level and delay)

### geo-map.traffic.ts
`TrafficController` class for live traffic visualization:
- Traffic layer rendering with color-coded congestion
- Auto-refresh logic with configurable interval
- Supports pluggable traffic providers

### geo-map.traffic.providers.ts
Traffic data provider implementations:
- `HereTrafficProvider` - HERE Traffic API v7 (freemium)
- `ValhallaTrafficProvider` - Self-hosted Valhalla server

### Usage of Controllers
```typescript
// SearchController is reusable
const search = new SearchController(
  { placeholder: 'Search...' },
  {
    onResultSelected: (result, coords, zoom) => { /* handle */ },
    onRequestUpdate: () => this.requestUpdate(),
  }
);

// NavigationController manages all navigation state
const nav = new NavigationController({
  onRouteCalculated: (event) => { /* dispatch */ },
  onRequestUpdate: () => this.requestUpdate(),
  getMap: () => this.map,
});
```

## Notes
- MapLibre CSS is loaded dynamically from CDN
- Terra-draw requires the separate maplibre-gl-adapter package
- The component uses Shadow DOM for style encapsulation

### UI Layout

The component uses a header toolbar above the map for a cleaner layout:

```
┌──────────────────────────────────────────────────────────────────────┐
│ HEADER TOOLBAR                                                        │
│ [Draw Tools] | [Search Bar] | [Nav Toggle] [Traffic] [Zoom +/-]      │
├──────────────────────────────────────────────────────────────────────┤
│                                                                      │
│  [Navigation]                      MAP                               │
│  (toggleable)                                                        │
│                                                                      │
│ [Traffic Legend]                                     [Feature Count] │
└──────────────────────────────────────────────────────────────────────┘
```

**Header Toolbar Sections:**
- **Left**: Draw tools (Point, Line, Polygon, Rectangle, Circle, Freehand, Select, Clear)
- **Center**: Search bar (expandable width)
- **Right**: Navigation toggle, Traffic toggle, Zoom in/out buttons

**Map Overlays:**
- Navigation panel: Toggleable overlay on top-left of map
- Traffic legend: Bottom-left overlay (when traffic enabled)
- Feature count: Bottom-left overlay (when features exist)

**Z-index hierarchy:**
- `z-index: 20` - Dropdowns (search results, nav search results)
- `z-index: 5` - Map overlays (navigation panel, traffic legend, feature count)

### Shadow DOM & Terra-Draw Drawing Fix
Terra-draw's event listeners normally intercept map events through MapLibre's canvas element. In Shadow DOM contexts, these events are scoped locally and don't propagate correctly, causing terra-draw handlers to fail while MapLibre's drag handlers continue working.

**Solution**: Manual drag coordination in `setTool()`:
- When a drawing tool is active (`polygon`, `rectangle`, `point`, `linestring`, `circle`, `freehand`), MapLibre's `dragPan` and `dragRotate` are disabled
- When `static` or `select` mode is active, dragging is re-enabled
- The `TerraDrawMapLibreGLAdapter` does NOT accept a `lib` parameter - only `map` is required
