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.
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));
var onLastStep = message.properties?["isLastStep"];
if (onLastStep == true) {
Widget okButton = TextButton(
child: Text("OK"),
onPressed: () {
Navigator.of(context).pop();
},
);
AlertDialog alert = AlertDialog(
title: Text("Navigation"),
content: Text("Your are on last navigation leg."),
actions: [
okButton,
],
);
showDialog(
context: context,
builder: (BuildContext context) {
return alert;
},
);
}
},
indoor_user_near_arrival: (msg) {
Widget okButton = TextButton(
child: Text("OK"),
onPressed: () {
Navigator.of(context).pop();
},
);
AlertDialog alert = AlertDialog(
title: Text("Indoor Navigation"),
content: Text("You are near to your destination"),
actions: [
okButton,
],
);
showDialog(
context: context,
builder: (BuildContext context) {
return alert;
},
);
},
);
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
DirectionParameteris deprecated. We suggest you use newIndoorDirectionRequestinstead.
- 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,levelorpoiidor 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 sectiondirectionsmethod will find the route between two points inside an indoor venue. This method returns arouteobject upon it’s completion. -
setDirections- This method will plot the givenrouteon the map. You can pass therouteobject returned bydirectionsmethod. -
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');
Future<void> hideVenue(): Temporarily hide indoor venue from screen.
_controller.hideVenue();
-
Future<void> showVenue(): Show indoor venue on screen if it was hidden using methodFuture<void> hideVenue()
_controller.showVenue();
</div>
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');