dynamic_maps_engine 0.0.7 copy "dynamic_maps_engine: ^0.0.7" to clipboard
dynamic_maps_engine: ^0.0.7 copied to clipboard

A plug-and-play Flutter map engine powered by Google Maps with smooth marker animation and ETA.

dynamic_maps_engine #

Pub Version Platform License: MIT

A robust, plug-and-play Flutter map engine for real-time courier/delivery tracking, with smooth animated markers, automatic rerouting, turn-by-turn voice navigation, and zero-cost routing via OSRM.


Table of Contents #

  1. Features
  2. Installation
  3. Quick Start
  4. DynamicMapWidget Parameters
  5. DynamicMapCubit — Full API Reference
  6. NavigationVoiceService — Full API Reference
  7. MarkerMotionService — Full API Reference
  8. LocationTrackingService — Full API Reference
  9. MapCameraService — Full API Reference
  10. RouteCalculationService — Full API Reference
  11. IconService — Full API Reference
  12. Cost Optimization
  13. Security Note

✨ Features #

Feature Description
🗺️ Plug-and-Play Widget Drop DynamicMapWidget into any screen. No boilerplate.
🎨 Gradient Polyline Route line rendered with smooth color gradient toward destination.
🚗 Smooth Marker Animation Driver icon glides along the route — no jumping or stuttering.
📍 Smart Road Snapping Driver marker stays clamped to the road polyline despite GPS jitter.
🔄 Auto Rerouting Detects off-route movement and recalculates in background.
🎙️ Voice Navigation Turn-by-turn TTS: "In 300 meters, turn right onto Jl. Sudirman"
🔀 Roundabout Support Accurately announces the correct exit number: "Take the 2nd exit"
🆓 Zero-Cost Routing Uses OSRM (OpenStreetMap) by default; falls back to Google Maps.
🔐 Secure API Key API keys are never stored inside the package. You pass them in.
📱 iOS & Android Optimized for both platforms, including background location.

📦 Installation #

For Development (Local Path) #

dependencies:
  dynamic_maps_engine:
    path: ../dynamic_maps_engine

For Production (pub.dev) #

dependencies:
  dynamic_maps_engine: ^0.0.7

🚀 Quick Start #

import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:dynamic_maps_engine/dynamic_maps_engine.dart';

class DeliveryScreen extends StatelessWidget {
  const DeliveryScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: DynamicMapWidget(
        apiKey: 'YOUR_GOOGLE_MAPS_API_KEY',
        origin: const LatLng(-6.200000, 106.816666),
        destination: const LatLng(-6.2100, 106.8200),
        onLocationUpdated: (position) {
          // Send to your backend every GPS tick
          print('Driver: ${position.latitude}, ${position.longitude}');
        },
      ),
    );
  }
}

⚙️ DynamicMapWidget Parameters #

Parameter Type Required Default Description
apiKey String Google Maps API key for map tiles & fallback routing
origin LatLng Starting coordinate (driver's current location)
destination LatLng Destination coordinate (customer address)
onLocationUpdated Function(Position)? null Callback fired on every GPS update
driverIcon BitmapDescriptor? Default pin Custom bitmap for driver marker
destinationIcon BitmapDescriptor? Default pin Custom bitmap for destination marker
enableSimulation bool false Simulate driving along the route (for testing)
simulationSpeedKmh double 40.0 Speed of simulation in km/h

🧠 DynamicMapCubit — Full API Reference #

The central state controller. Manages markers, polylines, camera, voice, and rerouting.

Class Constants #

Constant Type Value Description
offRouteDistance double 40.0 Meters off-route before rerouting is triggered
offRouteThreshold int 3 Consecutive off-route ticks before recalculating
minSpeedForReroute double 0.5 Min speed (m/s) for off-route detection to activate

Constructor Parameters #

DynamicMapCubit({
  required String apiKey,
  BitmapDescriptor? driverIcon,
  BitmapDescriptor? destinationIcon,
  void Function(Position)? onLocationUpdated,
})
Parameter Type Description
apiKey String Google Maps API key
driverIcon BitmapDescriptor? Custom driver marker icon
destinationIcon BitmapDescriptor? Custom destination marker icon
onLocationUpdated Function(Position)? Fired on every real GPS update (use for socket/backend sync)

🟢 Public Methods #

Method Returns Description
initialize({LatLng origin, LatLng destination, GoogleMapController? controller}) Future<void> One-time setup: loads route, sets up markers, starts GPS tracking
selectRoute(int index) void Switch between alternative routes (index from state.availableRoutes)
recalculateRoute() Future<void> Force reroute from current GPS position to existing destination
toggleSimulation(bool enable, {double? speedKmh}) void Start/stop simulation mode. speedKmh defaults to last set value
close() Future<void> Disposes all timers, streams, and voice service. Always call on dispose

🔒 Internal Methods (For Contributors) #

Method Returns Description
_setupMarkers(LatLng currentLocation, LatLng destination) Future<void> Creates driver and destination Marker objects with icons
_calculateAndSetRoute(LatLng start, LatLng end) Future<void> Calls RouteCalculationService, builds polylines, loads voice steps
_generateRoutePolylines(List<RouteData> routes, int selectedIndex) Set<Polyline> Builds all route polylines — selected route bold, alternatives faded
_buildGradientPolylines(List<LatLng> points) Set<Polyline> Segments route into color-graded sections (green → red gradient)
_startLocationTracking() void Starts LocationTrackingService stream and binds _handleLocationUpdate
_handleLocationUpdate(Position position, {bool forceUpdate}) void Entry point for GPS updates: saves raw GPS, triggers marker animation and onLocationUpdated callback
_updateDriverMarker(LatLng position, double bearing, int routeIndex) void Updates marker position & bearing; trims polyline to remaining route; recalculates live ETA
_startRerouteCheck() void Starts a 2-second periodic timer that calls _checkOffRoute
_checkOffRoute() void Measures driver distance from route polyline; increments _offRouteCount and calls recalculateRoute when threshold reached

State Fields (DynamicMapState) #

Field Type Description
markers Set<Marker> All visible map markers
polylines Set<Polyline> Currently drawn polylines (remaining route)
currentLocation LatLng? Latest known driver position
destinationLocation LatLng? Target destination
currentBearing double Current heading in degrees (0–360)
currentSpeed double Smoothed speed in km/h (8-sample average)
routeDistance String Remaining distance ("2.3 km")
routeDuration String Remaining ETA ("7 min")
routingEngine String "OSRM (Free)" or "Google Maps (Paid)"
isRerouting bool True while recalculating route
isSimulating bool True when simulation mode is active
availableRoutes List<RouteData> All calculated route alternatives
selectedRouteIndex int Index of active route

🎙️ NavigationVoiceService — Full API Reference #

Handles all turn-by-turn navigation logic: step detection, voice announcements, distance calculation.

🟢 Public Getters #

Getter Type Description
isNavigating bool Whether navigation is currently active
currentInstruction String? Instruction for the current active step (e.g. "Turn right")
nextInstruction String? Instruction for the next upcoming step
currentManeuverIcon String? Icon name for current maneuver (e.g. "turn_right")
nextManeuverIcon String? Icon name for upcoming maneuver
currentSpeed double Last known speed in km/h
nextStepDistance double Distance to end of current step in meters
remainingDistance double Total remaining distance (meters) to destination
remainingDuration double Estimated remaining duration in seconds
formattedRemainingDistance String Human readable: "1.2 km" or "850 m"
formattedRemainingDuration String Human readable: "5 min" or "1 hr 12 min"
currentSteps List<NavigationStep> All loaded navigation steps
currentStep NavigationStep? Currently active step object
roundaboutExit int? Exit number if current step is a roundabout

🟢 Public Methods #

Method Returns Description
startNavigation(List<Map<String, dynamic>> stepsData) Future<void> Loads step data, initializes TTS engine, sets first instruction
updatePosition(Position position) void Main update loop. Feed GPS positions here; handles step advancement and voice triggers
getManeuverIcon(String instruction, {String? maneuver}) String Returns icon name string for a given maneuver type or instruction text
dispose() void Stops TTS, cancels timers, clears all state

🔒 Internal Methods (For Contributors) #

Method Returns Description
_initializeTts() Future<void> Sets up flutter_tts engine: language (id-ID), pitch, rate, volume. Must be awaited before any speech.
_updateDisplayInstructions() void Refreshes _currentInstruction, _nextInstruction, _currentManeuverIcon, _nextManeuverIcon from current step index. Called after every step change.
_moveToNextStep() void Advances _currentStepIndex by 1, resets warning flags, calls _updateDisplayInstructions()
_snapToClosestStep(Position position) void If driver position is closest to a later step (not current), jumps _currentStepIndex forward. Prevents stuck navigation on wrong step.
_checkNavigationProgress(Position position) void Core logic: checks distance to step end, fires 300m/20m voice warnings, advances to next step when arrived
_calculateDistanceAlongPolyline(LatLng position, List<LatLng> polyline) double Calculates remaining meters along a step's polyline (not straight-line), for accurate ETA
_roundDistanceForSpeech(double meters) int Rounds distance to nearest 50m or 100m for clean voice output ("In 300 meters", not "In 287 meters")
_cleanHtmlInstruction(String html) String Strips HTML tags from Google Maps instructions (<b>, <div>, etc.)
Field Type Description
instruction String Cleaned human-readable instruction
distance double Step distance in meters
duration double Step duration in seconds
startLat / startLng double Coordinate of step start
endLat / endLng double Coordinate of step end
maneuver String? Raw maneuver type ("turn-right", "roundabout", etc.)
roundaboutExit int? Exit number for roundabouts (1 = first exit)
polylinePoints List<LatLng> All coordinates along this step's path
isRoundabout bool Shortcut: maneuver?.contains('roundabout') == true
formattedDistance String Human readable distance ("300m", "1.2km")
formattedDuration String Human readable duration ("2 min")

🚗 MarkerMotionService — Full API Reference #

Smoothly animates a map marker from one position to another using frame-by-frame interpolation.

🟢 Public Getters #

Getter Type Description
bearing double Current heading angle in degrees (0–360)
currentPosition LatLng? Current interpolated marker position
currentRouteIndex int Current index in the route polyline

🟢 Public Methods #

Method Returns Description
setRoutePoints(List<LatLng> points) void Sets the full route polyline for snapping and simulation
reset() void Resets all position, bearing, and index state
injectPosition(LatLng position, double bearing) void Force-sets position without animation (used when teleporting)
moveTo({required LatLng target, required Function(LatLng, double, int) onUpdate, double? initialBearing, double? heading}) void Animate marker to target. onUpdate called each frame with (position, bearing, routeIndex)
startSimulation(Function(LatLng, double, int) onUpdate, {double speedKmh, bool fromBeginning}) void Begins automatic route simulation at given speed. Calls onUpdate at ~25fps
stopSimulation() void Stops simulation timer
dispose() void Cancels all timers and cleans up resources

🔒 Internal Methods (For Contributors) #

Method Returns Description
_moveAlongRoute(LatLng target, Function onUpdate) void When route points exist, snaps to nearest route point and animates along road polyline
_smoothMove(LatLng target, Function onUpdate) void Fallback animation when no route points set — interpolates in straight line
_findNearestRoutePoint(LatLng position) int Returns index of closest route point to given position
_moveTowards(LatLng current, LatLng target, double distanceMeters) LatLng Moves distanceMeters from current toward target along great circle
_destinationPoint(LatLng start, double distance, double bearing) LatLng Calculates destination given start point, distance (m), and bearing
_lerp(LatLng a, LatLng b, double t) LatLng Linear interpolation between two coordinates (t = 0.0 to 1.0)
_calculateBearing(LatLng start, LatLng end) double Calculates compass bearing between two GPS points in degrees
_blendBearing(double current, double target, double factor) double Smoothly blends bearing to avoid 359°→1° flipping artifacts
_distanceInMeters(LatLng a, LatLng b) double Haversine distance between two points in meters

📡 LocationTrackingService — Full API Reference #

Wraps Geolocator to provide filtered, platform-optimized GPS streams.

🟢 Public Getters #

Getter Type Description
isTracking bool Whether tracking is currently active

🟢 Public Methods #

Method Returns Description
getCurrentPosition({LocationAccuracy accuracy}) Future<Position?> One-shot: gets current GPS fix. Returns null on failure.
getLastKnownPosition() Future<Position?> Returns last cached GPS position (fast, may be stale)
startTracking({required Function(Position) onPositionUpdate, Duration? interval, bool useStream}) void Start continuous GPS tracking. Always uses stream mode (recommended).
pauseTracking() void Temporarily stops the position stream without clearing state
resumeTracking() void Resumes a paused stream
stopTracking() void Fully stops tracking and clears all listeners
updateLocationSettings({int? interval, double? distanceFilter}) Future<void> Hot-update GPS interval and distance filter without restarting
dispose() void Stops tracking and releases all resources

🔒 Internal Methods (For Contributors) #

Method Returns Description
_startStreamTracking(Function(Position) onPositionUpdate) void Subscribes to Geolocator.getPositionStream() with distanceFilter: 0. All positions filtered by _shouldUpdate()
_startTimerTracking(Function(Position) onPositionUpdate, Duration interval) void Alternative: polls getCurrentPosition() on a timer. Used only if useStream: false
_shouldUpdate(Position newPosition) bool Returns true if driver moved >2m (iOS) / >3m (Android) OR >8s (iOS) / >10s (Android) since last update

Platform Defaults #

Setting iOS Android
Distance threshold 2.0 m 3.0 m
Time threshold 8 seconds 10 seconds
GPS update interval ~1s (system) ~1s (system)

📷 MapCameraService — Full API Reference #

Controls Google Map camera behavior: following driver, fitting route, manual mode.

Camera Modes #

Mode Enum Description
Following CameraMode.following Camera locks to driver, rotates with bearing
Center CameraMode.center Camera centers on driver, no rotation
AutoFit CameraMode.autoFit Camera zooms out to show full route
Manual CameraMode.manual User is panning — camera unlocked

🟢 Public Properties #

Property Type Description
currentZoom double Current map zoom level (default: 17.5)
isProgrammaticMove bool True while the engine is animating the camera (ignore user-pan events)
isFollowing bool True when mode is CameraMode.following
isCenter bool True when mode is CameraMode.center
isAutoFit bool True when mode is CameraMode.autoFit

🟢 Public Methods #

Method Returns Description
setController(GoogleMapController controller) void Binds the GoogleMapController after map is created
setMode(CameraMode mode) void Switch camera mode
activateManualMode({Duration? autoResetDuration}) void Lock camera to manual (user panning). Auto-resets to following after autoResetDuration (default: 10s)
followUser(Position position, {bool isSimulating}) Future<void> Animate camera to follow driver with tilt and bearing. Uses animateCamera.
centerToLocation(LatLng location, {double zoom}) Future<void> Move camera to a fixed location at given zoom
fitToRoute(LatLng start, LatLng destination, {bool isSimulating}) Future<void> Fit camera to show entire route between two points
fitBoundsWithPadding(LatLng start, LatLng end, {bool isRerouting}) Future<void> Fit camera to bounds with adaptive padding
droneArrival(Position position) Future<void> Cinematic arrival animation: zoom in, tilt down, rotate to face destination

🔒 Internal Methods (For Contributors) #

Method Returns Description
_smoothFitBounds(LatLng start, LatLng end, double padding, {bool isSimulating}) Future<void> Calculates LatLngBounds and calls animateCamera with padding
_getOptimalPadding(double distanceInMeters, {bool isRerouting}) double Returns padding value (30–120) scaled to route length

🗺️ RouteCalculationService — Full API Reference #

Calculates routes using OSRM (free) with automatic Google Maps Directions API fallback.

Constructor #

RouteCalculationService({required String apiKey})

🟢 Public Methods #

Method Returns Description
calculateRoutes(LatLng origin, LatLng destination) Future<List<RouteData>> Calculates all available routes (with alternatives). Tries OSRM → Google Maps → Fallback.
calculateRoute(LatLng origin, LatLng destination) Future<RouteData> Convenience: returns first (best) route from calculateRoutes
calculateDistance(LatLng point1, LatLng point2) double Haversine distance in meters between two points

🔒 Internal Methods (For Contributors) #

Method Returns Description
_parseDirectionsResponseMulti(Map data) List<RouteData> Parses full Google Maps Directions API JSON response into list of RouteData
_getAlternativeRoute(LatLng origin, LatLng destination) Future<RouteData?> Calls OSRM route/v1/driving/ API and parses geometry + steps into RouteData
_getFallbackRoute(LatLng origin, LatLng destination) RouteData Offline fallback: generates a grid-based straight-line route estimate
_generateGridBasedRoute(LatLng origin, LatLng destination) List<LatLng> Generates a 2-segment curved approximation of the path
_addIntermediatePoints(List<LatLng> points, LatLng start, LatLng end, int count) void Inserts count evenly-spaced points between start and end
_decodePolyline(String encoded) List<LatLng> Decodes Google Maps encoded polyline string into coordinate list
_estimateDistance(LatLng start, LatLng end) double Estimates driving distance (km) from straight-line × 1.25 factor
_estimateDuration(LatLng start, LatLng end) int Estimates duration (minutes) assuming average 30 km/h

Routing Flow #

calculateRoutes()
       │
       ▼
 Try Google Maps (paid) ──(OK)──▶ _parseDirectionsResponseMulti() ──▶ return routes
       │
    (fail / empty API key)
       │
       ▼
 Try OSRM (free) ──────(OK)──▶ parse geometry + steps ──▶ return route
       │
    (fail)
       │
       ▼
 _getFallbackRoute() ────────────▶ grid estimate ──▶ return offline route

RouteData Fields #

Field Type Description
points List<LatLng> Full polyline coordinates
duration String Human readable ETA ("7 min")
distance String Human readable distance ("2.3 km")
steps List<Map<String, dynamic>> Turn-by-turn instruction steps
routingEngine String "OSRM (Free)" or "Google Maps (Paid)"

Step Map Keys #

Key Type Description
instruction String Cleaned instruction text
distance num Step distance in meters
duration num Step duration in seconds
polyline String Encoded polyline string (Google) or empty (OSRM)
start_lat / start_lng double Step start coordinate
end_lat / end_lng double Step end coordinate
maneuver String? Maneuver type ("turn-right", "roundabout", etc.)
roundaboutExit int? Exit number for roundabout steps (OSRM only)

🖼️ IconService — Full API Reference #

Pre-loads and caches custom bitmap icons for use as Google Maps markers.

🟢 Static Methods #

Method Returns Description
preloadDriverIcon({Color color}) Future<void> Pre-renders driver chevron icon in given color. Default: Colors.blue
getDriverIcon() BitmapDescriptor Returns pre-loaded driver icon. Falls back to blue default pin if not preloaded.
getUserLocationIcon() BitmapDescriptor Returns user location dot icon
getDestinationIcon() BitmapDescriptor Returns destination icon. Falls back to green default pin.
getRealGpsIcon() BitmapDescriptor Returns raw GPS position indicator (debug use)
getConnectionDotIcon() BitmapDescriptor Returns animated connection status dot
getTurnArrowIcon() BitmapDescriptor Returns turn arrow icon for navigation overlay

🔒 Internal Methods (For Contributors) #

Method Returns Description
_createDriverChevron({Color color, double size}) Future<BitmapDescriptor> Renders a canvas-drawn chevron shape as a bitmap at given size pixels
_createUserLocationIcon({Color color}) Future<BitmapDescriptor> Renders a pulsing dot icon for user location indicator
_createConnectionDot() Future<BitmapDescriptor> Renders a small dot icon for connection status overlay
_createTurnArrow() Future<BitmapDescriptor> Renders a turn arrow for navigation UI overlay

Usage Example #

// In your init (before opening map screen)
await IconService.preloadDriverIcon(color: Colors.blue);

// Pass to DynamicMapWidget or DynamicMapCubit
DynamicMapCubit(
  apiKey: key,
  driverIcon: IconService.getDriverIcon(),
  destinationIcon: IconService.getDestinationIcon(),
)

💰 Cost Optimization #

By default, routing uses OSRM (100% free, OpenStreetMap). Only falls back to Google Maps Directions API (paid) when OSRM is unavailable.

Service Google Maps API Cost OSRM (This Package) Cost Savings
Routing / Directions ~$5.00 / 1000 requests $0.00 100%
Turn-by-turn Steps Included in Directions $0.00 100%
Map Tiles Rendering ~$7.00 / 1000 loads Normal GMap Cost
Geocoding ~$5.00 / 1000 requests Use OSM Nominatim ~95%+

🔐 Security Note #

This package never reads .env files internally. Always pass your apiKey from your application's own secure environment setup.

// ✅ Correct
DynamicMapWidget(apiKey: dotenv.env['GOOGLE_MAPS_KEY']!, ...)

// ❌ Never hardcode
DynamicMapWidget(apiKey: 'AIzaSy...', ...)

📝 License #

MIT License © 2024 Rayhan Rwa

1
likes
0
points
835
downloads

Publisher

unverified uploader

Weekly Downloads

A plug-and-play Flutter map engine powered by Google Maps with smooth marker animation and ETA.

Repository (GitHub)
View/report issues

License

unknown (license)

Dependencies

flutter, flutter_bloc, flutter_dotenv, flutter_tts, geolocator, google_maps_flutter, http, location, logger

More

Packages that depend on dynamic_maps_engine