JSPM

  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 39
  • Score
    100M100P100Q62995F
  • License MIT

Open source custom map library for Expo/React Native. Use your own tiles without Google Maps, Mapbox, or API keys. Created by ChaufFleet.

Package Exports

  • @chauffleet/expo-custom-map
  • @chauffleet/expo-custom-map/lib/index.js

This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (@chauffleet/expo-custom-map) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.

Readme

@chauffleet/expo-custom-map

Open source custom map library for Expo/React Native, created by Chauffleet for its mobile app. Purpose: Easily use fully custom maps in your app, without Google Maps, Mapbox, or any API keys. No hidden providersβ€”your tiles, your rules!

npm version License: MIT TypeScript

High-performance map library for Expo/React Native with custom tile support. πŸ—ΊοΈβš‘


Why this project?

  • Developed by Chauffleet for its mobile application.
  • 100% open source, MIT licensed.
  • Lets you use your own map tiles (OpenStreetMap, MapTiler, CartoDB, etc.)β€”no Google Maps, no Mapbox, no API keys required.
  • No hidden providers: Unlike react-native-maps and similar libraries, this does not use Google Maps or Mapbox under the hood.
  • Perfect for custom, private, or offline maps.

πŸš€ Features

  • 🏎️ High Performance: Native rendering with Skia, 60fps guaranteed
  • 🎯 Custom Tiles: Support for any tile provider (OpenStreetMap, Mapbox, etc.)
  • πŸ“± Optimized for Mobile: Smooth gestures, efficient memory usage
  • 🌐 Offline Support: Download and cache tiles for offline usage
  • πŸŽͺ Clustering: Automatic marker clustering for better performance
  • 🧭 Navigation: Built-in routing and turn-by-turn navigation
  • 🎨 Fully Customizable: Custom markers, overlays, and styling
  • πŸ“Š Performance Monitoring: Built-in performance statistics

πŸ“¦ Installation

npm install @chauffleet/expo-custom-map

Dependencies

npx expo install react-native-reanimated react-native-gesture-handler @shopify/react-native-skia @react-native-async-storage/async-storage

πŸ› οΈ Setup

1. Metro Configuration

// metro.config.js
const { getDefaultConfig } = require('expo/metro-config');
const config = getDefaultConfig(__dirname);
config.resolver.assetExts.push('bin', 'txt', 'jpg', 'png', 'json', 'mp4', 'ttf', 'otf', 'xml');
module.exports = config;

2. Babel Configuration

// babel.config.js
module.exports = {
  presets: ['babel-preset-expo'],
  plugins: ['react-native-reanimated/plugin'], // Must be last
};

🎯 Quick Start

import React from 'react';
import { View } from 'react-native';
import { CustomMapView } from '@chauffleet/expo-custom-map';

export default function App() {
  return (
    <View style={{ flex: 1 }}>
      <CustomMapView
        style={{ flex: 1 }}
        center={[2.3522, 48.8566]} // Paris [longitude, latitude]
        zoom={15}
        tileUrlTemplate="https://tile.openstreetmap.org/{z}/{x}/{y}.png"
        markers={[
          {
            coordinate: [2.3522, 48.8566],
            title: "Paris",
            children: <CustomMarker />
          }
        ]}
        onRegionChange={(region) => console.log(region)}
      />
    </View>
  );
}

πŸ“– API Reference

CustomMapView Props

Prop Type Default Description
center [number, number] Required Map center [longitude, latitude]
zoom number Required Initial zoom level
tileUrlTemplate string Required Tile URL template with {x}, {y}, {z} placeholders
style ViewStyle {} Style for the map container
markers MarkerProps[] [] Array of markers to display
onRegionChange (region: MapRegion) => void undefined Called when map region changes
onMapPress (coordinate: [number, number]) => void undefined Called when map is pressed
minZoom number 1 Minimum zoom level
maxZoom number 18 Maximum zoom level
enableClustering boolean false Enable automatic marker clustering
showUserLocation boolean false Show user's current location
followUserLocation boolean false Follow user's location automatically

MarkerProps

Prop Type Default Description
coordinate [number, number] Required Marker position [longitude, latitude]
children ReactNode Default marker Custom marker component
title string undefined Marker title
description string undefined Marker description
onPress () => void undefined Called when marker is pressed
draggable boolean false Enable marker dragging

🌍 Tile Providers

OpenStreetMap (Free)

tileUrlTemplate="https://tile.openstreetmap.org/{z}/{x}/{y}.png"

MapTiler

tileUrlTemplate="https://api.maptiler.com/maps/streets/{z}/{x}/{y}.png?key=YOUR_KEY"

CartoDB

tileUrlTemplate="https://basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png"

Stamen Terrain

tileUrlTemplate="https://stamen-tiles.a.ssl.fastly.net/terrain/{z}/{x}/{y}.png"

🎨 Advanced Usage

Custom Markers

import { CustomMapView } from '@chauffleet/expo-custom-map';
import { View, Text } from 'react-native';

const CustomMarker = ({ title }) => (
  <View style={{ 
    backgroundColor: 'red', 
    padding: 8, 
    borderRadius: 8 
  }}>
    <Text style={{ color: 'white', fontWeight: 'bold' }}>
      {title}
    </Text>
  </View>
);

<CustomMapView
  markers={[
    {
      coordinate: [2.3522, 48.8566],
      children: <CustomMarker title="Custom Pin" />
    }
  ]}
/>

Clustering

<CustomMapView
  enableClustering={true}
  clusterRadius={50}
  markers={largeMarkerArray}
  onClusterPress={(cluster) => {
    console.log(`Cluster with ${cluster.pointCount} markers`);
  }}
/>

Offline Maps

import { useOfflineMap } from '@chauffleet/expo-custom-map';

const OfflineMapExample = () => {
  const { downloadRegion, isDownloading } = useOfflineMap();

  const handleDownload = async () => {
    await downloadRegion({
      bounds: { north: 48.9, south: 48.8, east: 2.4, west: 2.3 },
      minZoom: 10,
      maxZoom: 16
    });
  };

  return (
    <CustomMapView
      tileUrlTemplate="offline://{z}/{x}/{y}"
      offlineTileProvider={(z, x, y) => getCachedTile(z, x, y)}
    />
  );
};
import { calculateRoute } from '@chauffleet/expo-custom-map';

const NavigationExample = () => {
  const [route, setRoute] = useState([]);

  const getDirections = async () => {
    const result = await calculateRoute(
      [2.3522, 48.8566], // Start
      [2.2945, 48.8584], // End
      { profile: 'driving' }
    );
    setRoute(result.coordinates);
  };

  return (
    <CustomMapView
      polylines={[{
        coordinates: route,
        strokeColor: '#007AFF',
        strokeWidth: 5
      }]}
    />
  );
};

πŸ”§ Hooks & Utilities

useMapPerformance

import { useMapPerformance } from '@chauffleet/expo-custom-map';

const MapWithStats = () => {
  const { stats, cache, preloader } = useMapPerformance();

  return (
    <View>
      <Text>FPS: {stats.fps}</Text>
      <Text>Cache Hit Rate: {stats.cacheHitRate}%</Text>
      <CustomMapView ... />
    </View>
  );
};

useOptimizedGestures

import { useOptimizedGestures } from '@chauffleet/expo-custom-map';

const OptimizedMap = () => {
  const { throttledRegionChange } = useOptimizedGestures((region) => {
    console.log('Region changed:', region);
  });

  return (
    <CustomMapView
      onRegionChange={throttledRegionChange}
    />
  );
};

πŸ“Š Performance Comparison

Feature WebView @chauffleet/expo-custom-map Improvement
FPS 30-45 55-60 +67%
Gesture Response 50-100ms 16-33ms -70%
Memory Usage 80-120MB 40-60MB -50%
Cold Start 2-4s 0.5-1s -75%

πŸ§ͺ Testing

npm run test
npm run test:watch

πŸš€ Building

npm run build
npm run build:watch

πŸ“± Example App

Run the example app:

cd example
npm install
expo start

🀝 Contributing

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/AmazingFeature)
  3. Commit your changes (git commit -m 'Add some AmazingFeature')
  4. Push to the branch (git push origin feature/AmazingFeature)
  5. Open a Pull Request

πŸ“ Changelog

See CHANGELOG.md for details.

πŸ“„ License

This project is licensed under the MIT License - see the LICENSE file for details.

πŸ™ Acknowledgments

πŸ†˜ Support


Made with ❀️ by Chauffleet