Skip to content

Floor Plan SDK guide ​

A modern Typescript SDK for dynamic display of floor plans

Overview ​

The Floor Plan SDK enables you to create interactive, customizable floor plan models embedded in your website using JavaScript or TypeScript.

Desk booking interface example ​

  • HTML markers show each desk: an avatar for an occupied desk, a green dot for an available one. Click an available desk to book it (one desk per person), click again to release it.
  • Custom attributes identify the occupied workstations
  • Desks whose markers would overlap on screen are grouped into one marker with the number of available desks. The groups follow the proximity of the desks: the neighbours of each desk are found once with a within query, and every zoom level merges the desks that are closer than a marker size (single linkage clustering). Desk islands stay intact and merge with their neighbours as you zoom out. Click a group to zoom to it.

Zoom or pan the plan and click the markers. Click the plan to zoom out again.

Quick start ​

Install the Floor Plan SDK JS package via npm.

bash
npm install @archilogic/floor-plan-sdk

You can then import it into your project:

html
<div id="floor-plan"></div>
ts
import '@archilogic/floor-plan-sdk/dist/style.css'
import { FloorPlanEngine } from '@archilogic/floor-plan-sdk'

const container = document.getElementById('floor-plan')
const floorPlan = new FloorPlanEngine({ container })

// Create publishable access token at https://app.archilogic.com/organization/settings/access-tokens
const publishableAccessToken = '<your-token>'
const floorId = '<your-floor-id>'
floorPlan.loadFloorById(floorId, { publishableAccessToken })

Startup Options ​

The FloorPlanEngine has an optional parameter options. See below the various options that can be set through this parameter. The options are passed like the following:

js
new FloorPlanEngine({ container, options })

Options can be changed at runtime using the set method

js
floorPlan.set(options)

Theme ​

The SDK offers a wide range of theming options.

byType ​

Nodes can be styled by node type, e.g. layout:space or element:asset

js
const options = {
  theme: {
    byType: {
      'layout:space': { fill: '#ffffff' },
      'element:asset': { fill: '#8800ff' }
    }
  }
}
const floorPlan = new FloorPlanEngine({ container, options })
floorPlan.loadFloorById(floorId, { publishableAccessToken })
ts
import type { FpeConfig } from '@archilogic/floor-plan-sdk'

const options: FpeConfig = {
  theme: {
    byType: {
      'layout:space': { fill: '#ffffff' },
      'element:asset': { fill: '#8800ff' }
    }
  }
}
const floorPlan = new FloorPlanEngine({ container, options })
floorPlan.loadFloorById(floorId, { publishableAccessToken })

byId ​

Nodes can be styled by node id.

js
const options = {
  theme: {
    byId: {
      '<space-1>': { fill: '#0088ff' },
      '<space-2>': { fill: '#ff0088' }
    }
  }
}

const floorPlan = new FloorPlanEngine({ container, options })
floorPlan.loadFloorById(floorId, { publishableAccessToken })
ts
import type { FpeConfig } from '@archilogic/floor-plan-sdk'

const options: FpeConfig = {
  theme: {
    byId: {
      '<space-1>': { fill: '#0088ff' },
      '<space-2>': { fill: '#ff0088' }
    }
  }
}
const floorPlan = new FloorPlanEngine({ container, options })
floorPlan.loadFloorById(floorId, { publishableAccessToken })

byFilter ​

Nodes can be styled using powerful filters: ElementFilter or SpaceFilter

The last matching filter for a resource is applied.

Filter meeting spaces depending on the value of custom attribute isBookable

js
const options = {
  theme: {
    byFilter: [
      {
        where: {
          subCategory: 'meetingRoom',
          customAttributes: { isBookable: true }
        },
        style: { fill: '#65c389' }
      },
      {
        where: {
          subCategory: 'meetingRoom',
          customAttributes: { isBookable: false }
        },
        style: { fill: '#e56a59' }
      }
    ]
  }
}

const floorPlan = new FloorPlanEngine({ container, options })
floorPlan.loadFloorById(floorId, { publishableAccessToken })
ts
import type { FpeConfig } from '@archilogic/floor-plan-sdk'

const options: FpeConfig = {
  theme: {
    byFilter: [
      {
        where: {
          subCategory: 'meetingRoom',
          customAttributes: { isBookable: true }
        },
        style: { fill: '#65c389' }
      },
      {
        where: {
          subCategory: 'meetingRoom',
          customAttributes: { isBookable: false }
        },
        style: { fill: '#e56a59' }
      }
    ]
  }
}
const floorPlan = new FloorPlanEngine({ container, options })
floorPlan.loadFloorById(floorId, { publishableAccessToken })

roomStamps ​

roomStampDisplay allows to set the properties and their order for all room stamps shown in the floor plan.

The default value is ['usage', 'area'].

js
const attributeId = 'department-name'
const options = {
  theme: {
    roomStamps: {
      roomStampDisplay: ['name', 'customId', 'usage', 'area', ['customAttribute', attributeId]]
    }
  }
}
const floorPlan = new FloorPlanEngine({ container, options })
floorPlan.loadFloorById(floorId, { publishableAccessToken })
ts
import type { FpeConfig } from '@archilogic/floor-plan-sdk'

const attributeId = 'department-name'
const options: FpeConfig = {
  theme: {
    roomStamps: {
      roomStampDisplay: ['name', 'customId', 'usage', 'area', ['customAttribute', attributeId]]
    }
  }
}
const floorPlan = new FloorPlanEngine({ container, options })
floorPlan.loadFloorById(floorId, { publishableAccessToken })

To set a name, customId for a space, you can use the Archilogic Editor.
Custom attributes are user defined properties, that can be defined for an organisation in the Dashboard or via API and then edited in the Editor.

Asset stamps ​

Assets can carry a stamp of their own — a text label drawn on top of the asset, configured with label on the element:asset theme entry. Set display to choose what it shows; without it no stamp is drawn.

Because stamps quickly become unreadable on a zoomed-out plan, visible takes a ZoomRange that restricts them to a zoom window, and fixedScreenSize controls how they scale.

js
const options = {
  theme: {
    byType: {
      'element:asset': {
        label: {
          display: ['customId'],
          text: [51, 51, 51],
          visible: [40, 300],
          fixedScreenSize: [40, 120]
        }
      }
    }
  }
}
const floorPlan = new FloorPlanEngine({ container, options })
floorPlan.loadFloorById(floorId, { publishableAccessToken })
ts
import type { FpeConfig } from '@archilogic/floor-plan-sdk'

const options: FpeConfig = {
  theme: {
    byType: {
      'element:asset': {
        label: {
          display: ['customId'],
          text: [51, 51, 51],
          visible: [40, 300],
          fixedScreenSize: [40, 120]
        }
      }
    }
  }
}
const floorPlan = new FloorPlanEngine({ container, options })
floorPlan.loadFloorById(floorId, { publishableAccessToken })

Only assets that have a customId are stamped. Set one in the Archilogic Editor or via the Space API.

Visibility ​

Show or hide elements and spaces without changing their style. Visibility uses the same byType / byId / byFilter composition as the theme, and is honored by every output — hidden nodes are left out of the rendered plan and of exportImage.

Each rule is { show: false } to hide or { show: true } to re-show. The most specific rule wins: byId over byFilter over byType.

byType ​

Show or hide whole node types, e.g. element:asset or roomStamp.

js
const options = {
  visibility: {
    byType: {
      'element:asset': { show: false }
    }
  }
}
const floorPlan = new FloorPlanEngine({ container, options })
floorPlan.loadFloorById(floorId, { publishableAccessToken })
ts
import type { FpeConfig } from '@archilogic/floor-plan-sdk'

const options: FpeConfig = {
  visibility: {
    byType: {
      'element:asset': { show: false }
    }
  }
}
const floorPlan = new FloorPlanEngine({ container, options })
floorPlan.loadFloorById(floorId, { publishableAccessToken })

byId ​

Show or hide individual elements and spaces by node id.

js
const options = {
  visibility: {
    byId: {
      '<space-1>': { show: false },
      '<asset-1>': { show: true }
    }
  }
}
const floorPlan = new FloorPlanEngine({ container, options })
floorPlan.loadFloorById(floorId, { publishableAccessToken })
ts
import type { FpeConfig } from '@archilogic/floor-plan-sdk'

const options: FpeConfig = {
  visibility: {
    byId: {
      '<space-1>': { show: false },
      '<asset-1>': { show: true }
    }
  }
}
const floorPlan = new FloorPlanEngine({ container, options })
floorPlan.loadFloorById(floorId, { publishableAccessToken })

byFilter ​

Show or hide nodes using ElementFilter or SpaceFilter. The last matching filter for a resource is applied, so a broad hide followed by a narrow show expresses "show only X".

Hide every asset, then re-show only workstations:

js
const options = {
  visibility: {
    byFilter: [
      { where: { type: 'element:asset' }, show: false },
      { where: { subCategory: 'workstation' }, show: true }
    ]
  }
}
const floorPlan = new FloorPlanEngine({ container, options })
floorPlan.loadFloorById(floorId, { publishableAccessToken })
ts
import type { FpeConfig } from '@archilogic/floor-plan-sdk'

const options: FpeConfig = {
  visibility: {
    byFilter: [
      { where: { type: 'element:asset' }, show: false },
      { where: { subCategory: 'workstation' }, show: true }
    ]
  }
}
const floorPlan = new FloorPlanEngine({ container, options })
floorPlan.loadFloorById(floorId, { publishableAccessToken })

Replaces hideElements

visibility supersedes the deprecated hideElements option. hideElements: ['element:asset'] is equivalent to visibility: { byType: { 'element:asset': { show: false } } }. hideElements still works but will be removed in a future major version.

Space label mapping ​

Map space labels by space usage or space id. Refer to the space taxonomy for reference.

js
const options = {
  spaceLabelMapping: {
    meetingRoom: '회의실'
  }
}
const floorPlan = new FloorPlanEngine({ container, options })
floorPlan.loadFloorById(demoSceneId, { publishableAccessToken })

Queries ​

Query methods have powerful filter options similar to the GraphQL API. They have the same interface as the Extension SDK queries, except not being async.

Query type inference ​

TIP

When using Typescript the return type of queries is properly inferred from the select type.

ts
const spaces = floorPlan.getSpaces({
  select: { area: true, id: true, contour: true }
})
spaces[0].area // type: number
spaces[0].id // type: string
spaces[0].contour // type: PolygonWithHoles

The default selector is { id: string, type: string }

ts
const spaces = floorPlan.getSpaces()
spaces[0].id // type: string
spaces[0].type // type: string

Get elements ​

Query elements with the getElements method by various properties and optionally select the shape of the returned objects.

ts
const largeWindows = floorPlan.getElements({
  where: { type: 'element:window', dimensions: { length: { gte: 3 } } }
})

at and within are spatial filters: at matches the elements at a point, within the elements whose bounding box intersects a rectangle, e.g. the desks in a 10m square around position.

ts
const [x, y] = position
const nearbyDesks = floorPlan.getElements({
  where: { subCategory: 'workstation', within: { min: [x - 5, y - 5], max: [x + 5, y + 5] } }
})

Get element by id ​

Retrieve specific properties from an element with getElementById

ts
const { dimensions, boundingBox } = floorPlan.getElementById({
  id: '<asset-id>',
  select: { boundingBox: true, dimensions: true }
})

Get spaces ​

Query spaces with the getSpaces method by various properties and optionally select the shape of the returned objects.

ts
const spaces = floorPlan.getSpaces({
  where: { seatCapacity: { gte: 5 } }
})

Get space by id ​

Retrieve specific properties from a space with getSpaceById

ts
const { labelPoint, contour, elements } = floorPlan.getSpaceById({
  id: '<space-id>',
  select: { labelPoint: true, contour: true, elements: true }
})

Get layout ​

Query layout properties like bounding box or custom attributes

ts
const { boundingBox, customAttributes } = floorPlan.getLayout({
  select: { boundingBox: true, customAttributes: true }
})

Events ​

The FloorPlanEngine instance exposes a few useful events

Subscribe

js
floorPlan.on(event, callback, context)

Subscribe for one event

js
floorPlan.once(event, callback, context)

Unsubscribe

js
floorPlan.off(event, callback)

click ​

Mouse click or touch event.

Instead of click you can also listen for dblclick

js
// returns the plan position, the sourceEvent and if present the id of the node that you clicked on
floorPlan.on('click', onClick)

function onClick({ position, sourceEvent, nodeId }) {
  // to get the top resource that was clicked on use the nodeId
  const asset = floorPlan.getElementById({ id: nodeId })
  const space = floorPlan.getSpaceById({ id: nodeId })
  // to get all resources for that position use the filter where.at
  const assets = floorPlan.getElements({ where: { at: position } })
  const spaces = floorPlan.getSpaces({ where: { at: position } })
}
ts
import type { FpePointerEvent } from '@archilogic/floor-plan-sdk'

// returns the plan position, the sourceEvent and if present the id of the node that you clicked on
floorPlan.on('click', onClick)

function onClick({ position, sourceEvent, nodeId }: FpePointerEvent) {
  // to get the top resource that was clicked on use the nodeId
  const asset = nodeId && floorPlan.layout.elementsById[nodeId]
  const space = nodeId && floorPlan.layout.spacesById[nodeId]
  // to get all resources for that position use the filter where.at
  const assets = floorPlan.getElements({ where: { at: position } })
  const spaces = floorPlan.getSpaces({ where: { at: position } })
}

mousemove ​

Fired when moving the mouse

js
floorPlan.on('mousemove', onMouseMove)

function onMouseMove({ position, sourceEvent, nodeId }) {
  // ...
}
ts
import type { FpePointerEvent } from '@archilogic/floor-plan-sdk'

floorPlan.on('mousemove', onMouseMove)

function onMouseMove({ position, sourceEvent, nodeId }: FpePointerEvent) {
  // ...
}

drop ​

Fired when dropping a draggable Element on the canvas

js
floorPlan.on('drop', onDrop)

function onDrop({ position, sourceEvent, nodeId }) {
  // ...
}
ts
import type { FpeDropEvent } from '@archilogic/floor-plan-sdk'

floorPlan.on('drop', onDrop)

function onDrop({ position, sourceEvent }: FpeDropEvent) {
  // ...
}

loading done ​

Fired when loading is done and the floor is rendered. This is an alternative to awaiting the promise of floorPlan.loadFloorById().

js
floorPlan.on('loading-done', onLoadingDone)

function onLoadingDone() {
  // ...
}

Zoom ​

The SDK provides various zoom methods

Zoom extents ​

Allows you to zoom to the extent of the scene, with a specified margin using zoomExtents.

Zoom to element ​

You can also zoom into an element (space, asset) with or without animation using the zoomToElement method.

js
// get a space ID
const spaces = floorPlan.getSpaces({ where: { category: 'meet' } })
const spaceId = spaces[0].id
// zoom to the space with 2m margin and 500ms animation time
floorPlan.zoomToElement(spaceId, 2, 500)

Zoom by factor ​

Zoom the current view by a factor with zoomByFactor. A zoom factor, larger than 1 zooms in, smaller than 1 zooms out.

js
floorPlan.zoomByFactor(1.2, true)

Set zoom ​

Set the view box by providing a bounding box using the setZoom method.

Markers ​

Add marker ​

The addMarker method can be used to add extra information to a given location within the floor plan. It requires the following parameters:

ts
floorPlan.addMarker({
  position: [7, 2],
  color: '#0c9'
})

Where

  • position is the position on the floor plan specified in meters where the info window points
  • width, height specifies the size of the info window

Returns Marker instance

Add Html marker ​

The addHtmlMarker method can be used to add extra information to a given location within the floor plan. It requires the following parameters:

ts
const el = document.createElement('div')
el.classList.add('my-marker')
floorPlan.addHtmlMarker({
  position: [7, 2],
  el
})

Where

  • position is the position on the floor plan specified in meters where the info window points
  • el is the HTML Element that you want to mount at that position

Returns Html Marker instance

Drawing ​

Add layer and graphics ​

Custom shapes can be drawn on top of the floor plan and organized by layers. Each shape can be styled differently.

Color formats

Colors in ShapeStyle (fill, stroke) accept three equivalent formats:

  • CSS hex string: '#ff0000'
  • Hex number: 0xff0000
  • RGB array: [255, 0, 0]

Note: MarkerPin.color only accepts a CSS color string.

js
const layer = floorPlan.addLayer({ id: 'circles' })
const list = Array.from({ length: 15 }, (_, i) => i + 1)

layer.addGraphic({
  shapes: list.map(radius => ({
    type: 'curve:circle',
    radius,
    position: [0, 0],
    style: { stroke: '#ffab00', strokeWidth: radius * 2 }
  }))
})
ts
import type { Shape } from '@archilogic/floor-plan-sdk'

const layer = floorPlan.addLayer({ id: 'circles' })
const list: number[] = Array.from({ length: 15 }, (_, i) => i + 1)

layer.addGraphic({
  shapes: list.map<Shape>(radius => ({
    type: 'curve:circle',
    radius,
    position: [0, 0],
    style: { stroke: '#ffab00', strokeWidth: radius * 2 }
  }))
})

Drawing a heatmap or image ​

Instead of a color fill shapes can use a texture URL as fill. This works for remote images aswell as realtime computed image data like a heatmap.

The shape curve acts as a mask for the image. For unmasked images choose the rectangle curve.

js
const layer = floorPlan.addLayer({ id: 'circles' })

const heatMapUrl = createHeatmapUrl()

layer.addGraphic({
  shapes: [
    {
      type: 'curve:polygon',
      points: [
        [0, 0],
        [10, 0],
        [10, 10],
        [0, 10]
      ],
      fill: `url(${heatMapUrl})`
    }
  ]
})

Highlight a resource ​

All exposed resources can be colored programmatically floorPlan.drawNodeUpdate

js
// use the setHighlight method to temporarily change its color and its outline
floorPlan.drawNodeUpdate('<node-id>', {
  fill: [236, 112, 99],
  stroke: [200, 42, 25],
  strokeWidth: 2
})
// use the same method to reset the color
floorPlan.drawNodeUpdate('<node-id>', false)

Example ​

Color all assets based on their position

ts
const floorPlan = new FloorPlanEngine({ container })
floorPlan.loadFloorById(floorId, { publishableAccessToken }).then(() => {
  highlightNodes()
})

function highlightNodes() {
  const assets = floorPlan.getElements({
    where: { type: 'element:asset' },
    select: { id: true, transform: true }
  })
  for (const asset of assets) {
    const fill = asset.transform.position.map(n => Math.min(255, Math.max(0, Math.round(n) * 10)))
    floorPlan.drawNodeUpdate(asset.id, { fill })
  }
}

Save floor plan as image ​

A method is provided to save the displayed floor plan as either jpg of png image: exportImage

js
floorPlan.exportImage({
  download: true,
  format: 'jpg'
})

Wayfinding ​

Compute walkable routes on the loaded floor. The navigation mesh is built on the first call and reused until another floor is loaded; the wayfinding module is loaded on demand. Points outside the walkable area are mapped to the closest walkable point.

Get path ​

Shortest walkable route between two points and its length in meters. path is empty when the points are not connected. getPath

ts
const route = await floorPlan.getPath({ start: [3, 4.5], end: [25, 12] })
// { path: Vector2[], distance: number }

Find closest ​

The closest reachable space or element matching a query filter, with the route to it. target is null when nothing matching is reachable. findClosest

ts
const closest = await floorPlan.findClosest({
  start: [3, 4.5],
  where: { subCategory: 'meetingRoom', customAttributes: { isBookable: true } }
})
// { path, distance, target: { id, position } | null }

The sample marks bookable meeting rooms through the theme's byFilter, starts at the elevator and routes to the closest bookable room with the same filter. Drag the start point to update the route.