powermap_sdk 0.2.0 copy "powermap_sdk: ^0.2.0" to clipboard
powermap_sdk: ^0.2.0 copied to clipboard

A comprehensive Flutter SDK for PowerMap, offering location plotting, geometry measurements, layer management, routing, search, and tracking.

PowerMap Flutter SDK πŸš€ #

Flutter Dart

A professional-grade, high-performance Map SDK for Flutter, built with a Powerful Native Engine. Optimized for logistics, real-time tracking, indoor mapping, and buttery-smooth 60FPS mobile map interactions with deep architectural parity to the PowerMap Web SDK.


1. πŸ“¦ Installation #

Add the package to your pubspec.yaml:

dependencies:
  powermap_sdk: ^0.2.0 

Then, run:

flutter pub get

2. πŸ›οΈ Architecture Overview #

The PowerMap Flutter SDK is built with a Layered Facade Architecture, ensuring that high-performance native rendering is wrapped in an easy-to-use Flutter API.

graph TD
    App[Flutter App] --> PowerMap[PowerMap Widget]
    PowerMap --> Controller[PowerMapController]
    
    subgraph "Facade Layer"
        Controller
    end

    subgraph "Manager Layer"
        Controller --> MarkerMgr[MarkerManager]
        Controller --> SearchMgr[SearchManager]
        Controller --> RouteMgr[RoutingManager]
        Controller --> GeomMgr[GeometryManager]
        Controller --> TrackingMgr[TrackingManager]
        Controller --> LayerMgr[LayerManager]
    end

    subgraph "Service Layer"
        MarkerMgr --> TileSvc[TileService]
        SearchMgr --> GeoSvc[GeocodingProvider]
        TileSvc --> Cache[3-Layer Cache]
    end

    subgraph "Native Engine"
        PowerMap --> NativeEngine[High-Performance Native Rendering]
    end

    Cache -.-> Disk[(Local Storage)]
    Cache -.-> CDN((PowerMap CDN))
  • Unified Facade: PowerMapController provides a single entry point for all features, matching the Web SDK's DX.
  • Native Rendering: Symbols, Lines, and Polygons are rendered in C++/OpenGL via our custom native engine for 60FPS performance.
  • 3-Layer Caching: Automated Memory/Disk/Network caching ensures offline resilience and fast style loading.
  • Hybrid Overlay: Arbitrary Flutter Widgets can be used as markers, perfectly synced with the map camera.

3. πŸš€ Quick Start #

Get a map up and running in less than 2 minutes. The SDK provides a powerful PowerMapController Facade.

Step A: Initialize Dual-Auth #

Setup the SDK with your API keys globally in your main.dart.

import 'package:flutter/material.dart';
import 'package:powermap_sdk/powermap_sdk.dart';

void main() {
  PowerMapSDK.initialize(
    mapApiKey: "YOUR_MAP_API_KEY", // Public key for tiles/base layers
    clientId: "YOUR_CLIENT_ID",    // Core Service Credentials 
    clientSecret: "YOUR_CLIENT_SECRET",
  );

  runApp(const MyApp());
}

Step B: The Map Widget #

class MapPage extends StatefulWidget {
  @override
  _MapPageState createState() => _MapPageState();
}

class _MapPageState extends State<MapPage> {
  PowerMapController? map;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: PowerMap(
        initialCenter: const LatLng(13.7563, 100.5018), // Bangkok
        initialZoom: 14.0,
        mapStyle: 'dark', // 'th', 'en', 'dark', 'gray'
        onMapCreated: (controller) => setState(() => map = controller),
        onMapClick: (coords) => print("Tapped at: $coords"),
      ),
    );
  }
}

4. πŸ› οΈ Configuration Reference #

PowerMap (Widget Properties) #

Parameter Type Default Description
initialCenter LatLng LatLng(13.7563, 100.5018) The initial center point of the map.
initialZoom double 14.0 Initial viewport zoom level (0-22).
mapStyle String 'th' Base tile style. Available: 'th', 'en', 'dark', 'gray'.
onMapCreated Function(PowerMapController) null Triggered when the GL context is fully initialized.
onMapClick Function(LatLng) null Coordinate where the user tapped.
onMapLongClick Function(LatLng) null Coordinate where user long-pressed.
onPoiTapped Function(Map<String, dynamic>) null Fired when a base map POI or custom Geometry is tapped. Returns GeoJSON feature.
onError Function(PowerMapException) null Global unified callback to catch map loading, network, or auth errors natively.

5. πŸ“ Marker Management (map.markers, map.clusters) #

The SDK renders native Symbol Layers for highest drawing performance. Markers support full customization matching the Web SDK's capabilities.

Core Marker Methods #

Method Arguments Description
addMarker(position, ...) LatLng, {color?, iconImage?, size?, data?, opacity?} Adds a GL-rendered map symbol marker. Best for performance.
addWidgetMarker(position, widget, ...) LatLng, widget, {id?, alignment?} Overlays a Flutter Widget as a marker. Best for complex UI.
setMarkersOpacity(opacity) double (0.0–1.0) Bulk-sets the opacity of all native markers. Use with AnimationController for smooth fade effects.
clearMarkers() - Removes all GL symbols and circles.
clearWidgetMarkers() - Removes all Flutter widget markers.

1. GL Symbol Markers (High Performance) #

Best for large datasets (100+ points). Rendered directly by the GPU.

await map?.addMarker(
  LatLng(13.76, 100.50),
  color: '#f97316',
  iconImage: 'packages/powermap_sdk/assets/markers/0101.png',
);

addMarker() Options

Option Type Default Description
position LatLng Required Coordinates for the marker.
color String? null Hex color code. If set without iconImage, renders a GL Circle pinpoint.
iconImage String? marker-o.png Asset path for the icon. Uses bundled default if omitted.
size double 1.0 Scale factor for the icon or circle radius.
data Map<String, dynamic>? null Metadata attached to the marker (accessible on tap).
opacity double 1.0 Initial visibility of the marker (0.0 = invisible, 1.0 = fully visible). Use with setMarkersOpacity() to animate a fade-in.

2. Flutter Widget Markers (High Interactivity) #

Best for complex UIs, buttons, or animations inside a marker. These markers are overlaid in a Stack and synchronized with the map's camera using pixel projection.

map?.addWidgetMarker(
  LatLng(13.75, 100.48),
  Container(
    padding: EdgeInsets.all(8),
    decoration: BoxDecoration(
      color: Colors.white,
      borderRadius: BorderRadius.circular(20),
      boxShadow: [BoxShadow(blurRadius: 4, color: Colors.black26)],
    ),
    child: Row(
      mainAxisSize: MainAxisSize.min,
      children: [
        Icon(Icons.restaurant, color: Colors.orange, size: 16),
        SizedBox(width: 4),
        Text("Delicious Cafe", style: TextStyle(fontSize: 12)),
      ],
    ),
  ),
  alignment: Alignment.bottomCenter,
);

addWidgetMarker() Options #

Option Type Default Description
position LatLng Required Geographic location to pin the widget.
widget Widget Required The Flutter widget to display.
id String? null Optional unique identifier.
alignment Alignment Alignment.center Anchor point of the widget relative to the position.

Bundled Icon Assets #

The SDK ships with 290+ marker icons copied directly from the Web SDK's asset library (assets/markers/). These include category icons, route waypoint markers, and the default pinpoint.

// 1. Default marker (uses bundled marker-o.png automatically)
await map?.addMarker(LatLng(13.7563, 100.5018));

// 2. Custom colored GL pinpoint (no image needed, like Web SDK)
await map?.addMarker(
  LatLng(13.76, 100.50),
  color: '#f97316', // Vibrant Orange
  size: 1.5,
  data: {'name': 'My Store'},
);

// 3. Custom icon from bundled assets
await map?.addMarker(
  LatLng(13.77, 100.51),
  iconImage: 'packages/powermap_sdk/assets/markers/0101.png',
);

// 4. High-Performance Clustering
final List<LatLng> stores = [ ... ];
await map?.setClusters(stores);

3. Marker Opacity & Fade Animation (v0.2.0+) #

Eliminate the visual "flash" that occurs when clearing and re-adding markers by using the opacity parameter together with setMarkersOpacity() and a Flutter AnimationController.

How it works:

  1. clearMarkers() β€” removes all old markers instantly
  2. addMarker(..., opacity: 0.0) β€” adds new markers invisibly
  3. setMarkersOpacity(value) driven by AnimationController β€” fades all markers in smoothly
// In your StatefulWidget, declare:
late final AnimationController _fadeCtrl;

@override
void initState() {
  super.initState();
  _fadeCtrl = AnimationController(
    vsync: this,
    duration: const Duration(milliseconds: 350),
  );
}

// Render markers with smooth fade-in:
Future<void> renderMarkersWithFade(List<LatLng> positions) async {
  // Step 1: Clear old markers
  await map?.clearMarkers();

  // Step 2: Add all new markers invisibly
  for (final pos in positions) {
    await map?.addMarker(
      pos,
      color: '#E42320',
      opacity: 0.0,          // Start invisible
    );
  }

  // Step 3: Fade in all markers together
  _fadeCtrl.addListener(() {
    map?.setMarkersOpacity(_fadeCtrl.value);
  });
  _fadeCtrl.forward(from: 0); // Animates 0.0 β†’ 1.0 over 350ms
}

@override
void dispose() {
  _fadeCtrl.dispose();
  super.dispose();
}

Tip

setMarkersOpacity() updates all GL Circles and Symbols in a single batch β€” there is no per-marker loop required from the application side.


6. πŸŽ₯ Camera & Viewport Control #

Directly manipulate the map viewport matching the fluidity of the Web SDK.

Movement Methods #

Method Arguments Description
moveCamera(target, ...) LatLng, zoom?, tilt?, bearing? Smooth cinematic fly-to animation with optional rotations.
zoomIn() - Increments zoom level by 1.0 with smooth animation.
zoomOut() - Decrements zoom level by 1.0 with smooth animation.
setTilt(deg) double Set tilt angle (0 = 2D, 60+ = 3D).
setBearing(deg) double Set direction (0 = North).
tiltUp() - Shortcut to animate the camera to a 3D perspective view.
tiltDown() - Shortcut to animate back to a top-down view.

State Functions #

Method Returns Description
getCenter() LatLng? Returns current view center.
getZoom() double? Returns current map zoom level.
getBearing() double? Returns current map rotation.
getTilt() double? Returns current camera pitch.
await map?.moveCamera(
  LatLng(13.7649, 100.5383), 
  zoom: 17.0,
  tilt: 60.0,
  bearing: 90.0,
);

7. πŸ” Search & Geocoding #

The Mobile SDK incorporates a fully custom GeocodingProvider interface. It mirrors the exact capabilities of the Web SDK while adding safety boundaries like Debouncing and LRU Caching.

Search Methods #

Method Arguments Description
search() query, location?, lang? Standard one-off search. Checks local LRU Cache first.
searchByCategory() categoryId, location, {dist?, lang?} Searches for places nearby by category ID (e.g. '2100' = Restaurant).
autocompleteDebounced() query, delay, onResult, location? Safe to bind to TextField.onChanged. Custom delay prevents quota burn.
reverseGeocode() location, lang? Converts coordinates into a structured address (PowerMapSearchResult).
clearSearchCache() - Clears the internal LRU cache manually.

Language Detection (lang Parameter) #

The lang parameter controls which search endpoint is used. The demo app automatically detects the language from the query text and passes the appropriate value:

lang value Endpoint When to use
'th' (default) /api/v2/map/address_th Query contains Thai characters only
'en' /api/v2/map/address_en Query contains Latin/English characters only
'mixed' /api/v2/map/address Query contains both Thai and English

Tip

The detection logic in the demo uses Unicode ranges: Thai (U+0E00–U+0E7F) and Latin (U+0041–U+007A). If a query contains both, 'mixed' is passed to use the unified endpoint.

PowerMapSearchResult Model #

Property Type Description
name String Primary title of the location.
address String Full formatted address string.
position LatLng Exact geographic coordinates.
raw Map<String, dynamic> Raw API response if backend schemas change.
// Language is detected automatically in the demo:
String detectLang(String query) {
  final hasLatin = query.runes.any((c) => (c >= 0x41 && c <= 0x5A) || (c >= 0x61 && c <= 0x7A));
  final hasThai  = query.runes.any((c) => c >= 0x0E00 && c <= 0x0E7F);
  if (hasLatin && !hasThai) return 'en';
  if (hasLatin && hasThai)  return 'mixed';
  return 'th';
}

// 1. Forward search with auto-detected lang
final results = await map?.search(query, lang: detectLang(query));

// 2. Debounced Autocomplete (safe for TextField)
map?.autocompleteDebounced(
  query,
  Duration(milliseconds: 500),
  (results) {
    if (results.isNotEmpty) {
      print("Found: ${results.first.name} at ${results.first.position}");
    }
  }
);

// 3. Reverse Geocode (Lat/Lng to Address)
final address = await map?.reverseGeocode(LatLng(14.2558, 100.9810));
if (address != null) {
  print("Address: ${address.name}, ${address.province}");
}

// 4. Category Search (Nearby POIs by type)
final myLocation = await map?.getCurrentLocation();
if (myLocation != null) {
  final restaurants = await map?.searchByCategory('2100', myLocation, dist: 5);
  print("Found ${restaurants?.length} restaurants nearby!");
}

8. πŸ›£οΈ Routing & Optimization (map.routing) #

Calculate logistics-grade paths containing step-by-step metadata.

addRoute() Options #

Option Type Default Description
start LatLng Required Origin coordinate.
destination LatLng Required Final destination coordinate.
waypoints List<LatLng> [] Intended stops between origin and destination.
optimize bool false If true, applies TSP logic to reorder waypoints for efficiency. Minimum 1 waypoint required.
profile String 'driving' Transportation mode: 'driving', 'walking', 'cycling'.
language String 'th' Return instructions in 'th' or 'en'.

PowerMapRouteResult Object #

Property Type Description
distance double Route length in meters.
duration double Estimated seconds en route.
distanceStr String Human-readable (e.g. "5.2 km").
durationStr String Human-readable (e.g. "12 mins").
steps List<PowerRouteStep> Step-by-step turn objects (contains text, distanceStr, location).
geometry List<LatLng> Raw polyline coordinates array.
final route = await map?.routing.addRoute(
  start: LatLng(13.7468, 100.5346),
  destination: LatLng(13.7649, 100.5383),
  optimize: true
);
print("Route calculated: ${route?.distanceStr}");

9. πŸ“ Geometry & Vector Data #

The Mobile SDK provides a robust API for handling GeoJSON data. You can import, render, and retrieve your map features with ease.

πŸ”Œ Geometry API Reference #

Method Arguments Description
getGeoJSON() String? id, Map? opts The primary way to retrieve your data. Returns feature(s) as a Map object.
exportGeometry() String? id, Map? opts Alias for getGeoJSON() for parity with the Web SDK.
addGeoJson() sourceId, geoJsonMap Injects raw GeoJSON into the map source for later styling.
importGeoJson() sourceId, geoJsonMap, ... Injects raw GeoJSON into the map and optionally renders it.
addIndoorExtrusionLayer() sourceId, {layerId} Automatically renders 3D walls using the height property.
addPolygonLayer() sourceId, {layerId} Draws standard 2D shapes (Fills and Outlines). Perfect for Geofences.
addPolylineLayer() sourceId, {layerId} Renders paths and lines with scalable widths (LineString).

πŸ” Code Example: Data Retrieval #

// 1. Get ALL geometry current in the session
final allFeatures = await map?.getGeoJSON();

// 2. Get a SPECIFIC feature by ID with format options
final specificFeature = await map?.getGeoJSON(
  'poi-123', 
  options: { 'format': 'standard' }
);

πŸ“₯ Code Example: Data Ingestion & Layer Creation #

// 1. Prepare your Geometry Data (GeoJSON format: Lng, Lat)
final geofenceData = {
  "type": "Feature",
  "geometry": {
    "type": "Polygon",
    "coordinates": [[
      [100.534, 13.746], [100.538, 13.746], 
      [100.538, 13.749], [100.534, 13.749], 
      [100.534, 13.746] // Must close the loop
    ]]
  }
};

// 2. Inject Data into the Map Source
await map?.geometry.addGeoJson("my-geofence", geofenceData);

// 3. Apply Visual Styles to that Source ID
await map?.geometry.addPolygonLayer(
  "my-geofence",
  fillColor: "#4264fb", 
  fillOpacity: 0.5,
  outlineColor: "#000000"
);

10. 🧭 Real-Time Tracking #

Powered by Geolocator for battery-efficient, high-accuracy GPS positioning. Designed for delivery apps and navigation use cases without burning battery on heavy Dart timers.

Tracking Modes #

Mode Description
TrackingMode.none Camera is unlocked β€” user can pan freely.
TrackingMode.follow Camera follows device location smoothly.
TrackingMode.followWithCompass Camera follows + rotates to match device heading (3D navigation view).

Core Methods #

Method Returns Description
enableFollowMode() Future<void> Locks camera smoothly on device GPS location. Auto-requests permission.
enableFollowModeWithCompass() Future<void> Locks camera + rotates map to match device heading with 3D tilt.
disableFollowMode() Future<void> Unlocks camera, stops GPS stream to conserve battery.
getCurrentLocation() Future<LatLng?> One-shot GPS request. Useful for "My Location" button.
requestPermission() Future<bool> Checks & requests location permission. Returns true if granted.

Usage Examples #

// 1. Follow device location smoothly
await map?.enableFollowMode();

// 2. Navigation mode with compass heading (3D view)
await map?.enableFollowModeWithCompass();

// 3. Stop tracking to save battery
await map?.disableFollowMode();

// 4. One-shot: Get current coordinates
final myLocation = await map?.getCurrentLocation();
if (myLocation != null) {
  print("I'm at: $myLocation");
}

// 5. Listen to position updates reactively
map?.tracking.positionNotifier.addListener(() {
  final pos = map?.tracking.positionNotifier.value;
  if (pos != null) {
    print("Lat: ${pos.latitude}, Lng: ${pos.longitude}");
  }
});

Important

Battery Efficiency: The GPS stream uses distanceFilter: 5 meters β€” updates only fire when the device actually moves β‰₯5m. This prevents unnecessary CPU/battery drain compared to timer-based polling.

Note

Permissions: enableFollowMode() and enableFollowModeWithCompass() automatically request location permissions. You can also call requestPermission() manually during onboarding to pre-ask the user.


11. πŸš— Turn-by-Turn Navigation & Simulation (PowerMapNavigator) #

The SDK includes a fully-featured, 60FPS native-feeling Navigation Engine that maintains parity with the PowerMap Android/Kotlin SDK. It supports real-time GPS driving, dynamic route simulation, smooth 3D camera tracking, and Voice Guidance (TTS).

Core Features #

  • Smooth 3D Tracking: Cinema-grade camera movement (60FPS interpolation) maintaining a 70.0 degree tilt and 19.5 zoom for maximum 3D depth and immersion.
  • High-Performance 2D Symbols: Renders the vehicle using native GL Symbol layers (iconSize: 1.0 with sharp Miter joins) to prevent flickering and guarantee hardware-accelerated drawing.
  • Voice Guidance (TTS): Built-in integration with flutter_tts using the Google Android TTS engine (com.google.android.tts). It intelligently parses VoiceInstruction cues and triggers voice announcements exactly when needed (+20m buffer before maneuvers).
  • HUD Synchronization: Exposes a ValueNotifier<NavigationState> so you can bind any custom Flutter UI (Top Banners, Bottom Boards, Speed Limits) directly to the simulation loop.

Getting Started #

// 1. Initialize the Navigator
final navigator = PowerMapNavigator(controller: mapController);

// 2. Fetch a Route
final route = await mapController.routing.addRoute(
  start: LatLng(13.7468, 100.5346),
  destination: LatLng(13.7649, 100.5383),
  profile: 'driving',
);

// 3. Start Navigation (GPS Mode with Map Matching)
await navigator.startNavigation(route, mode: PowerNavigationMode.gps);

// OR Start Simulation Mode for testing
// await navigator.startNavigation(route, mode: PowerNavigationMode.simulation);

GPS Map Matching (Snap-to-Route) #

When running in PowerNavigationMode.gps, the PowerMap SDK utilizes robust Map Matching (snapToRoute) mathematics. As location updates are received from the physical hardware, the SDK automatically orthogonally projects the coordinates directly onto the geometry of the active route. This perfectly mitigates GPS jitter inside buildings or urban canyons and ensures accurate distance remaining, maneuver detection, and correct triggering of Voice Instructions.

Simulation Controls #

The simulation mode allows you to control the playback of the route for testing and demo purposes:

Method Description
pauseSimulation() Halts the vehicle and camera movement instantly.
resumeSimulation() Resumes movement from the paused position.
setSimulationSpeed(multiplier) Adjusts the playback speed (e.g., 1X, 2X, 3X).
setTracking(bool) Toggles camera tracking to follow the vehicle.
stopNavigation() Kills the ticker, resets camera to Top-Down North (tilt 0), and clears markers.

Vehicle Customization & Interaction #

You can change the color of the navigation arrow on the fly, and even detect when the user taps on it!

// 1. Change vehicle color dynamically (e.g., via a Color Picker)
await navigator.setVehicleColor(Colors.blue);

// 2. Detect when the user taps the moving vehicle icon
navigator.onVehicleTapped = () {
  print("Vehicle icon tapped! Show a menu!");
};

Binding to the UI #

React to real-time navigation changes using the NavigationState object:

ValueListenableBuilder<NavigationState?>(
  valueListenable: navigator.stateNotifier,
  builder: (context, state, child) {
    if (state == null) return const SizedBox.shrink();

    return Column(
      children: [
        Text(state.instructionText),                   // 'Turn left onto Sukhumvit Rd'
        Text('${state.distanceToNextManeuver} m'),     // '500.0 m'
        Text('Speed: ${state.speedMps * 3.6} km/h'),   // Current driven speed
      ],
    );
  },
);

12. 🎨 UI & UX Best Practices #

The Facade Pattern #

For maximum DX, you do not need to dive into individual managers. All primary actions (search, addMarker, addRoute, moveCamera, setLayers, getGeoJSON) are available directly on the PowerMapController instance:

map?.search("Mall");
map?.getGeoJSON("poi-123");
map?.addRoute(...);

13. πŸ›  Build & Development (For Contributors) #

To compile the SDK:

  1. Clone Repository.
  2. flutter pub get.
  3. Check lib/managers/ for logic separation.
  4. Run dart analyze to ensure code meets standards.

14. πŸ›‘οΈ Error Handling System #

The SDK provides a unified PowerMapException class for handling all types of failures. Instead of generic errors, you get specific codes and descriptive messages.

PowerMapException Properties #

Property Type Description
code String Programmatic error code (e.g., NETWORK_ERROR).
message String Human-readable explanation in English.
details dynamic The underlying raw error (Stacktrace or Response body).

Common Error Codes #

Code Triggered By Reason
AUTH_FAILED Any API Missing/Incorrect mapApiKey or clientSecret.
NETWORK_ERROR Any API No internet connection or server unreachable.
STYLE_LOAD_FAILED Map View Failed to load the optimized style JSON.
ROUTE_NOT_FOUND Routing No path exists between the selected points.
SERVER_ERROR Any API Backend returned a 500 error.

Handling Errors in Code #

try {
  final results = await map.search("Siam Paragon");
} on PowerMapException catch (e) {
  if (e.code == PowerMapException.network) {
    print("Please check your connection!");
  } else {
    print("PowerMap Error: ${e.message}");
  }
}

Β© 2026 PowerMap Development Team. All rights reserved.

1
likes
0
points
265
downloads

Publisher

unverified uploader

Weekly Downloads

A comprehensive Flutter SDK for PowerMap, offering location plotting, geometry measurements, layer management, routing, search, and tracking.

Homepage
Repository (GitLab)
View/report issues

License

unknown (license)

Dependencies

flutter, flutter_background_service, flutter_compass, flutter_tts, geolocator, http, maplibre_gl, path_provider

More

Packages that depend on powermap_sdk