An open API service indexing awesome lists of open source software.

https://github.com/tracktor/map


https://github.com/tracktor/map

Last synced: 5 months ago
JSON representation

Awesome Lists containing this project

README

          

# πŸ—ΊοΈ @tracktor/map

A modern, lightweight React map library built on top of Mapbox GL JS and react-map-gl. Designed for simplicity, flexibility, and visual elegance.

Easily combine markers, routes, GeoJSON features, isochrones, and nearest-point calculations β€” all with a declarative, type-safe API.

[![npm version](https://img.shields.io/npm/v/@tracktor/map.svg)](https://www.npmjs.com/package/@tracktor/map)
[![License](https://img.shields.io/badge/license-UNLICENSED-red.svg)](LICENSE)

---

## πŸš€ Installation
```bash
npm install @tracktor/map
```

or
```bash
yarn add @tracktor/map
```

or
```bash
bun add @tracktor/map
```

---

## βš™οΈ Requirements

| Dependency | Version | Purpose |
|------------|---------|---------|
| `react` | 17+ / 18+ / 19+ | Core React runtime |
| `react-dom` | 17+ / 18+ / 19+ | React DOM rendering |
| `mapbox-gl` | β‰₯3.0.0 | Map rendering engine |
| `@tracktor/design-system` | β‰₯4.0.0 | UI theming and components |
| `@mui/icons-material` | * | Material UI icons |
| `@mui/x-license` | * | MUI X license integration |

πŸͺΆ **You'll also need a Mapbox access token** to render maps. Get one at [mapbox.com](https://account.mapbox.com/access-tokens/).

---

## ✨ Features

βœ… **Declarative API** β€” manage complex map interactions with simple props
βœ… **Markers & Popups** β€” customizable React components or image-based icons
βœ… **Routing & Isochrones** β€” visualize travel-time areas or compute optimal routes
βœ… **GeoJSON Layers** β€” render vector data dynamically
βœ… **Nearest Marker Search** β€” find and highlight closest points instantly
βœ… **Type-safe API** β€” full TypeScript support with smart IntelliSense
βœ… **Responsive Design** β€” automatically adapts to any container or screen size
βœ… **Built for performance** β€” minimal re-renders, efficient map updates
βœ… **Multiple Routing Engines** β€” supports both OSRM (free) and Mapbox Directions API
βœ… **Flexible Map Styles** β€” works with Mapbox styles, OpenStreetMap, or custom raster tiles

---

## 🧩 Quick Start
```tsx
import { MapProvider, MarkerMap } from "@tracktor/map";

const markers = [
{
id: 1,
lng: 2.3522,
lat: 48.8566,
Tooltip:

Paris
,
color: "primary",
variant: "default",
},
{
id: 2,
lng: -0.1276,
lat: 51.5074,
Tooltip:
London
,
color: "secondary",
variant: "default",
},
];

function App() {
return (

{
console.log("Clicked at:", lng, lat);
if (marker) console.log("Marker clicked:", marker);
}}
/>

);
}
```

---

## 🧭 Components Overview

### `MapProvider`

Wraps your map components and injects required providers (theme, tokens, MUI X license).

**Required Props:**
- `licenseMuiX` β€” Your MUI X license key
- `licenceMapbox` β€” Your Mapbox access token
```tsx

{/* Your map components */}

```

### `MapView` / `MarkerMap`

Main map component that handles:
- Marker rendering with custom icons or React components
- Interactive popups with hover/click modes
- Automatic bounds fitting
- Map click events
- Responsive container sizing

### Specialized Components

- **`RouteMap`** β†’ Draw routes between two points using OSRM or Mapbox
- **`IsochroneMap`** β†’ Compute and display travel-time polygons
- **`FeatureMap`** β†’ Display custom GeoJSON layers with styling

---

## 🧱 Props Reference

### `MapView` Props

#### Core Map Props

| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `center` | `LngLatLike \| number[]` | `[2.3522, 48.8566]` | Initial map center coordinates [lng, lat] |
| `zoom` | `number` | `5` | Initial zoom level (0-22) |
| `width` | `string \| number` | `"100%"` | Map container width |
| `height` | `string \| number` | `300` | Map container height |
| `loading` | `boolean` | `false` | Show skeleton loader |
| `square` | `boolean` | `false` | Enforce 1:1 aspect ratio |
| `containerStyle` | `SxProps` | `undefined` | Custom MUI sx styles |

#### Map Appearance

| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `theme` | `"light" \| "dark"` | `"light"` | Map color theme |
| `baseMapView` | `"street" \| "satellite"` | `"street"` | Base map layer type |
| `mapStyle` | `string` | - | Custom Mapbox style URL |
| `projection` | `ProjectionSpecification` | `"mercator"` | Map projection system |

#### Interaction Props

| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `cooperativeGestures` | `boolean` | `true` | Require modifier key for zoom/pan |
| `doubleClickZoom` | `boolean` | `true` | Enable double-click to zoom |
| `onMapClick` | `(lng, lat, marker?) => void` | - | Callback for map clicks (includes clicked marker if applicable) |

#### Marker Props

| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `markers` | `MarkerProps[]` | `[]` | Array of markers to display |
| `markerImageURL` | `string` | - | Custom marker icon URL |
| `openPopup` | `string \| number` | `undefined` | ID of marker with open popup |
| `openPopupOnHover` | `boolean` | `false` | Open popups on hover instead of click |
| `popupMaxWidth` | `string` | `"300px"` | Maximum popup width |

#### Bounds & Animation

| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `fitBounds` | `boolean` | `true` | Auto-fit map to show all markers |
| `fitBoundsPadding` | `number` | `0` | Padding (px) around fitted bounds |
| `fitBoundDuration` | `number` | `500` | Animation duration (ms) |
| `disableAnimation` | `boolean` | `false` | Disable all animations |
| `fitBoundsAnimationKey` | `unknown` | - | Change to re-trigger fit bounds |

---

### Marker Props (`MarkerProps`)

| Prop | Type | Required | Description |
|------|------|----------|-------------|
| `id` | `string \| number` | βœ… | Unique marker identifier |
| `lng` | `number` | βœ… | Longitude coordinate |
| `lat` | `number` | βœ… | Latitude coordinate |
| `Tooltip` | `ReactNode` | - | Content for popup/tooltip |
| `IconComponent` | `React.ComponentType` | - | Custom React icon component |
| `iconProps` | `object` | - | Props passed to IconComponent |
| `color` | `string` | - | Marker color (MUI palette) |
| `variant` | `string` | - | Marker style variant |

**Example with custom icon:**
```tsx
import LocationOnIcon from '@mui/icons-material/LocationOn';

const marker = {
id: 1,
lng: 2.3522,
lat: 48.8566,
IconComponent: LocationOnIcon,
iconProps: { fontSize: 'large', color: 'error' },
Tooltip:

Custom Icon Marker

};
```

---

### Itinerary Props (`itineraryParams`)

Draw a route between two points with customizable styling and routing engines.

| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `from` | `[number, number]` | - | Route starting point [lng, lat] |
| `to` | `[number, number]` | - | Route ending point [lng, lat] |
| `profile` | `"driving" \| "walking" \| "cycling"` | `"driving"` | Transportation mode |
| `engine` | `"OSRM" \| "Mapbox"` | `"OSRM"` | Routing service to use |
| `itineraryLineStyle` | `Partial` | `{ color: "#3b82f6", width: 4, opacity: 0.8 }` | Route line appearance |
| `initialRoute` | `Feature` | - | Precomputed GeoJSON route |
| `onRouteComputed` | `(route) => void` | - | Callback fired when route is computed |
| `itineraryLabel` | `ReactNode` | - | Label displayed along the route (e.g., "12 min") |

**Example:**
```tsx
Route principale,
onRouteComputed: (route) => {
console.log("Route computed:", route);
}
}}
/>
```

---

### Nearest Marker Search (`findNearestMarker`)

Find and highlight the closest marker to a given point within a maximum distance.

| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `origin` | `[number, number]` | - | Starting point for search [lng, lat] |
| `destinations` | `Array<{id, lng, lat}>` | - | Candidate destinations |
| `maxDistanceMeters` | `number` | - | Maximum search radius in meters |
| `profile` | `"driving" \| "walking" \| "cycling"` | `"driving"` | Routing profile for distance calculation |
| `engine` | `"OSRM" \| "Mapbox"` | `"OSRM"` | Routing engine to use |
| `onNearestFound` | `(results) => void` | - | Callback with all nearest results |
| `initialNearestResults` | `NearestResult[]` | - | Precomputed nearest results |
| `itineraryLineStyle` | `Partial` | - | Style override for auto-generated itinerary |

**NearestResult Type:**
```tsx
interface NearestResult {
id: number | string;
point: [number, number]; // [lng, lat]
distance: number; // in meters
routeFeature?: Feature | null;
}
```

**Example:**
```tsx
({
id: m.id,
lng: m.lng,
lat: m.lat
})),
maxDistanceMeters: 5000,
profile: "walking",
engine: "OSRM",
onNearestFound: (results) => {
console.log(`Found ${results.length} markers within range`);
results.forEach(r => {
console.log(`Marker ${r.id} at ${r.distance}m`);
});
}
}}
/>
```

---

### Isochrone Props (`isochrone`)

Compute and display areas reachable within specific time intervals.

| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `origin` | `[number, number]` | - | Center point for isochrone [lng, lat] |
| `profile` | `"driving" \| "walking" \| "cycling"` | `"driving"` | Transportation mode |
| `intervals` | `number[]` | `[5, 10, 15]` | Time intervals in minutes |
| `onIsochroneLoaded` | `(data) => void` | - | Callback with GeoJSON result |

**Example:**
```tsx
{
console.log("Isochrone data:", geojson);
}
}}
/>
```

---

### GeoJSON Features (`features`)

Display custom vector features like polygons, lines, or points.

| Prop | Type | Description |
|------|------|-------------|
| `features` | `Feature \| Feature[] \| FeatureCollection` | GeoJSON data to render |

**Example:**
```tsx

```

---

## 🧠 Advanced Use Cases

### 🧭 Real-time GPS Tracking
```tsx
function LiveTracking() {
const [position, setPosition] = useState([2.3522, 48.8566]);

useEffect(() => {
const watchId = navigator.geolocation.watchPosition((pos) => {
setPosition([pos.coords.longitude, pos.coords.latitude]);
});
return () => navigator.geolocation.clearWatch(watchId);
}, []);

return (
You are here
}]}
center={position}
zoom={15}
fitBounds={false}
/>
);
}
```

### πŸ”„ Dynamic Data with React Query
```tsx
import { useQuery } from '@tanstack/react-query';

function DynamicMarkers() {
const { data: markers } = useQuery({
queryKey: ['locations'],
queryFn: fetchLocations,
refetchInterval: 5000 // Refresh every 5s
});

return (

);
}
```

### 🎨 Custom Marker Components
```tsx
function CustomMarker({ isActive, count }) {
return (

{count}

);
}

```

### πŸ—ΊοΈ Multi-Route Comparison
```tsx

```

### 🎯 Click-to-Add Markers
```tsx
function InteractiveMap() {
const [markers, setMarkers] = useState([]);

const handleMapClick = (lng, lat) => {
setMarkers(prev => [...prev, {
id: Date.now(),
lng,
lat,
Tooltip:

Point {markers.length + 1}

}]);
};

return (

);
}
```

### πŸš— Combined Routing & Nearest Search
```tsx
function DeliveryMap() {
const [origin] = useState([2.3522, 48.8566]);
const [destinations] = useState([
{ id: 1, lng: 2.35, lat: 48.86 },
{ id: 2, lng: 2.36, lat: 48.85 },
{ id: 3, lng: 2.34, lat: 48.87 }
]);

return (
({
id: d.id,
lng: d.lng,
lat: d.lat,
Tooltip:

Destination {d.id}

}))}
findNearestMarker={{
origin,
destinations,
maxDistanceMeters: 10000,
profile: "driving",
engine: "OSRM",
itineraryLineStyle: {
color: "#22c55e",
width: 4,
opacity: 0.8
},
onNearestFound: (results) => {
console.log("Nearest destinations:", results);
}
}}
/>
);
}
```

---

## πŸ’‘ Tips & Best Practices

### Performance Optimization

- **Memoize marker data** to prevent unnecessary re-renders
- **Use `fitBoundsAnimationKey`** to control when bounds recalculate
- **Disable animations** for large datasets: `disableAnimation={true}`
- **Debounce dynamic updates** when tracking real-time data
- **Use `initialRoute` and `initialNearestResults`** to avoid redundant API calls

### UX Improvements

- Combine `openPopupOnHover` and `disableAnimation` for smooth interactions
- Use `fitBoundsPadding` to ensure markers aren't at screen edges
- Set appropriate `popupMaxWidth` for mobile responsiveness
- Provide visual feedback with custom `IconComponent` states
- Use `itineraryLabel` to display route duration or distance

### Routing Best Practices

- **Use OSRM** (free) for basic routing needs
- **Use Mapbox** for production apps requiring SLA and support
- Cache route results with `initialRoute` to minimize API calls
- Handle network errors gracefully with `onRouteComputed` callback
- Combine `findNearestMarker` with `itineraryParams` for optimal routing workflows

---

## πŸ§‘β€πŸ’» Development

### Prerequisites

- **Bun** β‰₯1.1.0 (recommended) or Node.js 18+
- Git

### Setup
```bash
# Clone the repository
git clone https://github.com/tracktor-tech/tracktor-map.git
cd tracktor-map

# Install dependencies
bun install

# Start development sandbox
bun run sandbox
# or
bun run dev:sandbox
```

### Available Scripts

| Command | Description |
|---------|-------------|
| `bun run sandbox` | Start interactive development playground |
| `bun run build` | Build library for production |
| `bun run build:sandbox` | Build sandbox demo site |
| `bun run deploy:sandbox` | Deploy sandbox to GitHub Pages |
| `bun run lint` | Check code quality and types |
| `bun run lint:fix` | Auto-fix linting issues |
| `bun run test` | Run test suite |
| `bun run test:watch` | Run tests in watch mode |
| `bun run version` | Bump version with changelog |
| `bun run release` | Build and publish to npm |

### Project Structure
```
@tracktor/map/
β”œβ”€β”€ src/
β”‚ β”œβ”€β”€ components/ # Reusable map and UI components (Marker, Popup, etc.)
β”‚ β”œβ”€β”€ constants/ # Shared configuration values and styling constants
β”‚ β”œβ”€β”€ context/ # React context providers (e.g. map state)
β”‚ β”œβ”€β”€ features/ # Core map features (routes, isochrones, nearest, etc.)
β”‚ β”œβ”€β”€ services/ # External APIs and utility services
β”‚ β”œβ”€β”€ types/ # TypeScript interfaces and types
β”‚ β”œβ”€β”€ utils/ # Generic helpers and formatting functions
β”‚ └── main.ts # Library entry point
β”‚
β”œβ”€β”€ sandbox/ # Development playground (example app & live demos)
β”‚ β”œβ”€β”€ context/ # Demo context providers
β”‚ β”œβ”€β”€ examples/ # Interactive usage examples
β”‚ β”œβ”€β”€ features/ # Components used in the docs/demo
β”‚ β”œβ”€β”€ public/ # Static assets (images, previews, etc.)
β”‚ β”œβ”€β”€ App.tsx # Sandbox root component
β”‚ └── index.tsx # Sandbox entry file
β”‚
└── test/ # Unit and integration tests
```

### Testing
```bash
# Run all tests
bun test

# Watch mode
bun test:watch

# Run specific test file
bun test src/components/MapView.test.tsx
```

### Contributing

We welcome contributions! Please:

1. Fork the repository
2. Create a feature branch (`git checkout -b feature/amazing-feature`)
3. Make your changes
4. Run tests and linting (`bun run test && bun run lint`)
5. Commit your changes (`git commit -m 'Add amazing feature'`)
6. Push to the branch (`git push origin feature/amazing-feature`)
7. Open a Pull Request

**Code Style:**
- Follow existing patterns and conventions
- Use TypeScript for all new code
- Add tests for new features
- Update documentation as needed

---

## πŸ“˜ Documentation & Examples

Explore interactive examples and comprehensive API documentation:

πŸ‘‰ **[Live Documentation & Sandbox](https://tracktor.github.io/map)**

The sandbox includes:
- Interactive code examples
- Live preview of all features
- Copy-paste ready snippets
- API reference with search

---

## πŸ“¦ Publishing & Deployment

### Publish to npm
```bash
# Update version and generate changelog
bun run version

# Build and publish
bun run release
```

### Deploy Sandbox to GitHub Pages
```bash
bun run deploy:sandbox
```

This will:
1. Build the sandbox with production optimizations
2. Generate a 404.html for client-side routing
3. Push to the `gh-pages` branch
4. Update the live documentation site

---

## πŸ”§ Troubleshooting

### Common Issues

**Map not rendering:**
- Verify your Mapbox token is valid
- Check browser console for errors
- Ensure mapbox-gl CSS is imported

**TypeScript errors:**
- Run `bun install` to update type definitions
- Check peer dependency versions match

**Performance issues:**
- Reduce marker count or use clustering
- Disable animations for large datasets
- Memoize marker data
- Use `initialRoute` and `initialNearestResults` for cached data

**Routing not working:**
- Verify coordinates are in [lng, lat] format (not lat, lng)
- Check that routing engine is accessible
- Ensure profile matches your use case
- Verify maxDistanceMeters is reasonable for nearest search

### Getting Help

- πŸ“– Check the [documentation](https://github.com/Tracktor/map)
- πŸ› [Report bugs](https://github.com/tracktor-tech/tracktor-map/issues)
- πŸ’¬ Join discussions in GitHub Discussions

---

## πŸ“„ License

**UNLICENSED** β€” This package is proprietary software.
Β© [Tracktor β€” Kevin Graff]

---

## 🧭 Links

- πŸ“¦ **npm**: [@tracktor/map](https://www.npmjs.com/package/@tracktor/map)
- πŸ’» **GitHub**: [@tracktor/map](https://github.com/Tracktor/map)
- 🌐 **Docs**: [tracktor.github.io/map](https://tracktor.github.io/map)
- 🎨 **Design System**: [@tracktor/design-system](https://www.npmjs.com/package/@tracktor/design-system)
- Sandbox Demo: [tracktor.github.io/map/sandbox](https://tracktor.github.io/map)

---

## πŸ™ Acknowledgments

Built with:
- [Mapbox GL JS](https://docs.mapbox.com/mapbox-gl-js/) β€” Powerful map rendering
- [react-map-gl](https://visgl.github.io/react-map-gl/) β€” React wrapper for Mapbox
- [OSRM](http://project-osrm.org/) β€” Free routing engine
- [@tracktor/design-system](https://www.npmjs.com/package/@tracktor/design-system) β€” UI components