Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@wework/floormap-sdk

Package Overview
Dependencies
Maintainers
20
Versions
301
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@wework/floormap-sdk

[![CircleCI](https://circleci.com/gh/WeConnect/floormap-sdk/tree/master.svg?style=svg&circle-token=679c562fecb8e63401d492b82329d3d17a8c3430)](https://circleci.com/gh/WeConnect/floormap-sdk/tree/master) [![Coverage Status](https://coveralls.io/repos/github

  • 0.0.8
  • npm
  • Socket score

Version published
Weekly downloads
36
increased by1100%
Maintainers
20
Weekly downloads
 
Created
Source

FloorMap SDK

CircleCI Coverage Status

Installation

NPM

You might need npm login

You will need to be logged in to install dependency. Execute npm login and use the username, password, and e-mail found in 1Password under npmjs (dev-team).

npm install @wework/floormap-sdk

# Yarn
yarn add @wework/floormap-sdk

And import the SDK with:

import * as FloorMap from '@wework/floormap-sdk'

// you also can cherry-pick import a module from sdk by
// import { Manager } from '@wework/floormap-sdk'

UMD

By using the UMD format, You can access the SDK via FloorMap variable

<script type="text/javascript" src="floormap-sdk.min.js"></script>

In JavaScript

const manager = new FloorMap.Manager({ /* ... */ })
const floorMap = manager.createFloorMap(target, { /* ... */ })

Please see example/sample for UMD usage

Getting started

Authentication

Before create and render a floor map, you need to authenticate with MilkyWay service by creating Manager object and providing a credential

To request for an appId/appSecret, kindly email tech-sg@wework.com with the subject Request for FloorMap SDK credentials and a brief explanation of its intended purpose.

const manager = new FloorMap.Manager({
  appId: /* App ID */,
  appSecret: /* App Secret */,
  baseUrl: 'https://occupancy-api-staging.spacemob.co',
})

Then, use .authenticate function to start authenticating

manager.authenticate().then((mwAccessToken) => {
  // Authenticated
}).catch((e) => {
  // Authenticating Error
})

Spaceman JWT Token

Spaceman JWT Token is supported directly by the SDK, You can pass Spaceman JWT while constructing maanger instance.

const manager = new FloorMap.Manager({
  appId: /* App ID */,
  appSecret: /* App Secret */,
  baseUrl: 'https://occupancy-api-staging.spacemob.co',
  spacemanToken: /* Spaceman JWT */
})

Store result mwAccessToken for futher usage

authenticate function resolves mwAccessToken object. You can store the access token object for futher use and provide the token object next time you're creating a manager.

manager.authenticate().then((mwAccessToken) => {
  // Authenticated
  localStorage.setItem('MW_TOKEN_STORAGE_KEY', JSON.stringify(mwAccessToken))
})

// Next time
const mwAccessToken = JSON.parse(localStorage.getItem('MW_TOKEN_STORAGE_KEY'))
const manager = new FloorMap.Manager({
  /* ... */
  mwAccessToken: mwAccessToken
})

After this point, the manager instance is ready to create and render the floormap.

Create a floor map

First, create an emtry html element for the map to render itself

<body>
  <section id="container"></section>
</body>

Next, Use maanger instance to create and render a floormap and provide target element.

const target = document.getElementById('container')
const floorMap = manager.createFloorMap(target, options)

FloorMap options

  • options.backgroundColor - Background color of the map
  • options.deskLayout - Show desk layout
  • options.deskInteractable - Allow desk/chair to be interactable

After created the floormap, Call render function with buildingId and floorId to render a floor map into the screen (if floorId is omitted, the lowest floor of the building will be rendered)

// Render Map
floorMap.render({
  buildingId: 'b308b94c-bca6-4318-b906-1c148f7ca183',
  /* floorId: '' */
})

Final source code

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>FloorMap</title>

    <style>
      body {
        margin: 0;
        padding: 0;
      }
      #main {
        position: fixed;
        top: 0;
        right: 0;
        bottom: 0;
        left: 0;
      }
    </style>
  </head>
  <body>
    <div id="container"></div>

    <script src="../../dist/floormap-sdk.js"></script>
    <script>
      async function renderMap() {
        const target = document.getElementById('container')
        let currentId = null

        // Credential
        const manager = new FloorMap.Manager({
          appId: /* APP_ID */,
          appSecret: /* APP_SECRET */,
          baseUrl: 'https://occupancy-api-staging.spacemob.co',
        })

        // Authenticating
        await manager.authenticate()

        // Create Floor Map
        const floorMap = manager.createFloorMap(target, {
          backgroundColor: '#303030',
        })

        // Render Floor
        floorMap.render({
            buildingId: 'b308b94c-bca6-4318-b906-1c148f7ca183',
        })
      }

      renderMap()
    </script>
  </body>
</html>

Map Event

You can subscribe to user interaction and data event on the map by using addEventlistener and removeEventListener to remove a listener on the floor map instance

// Mouse moveover a space
floorMap.addEventListener('onmouseover', (event) => {})

// Mouse moveout a space
floorMap.addEventListener('onmouseout', (event) => {})

// On click a space
floorMap.addEventListener('onclick', (event) => {})

// When user moving mouse cursor on the map
floorMap.addEventListener('onmousemove', (event) => {})

// When physical data change
floorMap.addEventListener('datachange', (event) => {})

// Renderer event (mostly use for debugging purpose)
floorMap.addEventListener('onerror', (event) => {})
floorMap.addEventListener('onrender', (event) => {})

An event object will contain:

  • type - Event type
  • payload - An informations of the interaction
  • data - Space data, If an interaction is on space/object

Example payload

{
  "type": "onclick",
  "payload": {
    "id": "cdc9c84e-d092-11e7-9d13-0642b0acf810",
    "point": { "x": 14.237798863250575, "y": 74.47726859122804, "z": -3 },
    "mousePos": { "x": 530, "y": 203 }
  },
  "data": {
    /* Space Data */
  }
}

Styling

You can manipulate the style of space, table, and chair by using functions on floorMap instance:

  • applyStyle(spaceUUID, style, key) - Apply style to space
  • revertStyle(spaceUUID, key) - Revert style with matched key from a given space
  • resetStyle(spaceUUID) - Reset all styles from a given space
floorMap.applyStyle(spaceUUID, { color: 'aqua' }, 'highlight')

Style is Stack

When we call applyStyle, we can think of pushing thing into the stack. If we call applyStyle with different key, the later style will be push of top of the stack of overwrite property in previous items in the stack.

Also we call applyStyle with a key that already exist in the stack, that style with key will be replaced with new style instead of merging and stay in the current position in the stack instead of bumb to the top

For example:

// Stack
//
// - somekey:{ color: 'red', opacity: 0.8 }
//
// result style: { color: 'red', opacity: 0.8  }
floorMap.applyStyle(spaceUUID, { color: 'red', opacity: 0.8 }, 'somekey')


// Apply style with new key `somekey`
//
// Stack
//
// - otherkey: { opacity: 0.5 }
// - somekey: { color: 'red', opacity: 0.8 }
//
// result style: { color: 'red', opacity: 0.5 }
floorMap.applyStyle(spaceUUID, { opacity: 0.5 }, 'otherkey')


// Apply style to existing key `somekey`
//
// Stack
//
// - otherkey: { opacity: 0.5 }
// - somekey: { color: 'red', opacity: 1.0 }
//
// result style: { color: 'red', opacity: 0.5 }
floorMap.applyStyle(spaceUUID, { color: 'red', opacity: 1.0 }, 'somekey')


// We revert 'somekey' style
// Stack
//
// - otherkey: { opacity: 0.5 }
//
// result style: { opacity: 0.5 }
floorMap.revertStyle(spaceUUID, 'somekey')


// Remove all style in stack
floorMap.resetStyle(spaceUUID)

Combine event and style to create an user interaction feedback

// - Event Handling
floorMap.addEventListener('onmouseover', event => {
  const { payload, data } = event

  // Highlight Space
  floorMap.applyStyle(payload.id, { color: 'aqua' }, 'HOVER')
})

floorMap.addEventListener('onmouseout', event => {
  const { payload, data } = event

  // unhighlight Space
  floorMap.applyStyle(payload.id, {}, 'HOVER')

  // You also can use revertStyle
  // floorMap.revertStyle(payload.id, 'HOVER')
})

Map lifecycle hooks

Map lifecycle give an opportunitues to you to start loading data along with when the map start loading data, modify physical data or apply style to an object before the map start render an object into the screen.

onLoad -> didLoad -> onRender -> didRender

onLoad

onLoad hook allow you to prepare your own data while map start loading their data. You can return a Promise from the function, The map will wait until your Promise to be resolved before go to next lifecycle

floorMap.onLoad(({ building, floor, options, errors }) => {
  return fetch(/* ... */)
})

didLoad

didLoad will get called when the map finished loading their and the Promise from onLoad(s) has been resolved. You can use this function to modify the physical data in the map

floorMap.didLoad(({ building, floor, options, errors }) => {
  // Change room type
  floorMap.updateData(spaceeUUID, { roomType: 'Private Large Office' })
})

onRender

onRender will get called during the map is preparing render object for rendering into the screen, but not yet rendered into the screen. This function give you an opportunity to apply style to spaces.

floorMap.onRender(({ building, floor, options, errors }) => {
  floorMap.applyStyle(spaceUUID, { color: 'aqua'}, 'occupancy-style')
})

didRender

didRender will get called when the map finished render objects into screen. You can add custom overlay into the map on this lifecycle (We will talk about map overlay in next section)

floorMap.didRender(({ building, floor, options, errors }) => {
  const imageOverlay = new ImageOverlay(noteIcon, {
    width: 3,
    height: 3,
  })

  imageOverlay.spaceUUID = spaceUUID
  floorMap.addObject(imageOverlay)
})

Control the map

setZoomLevel

Set the zoom level

floorMap.setZoomLevel(zoomLevel: number)

getZoomLevel

Get current zoom level of the map

floorMap.getZoomLevel(): number

setCenter

Set the camera rotation view angle

floorMap.setCenter({ x: number, y:number, z: number })

Example
floorMap.setCenter({ x: 2, y: 0, z: 5 })

setRotation

Rotate the map

floorMap.setRotation(veticalDegree: number, horozontalDegree: number)

  • rotationDegree Vetical rotation degree
  • polarAngle Horizontal rotation degree
Example
floorMap.setRotation(rotationDegree, polarAngle)

Object Overlay

ImageOverlay

const imageOverlay = new FloorMap.ImageOverlay(imageUrl, {
  width: 3,
  height: 3,
})

// Add image into space
// This will automatically calculate position of the image
imageOverlay.spaceUUID = '[PHYSICAL_SPACE_UUUD]'

floorMap.addObject(imageOverlay)

TextOverlay

const textOverlay = new FloorMap.TextOverlay('FloorMapSDK!!')

textOverlay.position = { x: 0, y: 0, z: 0 }
textOverlay.scalar = 2
textOverlay.style = {
  color: '#000000',
  fontFamily: 'Arial, Helvetica, sans-serif',
  textAlign: 'center',
  fontWeight: 'normal', // normal, bold, bolder, lighter
  fontStyle: 'normal', // normal, italic, oblique
}

floorMap.addObject(overlay)

LineOverlay

const lineOverlay = new FloorMap.LineOverlay()
lineOverlay.style = {
  color: '#303030'
}

lineOverlay.addPoint({ x: 100, y: 100 })
lineOverlay.addPoint({ x: 100, y: 200 })

// Add Overlay to floormap
floorMap.addObject(lineOverlay)

// Update point at index
// updatePoint(index, point)
lineOverlay.updatePoint(1, { x: 100, y: 300 })

// Remove point at index
// removePoint(index, point)
lineOverlay.removePoint(1, { x: 100, y: 300 })

// Update current overlay
floorMap.updateObject(lineOverlay)

PolygonOverlay

const polygon = new FloorMap.PolygonOverlay(
  [
    { x: x - 10, y: y - 10 },
    { x: x + 10, y: y - 10 },
    { x: x + 10, y: y + 10 },
    { x: x - 10, y: y + 10 },
  ],
  { color: 'aqua', opacity: 0.6 }
)
polygon.style = { color = '#000000', outline, opacity = 1 }
polygon.interactable = true

floorMap.addObject(polygon)

FloorMapGL Render Object

ImageOverlay, TextOverlay, LineOverlay, and PloygonOverlay are the abstractions of floormap.gl object. That means we can add floormap.gl's object using .addObject function as well.

floorMap.addObject({
  id: '001', // required
  tags: ['level 3'],
  type: 'MESH',
  style: {
    color: 'rgb(155, 255, 55)',
    side: 'FRONT',
    texture: {
      img: '',
      repeat: 0.5
    }
    outline: {
      color: 'rgb(255, 0, 0)',
      width: 0.2,
      only: false
    }
  },
  points: [
    { x: -1, y: -1 },
    { x: 1, y: -1 },
    { x: 1, y: 1 },
    { x: -1, y: 1 }
  ],
  geometryTranslate: {x: -1, y: -1, z: 0},
  interactable: true,
  visible: true,
  extrude: 2,
  position: { x: 0, y: 0, z: 0 },
  rotation: { x: 0, y: 0, z: 0 },
  scale: { x: 1, y: 1, z: 1 }
})

The documentation on floormap.gl render object can be found on Floormap.GL repository

Add Object

floorMap.addObject(overlay)

// You can add multiple objects as once by passing array of objects
floorMap.addObject([overlay, overlay2])

Remove Object

FloorMap overlay/object can be removed by calling .removeObject with object or id

floorMap.removeObject(overlay)
floorMap.removeObject(id)

// Remove multiple objects as once
floorMap.removeObject([overlay1, overlay2])
floorMap.removeObject([id1, id2])

Overlay Positioning

To position an overlay on the map we can set position property.

const imageOverlay = new ImageOverlay()
imageOverlay.position = { x: 100, y: 100 }

floorMap.addObject(imageOverlay)

In case you want to add an overlay into the specific space/room. Instead of manually calculate the position of a room, we can omit position value and assign spaceUUID to an overlay. The floor map will calculate the center position of the room and assign it to the overlay.

const imageOverlay = new ImageOverlay()
imageOverlay.spaceUUID = 'SPACE_UUID'

floorMap.addObject(imageOverlay)

Separate of concern with extension

Create extension

To be added


Built-in extensions

Reservable extension
  • Apply map style and icon based on occupancy status
  • Provide reservable filter function
  • Update office note
  • Creaet/Update/Remove office hold
const occupancyExtension = new FloorMap.OccupancyExtension()
floorMap.registerExtension(occupancyExtension)

// by space or object Id
floorMap.extensions.reservable.getDataById(spaceOrObjectId)
// by reservable Id
floorMap.extensions.reservable.getDataByReservableId(reservableId)

// Filter
// Filter by text
floorMap.extensions.reservable.filter({ search: '100'})

// Filter by type(s)
floorMap.extensions.reservable.filter({ type: 'Office' })
floorMap.extensions.reservable.filter({ type: ['Office', 'DESK'] })

// Filter by capacity
floorMap.extensions.reservable.filter({ capacity: '4-6' })
floorMap.extensions.reservable.filter({ capacity: ['2-4', '8', '12-20'] })

// Filter by price range
floorMap.extensions.reservable.filter({ price: { min: 1000, max: 3000 }})

// Filter by availablity and MIMO
floorMap.extensions.reservable.filter({ availability: { from: '2018-01-01', to: '2018-01-31'} })
floorMap.extensions.reservable.filter({ mimo: { mi: '2018-01-01', mo: '2018-01-31'} })

// Office note
floorMap.extensions.reservable.updateOfficeNote(reservableUUID, note)

BuildingIndex extension
  • Provide building index filter function
const buildingIndexExt = new FloorMap.BuildingIndexExtension()
floorMap.registerExtension(buildingIndexExt)

/**
 * @typedef BuildingIndexFilterOptions
 * @type {Object}
 * @property {string} [search]
 * @property {number|string|string[]} [desks]
 * @property {string|string[]} [programType]
 * @property {string|string[]} [subType]
 * @property {hasWindow} [hasWindow]
 * @property {hasInternalRoom} [hasInternalRoom]
 */
buildingIndexExt.filter(BuildingIndexFilterOptions)
// or
floorMap.extensions.buildingIndex.filter(BuildingIndexFilterOptions)

Discount extension
  • Provide fetch discount function
const discountExtension = new FloorMap.DiscountExtension()
floorMap.registerExtension(discountExtension)

const discount = await discountExtension.getDiscounts(systemPropertyUUID, reservableId)

Example

# Clone
git clone git@github.com:WeConnect/floormap-sdk.git
cd floormap-sdk

# Install dependencies
yarn install

# Start demo and development
yarn start:demo

Open http//localhost:3000/

FAQs

Package last updated on 16 Jan 2019

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc