vietmap_flutter_gl 4.1.1 copy "vietmap_flutter_gl: ^4.1.1" to clipboard
vietmap_flutter_gl: ^4.1.1 copied to clipboard

A Flutter map plugin for integrating Vietmap sdk inside a Flutter application, support for show a vector and raster map in Flutter. Supported on Android, iOS platforms .

Vietmap Flutter GL - Flutter map SDK #

Follow the instructions at Map API Docs to register a valid key.

Getting started #

Add library to pubspec.yaml file

  vietmap_flutter_gl: latest_version

Check the latest version at https://pub.dev/packages/vietmap_flutter_gl

or run this command in the terminal to add the library to the project:

  flutter pub add vietmap_flutter_gl

Android config #

Add the below code to the build.gradle (project) file at path: android/build.gradle

 maven { url "https://jitpack.io" }

at the repositories block


  allprojects {
      repositories {
          google()
          mavenCentral()
          maven { url "https://jitpack.io" }
      }
  }

Upgrade the minSdkVersion to a minimum of 24 in the build.gradle (app) file, at path android/app/build.gradle

  minSdkVersion 24

iOS config #

Add the code below to the Info.plist file.

  <key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
  <string>Your request location description</string>
  <key>NSLocationAlwaysUsageDescription</key>
  <string>Your request location description</string>
  <key>NSLocationWhenInUseUsageDescription</key>
  <string>Your request location description</string>

Upgrade min ios version to 12.0 in the Podfile (iOS) file, at path ios/Podfile (uncomment the line below)

  platform :ios, '12.0' 

In your terminal, cd to the ios folder and run the command below to install the pod file (you can skip this step if you only build for Android or run the app on the Windows/Linux PC)

  cd ios && pod install && cd ..
  • If the project shows an issue when upgrading to the new version when running the pod install command, please remove the ios/.symlinks, ios/Pods folders, and Podfile.lock file, then run the below command to update the pod file.
  pod install --repo-update

Main characteristics #

Show the map #

    VietmapGL(
      styleString:
          'https://maps.vietmap.vn/maps/styles/tm/style.json?apikey=YOUR_API_KEY_HERE',
      initialCameraPosition:
          CameraPosition(target: LatLng(10.762317, 106.654551), zoom: 14),
      onMapCreated: (VietmapController controller) {
          setState(() {
            _mapController = controller;
          });
        },
    );

Change map style #

Style Description URL
Vector Default The default style for VIETMAP maps, suitable for general use. https://maps.vietmap.vn/maps/styles/tm/style.json?apikey=YOUR_API_KEY_HERE
Vector Light A lighter version of the default style, optimized for readability in bright conditions. https://maps.vietmap.vn/maps/styles/lm/style.json?apikey=YOUR_API_KEY_HERE
Vector Dark A dark-themed style for better visibility in low-light conditions. https://maps.vietmap.vn/maps/styles/dm/style.json?apikey=YOUR_API_KEY_HERE
  • To change the map style, you need to get the style URL from Vietmap and use the setStyle function.
  _mapController?.setStyle(
      "https://maps.vietmap.vn/maps/styles/tm/style.json?apikey=YOUR_API_KEY_HERE");
  • You can also keep/remove the annotations on the map with input params keepExistingAnnotations. (This function did not remove annotations inside the MarkerLayer and StaticMarkerLayer)
  _mapController?.setStyle(
      "https://maps.vietmap.vn/maps/styles/tm/style.json?apikey=YOUR_API_KEY_HERE",
      keepExistingAnnotations: true);

VIETMAP now provides many types of custom maps, including Vector, Satellite, and Hybrid maps. More information about the types of maps can be found below:

https://maps.vietmap.vn/docs/map-api/tilemap/#vietmap-maps-sdk-integration

Read more about Vector

Email us to get the Satellite and Hybrid map style URL.

Map Interactions #

The VietmapGL Maps Flutter SDK allows you to define interactions that you can activate on the map to enable gestures and click events. The following interactions are supported

Zoom Controls

The map supports the familiar two-finger pinch and zooms to change the zoom level as well as double tap to zoom in. Set zoom to 4 for country-level display and 18 for house number display. In this SDK the camera position plays an important role

And following operations can be performed using the CameraPosition

Target

The target is a single latitude and longitude coordinate that the camera centers it on. Changing the camera's target will move the camera to the inputted coordinates. The target is a LatLng object. The target coordinate is always at the center of the viewport.

Tilt

Tilt is the camera's angle from the nadir (directly facing the Earth) and uses unit degrees. The camera's minimum (default) tilt is 0 degrees, and the maximum tilt is 60. Tilt levels use six decimal points of precision, which enables you to restrict/set/lock a map's bearing with extreme precision.

The map camera tilt can also adjust by placing two fingertips on the map and moving both fingers up and down in parallel at the same time or

Bearing

Bearing represents the direction that the camera is pointing in and is measured in degrees clockwise from north.

The camera's default bearing is 0 degrees (i.e. "true north") causing the map compass to hide until the camera bearing becomes a non-zero value. Bearing levels use six decimal point precision, which enables you to restrict/set/lock a map's bearing with extreme precision. In addition to programmatically adjusting the camera bearing, the user can place two fingertips on the map and rotate their fingers.

Zoom

Zoom controls the scale of the map and consumes any value between 0 and 22. At zoom level 0, the viewport shows continents and other world features. A middle value of 11 will show city-level details. At a higher zoom level, the map will begin to show buildings and points of interest. The camera can zoom in the following ways:

  • Pinch motion two fingers to zoom in and out.
  • Quickly tap twice on the map with a single finger to zoom in.
  • Quickly tap twice on the map with a single finger and hold your finger down on the screen after the second tap.
  • Then slide the finger up to zoom out and down to zoom in.
SDK allows various methods to move, and animate the camera to a particular location :
  _mapController?.moveCamera(CameraUpdate.newLatLngZoom(LatLng(22.553147478403194, 77.23388671875), 14));  
  _mapController?.animateCamera(CameraUpdate.newLatLngZoom(LatLng(28.698791, 77.121243), 14));  

Eased camera animations

animateCamera always eases in and out. That looks right for a one-off jump, but wrong for a camera that follows the user: every animation decelerates before the next one starts, so a stream of updates turns into a visible stutter once per update.

easeCamera lets you pick the curve instead:

await _mapController?.easeCamera(
  CameraUpdate.newLatLng(currentLocation),
  duration: const Duration(seconds: 1),
  interpolation: CameraAnimationInterpolation.linear,
);

CameraAnimationInterpolation has four values:

Value Use it for
linear Follow-the-user loops - constant velocity, no stutter between calls
easeInOut Same feel as animateCamera (the default when interpolation is omitted)
easeOut Arriving at a destination
fastOutLinearIn Leaving the current position quickly

Returns true when the animation ran to completion and false when it was cancelled - for example because the user panned the map mid-animation.

Android: only linear is distinct. The native SDK exposes a boolean rather than a curve, so easeOut and fastOutLinearIn fall back to the platform ease-in/ease-out. All four are distinct on iOS.

Take a map snapshot #

takeSnapshot() renders the map to PNG bytes:

final Uint8List bytes = await _mapController!.takeSnapshot();

// ... or at a specific size, in logical pixels:
final Uint8List thumbnail =
    await _mapController!.takeSnapshot(width: 400, height: 300);

// The result is a plain PNG, so it drops straight into Image.memory:
Image.memory(bytes);

When width and height are given the map is re-rendered offscreen at that size, keeping the current camera position and style.

Two things to know before using it:

  • Runtime additions are not included. The offscreen renderer re-fetches the style from its URL, so annotations, layers added through addLayer and images registered with addImage are absent - only what the style file itself defines is drawn.
  • It throws a PlatformException if the style has not finished loading. Call it from onStyleLoadedCallback or later.

Not implemented on web.

Map Events #

Map Click/Long click #

If you want to respond to a user tapping on a point on the map, you can use an onMapClick callback.

It sets a callback that's invoked when the user clicks on the map:

  VietmapGL(    
    initialCameraPosition: _kInitialPosition,    
    onMapClick: (point, latlng) {    
      print(latlng.toString());  
    }, 
  )  
Sets a callback that's invoked when the user long clicks on the map view.
  VietmapGL(    
    initialCameraPosition: _kInitialPosition,    
    onMapLongClick: (point, latlng) {    
      print(latlng.toString());  
    }, 
  )  
Sets a callback that's invoked when the map is completely rendered.
Encourage this callback to call some action on the initial, after the map is completely loaded
  VietmapGL(    
    initialCameraPosition: _kInitialPosition,    
    onMapRenderedCallback: () {
              _mapController?.animateCamera(CameraUpdate.newCameraPosition(
                  CameraPosition(
                      target: LatLng(10.739031, 106.680524),
                      zoom: 10,
                      tilt: 60)));
      },
    )  

Camera move #

onCameraMove fires continuously while the camera is moving - on gestures and on programmatic animations alike.

  VietmapGL(
    initialCameraPosition: _kInitialPosition,
    // Required. Without it the SDK skips computing the camera position on every
    // frame, and onCameraMove never fires.
    trackCameraPosition: true,
    onCameraMove: (CameraPosition position) {
      print('${position.target} @ zoom ${position.zoom}');
    },
  )

Use onCameraIdle instead if you only need the final position - onCameraMove runs once per frame, so keep the callback cheap.

Feature hover (web only) #

Layers registered with enableInteraction: true report pointer hover through VietmapController.onFeatureHover. Android and iOS have no pointer-hover concept and never fire it.

  void _onHover(dynamic id, Point<double> point, LatLng coordinates,
      String layerId, HoverEventType eventType) {
    switch (eventType) {
      case HoverEventType.enter:  // pointer entered a feature
      case HoverEventType.move:   // pointer moved within the same feature
      case HoverEventType.leave:  // pointer left the feature
    }
  }

  void _onMapCreated(VietmapController controller) {
    controller.onFeatureHover.add(_onHover);
  }

  @override
  void dispose() {
    _controller?.onFeatureHover.remove(_onHover);
    super.dispose();
  }

id is the feature id. To get your own identifier back, promote it when adding the source:

  await controller.addGeoJsonSource('points', featureCollection, promoteId: 'id');
  await controller.addCircleLayer('points', 'circles', properties,
      enableInteraction: true);

Map Overlays #

Add marker (Marked a point in the map with a custom widget) #

  • We provide two types of markers, the first is a simple marker, and the second is a static marker. The simple marker will not rotate when the map rotates, and the static marker will rotate with the map.
drawing

Add a simple marker (Marked a point in the map with a custom widget, the marker will not rotate when the map rotates) #

  • The marker support anchor with input is an alignment, which requires width and height to calculate the position of the marker, the default for both of them is 20
  • Make sure the width and height of the marker match with its child's width and height to the marker display exactly
  Stack(
    children: [
      VietmapGL(
        trackCameraPosition: true, // Will track the map change to update the marker position in realtime
        ...
      ),
      MarkerLayer(
        ignorePointer: true, // Will ignore all user gestures on the marker
        mapController: _mapController!,
        markers: [
              Marker(
                  child: Container(
                    width: 50,
                    height: 50,
                    decoration: BoxDecoration(
                        color: Colors.red,
                        shape: BoxShape.circle),
                    child: Center(
                      child: Text(
                        'Simple text marker',
                        style: TextStyle(
                            color: Colors.white,
                            fontSize: 20,
                            fontWeight: FontWeight.bold),
                      ),
                    ),
                  ),
                  latLng: LatLng(10.727416, 106.735597)),
              Marker(
                  child: Icon(Icons.location_on),
                  latLng: LatLng(10.792765, 106.674143)),
        ])
  ])
    

Add a static marker (Marked a point in the map with a custom widget, the marker will rotate with the map) #

  • The static marker supports rotation with input as a bearing, you can find this value when getting GPS location.

  • We recommend using this marker for location-based applications, tracking the location of the driver. Then the driver's vehicle will rotate in the right direction even when the user rotates the map at any angle.

  Stack(
    children: [
      VietmapGL(
        trackCameraPosition: true, // Will track the map change to update the marker position in realtime
        ...
        ),
      StaticMarkerLayer(
        ignorePointer: true,
        mapController: _mapController!,
        markers: [
          StaticMarker(
            width: 50,
            height: 50,
            bearing: 0,
            child: Container(
              width: 50,
              height: 50,
              child: Icon(Icons.arrow_downward_rounded)),
            latLng: LatLng(10.736657, 106.672240)),
          ]),
  ])

Cluster Marker (Group multiple markers into a single marker) #

  • The cluster marker will group multiple markers into a single marker when they are close to each other, and the number of markers is defined in the customClusterWidget value.
  • The cluster marker will show the number of markers inside it, and you can customize the cluster marker with the customClusterWidget value. The key of the customClusterWidget is the number of markers inside the cluster marker, and the value is the widget that you want to show. It will find the nearest (round down) number of markers inside the cluster marker to show the widget. You should provide the widget for the number of markers from the smallest (2 is the smallest).
  ClusterLayer(
      customClusterWidget: {
        5: Container(
          width: 50,
          height: 50,
          decoration: BoxDecoration(
            color: Colors.red,
            shape: BoxShape.circle,
          ),
          alignment: Alignment.center,
        ),
        3: Container(
          width: 50,
          height: 50,
          decoration: BoxDecoration(
            color: Colors.green,
            shape: BoxShape.circle,
          ),
          alignment: Alignment.center,
        ),
        2: Container(
          width: 50,
          height: 50,
          decoration: BoxDecoration(
            color: Colors.blue,
            shape: BoxShape.circle,
          ),
          alignment: Alignment.center,
        )
      },
      ignorePointer: true,
      clusterTextStyle: TextStyle(
        color: Colors.white,
        fontSize: 20,
      ),
      mapController: _mapController!,
      markers: [
        Marker(
            width: 50,
            height: 50,
            child: Icon(Icons.arrow_upward_rounded),
            latLng: LatLng(10.759305, 106.675912)),
        Marker(
            width: 50,
            height: 50,
            child: Icon(Icons.arrow_upward_rounded),
            latLng: LatLng(10.769305, 106.685912)),
        Marker(
            width: 50,
            height: 50,
            child: Icon(Icons.arrow_upward_rounded),
            latLng: LatLng(10.749305, 106.665912)), 
      ]),

Show User Location #

  • To show the user's location on the map, you need to enable the myLocationEnabled property in the VietmapGL widget.
  myLocationEnabled: true,
  myLocationTrackingMode: MyLocationTrackingMode.TrackingCompass,
  myLocationRenderMode: MyLocationRenderMode.COMPASS,
  • Custom user location icon as below:

The bearing icon is the icon that shows the direction of the user's location, you can customize it with the bearingIcon property.

Add the below code to the Stack which contains the VietmapGL and other MarkerLayer widgets to show the user's location on the map.

  _mapController == null
    ? SizedBox.shrink()
    : UserLocationLayer(
        mapController: _mapController!,
        locationIcon: Icon(
          Icons.circle,
          color: Colors.blue,
          size: 50,
        ),
        bearingIcon: Container(
          width: 30,
          height: 30,
          alignment: Alignment.center,
          decoration: BoxDecoration(
              shape: BoxShape.circle, color: Colors.white),
          child: Icon(
            Icons.arrow_upward,
            color: Colors.red,
            size: 15,
          ),
        ),
        ignorePointer: true,
      ),

Note: You must enable trackCameraPosition: true, at _VietmapGL, which ensures the MarkerLayer renders normally

Add a Line/Polyline (A line connects 2 points on the map) #

    Line? line = await _mapController?.addPolyline(
      PolylineOptions(
          geometry: [
            LatLng(10.736657, 106.672240),
            LatLng(10.766543, 106.742378),
            LatLng(10.775818, 106.640497),
            LatLng(10.727416, 106.735597),
            LatLng(10.792765, 106.674143),
            LatLng(10.736657, 106.672240),
          ],
          polylineColor: Colors.red,
          polylineWidth: 14.0,
          polylineOpacity: 0.5),
    );

Update polyLine #

      _mapController?.updatePolyline(
        line,
        PolylineOptions(
            geometry: [
              LatLng(10.736657, 106.672240),
              LatLng(10.766543, 106.742378),
              LatLng(10.775818, 106.640497),
              LatLng(10.727416, 106.735597),
              LatLng(10.792765, 106.674143),
              LatLng(10.736657, 106.672240),
            ],
            polylineColor: Colors.blue,
            polylineWidth: 14.0,
            polylineOpacity: 1,
            draggable: true),
      );

Remove a Polyline #

    _mapController?.removePolyline(line);  

Remove all Polyline #

    _mapController?.clearPolylines();

Add a Fill/Polygon #

    Polygon? polygon = await _mapController?.addPolygon(
      PolygonOptions(
          geometry: [
            [
              LatLng(10.736657, 106.672240),
              LatLng(10.766543, 106.742378),
              LatLng(10.775818, 106.640497),
              LatLng(10.727416, 106.735597),
              LatLng(10.792765, 106.674143),
              LatLng(10.736657, 106.672240),
            ]
          ],
          polygonColor: Colors.red,
          polygonOpacity: 0.5,
          draggable: true),
    );

Update Polygon #

      _mapController?.updatePolygon(
        polygon,
        PolygonOptions(
            geometry: [
              [
                LatLng(10.736657, 106.672240),
                LatLng(10.766543, 106.742378),
                LatLng(10.775818, 106.640497),
                LatLng(10.727416, 106.735597),
                LatLng(10.792765, 106.674143),
                LatLng(10.736657, 106.672240),
              ]
            ],
            polygonColor: Colors.blue,
            polygonOpacity: 1,
            draggable: true),
      );

Remove a Polygon #

      _mapController?.removePolygon(polygon);  

Remove all Polygon #

    _mapController?.clearPolygons();

Find a route between 2 or more points #

  • We've created a package to support finding a route between 2 or more points and other features, you can find the vietmap_flutter_plugin to use it.
  • Run this command in the terminal to add the library to the project:
  flutter pub add vietmap_flutter_plugin
  • Example code:
  List<LatLng> points = [];
  /// Get the route between 2 points
  var routingResponse = await Vietmap.routing(VietMapRoutingParams(points: [
    const LatLng(21.027763, 105.834160),
    const LatLng(21.027763, 105.834160)
  ]));

  /// Handle the response
  routingResponse.fold((Failure failure) {
    // handle failure here
  }, (VietMapRoutingModel success) {
    // handle success here
    points = success.paths?.first.points ?? [];
  });

  /// Draw the route on the map
  Line? line = await _mapController?.addPolyline(
    PolylineOptions(
        geometry: points,
        polylineColor: Colors.red,
        polylineWidth: 14.0,
        polylineOpacity: 0.5),
  );

Route simulator #

  • We've created a class for simulating the route from the list of points, you can find the RouteSimulator class in this example code.
  • Please change the upperBound, duration, and speed to get the best experience for the simulator.
  • Do not repeat the simulator too quickly and too often, it will make the app lag.
drawing
  • Example code:
  /// Decode the polyline to list of LatLng
  var latLngList = VietmapPolylineDecoder.decodePolyline(
      '}s{`Ac_hjSjAkCFQRu@Lu@F_@D]Ng@ZaALa@JY~AoDDEmBiBe@[WMg@M_@KmA]uA_@a@KkA]qA[[Gs@MUE_AKu@Co@Ew@CYAmAGeBKaAEsAKCQMQUGM?KBIFGHCJoBO{@Ck@AQ@MZAJAjAG|ACz@MnCEnAGlBCx@EjA?\\EvAEjBE~@Cr@F?HqBv@DBSDIBAl@HFADAVSD@JLB@h@BDADEDAJ@',
      false); 

  List<LatLng> listData = [];
  Line? lineDrive; 
  /// Create the simulator
  RouteSimulator routeSimulator =
      RouteSimulator(
      latLngList, this,
      duration: Duration(seconds: 15), 
      repeat: false);

  /// Add the polyline to the map
  lineDrive = await _mapController?.addPolyline(PolylineOptions(
    geometry: latLngList,
    polylineColor: Colors.black,
    polylineWidth: 2.0,
  ));
  routeSimulator.addV2Listener(
      (LatLng? latLng, int? index, double? distance, LatLng? previousLatLng) =>
          this.setState(() {
            /// Clear old data
            listData.clear();
            int i = 0;
            /// Find the current route from list of points
            listData = latLngList.where((element) {
              return i++ <= index!;
            }).toList();
            if (previousLatLng != null) {
              _busBearing =
                  VietmapPolyline.calculateFinalBearing(previousLatLng, latLng);
            }
            if (latLng != null) {
              /// Add latest location to the list
              listData.add(latLng);
              currentLatLng = latLng;
              if (lineDrive != null && listData.length >= 2)
                /// Update the polyline with the latest location
                _mapController?.updatePolyline(
                    lineDrive,
                    PolylineOptions(
                      geometry: listData,
                      polylineColor: Colors.red,
                      polylineWidth: 14.0,
                      polylineJoin: "round",
                    ));
              }
          }));
  /// Start the simulator
  routeSimulator.start();

API Key Registration and Management #

Register a new API Key #

To use VietMap services, you need to register for an API key. Follow these steps:

1. Access the Registration Page #

Navigate to the registration page at: https://maps.vietmap.vn/console/register

2. Fill in Registration Information #

You need to provide all required information:

  • For Students: Use your school name for Company Name, and education email for Company Email.
  • For Individuals: Use "Individual" for Company Name, and your personal email for Company Email.

3. Accept Terms and Conditions #

  • Read and agree to VietMap's Terms and Conditions
  • Check the box "I accept the terms and conditions"

4. Complete Registration #

  • After filling in all required information and accepting the terms, submit the form.
  • A verification email will be sent to the provided email address.

5. Verify Your Account #

  • Check your inbox or spam folder for the verification email.
  • Click the verification link within 24 hours.
drawing

6. Get Your API Keys #

After successful verification, you will receive:

  • Tilemap API Key: For map tiles and map rendering
  • Map API Key: For other Map APIs (routing, geocoding, etc.)
drawing
Each key has its own usage limits and restrictions.

Manage Your API Key #

1. Log in to the Console #

Go to https://maps.vietmap.vn/console/ and enter your registered email and password.

2. Manage API Keys by Project #

  • Navigate to the "Consumers" section in the left side menu to view and manage your projects.
  • Click Detail on each project to view and manage the API keys associated with that project.

You can perform the following actions:

  • Add new API keys
  • Delete existing keys
  • Add whitelisted IPs
  • Set domain restrictions
  • Limit usage per key or per IP
  • Restrict specific API features

3. Security Best Practices #

To protect your API key from unauthorized use:

  1. Restrict usage to specific domains if the API key is used in a web application or is publicly accessible.
  2. Add limitations per key or per IP to prevent abuse.
  3. Regularly review your API key usage in the console to detect any unusual activity.
  4. Regenerate immediately if you suspect your API key has been compromised.
  5. Never share your API key publicly or include it in client-side code without restrictions.

Note: You can read more detail at https://maps.vietmap.vn/docs/map-api/console/manage-api-key


Monitor API Key Usage #

1. Access Daily Report #

2. View Usage Statistics #

The Daily Report section provides detailed statistics including:

  • Total requests made by each API key
  • Breakdown of requests by API service
  • Daily usage over time
drawing

3. Filter by Date Range and Project #

You can filter the usage data by selecting specific date ranges and projects to analyze the performance of your applications more effectively.


Support #

If you encounter any issues, please contact:

For more information:


Troubleshooting #

  • Our SDK uses the key to identify the markers and update their location while the user does some gestures, so we strongly recommend you add the key for all of the widgets in the screen that use the map SDK:
 Stack(
   children:[
     MarkerLayer(
       ...
     ),
     Positioned(
       key: const Key('yourWidgetKey'),
       ...
     ),
   ]
 )

Demo code here

Note: Replace all YOUR_API_KEY_HERE tags with the API key provided by VietMap so that the application works normally. #





Email us: maps-api.support@vietmap.vn

Contact for support

Vietmap API document here

Have a bug to report? Open an issue. If possible, include a full log and information that shows the issue. Have a feature request? Open an issue. Tell us what the feature should do and why you want the feature.

10
likes
140
points
783
downloads

Documentation

API reference

Publisher

verified publishermaps.vietmap.vn

Weekly Downloads

A Flutter map plugin for integrating Vietmap sdk inside a Flutter application, support for show a vector and raster map in Flutter. Supported on Android, iOS platforms .

Homepage
Repository (GitHub)
View/report issues

Topics

#vietmap #map #flutter-map #map-api

License

BSD-3-Clause (license)

Dependencies

collection, flutter, supercluster, turf, vietmap_flutter_gl_web, vietmap_gl_platform_interface

More

Packages that depend on vietmap_flutter_gl

Packages that implement vietmap_flutter_gl