Building & Level Selection
This guide connects HTML select elements with venue data to add a building and level selector. This will allow listing of all buildings, the levels of each building and the ability to switch between them.
This code sample requires a <div>
element in the HTML with an id
of selectorDiv
, which will hold the selectors. This should be placed in the <body>
after the map element.
<!DOCTYPE html>
<html>
<head>
<title>Mappedin JS v5 Building and Level Selector</title>
<meta charset="UTF-8" />
<style>
* {
margin: 0;
padding: 0;
}
html,
body {
width: 100%;
height: 100%;
}
#app {
height: 100%;
width: 100%;
position: relative;
}
</style>
</head>
<body>
<div id="app"></div>
<div id="selectorDiv"></div>
<script src="src/index.ts"></script>
</body>
</html>
The following creates the necessary select
elements in TypeScript. This helps to populate the selectors with buildings and levels. It will also lift the mapView
and venue
variables outside of the init()
function to be used globally. Basic styling is applied to the level selector div.
import { getVenue, showVenue, TGetVenueOptions, MapView, MappedinMap, Mappedin } from '@mappedin/mappedin-js';
import '@mappedin/mappedin-js/lib/mappedin.css';
// See Trial API key Terms and Conditions
// https://developer.mappedin.com/docs/demo-keys-and-maps
const options: TGetVenueOptions = {
venue: 'mappedin-demo-campus',
clientId: '5eab30aa91b055001a68e996',
clientSecret: 'RJyRXKcryCMy4erZqqCbuB1NbR66QTGNXVE0x3Pg6oCIlUR1',
};
let mapView: MapView;
let venue: Mappedin;
const selectorDiv = document.getElementById('selectorDiv')!;
const mapGroupSelectElement = document.createElement('select');
const mapLevelSelectElement = document.createElement('select');
selectorDiv.appendChild(mapGroupSelectElement);
selectorDiv.appendChild(mapLevelSelectElement);
selectorDiv.style.cssText = 'position: fixed; top: 1rem; left: 1rem;';
async function init() {
venue = await getVenue(options);
mapView = await showVenue(document.getElementById('app')!, venue);
}
init();
A building is represented by a MapGroup. A MapGroup can contain one to many levels, representing floors of a building. If your venue contains a single building, you won’t need to use a MapGroup.
Once the map is loaded, the building selector is populated with the available buildings. To achieve this, a short function called populateMapGroups()
initializes the building selector values. Additionally, changing the building selector value will change the levels listed in the level selector. The sample uses an onLevelChange()
handler to update the level selector. The levels are sorted based on their elevation, so that the bottom level is at the bottom of the selector and the top level at the top.
function populateMapGroups() {
mapGroupSelectElement.innerHTML = '';
const mapGroups = venue.mapGroups;
//Add each MapGroup to the select element.
mapGroups.forEach((mg) => {
const option = document.createElement('option');
option.value = mg.id;
option.text = mg.name;
mapGroupSelectElement.appendChild(option);
});
//Get and sort maps by elevation.
const maps = mapGroups[0].maps.sort((a, b) => b.elevation - a.elevation);
populateMaps(maps);
}
mapGroupSelectElement.onchange = async (ev: Event) => {
const mg = venue.mapGroups.find((mg) => mg.id === mapGroupSelectElement.value)!;
//Get and sort maps by elevation.
const maps = mg.maps.sort((a, b) => b.elevation - a.elevation);
//Display the ground floor.
const map = maps[maps.length - 1];
await mapView.setMap(map);
populateMaps(maps);
};
When the venue is first loaded or a user chooses a new level, the level selector must be populated. The populateMaps()
method handles this task. Another onChange event is used and connected to the onLevelChange()
method to react to the user’s selection. When a new level is chosen, mapView.setMap()
is called to display the new map.
function onLevelChange(event: Event) {
const id = (event.target as HTMLSelectElement).value;
mapView.setMap(id);
}
function populateMaps(maps: MappedinMap[]) {
mapLevelSelectElement.innerHTML = '';
mapLevelSelectElement.onchange = onLevelChange;
// Add each map as an option to the level select.
maps.forEach((map) => {
const option = document.createElement('option');
option.text = map.name;
option.value = map.id;
mapLevelSelectElement.add(option);
});
// Set the initial value of the level selector to the current map.
mapLevelSelectElement.value = mapView.currentMap.id;
}
To initialize the selectors on page load, call populateMapGroups()
after showVenue()
.
async function init() {
venue = await getVenue(options);
mapView = await showVenue(document.getElementById('app')!, venue);
populateMapGroups();
}
init();
The sample should now display a venue with two select elements in the top left corner. A user can choose from these lists to adjust the building and level to update the map. The results can be seen in the following CodeSandbox.
Listening for Map Change
Other user interaction can change the map, such as Multi-Floor Wayfinding or Dynamic Focus. To keep the building and level selector in sync with the current map, subscribe to the E_SDK_EVENT.MAP_CHANGED
and repopulate the selectors when this callback occurs.
mapView.on(E_SDK_EVENT.MAP_CHANGED, (map) => {
const mapGroup = map.mapGroup;
// Update select elements
if (mapGroup) {
mapGroupSelectElement.value = mapGroup.id;
populateMaps(mapGroup.maps);
}
mapLevelSelectElement.value = map.id;
});