npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@tracktor/map

v1.8.13

Published

A React library to easily display map with multiple tools

Downloads

1,033

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 License


🚀 Installation

npm install @tracktor/map

or

yarn add @tracktor/map

or

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.


✨ 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

import { MapProvider, MarkerMap } from "@tracktor/map";

const markers = [
    {
        id: 1,
        lng: 2.3522,
        lat: 48.8566,
        Tooltip: <div>Paris</div>,
        color: "primary",
        variant: "default",
    },
    {
        id: 2,
        lng: -0.1276,
        lat: 51.5074,
        Tooltip: <div>London</div>,
        color: "secondary",
        variant: "default",
    },
];

function App() {
    return (
        <MapProvider
            licenseMuiX="your-muix-license"
            licenceMapbox="your-mapbox-token"
        >
            <MarkerMap
                markers={markers}
                center={[2.3522, 48.8566]}
                zoom={5}
                fitBounds
                height={500}
                width="100%"
                onMapClick={(lng, lat, marker) => {
                    console.log("Clicked at:", lng, lat);
                    if (marker) console.log("Marker clicked:", marker);
                }}
            />
        </MapProvider>
    );
}

🧭 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
<MapProvider
    licenseMuiX="your-license"
    licenceMapbox="your-token"
>
    {/* Your map components */}
</MapProvider>

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:

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: <div>Custom Icon Marker</div>
};

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<ItineraryLineStyle> | { color: "#3b82f6", width: 4, opacity: 0.8 } | Route line appearance | | initialRoute | Feature<LineString> | - | Precomputed GeoJSON route | | onRouteComputed | (route) => void | - | Callback fired when route is computed | | itineraryLabel | ReactNode | - | Label displayed along the route (e.g., "12 min") |

Example:

<MapView
  itineraryParams={{
    from: [2.3522, 48.8566], // Paris
    to: [-0.1276, 51.5074],   // London
    profile: "driving",
    engine: "OSRM",
    itineraryLineStyle: {
      color: "#10b981",
      width: 5,
      opacity: 0.9
    },
    itineraryLabel: <span>Route principale</span>,
    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<ItineraryLineStyle> | - | Style override for auto-generated itinerary |

NearestResult Type:

interface NearestResult {
  id: number | string;
  point: [number, number]; // [lng, lat]
  distance: number; // in meters
  routeFeature?: Feature<LineString> | null;
}

Example:

<MapView
  findNearestMarker={{
    origin: [2.3522, 48.8566],
    destinations: markers.map(m => ({ 
      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:

<MapView
  isochrone={{
    origin: [2.3522, 48.8566],
    profile: "driving",
    intervals: [5, 10, 15, 20], // 5, 10, 15, 20 minutes
    onIsochroneLoaded: (geojson) => {
      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:

<MapView
  features={{
    type: "Feature",
    geometry: {
      type: "LineString",
      coordinates: [
        [2.3, 48.8],
        [2.4, 48.9],
        [2.5, 48.85]
      ]
    },
    properties: {
      color: "#ef4444"
    }
  }}
/>

🧠 Advanced Use Cases

🧭 Real-time GPS Tracking

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 (
    <MapView
      markers={[{
        id: 'current',
        lng: position[0],
        lat: position[1],
        Tooltip: <div>You are here</div>
      }]}
      center={position}
      zoom={15}
      fitBounds={false}
    />
  );
}

🔄 Dynamic Data with React Query

import { useQuery } from '@tanstack/react-query';

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

  return (
    <MapView
      markers={markers}
      fitBounds
      fitBoundsAnimationKey={markers?.length}
    />
  );
}

🎨 Custom Marker Components

function CustomMarker({ isActive, count }) {
  return (
    <Box
      sx={{
        width: 40,
        height: 40,
        borderRadius: '50%',
        bgcolor: isActive ? 'success.main' : 'grey.500',
        display: 'flex',
        alignItems: 'center',
        justifyContent: 'center',
        color: 'white',
        fontWeight: 'bold',
        border: '2px solid white',
        boxShadow: 2
      }}
    >
      {count}
    </Box>
  );
}

<MapView
  markers={[{
    id: 1,
    lng: 2.3522,
    lat: 48.8566,
    IconComponent: CustomMarker,
    iconProps: { isActive: true, count: 5 }
  }]}
/>

🗺️ Multi-Route Comparison

<MapView
  features={[
    {
      type: "Feature",
      geometry: {
        type: "LineString",
        coordinates: route1
      },
      properties: { color: "#3b82f6" }
    },
    {
      type: "Feature",
      geometry: {
        type: "LineString",
        coordinates: route2
      },
      properties: { color: "#ef4444" }
    }
  ]}
/>

🎯 Click-to-Add Markers

function InteractiveMap() {
  const [markers, setMarkers] = useState([]);

  const handleMapClick = (lng, lat) => {
    setMarkers(prev => [...prev, {
      id: Date.now(),
      lng,
      lat,
      Tooltip: <div>Point {markers.length + 1}</div>
    }]);
  };

  return (
    <MapView
      markers={markers}
      onMapClick={handleMapClick}
    />
  );
}

🚗 Combined Routing & Nearest Search

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 (
    <MapView
      markers={destinations.map(d => ({
        id: d.id,
        lng: d.lng,
        lat: d.lat,
        Tooltip: <div>Destination {d.id}</div>
      }))}
      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

# 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

# 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

The sandbox includes:

  • Interactive code examples
  • Live preview of all features
  • Copy-paste ready snippets
  • API reference with search

📦 Publishing & Deployment

Publish to npm

# Update version and generate changelog
bun run version

# Build and publish
bun run release

Deploy Sandbox to GitHub Pages

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


📄 License

UNLICENSED — This package is proprietary software.
© [Tracktor — Kevin Graff]


🧭 Links


🙏 Acknowledgments

Built with: