This repository has been deprecated and is no longer supported. Please visit the Mappedin Developer Portal for up to date SDK information.
Welcome to the Mappedin Web SDK. Please report any issues you find directly to your Mappedin technical contact.
Check out the demo, and the full API docs.
The current version of the Mappedin Web SDK is v1.63.16, and can be included in your application via script tag, like so:
<script src="https://d1p5cqqchvbqmy.cloudfront.net/websdk/v1.69.0/mappedin.js"></script>
In order to use the Mappedin Web SDK you will need an API Key and Secret. To get you started we've provided a key and secret in this repo that has access to some demo venues. When you're ready to start using your own venues with the Mappedin Web SDK you will need to contact a Mappedin representative to get your own unique key and secret.
The Mappedin Web SDK provides a simple way to use all of the data stored in the Mappedin CMS. It consists of four main components:
- Venue: The Mappedin.Venue object contains all of the data for a given Venue. All the communication with the Mappedin backend is handled for you, resulting in a single Venue object with all the data (locations, maps, categories, etc) ready and linked together.
- MapView: This gives you a single, prebuilt component that handles displaying a fully 3D map (with an automatic 2D fallback) of your Venue. It features things like selectable polygons, wayfinding, 2D markers with auto layout, hover labels, and 3D text labels.
- Search: Mappedin.Search gives you easy access to the powerful Mappedin Smart Search API. It provides a fast Suggestion API designed to provide real time autocomplete, and a powerful Search API for more detailed results.
- Analytics: Mappedin.Analytics provides a few simple analytics calls that will improve the Search experience and provide Venue owners with data and key insights. You should call locationSelected when a user selects a location.
To get started, you need to add the latest version of mappedin.js to your project, which you can find above.
Then, when you are ready to show the map, call Mappedin.initialize(options, container)
.
This takes a options object with all the configuration data the Mappedin SDK needs, and a container to put the MapView in, and returns a Promise that will be resolved when the Venue data is downloaded and the other objects are created, or fail because of something like invalid credentials or a non-existent venue slug.
You'll probably do something like this:
Mappedin.initialize(options, div).then(function (data) {
mapView = data.mapview;
venue = data.venue;
search = data.search;
},function (error) {
window.alert("Mappedin " + error);
});
There are a number of options you can specify for initialize. We'll break down each of the high level groups next:
var options = {
venue: venueOptions,
mapview: mapviewOptions,
search: searchOptions
}
This will be the most complicated set of options. It is here you specify your API key, secret, perspective, and "slug" for the Venue you want to download. To get you started we've provided a key and secret, which we've added to each sample that has access to some demo venues.
You will also specify which fields you are interested in downloading for each Mappedin object. The Mappedin CMS is very flexible, and objects like Locations can have a lot of information stored on them, some of which is custom for your Venue, and not all of which needs to be downloaded by the user when they visit your web page. The Mappedin Web SDK will ensure it downloads the information it needs for itself (like the 3D or 2D files for your Map), and it's recommended to you only add the data you will actually use yourself to keep things snappy.
A typical venueOptions might look like this:
var venueOptions = {
clientId: "<Your API Key Here>",
clientSecret: "<Your API Secret Here>",
perspective: "Website",
things: {
venue: ['slug', 'name'],
locations: ['name', 'type', 'description', 'icon', 'logo'],
categories: ['name'],
maps: ['name', 'elevation', 'shortName']
},
venue: "<Your venue slug here>"
};
These are options used by the MapView during construction. All of these are optional, though you almost certainly want at least one of onFirstMapLoaded
and onDataLoaded
.
Yours might look something like this:
var mapviewOptions = {
antialias: "AUTO",
mode: Mappedin.modes.TEST,
onFirstMapLoaded: function () {
console.log("First map fully loaded. No more pop in.");
},
onDataLoaded: function() {
console.log("3D data loaded, map usable. Could hide loading screen here, but things will be popping in. Now you can do things that interact with the 3D scene");
onDataLoaded();
};
};
Antialias is on AUTO by default, which means it's on unless you are running a High DPI display (like a 4K screen). Antialiasing gets very expensive as resolution gets higher.
Mode is set to Mappedin.modes.TEST
by default as well. This will perform the 3D test the first time your page is loaded, save the result in local storage, and then either load the 2D or 3D MapView and associated resources for you. You can set it to 'Mappedin.modes.FORCE' to force the test to re-run (useful if your device was very busy doing something else when the initial test ran, and failed the performance benchmark). You can also force the MapView directly into 2D or 3D with ''Mappedin.modes["2D"]' and ''Mappedin.modes["3D"]' respectively. 2D should always work, but note that not all device/browsers have the WebGL support needed for 3D mode, which may lead to an exception.
Most developers will leave the above settings at their default (and not even specify them), but you almost certainly want to set an onDataLoaded
or onFirstMapLoaded
callback. This will let you know when the MapView has entered into the various states of usability, from initalize's promise resolving, to onDataLoaded, to onFirstMapLoaded. Here's what each state means:
When the promise from initialize is resolved successfully, you will have a fully populated Venue object, a 2D or 3D MapView that is on the page but likely empty, and a Search and Analytics object ready for use. At this point the user can start Searching, you can show location and category information in your UI, but the MapView is not ready to be used yet. Assets will stream in as it goes, but you may want to cover it with a loading screen.
This event is fired when the 3D files for the maps have been downloaded from the internet and processed. At this point you can add interactive polygons, label locations, highlight polygons, etc. You can do everything, and the map is fully interactive, but the textures and geometry may still be popping in. Hide your loading screen here if you want to minimize the "time to first interaction" for the user.
This event is called when the first map is finished loading everything, definitely hide your loading screen now. All the geometry and textures will be there, and there will be no more pop in. Note that if you called labelAllLocations (or labeled individual polygons yourself) in onDataLoaded, this will also be done before onFirstMapLoaded is called. Those labels pop in over a number of frames to keep the UI snappy, so if you would prefer to show the user the map when the map itself is there but not wait for the labels to pop in, create them in this callback.
The time difference between onDataLoaded and onFirstMapLoaded will be fairly small on a high end PC, but could be quite substantial on a low end device (especially if you are calling labelAllLocations in onDataLoaded.) Our general recommendation is to either a) Hide the loading screen in onDataLoaded, or b) hide it in onFirstMapLoaded, but also start labeling you polygons at that point too. Waiting for the labels to pop in can take several seconds, and will not provide a good user experience.
As mentioned above, once you get the onDataLoaded callback the MapView is fully usable, and all function calls should work as expected. There are a few things you will typically want to do in this callback.
The MapView will use a nice selection of colors by default, but you probably have specific brand colours you would like to use for things like polygon selection and the path. Colours can generally be set in the function that uses them (so you can highlight one polygon with one colour, and another using a second), but for convenience you can change the defaults by setting the values in your MapView's colors
object.
Here are the defaults for your reference:
mapView.colors = {
hover: 0xcccccc,
select: 0x4ca1fc,
text: 0x000000,
path: 0xff834c,
pathPulse: 0xffffff,
textSelect: 0xffffff
};
Both the 2D and 3D maps are made out of polygons. Some of them, like those representing a specific store, should be intractable by the user. They should be able to hover over them to know it's important, and click on them to select them for more details or wayfinding. Most polygons, however, will be things like the walls and floor. Things that are just decoration and should not be clickable at all. That's where MapView.addInteractivePolygons
comes in.
There is a convenience function available as of version 1.54.0 that makes all polygons attached to a location clickable/hoverable. This function is called MapView.addInteractivePolygonsForAllLocations
. You may also choose to do this by adding each polygon individually using something like:
var locations = venue.locations;
for (var j = 0, jLen = locations.length; j < jLen; ++j) {
var location = locations[j];
if (location.polygons.length > 0) {
polygonedLocations.push(location);
}
var locationPolygons = location.polygons;
for (var k = 0, kLen = locationPolygons.length; k < kLen; ++k) {
var polygon = locationPolygons[k];
mapView.addInteractivePolygon(polygon.id);
};
};
This will also make all polygons attached to a location clickable/hoverable. Without using either of these options, the map will not be very interactive.
The Mappedin MapView makes it easy to add text labels directly to the scene in 3D. It also supports a hovering label banner, attached to the cursor, that is displayed when the user mouses over a specific polygon in 2D or 3D. This is done either with the MapView.labelAllLocations
function, or directly with the MapView.labelPolygon
function.
There are a number of options you can set to customize the look and feel of your labels. See the documentation for more details. For now, you probably want to just call MapView.labelAllLocations().
This will put a 3D Text Label, and a hover label, on each Polygon attached to a Location.
The user can hover over Interactive Polygons to get the hover effect, but nothing will happen when they are clicked until you set your MapView's onPolygonClicked property. This should be a function that takes a polygon ID, and returns false if no polygons below this one should get an onPolygonClicked event. This is the typical behaviour, but you may have a special case with, say, a food court polygon that overlaps individual restaurants.
This function will likely get more complicated once you have a UI for wayfinding, but by default you probably just want to clear any existing polygon highlighting, highlight this one, and perhaps focus in on it like so:
function onPolygonClicked (polygonId) {
mapView.clearAllPolygonColors();
mapView.setPolygonColor(polygonId, mapView.colors.select);
var polygon = venue.getCollectionItemById("POLYGON", polygonId)
mapView.focusOn({polygons:[polygon]})
console.log(polygonId + " clicked");
return false;
};
There is also an onNothingClicked event that is fired if nothing interactive is clicked on, or if your onPolygonClicked event returned true and there was nothing underneath it. This is a good opportunity to clear the UI up a bit:
function onNothingClicked() {
console.log("onNothingClicked");
mapView.clearAllPolygonColors();
};
Most Venues will have more than one map, representing the different floors of a building. If there is a "default map" set for the Venue, that map will be loaded first. Otherwise, it's just the first one returned by the API.
Typically, maps in a multi-floor Venue will have an elevation
property set. 0 or 1 will be the ground floor (depending on the Venue's convention) and the other maps can be sorted above and below using the elevation property. You probably want to construct some sort of map selector widget to let the user pick the map they are interested in. A simple dropdown might look something like this:
var maps = venue.maps;
for (var m = 0, mLen = maps.length; m < mLen; ++m) {
var map = maps[m];
var mapId = map.id;
var item = document.createElement("option");
item.text = map.shortName;
item.value = map.id;
item.id = map.id;
if (mapId == mapView.currentMap) {
item.selected = true;
};
mapList.add(item);
};
As you can see, Maps tend to have a short name and a long name. Which you display to the user will depend on context, the Venue, and screen real estate.
To change maps, use mapView.setMap(map, callback)
. This will replace the current map with the one you specify. It's worth noting that all of the MapView functions that accept Mappedin data can either take the object itself (the Map, Location, Node, etc from the Venue object) or just the Mappedin ID. This is especially useful when integrating with the Search API, which will return the ID but not the entire object. Avoid storing the ID outside the life of the Venue object, however, as if an object in the Mappedin CMS is destroyed and recreated with the same data, it will still have a different ID. Talk to Mappedin if you need something more durable to identify a specific resource.
The callback will be executed when the new map is fully loaded. The first time a Map is displayed, there will be a small delay as the 3D data is sent to the graphics card. Subsequent loads should be instantaneous, but for the first time you can consider a loading screen. When your callback fires, hide the loading screen.
The Mappedin Web SDK has built in wayfinding, with text directions and an animated, 3D path. You can navigate from a Node to another Node, or to a Location. This lets you go from a specific point on the map (ie, where the user is right now) to the closest entrance for their desired destination. This is especially useful for things that have multiple functionally identical locations throughout a venue, like Washrooms. Those are typically represented as a single location, with multiple entrances throughout the Venue. This makes it trivial to have a "Find nearest washroom" button.
To find directions, use the directionsTo
function (there is a similar directionsFrom
) on a Node, Polygon, or Location. This takes a destination, an options object indicating whether you want accessible directions or not (ie, don't take stairs and escalators) whether you want offline or the legacy online directions, and a callback for when the directions have been calculated and returned.
In your callback, if successful you will get a directions object with a path property you can pass to mapView.drawPath()
and mapView.focusOn()
.
startNode.directionsTo(endNode, { accessible: false, directionsProvider: "offline" }, function(error, directions) {
if (error || directions.path.length == 0) {
// Some kind of network error, or those two points aren't connected, or are invalid
return;
};
mapView.clearAllPolygonColors();
setMap(startPolygon.map);
mapView.setPolygonColor(startPolygon.id, mapView.colors.path);
mapView.setPolygonColor(endPolygon.id, mapView.colors.select);
mapView.focusOn(directions.path, [startPolygon, endPolygon], true, 2000);
mapView.removeAllPaths();
mapView.drawPath(directions.path);
});
When you call drawPath it will attempt to automatically handle breaking the path into multiple path segments and placing them on the correct map, animating them in sequence. You are responsible for placing any Markers to denote map transitions.
The directions engine will also return a set of text directions that you can display to the user. You may not need to, however, as most users understand where to go using only the animated 3D path.
You've already seen this in a few previous snippets, but it's worth a separate discussion. There will be many situations in which you would like to move the camera to draw attention to or provide a better view of certain map elements. Typically one or more nodes (either a specific point or a path), one or more polygons, or both. This is accomplished with the mapView.focusOn(options)
function.
focusOn will take some nodes and/or polygons and animate the camera into the midpoint of them. By default, it will also change the zoom level (in or out) to fit all of those objects into the camera's field of view. It will not switch maps for you (and will actually ignore nodes and polygons not on the current map). This means you can safely pass in the entire path you get from a directionsTo
call and not worry about which parts are on the current floor.
There are more advanced options in focusOn, including being able to set the animation duration and curve. See the docs for more details.
The Mappedin SDK comes with a powerful set of 2D marker controls. You can create markers containing arbitrary HTML and anchor them directly to a node or polygon. They will stay the same size on screen as the user zooms in and out, and can automatically shuffle themselves so that there is no overlap with adjacent markers.
To create a marker, use the simple mapView.createMarker
function.
var marker = mapView.createMarker(markerString, mapView.getPositionNode(node.id), "", node.map);
It will create a marker at the position use specified, with the HTML you supplied, and add it to the scene on map you specify. The position should be something you got from mapView.getPositionNode
or mapView.getPositionPolygon
. Trying to position something at arbitrary coordinates is not recommended at this time, as the underlying coordinate system is set to change.
In a future beta release, there will be a more advanced Marker class that will let you do things like turn the collision avoidance off, or lock the marker to rotate with the camera, and have full control over when the marker is added to the MapView.
It's possible to attach the rotation of an arbitrary HTML element to that of the map (with some offset). This lets you add a compass rose (ie, a little arrow pointing north) to the scene. This is done with the mapView.lockNorth(element, offset)
. For example:
var compass = document.getElementById("compass");
mapView.lockNorth(compass);
The Mappedin Web SDK does not have offline support built in, but it can be enabled via a Service Worker. Service Workers are a relatively new part of the web, and are not well supported on many browsers. However, modern versions of Chrome and Firefox do have support, making this an excellent tool when you are building your own standalone directory type application.
Check out the Mozilla docs for more information, but in brief Service Workers let you run your own JavaScript code to handle any network request from your page, and lets you provide your own response. There is an example implementation in the demo that should cover most use cases. It applies a cache fallback strategy: Any network requests are executed as they come in, and the results are saved in the cache and then returned to the app. If a network request fails (because of no internet access), the cached result is returned instead. This ensures you always have fresh data when you can access the network, but have a fallback option if you cannot.
This works because the Mappedin Web SDK (at least in 3D mode) downloads everything it needs ahead of time. When you call Mappedin.init, it starts the process, and when you get onDataLoaded, all the data the Web SDK needs has been downloaded and cached.
This strategy is designed to for the "mostly online" situation, where you generally have network access when needed, but there may be the occasional special case where, say, the power goes out and the kiosk application boots up before the network is back online. It is not designed to handle environments where the network is unreliable and going up and down during an update. For that situation, you could implement a strategy where you at each initialization you save to a new cache and if a network failure occurs before onDataLoaded is fired, you swap back to the old cache and re-init.
As touched on above, offline mode only works with 3D mode. The 2D fallback downloads tiles on the fly. We recommend simply using 3D mode, as it's quite able to run even on low end hardware, but you could also download the tiles ahead of time too. A bigger issue is that it will not automatically download any images attached to Mappedin objects (for example, icons and logos on Locations). This is because there are a number of possible sizes and you may or may not want to download any of them for your use case. If you do want them, just make sure you download them up front, and they will automatically be cached through the Service Worker. Smart Search and Analytics will not work while offline.