Skip to content

Latest commit

 

History

History
349 lines (295 loc) · 12.4 KB

File metadata and controls

349 lines (295 loc) · 12.4 KB

MapView

Main map component.

Usage

import { MapView } from '@lugg/maps';

<MapView
  style={{ flex: 1 }}
  provider="google"
  initialCoordinate={{ latitude: 37.7749, longitude: -122.4194 }}
  initialZoom={12}
  onCameraMove={(e) => console.log(e.nativeEvent)}
  onCameraIdle={(e) => console.log(e.nativeEvent)}
>
  {/* Markers, Polylines, etc. */}
</MapView>

Props

Prop Type Default Description
provider MapProvider 'apple' (iOS), 'google' (Android) Map provider
mapType MapType 'standard' Map display type
mapId string - Map style ID (Google) or configuration name (Apple)
initialCoordinate Coordinate - Initial camera coordinate
initialZoom number 10 Initial zoom level
zoomEnabled boolean true Enable zoom gestures
scrollEnabled boolean true Enable scroll/pan gestures
rotateEnabled boolean true Enable rotation gestures
pitchEnabled boolean true Enable pitch/tilt gestures
compassEnabled boolean true Show compass on the map (rotate control on web)
staticMode boolean false Render as a non-interactive static map. Ideal for list views
staticKey string - Stable identity for the static snapshot cache (iOS). See Static Maps
edgeInsets EdgeInsets - Map content edge insets
userLocationEnabled boolean false Show current user location on the map
userLocationButtonEnabled boolean false Show native my-location button (Android only)
poiEnabled boolean true Show points of interest (Apple Maps only)
poiFilter PoiFilter - Filter POI categories (Apple Maps only)
theme MapTheme 'system' Map color theme
insetAdjustment 'automatic' | 'never' 'never' Safe area inset adjustment behavior
onPress (event: MapPressEvent) => void - Called when the map is pressed
onLongPress (event: MapPressEvent) => void - Called when the map is long pressed
onCameraMove (event: MapCameraEvent) => void - Called when camera moves
onCameraIdle (event: MapCameraEvent) => void - Called when camera stops moving
onReady () => void - Called when map is loaded and ready

Static Maps

Set staticMode to render a non-interactive map optimized for list views, where mounting many live maps is expensive:

  • Android (Google) - uses lite mode, which renders a static bitmap instead of a live GL surface. Lite mode does not support cloud-based styling, so mapId is ignored on lite static maps. Lite mode caps its bitmap at ~2048px per dimension, so larger views (e.g. full-screen maps) fall back to a full map with all gestures disabled.
  • iOS (Apple) - the base map is rendered with MKMapSnapshotter, which loads entirely off the main thread (no live map view is ever created), so static maps keep loading while scrolling. Markers stay live views positioned over the base map; polylines, polygons, circles, and ground overlays are drawn onto it. Tile overlays are not supported.
  • iOS (Google) - markers and shapes render as live overlay views, exactly like Apple static maps. Only the base map needs the SDK (which has no async snapshotter): a live, tiles-only map warms up briefly under the overlays and is replaced with a rendered image once tiles finish loading, releasing the map's rendering resources. Warmup work scales with how many rows mount at once - bound it with your list's windowSize / initialNumToRender / maxToRenderPerBatch.
  • Web (Google) - gestures, POI clicks, keyboard interaction, and press events are disabled; the map itself stays live.
<Pressable onPress={() => openPlace(place)}>
  <View style={{ height: 140 }} pointerEvents="none">
    <MapView
      staticMode
      staticKey={place.id}
      style={StyleSheet.absoluteFill}
      initialCoordinate={place.coordinate}
      initialZoom={14}
    >
      <Marker coordinate={place.coordinate} />
    </MapView>
  </View>
</Pressable>

Notes:

  • staticMode is creation-time only and cannot be toggled after the map is created.
  • Ref methods (moveCamera, fitCoordinates, setEdgeInsets) work like on a live map, minus animation - duration is ignored and the map re-renders at the final camera (iOS) or re-centers (Android). Map-setting prop updates (e.g. mapType) after the snapshot are still ignored on iOS.
  • edgeInsets shift the visible center like on a live map, so the coordinate centers in the inset viewport. Changing insets after the render re-renders the base map (iOS) or re-centers the camera (Android).
  • For taps, wrap the map in a Pressable with pointerEvents="none" on the map container (as above) instead of relying on onPress.
  • animated polylines render as complete static polylines, so the snapshot never freezes a mid-animation frame.
  • On iOS, markers are live views over the base map, revealed together with it - marker content that loads asynchronously (e.g. remote images) appears when ready, and marker prop updates still apply.
  • While a static map loads, a theme-aware placeholder background is shown. Set a backgroundColor style on the MapView to use your own.
  • Set staticKey (e.g. your list item's id) to cache base map images across list recycling on iOS - scrolling back to a row reuses its image instead of rendering the map again (markers and shapes stay live and re-render from props). The camera and map settings are part of the cache key automatically. Changing staticKey discards the current image and re-renders. The cache is bounded by count and total memory.
  • Alternatively, keeping rows mounted (larger windowSize with removeClippedSubviews) avoids re-rendering entirely at the cost of holding every row's snapshot in memory.
  • In long lists, limit how many rows mount at once (e.g. windowSize, initialNumToRender, maxToRenderPerBatch on FlatList) - every mounted static map holds its snapshot image in memory.

Types

MapProvider

Value Description
'google' Google Maps
'apple' Apple Maps (iOS only)

MapType

Value Description
'standard' Default map style
'satellite' Satellite imagery
'terrain' Terrain/topographic map
'hybrid' Satellite imagery with labels
'muted-standard' Muted standard style (Apple Maps only, falls back to standard on Google Maps)

MapTheme

Value Description
'light' Light appearance
'dark' Dark appearance
'system' Follow system appearance

InsetAdjustment

Value Description
'never' No safe area inset adjustment
'automatic' Automatically adjust for safe area insets

PoiFilter

interface PoiFilter {
  mode?: 'including' | 'excluding'; // default: 'including'
  categories: PoiCategory[];
}

When mode is 'including', only the specified categories are shown. When 'excluding', all categories are shown except the specified ones.

PoiCategory

Value Description Availability
'airport' Airports iOS 13+
'amusement-park' Amusement parks iOS 13+
'animal-service' Animal services iOS 18+
'aquarium' Aquariums iOS 13+
'atm' ATMs iOS 13+
'automotive-repair' Automotive repair iOS 18+
'bakery' Bakeries iOS 13+
'bank' Banks iOS 13+
'baseball' Baseball iOS 18+
'basketball' Basketball iOS 18+
'beach' Beaches iOS 13+
'beauty' Beauty services iOS 18+
'bowling' Bowling iOS 18+
'brewery' Breweries iOS 13+
'cafe' Cafes iOS 13+
'campground' Campgrounds iOS 13+
'car-rental' Car rental locations iOS 13+
'castle' Castles iOS 18+
'convention-center' Convention centers iOS 18+
'distillery' Distilleries iOS 18+
'ev-charger' EV charging stations iOS 13+
'fairground' Fairgrounds iOS 18+
'fire-station' Fire stations iOS 13+
'fishing' Fishing iOS 18+
'fitness-center' Fitness centers iOS 13+
'food-market' Food markets iOS 13+
'fortress' Fortresses iOS 18+
'gas-station' Gas stations iOS 13+
'go-kart' Go-kart iOS 18+
'golf' Golf iOS 18+
'hiking' Hiking iOS 18+
'hospital' Hospitals iOS 13+
'hotel' Hotels iOS 13+
'kayaking' Kayaking iOS 18+
'landmark' Landmarks iOS 18+
'laundry' Laundry services iOS 13+
'library' Libraries iOS 13+
'mailbox' Mailboxes iOS 18+
'marina' Marinas iOS 13+
'mini-golf' Mini golf iOS 18+
'movie-theater' Movie theaters iOS 13+
'museum' Museums iOS 13+
'music-venue' Music venues iOS 18+
'national-monument' National monuments iOS 18+
'national-park' National parks iOS 13+
'nightlife' Nightlife venues iOS 13+
'park' Parks iOS 13+
'parking' Parking lots iOS 13+
'pharmacy' Pharmacies iOS 13+
'planetarium' Planetariums iOS 18+
'police' Police stations iOS 13+
'post-office' Post offices iOS 13+
'public-transport' Public transport stations iOS 13+
'restaurant' Restaurants iOS 13+
'restroom' Restrooms iOS 13+
'rock-climbing' Rock climbing iOS 18+
'rv-park' RV parks iOS 18+
'school' Schools iOS 13+
'skate-park' Skate parks iOS 18+
'skating' Skating iOS 18+
'skiing' Skiing iOS 18+
'soccer' Soccer iOS 18+
'spa' Spas iOS 18+
'stadium' Stadiums iOS 13+
'store' Stores iOS 13+
'surfing' Surfing iOS 18+
'swimming' Swimming iOS 18+
'tennis' Tennis iOS 18+
'theater' Theaters iOS 13+
'university' Universities iOS 13+
'volleyball' Volleyball iOS 18+
'winery' Wineries iOS 13+
'zoo' Zoos iOS 13+

Ref Methods

import { useRef } from 'react';
import { MapView, MapViewRef } from '@lugg/maps';

const mapRef = useRef<MapViewRef>(null);

// Move camera to coordinate
mapRef.current?.moveCamera(
  { latitude: 37.7749, longitude: -122.4194 },
  { zoom: 15, duration: 500 }
);

// Fit coordinates in view
mapRef.current?.fitCoordinates(
  [
    { latitude: 37.7749, longitude: -122.4194 },
    { latitude: 37.8049, longitude: -122.4094 },
  ],
  { padding: { top: 50, left: 50, bottom: 50, right: 50 }, duration: 500 }
);

// Set edge insets with animation
mapRef.current?.setEdgeInsets(
  { top: 0, left: 0, bottom: 200, right: 0 },
  { duration: 300 }
);

moveCamera

Move the camera to a coordinate with optional zoom and animation duration. The current heading and pitch are preserved.

moveCamera(coordinate: Coordinate, options: MoveCameraOptions): void

interface MoveCameraOptions {
  zoom: number;
  duration?: number; // milliseconds, -1 for default
}

fitCoordinates

Fit multiple coordinates in the visible map area. Resets heading to north ().

fitCoordinates(coordinates: Coordinate[], options?: FitCoordinatesOptions): void

interface FitCoordinatesOptions {
  padding?: EdgeInsets;
  duration?: number; // milliseconds, -1 for default
}

setEdgeInsets

Programmatically update the map's edge insets with optional animation.

setEdgeInsets(edgeInsets: EdgeInsets, options?: SetEdgeInsetsOptions): void

interface SetEdgeInsetsOptions {
  duration?: number; // milliseconds, -1 for default animation, 0 for instant
}

Events

onPress / onLongPress

Called when the map is pressed or long pressed. Event includes the geographic coordinate and screen point.

interface PressEventPayload {
  coordinate: Coordinate;
  point: Point;
}

onCameraMove

Called continuously while the camera is moving.

interface CameraMoveEvent {
  coordinate: Coordinate;
  zoom: number;
  dragging: boolean; // true if user is dragging
}

onCameraIdle

Called when the camera stops moving.

interface CameraIdleEvent {
  coordinate: Coordinate;
  zoom: number;
}