Skip to main content
Version: 6.0

Using React

Mappedin SDK version 6 is currently in a beta state while Mappedin perfects new features and APIs. Open the v6 release notes to view the latest changes.
Using Mappedin JS with your own map requires a Pro license. Try a demo map for free or refer to the Pricing page for more information.

Mappedin publishes a version of the JS package which is compatible with React applications. The package can be found here on NPM @mappedin/react-sdk.

The Mappedin React SDK exports convenient JSX components to render and manipulate the 3D map. Additionally, everything included in the @mappedin/mappedin-js is exported from the React SDK under the default export.

Local Development

For local development, start a project using Vite. Refer to the Vite Getting Started guide for setup details. Guides are written in TypeScript (JavaScript), as the SDK is written in Typescript and uses comprehensive types.

1. Create a Project

Run these shell commands to set up a new project and install Mappedin JS with React.

With Yarn

yarn create vite mappedin-quickstart --template react-ts
cd mappedin-quickstart
yarn add @mappedin/react-sdk@beta

With NPM

npm create vite@latest mappedin-quickstart -- --template react-ts
cd mappedin-quickstart
npm add @mappedin/react-sdk@beta

2. Update index.html, App.tsx

Modify & update the contents of index.html to match the following.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Mappedin JS v6 Getting Started</title>
<style>
* {
margin: 0;
padding: 0;
}
html,
body {
width: 100%;
height: 100%;
}
#root {
height: 100%;
width: 100%;
position: relative;
}
</style>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>

Modify & update the contents of App.tsx file under the src directory to match the following.

import React from 'react';
import { MapView, useMapData, useMap, Label } from '@mappedin/react-sdk';
import '@mappedin/react-sdk/lib/esm/index.css';

function MyCustomComponent() {
const { mapData } = useMap();

return mapData.getByType('space').map((space) => {
return <Label target={space.center} text={space.name} />;
});
}

export default function App() {
// See Demo API key Terms and Conditions
// https://developer.mappedin.com/v6/demo-keys-and-maps/
const { isLoading, error, mapData } = useMapData({
key: 'mik_yeBk0Vf0nNJtpesfu560e07e5',
secret: 'mis_2g9ST8ZcSFb5R9fPnsvYhrX3RyRwPtDGbMGweCYKEq385431022',
mapId: '65c0ff7430b94e3fabd5bb8c',
});

if (isLoading) {
return <div>Loading...</div>;
}

if (error) {
return <div>{error.message}</div>;
}

return mapData ? (
<MapView mapData={mapData}>
<MyCustomComponent />
</MapView>
) : null;
}

3. Run the Project

To run the demo (with hotloading), use the following command:

With Yarn

yarn run dev

With NPM

npm run dev

This should result in a prompt showing the project being served at http://127.0.0.1:5173 (default port). The 3D rendered map can be zoomed, panned and rotated via mouse or fingers.

MapView

The MapView component contains the DOM element of the 3D map and the context wrapper for control of the map. Components which reference the 3D map must be children of the MapView component to have access to the context. The Mappedin CSS must be imported alongside the MapView.

import React from 'react';
import { MapView, useMapData, useMap, Label } from '@mappedin/react-sdk';
import '@mappedin/react-sdk/lib/esm/index.css';

function MyCustomComponent() {
const { mapView, mapData } = useMap();

return mapData.getByType('space').map((space) => {
return <Label target={space.center} text={space.name} />;
});
}

export default function App() {
// See Demo API key Terms and Conditions
// https://developer.mappedin.com/v6/demo-keys-and-maps/
const { isLoading, error, mapData } = useMapData({
key: 'mik_yeBk0Vf0nNJtpesfu560e07e5',
secret: 'mis_2g9ST8ZcSFb5R9fPnsvYhrX3RyRwPtDGbMGweCYKEq385431022',
mapId: '65c0ff7430b94e3fabd5bb8c',
});

if (isLoading) {
return <div>Loading...</div>;
}

if (error) {
return <div>{error.message}</div>;
}

return mapData ? (
<MapView mapData={mapData} style={{ width: '650px', height: '650px' }}>
<MyCustomComponent />
</MapView>
) : null;
}

useMapData and useMap

The useMapData hook fetches and hydrates new Map Data from Mappedin servers. It is recommended to only do this once at the beginning of your application to limit the amount of network requests for the user.

It returns an object containing isLoading, error, and mapData. These can be used to monitor the state of the fetch and display feedback for the user.

// See Demo API key Terms and Conditions
// https://developer.mappedin.com/v6/demo-keys-and-maps/
const { isLoading, error, mapData } = useMapData({
key: 'mik_yeBk0Vf0nNJtpesfu560e07e5',
secret: 'mis_2g9ST8ZcSFb5R9fPnsvYhrX3RyRwPtDGbMGweCYKEq385431022',
mapId: '65c0ff7430b94e3fabd5bb8c',
});

The useMap hook returns an object containing the mapView and mapData once the 3D map has been rendered. Once the MapData has been initially fetched and passed to the <MapView>, useMap should be used to reference the hydrated data. useMap must be used in a child component of the <MapView>.

function MyCustomComponent() {
const { mapView, mapData } = useMap();

return mapData.getByType('space').map((space) => {
return <Label target={space.center} text={space.name} />;
});
}

useEvent

The useEvent hook enables subscribing to interactive map events and triggering a callback when they occur.

For example, the following snippet subscribes to the click event and updates state using the click coordinate. Labels are rendered based on the updated state. The click event contains all the interactive elements that the click action passed through.

See full JavaScript guides about Interactivity and the Camera for more information about events.

function MyCustomComponent() {
const { mapView, mapData } = useMap();
const [labels, setLabels] = useState([]);

useEvent('click', (event) => {
setLabels((prevLabels) => [...prevLabels, { target: event.coordinate, text: 'Hello, World!' }]);
});

return labels.map((label, idx) => <Label key={idx} {...label} />);
}

Other useful events include hover, camera-change, and floor-change.

The hover event is very similar to the click event and will contain all the interactive elements that are underneath the mouse cursor.

useEvent('hover', (event) => {
console.log('hover', event);
});

The camera-change event fires when the camera is adjusted. It contains the new bearing, pitch, zoomLevel and camera center coordinate.

useEvent('camera-change', (event) => {
console.log('camera-change', event.bearing, event.pitch, event.zoomLevel, event.center);
});

The floor-change event fires whenever the building floor is changed. It contains the floor and the reason that the change occurred.

useEvent('floor-change', (event) => {
console.log('floor-change', event.floor, event.reason);
});

Labels

The Label component renders a 2D point of interest label on the map. Typically, they are used to show the name of each Space in the building. Labelling each Space can be achieved by iterating through mapData.getByType('space') and returning a Label for each item.

See full JavaScript guide on Labels for more information.

function MyCustomComponent() {
const { mapData } = useMap();

return mapData.getByType('space').map((space) => {
return <Label target={space.center} text={space.name} />;
});
}

Markers

The Marker component pins a 2D DOM element to a coordinate on the map. React components can be provided as children of a Marker with their own state and interactivity.

The following example creates a simple Marker which will change its background color to "red" on click.

See full JavaScript guide on Markers for more information.

function CustomMarker() {
const [color, setColor] = useState('white');

return (
<div
style={{
backgroundColor: color,
padding: '10px',
border: '1px solid black',
}}
onClick={() => {
setColor('red');
}}
>
Hello, world!
</div>
);
}

function MyCustomComponent() {
const [coordinate] = useState(new Mappedin.Coordinate(43.46330802307551, -80.52367172398456));

return (
<Marker target={coordinate}>
<CustomMarker />
</Marker>
);
}

Paths

Paths can be drawn from A to B using the Path component. The Path component requires directions which must be created between two mapData objects.

The following example creates a Path from the first space in the data to the second.

See full JavaScript guide on Wayfinding for more information.

function MyCustomComponent() {
const { mapData, mapView } = useMap();

const space1 = mapData.getByType('space')[0];
const space2 = mapData.getByType('space')[1];
const directions = mapView.getDirections(space1, space2);

return directions ? <Path coordinate={directions.coordinates} options={{ color: 'blue' }} /> : null;
}

The Navigation component appears similar to the Path but with extra functionality to handle floor changes, start and end Markers, and styling.

See full JavaScript guide on Wayfinding for more information.

function MyCustomComponent() {
const { mapData, mapView } = useMap();

const space1 = mapData.getByType('space')[0];
const space2 = mapData.getByType('space')[1];
const directions = mapView.getDirections(space1, space2);

return directions ? <Navigation directions={directions} /> : null;
}

Shapes

The Shapes component takes a GeoJSON feature collection and renders it to the map in 3D.

function MyCustomComponent() {
return (
<Shape
geometry={featureCollection}
style={{
color: "red",
altitude: 0.2,
height: 2,
opacity: 0.7,
}}
/>
);
}

const featureCollection = {
type: "FeatureCollection",
features: [
{
type: "Feature",
properties: {},
geometry: {
type: "Polygon",
coordinates: [
..., // Some valid GeoJSON coordinates
],
},
},
],
};

Models

The Model component adds an instanced GLB/GLTF model to the map. The models prop accepts one or many targets to place the model at.

See full JavaScript guide on 3D Models for more information.

function MyCustomComponent() {
const { mapData } = useMap();

return (
<Model
models={mapData.getByType('space').map((space) => ({
target: space,
scale: [0.01, 0.01, 0.01],
rotation: [90, 0, 0],
opacity: 0.5,
}))}
options={{
url: 'https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Models/master/2.0/Duck/glTF-Binary/Duck.glb',
}}
/>
);
}

The following CodeSandbox implements all the features mentioned above.