Vietmap Flutter GL - Flutter map SDK
Contact vietmap.vn 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 is 24 in the build.gradle (app) file, at path android/app/build.gradle
minSdkVersion 24
iOS config
Add the below codes 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 theios/.symlinks
,ios/Pods
folders, andPodfile.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/api/maps/light/styles.json?apikey=6411732992b3c4def7a117893215b9163a15e69065c0874d',
initialCameraPosition:
CameraPosition(target: LatLng(10.762317, 106.654551)),
onMapCreated: (VietmapController controller) {
setState(() {
_mapController = controller;
});
},
);
Change map style
- 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/api/maps/raster/styles.json?apikey=6411732992b3c4def7a117893215b9163a15e69065c0874d");
- You can also keep/remove the annotations on the map with input params
keepExistingAnnotations
. (This function did not remove annotations inside theMarkerLayer
andStaticMarkerLayer
)
_mapController?.setStyle(
"https://maps.vietmap.vn/api/maps/light/styles.json?apikey=6411732992b3c4def7a117893215b9163a15e69065c0874d",
keepExistingAnnotations: true);
VIETMAP now provides many types of custom maps
Name | Description |
---|---|
Raster | The map data is typically stored as raster images, which are then divided into a grid of small tiles, each containing a specific portion of the map. |
Raster url | https://maps.vietmap.vn/api/maps/raster/styles.json?apikey=6411732992b3c4def7a117893215b9163a15e69065c0874d |
Vector | Vector tiles are small packages of vector data that can be downloaded and rendered on a client device, such as a web browser or mobile app. The vector data can include information such as street names, building footprints, and topographic features. |
Vector url | https://maps.vietmap.vn/api/maps/light/styles.json?apikey=6411732992b3c4def7a117893215b9163a15e69065c0874d |
Satellite | Satellite imagery consists of photographs of Earth or other planets made by means of artificial satellites. |
Hybrid | Hybrid maps are a combination of satellite imagery overlaid with vector data that provides a visual reference for locations and features. |
Read more about Raster and 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 out.
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));
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)));
},
)
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 astatic marker
. The simple markerwill not rotate
when the map rotates, and the static markerwill rotate
with the map.
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 support rotates with input is a bearing, you can find this value when get 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 define 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 thecustomClusterWidget
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 theVietmapGL
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?.clearLines();
Add a Fill/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
});
/// Draw the route on the map
Line? line = await _mapController?.addPolyline(
PolylineOptions(
geometry: pointsLatLng,
polylineColor: Colors.red,
polylineWidth: 14.0,
polylineOpacity: 0.5),
);
Route simulator
- We're 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
, andspeed
to get the best experience for the simulator. - Did not repeat the simulator too quick and too much, it will make the app lag.
- 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();
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 apikey which is provided by VietMap to all 6411732992b3c4def7a117893215b9163a15e69065c0874d tags to the application works normally
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.