Appearance
Multi-floor buildings
One plan can hold a whole building: basements, ground floor and any number of floors above. Everything stays in one JSON document, and every component knows which floor it's showing.
The hotel below has four floors. Pick a floor with the buttons on the right, and switch between Floor, Building and Exploded at the bottom right.
Loading the live demo…
Floors in the editor
The floor menu sits at the left of the toolbar in the top-right corner. It shows the floor you're editing, for example G Ground floor.
| Action | How |
|---|---|
| Switch floor | Pick it in the floor menu, or press Page Up / Page Down |
| Add a floor | Add floor above / Add floor below in the floor menu |
| Rename, set height | Floor settings in the floor menu |
| Copy a floor | Floor settings → Duplicate floor: copies the walls, rooms, doors and furniture onto a new floor on top. Perfect for hotels and offices with repeating floors. |
| Reorder | Floor settings → Move up / Move down swaps the floor with its neighbour |
| Delete | Floor settings → Delete floor (a building always keeps at least one floor) |
While you edit a floor, the floor below is drawn faintly underneath as a guide, so outer walls, stairs and lift shafts line up. Undo and redo cover floor changes too.
vue
<FloorPlanEditor v-model="plan" v-model:floor="floorId" />tsx
<FloorplanEditor plan={plan} onChange={setPlan} floor={floorId} onFloorChange={setFloorId} />html
<floorplan-editor></floorplan-editor>
<script type="module">
const editor = document.querySelector('floorplan-editor')
editor.plan = plan
editor.floor = floorId
editor.addEventListener('floor-change', (e) => (floorId = e.detail.floor))
</script>The floor binding is optional. Use it to start on a particular floor or to keep the floor in sync with the rest of your page.
Floors in the 2D viewer
When a plan has more than one floor, a column of floor buttons appears in the top-right corner. The view keeps its position when you switch floors, because all floors share the same coordinates.
- Markers show on their own floor (see Markers).
plan-click,marker-moveandmarker-draginclude thefloorthe event happened on.focusMarker(id)andfocusRoom(id)switch to the right floor automatically.
vue
<FloorPlanViewer :plan="plan" :markers="markers" v-model:floor="floorId" @plan-click="({ x, y, floor }) => …" />tsx
<FloorplanViewer
plan={plan}
markers={markers}
floor={floorId}
onFloorChange={setFloorId}
onPlanClick={({ x, y, floor }) => …}
/>html
<floorplan-viewer></floorplan-viewer>
<script type="module">
const viewer = document.querySelector('floorplan-viewer')
viewer.plan = plan
viewer.markers = markers
viewer.floor = floorId
viewer.addEventListener('floor-change', (e) => (floorId = e.detail.floor))
viewer.addEventListener('plan-click', (e) => {
const { x, y, floor } = e.detail
})
</script>Set showFloorSwitcher to false to hide the buttons and drive the floor from your own UI (:show-floor-switcher="false" in Vue, showFloorSwitcher={false} in React, viewer.showFloorSwitcher = false on the element).
Try it in 2D: switch floors with the buttons on the right, and notice the view stays where it is.
Loading the live demo…
The whole building in 3D
The 3D viewer has three ways to show a multi-floor building. Pick one with the buttons at the bottom right or the mode prop:
| Mode | What you see |
|---|---|
Floor ('floor') | Only the selected floor. |
Building ('stacked', default) | The real building: floors stacked at their heights. Floors above the selected one fade to a light wireframe, so you can look straight into the selected floor. Pick another floor and the camera moves up or down with it. |
Exploded ('exploded') | Floors pulled apart vertically and viewed from a lower angle, so every floor is visible at once. Every floor's markers show; room labels are hidden to keep the overview clean. Clicking a floor selects it. |
Cutaway works in every mode. In Building mode it slices the selected floor at about 1.1 m.
vue
<FloorPlanViewer3D :plan="plan" :markers="markers" v-model:floor="floorId" mode="exploded" />
<!-- or keep the mode in sync both ways -->
<FloorPlanViewer3D :plan="plan" v-model:floor="floorId" v-model:mode="mode" />tsx
<FloorplanViewer3D plan={plan} markers={markers} floor={floorId} onFloorChange={setFloorId} mode="exploded" />
// or keep the mode in sync both ways
<FloorplanViewer3D plan={plan} floor={floorId} onFloorChange={setFloorId} mode={mode} onModeChange={setMode} />html
<floorplan-viewer-3d mode="exploded"></floorplan-viewer-3d>
<script type="module">
import '@jbaysolutions/floorplan-elements/3d'
const viewer3d = document.querySelector('floorplan-viewer-3d')
viewer3d.plan = plan
viewer3d.markers = markers
viewer3d.floor = floorId
viewer3d.addEventListener('floor-change', (e) => (floorId = e.detail.floor))
viewer3d.addEventListener('mode-change', (e) => console.log(e.detail.mode)) // 'floor' | 'stacked' | 'exploded'
</script>Heights
Each floor has its own floor-to-floor height (height, default 280 cm), so a tall lobby or a low basement is easy. In 3D, walls are the floor height minus the 20 cm slab, and each floor sits on the one below.
See Data model for the Floor fields and the floor helpers (sortedFloors, defaultFloor, floorElevations…).