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

  1. Instantiating a WoosmapMapViewWidget.
lib/indoor_snippet.dart
        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
lib/indoor_snippet.dart
        _controller.setVenue('wgs_mtp');

    
  • Show all venue
lib/indoor_snippet.dart
        _controller.loadIndoorMap('');

    
  • Change Indoor Floor
lib/indoor_snippet.dart
        _controller.setFloor(3);

    
  • Display use position on map
lib/indoor_snippet.dart
        _controller.setUserLocation(43.606573820824764, 3.92177514731884, 3, 0, true);

    
  • Showing Information about any indoor area
lib/indoor_snippet.dart
        _controller.highlightFeatureByRef('tropiques');

    
  • Change Direction mode (Widget specific)
lib/indoor_snippet.dart
        _controller.setDirectionsMode('wheelchair');

    
  • Filter POI to display only labels and icons of POIs which are matching the filters
lib/indoor_snippet.dart
        _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 new IndoorDirectionRequest instead.

  • By using Lat/Lng
lib/indoor_snippet.dart
        _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
lib/indoor_snippet.dart
        _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
lib/indoor_snippet.dart
        _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 or poiid or ref:poiref)
lib/indoor_snippet.dart
        _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.

  1. directions - As explained in the earlier section directions method will find the route between two points inside an indoor venue. This method returns a route object upon it’s completion.

  2. setDirections - This method will plot the given route on the map. You can pass the route object returned by directions method.

  3. startNavigation - This method will initiate the “Turn By Turn” navigation experience.

lib/indoor_snippet.dart
        _controller.startNavigation();

    
  1. exitNavigation - This method will result in the exit from “Turn By Turn” navigation mode.
lib/indoor_snippet.dart
        _controller.exitNavigation();

    
  1. 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.
lib/indoor_snippet.dart
        _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.
lib/indoor_snippet.dart
        _controller.setUserLocation(
        lat: 43.606573820824764,
        lng: 3.92177514731884,
        level: 3,
        forcefocus: true);

    
  • Future<IndoorPosition> getUserLocation() -: Returns the current user location.
lib/indoor_snippet.dart
        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
lib/indoor_snippet.dart
            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.
lib/indoor_snippet.dart
            result = await _controller.getLevel();

    
  • Future<void> setVenue(String venueId) -: Renders map with the selected venue
lib/indoor_snippet.dart
            _controller.setVenue(`test`);

    
  • Future<void> setFloor(int floor) -: Sets the floor for the venue
lib/indoor_snippet.dart
        _controller?.setFloor(3);

    
  • Future<void> highlightFeatureByRef({required String byref, WoosPadding? padding}) -: Renders a map with a POI highlighted by ref
lib/indoor_snippet.dart
        _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
lib/indoor_snippet.dart
        _controller.highlightFeature(
        featureId: '34349', silent: false);

    
  • Future<void> setDirectionsMode(String mode) -: Sets the routing profile (or directions mode) (‘security’ ‘wheelchair’) for way finding
lib/indoor_snippet.dart
            _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
lib/indoor_snippet.dart
        _controller.filterPois(advancedFilter: 'room:=meeting');

    
  • Future<void> hideVenue() : Temporarily hide indoor venue from screen.
lib/indoor_snippet.dart
        _controller.hideVenue();

    
  • Future<void> showVenue() : Show indoor venue on screen if it was hidden using method Future<void> hideVenue()

lib/indoor_snippet.dart
        _controller.showVenue();

    

</div>

Supporting IndoorWidget function

  • Future<void> showItinerary({dynamic origin, dynamic destination}) -: Opens the widget’s panel in itinerary mode.
lib/indoor_snippet.dart
            _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');

    
Was this helpful?