Woosmap for Flutter - Show Indoor map
Get started with the Woosmap Indoor JS API. View simple examples, learn the concepts, and create custom indoor maps for your application.
- How to display a Indoor maps
- Accessing various functions in
WoosmapMapViewWidget
- Fetching and displaying direction
- Indoor Navigation
- Supporting Indoor function
- Supporting IndoorWidget function
You can use the Woosmap Map-Js flutter plugin to embed interactive indoor maps directly into your Application.
How to display a Indoor maps
- Instantiating a WoosmapMapViewWidget.
WoosmapMapViewWidget.create(
wooskey: AppConstants.of(context)?.wooskey ?? "",
widget: true,
activate_indoor_product: true,
indoorRendererConfiguration: IndoorRendererOptions(
centerMap: true,
defaultFloor: 3
),
indoorWidgetConfiguration: IndoorWidgetOptions (
units: UnitSystem.metric,
ui: IndoorWidgetOptionsUI(
primaryColor: "#318276",
secondaryColor: "#004651"
),
),
onRef: (p0) async {
_controller = p0;
reloadMenu();
},
indoor_venue_loaded: (message) {
debugPrint(jsonEncode(message));
},
indoor_feature_selected: (message) {
debugPrint(jsonEncode(message));
},
indoor_level_changed: (message) {
debugPrint("$message");
},
indoor_user_location: (message) {
debugPrint(jsonEncode(message));
},
indoor_directions: (message) {
_controller?.setDirections(message);
debugPrint(jsonEncode(message));
},
indoor_highlight_step: (message) {
debugPrint(jsonEncode(message));
},
);
import 'package:flutter/widgets.dart';
class AppConstants extends InheritedWidget {
static AppConstants? of(BuildContext context) =>
context.dependOnInheritedWidgetOfExactType<AppConstants>();
const AppConstants({required super.child, super.key});
final String privateKeyiOS = "<<Your private iOS woosmap key>>";
final String privateKeyAndroid = "<<Your private Android woosmap key>>";
@override
bool updateShouldNotify(AppConstants oldWidget) => false;
}
import 'dart:convert';
import 'dart:io';
import 'package:flutter/material.dart';
import 'dart:async';
import 'package:woosmap_flutter/woosmap_flutter.dart';
import './constants.dart';
class IndoorSnippet extends StatefulWidget {
const IndoorSnippet({super.key});
@override
State<IndoorSnippet> createState() => _IndoorSnippetState();
}
class _IndoorSnippetState extends State<IndoorSnippet> {
WoosmapController? _controller;
@override
void initState() {
super.initState();
if (_controller != null) {
debugPrint("info ===> Indoor controller not initialize");
}
}
Future<void> reloadMenu() async {
setState(() {});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Woosmap Indoor app'),
actions: <Widget>[
SampleMenu(webViewController: _controller, indoorVenue: "wgs_mtp"),
],
),
body: SafeArea(
child: Column(
mainAxisSize: MainAxisSize.max,
children: <Widget>[
Expanded(
child: Align(
alignment: const AlignmentDirectional(-1, -1),
child: WoosmapMapViewWidget.create(
wooskey: Platform.isAndroid
? AppConstants.of(context)?.privateKeyAndroid ?? ""
: AppConstants.of(context)?.privateKeyiOS ?? "",
widget: true,
activate_indoor_product: true,
default_indoor_venue_key: "wgs_mtp",
indoorRendererConfiguration: IndoorRendererOptions(
centerMap: true,
defaultFloor: 3,
snapToVenueBounds: true,
polylineOptions: IndoorPolylineOptions(
color: "#643843",
strokeColor: "#643843",
highlightColor: "#C88EA7")),
indoorWidgetConfiguration: IndoorWidgetOptions(
units: UnitSystem.metric,
ui: IndoorWidgetOptionsUI(
primaryColor: "#318276",
secondaryColor: "#004651",
),
),
onRef: (p0) async {
_controller = p0;
reloadMenu();
},
indoor_venue_loaded: (message) {
debugPrint(jsonEncode(message));
// ScaffoldMessenger.of(context).showSnackBar(
// SnackBar(content: Text(jsonEncode(message))),
// );
},
indoor_feature_selected: (message) {
debugPrint(jsonEncode(message));
},
indoor_level_changed: (message) {
debugPrint("$message");
},
indoor_user_location: (message) {
debugPrint(jsonEncode(message));
},
indoor_directions: (message) {
_controller?.setDirections(message);
debugPrint(jsonEncode(message));
},
indoor_highlight_step: (message) {
debugPrint(jsonEncode(message));
},
indoor_navigation_started: () {
debugPrint("indoor_navigation_started");
},
indoor_navigation_exited: () {
debugPrint("indoor_navigation_exited");
},
dblclick: (location) {
_controller?.getLevel().then((level) {
_controller?.setUserLocation(
lat: location.lat,
lng: location.lng,
level: level,
bearing: 0,
forcefocus: false);
});
},
)))
],
),
),
);
}
}
enum MenuOptions {
showVenue,
showWorldMap,
changeFloor,
getFloor,
showUserPosition,
getUserPosition,
showItinerary,
checkUserInside,
highlightFeatureByRef,
highlightFeature,
directions,
directionsPoi,
directionsRef,
directionsWayPoint,
directionsMode,
startNavigation,
exitNavigation,
clearDirections,
filterPois,
clearFilterPois,
}
class SampleMenu extends StatelessWidget {
const SampleMenu(
{super.key, required this.webViewController, required this.indoorVenue});
final WoosmapController? webViewController;
final String indoorVenue;
@override
Widget build(BuildContext context) {
return PopupMenuButton<MenuOptions>(
key: const ValueKey<String>('ShowPopupMenu'),
onSelected: (MenuOptions value) {
switch (value) {
case MenuOptions.showVenue:
_onShowVenue();
break;
case MenuOptions.showUserPosition:
_onShowUserPosition();
break;
case MenuOptions.changeFloor:
_onChangeFloor();
break;
case MenuOptions.showWorldMap:
_onShowWorldMap();
break;
case MenuOptions.highlightFeatureByRef:
_onHighlightFeatureByRef();
break;
case MenuOptions.highlightFeature:
_onHighlightFeature();
break;
case MenuOptions.directionsMode:
_onDirectionsMode();
break;
case MenuOptions.directions:
_onDirections();
break;
case MenuOptions.directionsPoi:
_onDirectionsPoi();
break;
case MenuOptions.directionsRef:
_onDirectionsRef();
break;
case MenuOptions.directionsWayPoint:
_onDirectionsWayPoint();
break;
case MenuOptions.startNavigation:
_startNavigation();
break;
case MenuOptions.exitNavigation:
_exitNavigation();
break;
case MenuOptions.clearDirections:
_onClearDirections();
break;
case MenuOptions.filterPois:
_onFilterPOIs();
break;
case MenuOptions.clearFilterPois:
_onClearFilterPOIs();
break;
case MenuOptions.getFloor:
_onGetFloor().then((value) {
if (value != null) {
if (!context.mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text("You are on floor $value")),
);
}
});
break;
case MenuOptions.getUserPosition:
_onGetIndoorUserLocation().then((value) {
if (value != null) {
if (!context.mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
"You are at ${value.position.lat},${value.position.lng} on floor ${value.level}")),
);
}
});
break;
case MenuOptions.showItinerary:
_onShowItinerary();
break;
case MenuOptions.checkUserInside:
_onCheckUserInside().then((value) {
if (value != null) {
if (!context.mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
"You are ${value == true ? "inside" : "outside"}")),
);
}
});
break;
}
},
itemBuilder: (BuildContext context) => [
const PopupMenuItem<MenuOptions>(
value: MenuOptions.showWorldMap,
child: Text('Show World Map'),
),
const PopupMenuItem<MenuOptions>(
value: MenuOptions.showVenue,
child: Text('Show Indoor venue(MTP)'),
),
const PopupMenuItem<MenuOptions>(
value: MenuOptions.changeFloor,
child: Text('Change floor to 3'),
),
const PopupMenuItem<MenuOptions>(
value: MenuOptions.getFloor,
child: Text('Get Floor number'),
),
const PopupMenuDivider(
height: 20,
),
const PopupMenuItem<MenuOptions>(
value: MenuOptions.highlightFeatureByRef,
child: Text('Highlight feature (Ref)'),
),
const PopupMenuItem<MenuOptions>(
value: MenuOptions.highlightFeature,
child: Text('Highlight feature (id)'),
),
const PopupMenuDivider(
height: 20,
),
const PopupMenuItem<MenuOptions>(
value: MenuOptions.showUserPosition,
child: Text('User Position'),
),
const PopupMenuItem<MenuOptions>(
value: MenuOptions.getUserPosition,
child: Text('Get User Position'),
),
const PopupMenuItem<MenuOptions>(
value: MenuOptions.checkUserInside,
child: Text('Check User inside'),
),
const PopupMenuDivider(
height: 20,
),
const PopupMenuItem<MenuOptions>(
value: MenuOptions.showItinerary,
child: Text('Show Itinerary'),
),
const PopupMenuDivider(
height: 20,
),
const PopupMenuItem<MenuOptions>(
value: MenuOptions.directionsMode,
child: Text('Directions Mode (wheelchair)'),
),
const PopupMenuDivider(
height: 20,
),
const PopupMenuItem<MenuOptions>(
value: MenuOptions.directions,
child: Text('Directions(Lat/Lng)'),
),
const PopupMenuItem<MenuOptions>(
value: MenuOptions.directionsPoi,
child: Text('Directions (Poi id)'),
),
const PopupMenuItem<MenuOptions>(
value: MenuOptions.directionsRef,
child: Text('Directions (Poi Ref)'),
),
const PopupMenuItem<MenuOptions>(
value: MenuOptions.directionsWayPoint,
child: Text('Directions (waypoint)'),
),
const PopupMenuItem<MenuOptions>(
value: MenuOptions.startNavigation,
child: Text('Start Navigation'),
),
const PopupMenuItem<MenuOptions>(
value: MenuOptions.exitNavigation,
child: Text('Exit Navigation'),
),
const PopupMenuItem<MenuOptions>(
value: MenuOptions.clearDirections,
child: Text('Remove Path'),
),
const PopupMenuDivider(
height: 20,
),
const PopupMenuItem<MenuOptions>(
value: MenuOptions.filterPois,
child: Text('Filter POIs'),
),
const PopupMenuItem<MenuOptions>(
value: MenuOptions.clearFilterPois,
child: Text('Remove Filter on POIs'),
),
],
);
}
Future<void>? _onShowVenue() {
// Send a message with the user agent string to the Toaster JavaScript channel we registered
// with the WebView.
return webViewController?.setVenue(indoorVenue);
}
Future<void>? _onShowWorldMap() {
// Send a message with the user agent string to the Toaster JavaScript channel we registered
// with the WebView.
return webViewController?.loadIndoorMap('');
}
Future<void>? _onChangeFloor() {
// Send a message with the user agent string to the Toaster JavaScript channel we registered
// with the WebView.
return webViewController?.setFloor(3);
}
Future<void>? _onShowUserPosition() {
return webViewController?.setUserLocation(
lat: 43.606573820824764,
lng: 3.92177514731884,
level: 3,
forcefocus: true);
}
Future<void>? _onHighlightFeatureByRef() {
return webViewController?.highlightFeatureByRef(
byref: 'tropiques',
padding: WoosPadding(top: 300, bottom: 0, left: 0, right: 0));
}
Future<void>? _onHighlightFeature() {
return webViewController?.highlightFeature(
featureId: '34349', silent: false);
}
Future<void>? _onDirectionsMode() {
return webViewController?.setDirectionsMode('wheelchair');
}
Future<void>? _onDirections() {
webViewController
?.directions(DirectionParameter(
venueId: indoorVenue,
origin: LatLng(lat: 43.60664187325, lng: 3.921814671575),
originLevel: 3,
destination: LatLng(lat: 43.60665215333, lng: 3.921680093435),
destinationLevel: 3,
language: "en",
units: UnitSystem.metric,
mode: "wheelchair"))
.then((route) => {
if (route != null) {webViewController?.setDirections(route)}
});
return null;
}
Future<void>? _onDirectionsPoi() {
webViewController
?.directions(DirectionParameter(
venueId: indoorVenue,
originId: 5071897,
destinationId: 5071858,
language: "en",
units: UnitSystem.metric,
mode: "wheelchair"))
.then((route) => {
if (route != null) {webViewController?.setDirections(route)}
});
return null;
}
Future<void>? _onDirectionsRef() {
webViewController
?.directions(DirectionParameter(
venueId: indoorVenue,
originId: "ref:meeting001",
destinationId: "ref:tropiques",
language: "en",
units: UnitSystem.metric,
mode: "wheelchair"))
.then((route) => {
if (route != null) {webViewController?.setDirections(route)}
});
return null;
}
Future<void>? _onDirectionsWayPoint() {
webViewController
?.directions(DirectionParameter(
venueId: indoorVenue,
origin: LatLng(lat: 43.60664187325, lng: 3.921814671575),
originLevel: 3,
destination: LatLng(lat: 43.60665215333, lng: 3.921680093435),
destinationLevel: 3,
language: "en",
units: UnitSystem.metric,
mode: "wheelchair",
waypoints: ["ref:meeting001", "ref:tropiques"]))
.then((route) => {
if (route != null) {webViewController?.setDirections(route)}
});
return null;
}
Future<void>? _startNavigation() {
return webViewController?.startNavigation();
}
Future<void>? _exitNavigation() {
return webViewController?.exitNavigation();
}
Future<void>? _onClearDirections() {
return webViewController?.clearDirections();
}
Future<void>? _onFilterPOIs() {
return webViewController?.filterPois(advancedFilter: 'room:=meeting');
}
Future<void>? _onClearFilterPOIs() {
return webViewController?.filterPois(advancedFilter: '');
}
Future<int?> _onGetFloor() async {
int? result;
result = await webViewController?.getLevel();
return result;
}
Future<IndoorPosition?> _onGetIndoorUserLocation() async {
try {
IndoorPosition? currentPosition =
await webViewController?.getUserLocation();
return currentPosition;
} catch (e) {
return null;
}
}
Future<bool?> _onCheckUserInside() async {
bool? result;
try {
IndoorPosition? currentPosition =
await webViewController?.getUserLocation();
if (currentPosition == null) return null;
result = await webViewController?.isUserInsideVenue(
lat: currentPosition.position.lat, lng: currentPosition.position.lng);
} catch (e) {
return null;
}
return result;
}
Future<void>? _onShowItinerary() {
// return webViewController?.showItinerary();
return webViewController?.showItinerary(
origin: null, destination: '9758902');
}
}
Accessing various functions in WoosmapMapViewWidget
- Load Indoor map
_controller.setVenue('wgs_mtp');
- Show all venue
_controller.loadIndoorMap('');
- Change Indoor Floor
_controller.setFloor(3);
- Display use position on map
_controller.setUserLocation(43.606573820824764, 3.92177514731884, 3, 0, true);
- Showing Information about any indoor area
_controller.highlightFeatureByRef('tropiques');
- Change Direction mode (Widget specific)
_controller.setDirectionsMode('wheelchair');
- Filter POI to display only labels and icons of POIs which are matching the filters
_controller.filterPois(advancedFilter: 'room:=meeting');
you can also pass an optional boolean parameter ignoreZoomRules
. If true, ignores the zoom rules for the filtered POIs. Default value if false.
Fetching and displaying direction
Note: Class
DirectionParameter
is deprecated. We suggest you use newIndoorDirectionRequest
instead.
- By using Lat/Lng
_controller.directions(IndoorDirectionRequest(
venueId: 'wgs_mtp',
origin: LatLng(lat: 43.60664187325, lng: 3.921814671575),
originLevel: 3,
destination: LatLng(lat: 43.60665215333, lng: 3.921680093435),
destinationLevel: 3,
language: "en",
units: UnitSystem.metric,
mode: "wheelchair",
))
.then((route) => {_controller.setDirections(route)});
- By using Poi ID
_controller.directions(IndoorDirectionRequest(
venueId: 'wgs_mtp',
originId: 3694972,
destinationId: 3694921,
language: "en",
units: UnitSystem.metric,
mode: "wheelchair",
))
.then((route) => {_controller?.setDirections(route)});
- By using Poi Ref
_controller.directions(IndoorDirectionRequest(
venueId: 'wgs_mtp',
originId: "ref:meeting002",
destinationId: "ref:tropiques",
language: "en",
units: UnitSystem.metric,
mode: "wheelchair"
))
.then((route) => {_controller.setDirections(route)});
- By using WayPoint (Valid Waypoint formats are
lat,lng,level
orpoiid
or ref:poiref
)
_controller.directions(IndoorDirectionRequest(
venueId: 'wgs_mtp',
originId: "ref:meeting002",
destinationId: "ref:tropiques",
waypoints: ["ref:meeting001", "ref:tropiques"]
))
.then((route) => {_controller.setDirections(route)});
Indoor Navigation
To initiate navigation experience you need to call following methods of the WoosmapController
object in the same order as given below.
-
directions
- As explained in the earlier sectiondirections
method will find the route between two points inside an indoor venue. This method returns aroute
object upon it’s completion. -
setDirections
- This method will plot the givenroute
on the map. You can pass theroute
object returned bydirections
method. -
startNavigation
- This method will initiate the “Turn By Turn” navigation experience.
_controller.startNavigation();
exitNavigation
- This method will result in the exit from “Turn By Turn” navigation mode.
_controller.exitNavigation();
clearDirections
- Removes the plotted path on the map. If the navigation experience is started then it first exits from the navigation then removes the path.
_controller.clearDirections();
Please note that setDirections
method will no longer trigger navigation. Method startNavigation
should explicitly be called to initiate the navigation.
Supporting Indoor function
Future<void> setUserLocation({required double lat,required double lng,required int level,int? bearing,bool? forcefocus})
-: Set the current user location. A blue dot is going to be displayed.
_controller.setUserLocation(
lat: 43.606573820824764,
lng: 3.92177514731884,
level: 3,
forcefocus: true);
Future<IndoorPosition> getUserLocation()
-: Returns the current user location.
IndoorPosition currentPosition =
await _controller.getUserLocation();
Future<bool> isUserInsideVenue({required num lat, required num lng})
-: Detects whether user location is found inside venue’s bounding box
bool? status;
try {
IndoorPosition? currentPosition =
await _controller.getUserLocation();
if (currentPosition == null) return null;
status = await _controller.isUserInsideVenue(
lat: currentPosition.position.lat, lng: currentPosition.position.lng);
} catch (e) {
return null;
}
Future<int> getLevel()
:- Get the displayed level.
result = await _controller.getLevel();
Future<void> setVenue(String venueId)
-: Renders map with the selected venue
_controller.setVenue(`test`);
Future<void> setFloor(int floor)
-: Sets the floor for the venue
_controller?.setFloor(3);
Future<void> highlightFeatureByRef({required String byref, WoosPadding? padding})
-: Renders a map with a POI highlighted by ref
_controller?.highlightFeatureByRef(
byref: 'tropiques',
padding: WoosPadding(top: 300, bottom: 0, left: 0, right: 0));
Future<void> highlightFeature({required String featureId, required bool silent, WoosPadding? padding})
-: Renders a map with a POI highlighted by pk or id
_controller.highlightFeature(
featureId: '34349', silent: false);
-
Future<void> setDirectionsMode(String mode)
-: Sets the routing profile (or directions mode) (‘security’‘wheelchair’) for way finding
_controller.setDirectionsMode('wheelchair');
Future<void> filterPois({required String advancedFilter, bool ignoreZoomRules = false})
-: Filter the map to display only labels and icons of POIs which are matching the filters
_controller.filterPois(advancedFilter: 'room:=meeting');
Supporting IndoorWidget function
Future<void> showItinerary({dynamic origin, dynamic destination})
-: Opens the widget’s panel in itinerary mode.
_controller.showItinerary();
_controller.showItinerary(
origin: '9754000', destination: '9758902');
_controller.showItinerary(
origin: '43.606573820824764,3.92177514731884,3', destination: '9758902');
_controller.showItinerary(
origin: '<<User position>>', destination: '9758902');