2026-02-05 15:07:33 +00:00
2026-02-05 12:03:22 +00:00
2026-02-05 12:03:22 +00:00
2026-02-05 12:03:22 +00:00
2026-02-05 12:03:22 +00:00
2026-02-05 15:07:33 +00:00
2026-02-05 12:03:22 +00:00

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:

// 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)

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

// 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
Description
No description provided
Readme 6.9 MiB
Languages
TypeScript 99.7%
HTML 0.3%