Creating a Dynamic Floor Plan
Introduction
A dynamic floor plan is an SVG-based visualization that overlays live data from Mango data points onto a building layout. Users can see real-time sensor readings (temperature, status, mode) positioned on an architectural drawing, with interactive zones that respond to clicks and hover events.
This technique is commonly used in building automation and HVAC monitoring, where operators need a spatial overview of equipment status across floors or zones.
The Mango UI provides the <ma-svg> component for embedding SVG files and binding data points to specific elements within the SVG. Combined with watch lists, AngularJS Material cards, and AngularJS expressions, you can build fully interactive floor plan dashboards.
What You Will Build
In this tutorial, you will create a floor plan page that:
- Displays an SVG building layout scaled to fit the browser window
- Highlights HVAC zones on hover and navigates to zone details on click
- Shows live temperature readings overlaid on each zone
- Displays a detail card with controls (on/off, mode, fan speed, setpoint) for the selected zone
Prerequisites
Before starting, ensure you have:
- A running Mango instance with development mode enabled
- An SVG floor plan file -- An architectural drawing exported as SVG with named groups/elements for each zone (e.g.,
#FC001,#FC002). Upload this to a Mango file store (e.g.,default/floorplans/). - A watch list configured with parameters for filtering points by zone. The watch list should accept parameters such as
fc(floor controller group) anddn(display name). - Data points for each zone -- temperature, mode, fan speed, setpoint, and on/off status. For testing, a Virtual Data Source with simulated values works well.
Step 1: Set Up the Page Structure
Start by creating the outer container. The ma-watch-list-get component loads a watch list and makes its points available to the page. The root div with ma-designer-root scales the layout to fit the viewport.
<!-- Load the watch list and bind points to the designer scope -->
<ma-watch-list-get
ng-model="designer.watchList"
parameters="designer.parameters"
on-points-change="designer.points = $points"
watch-list-xid="WL_your-watch-list-xid">
</ma-watch-list-get>
<!-- Root container: scales the SVG layout to fit the page -->
<div class="ma-designer-root"
style="width: 1920px; height: 1080px; position: relative;"
ma-scale-to="ma-ui-page-view"
ma-center="true"
ma-maintain-ratio="letterbox">
<!-- Floor plan and overlays go here -->
</div>
Key attributes:
ma-scale-to="ma-ui-page-view"-- Scales the fixed-size container to fit the Mango page view area.ma-maintain-ratio="letterbox"-- Preserves the aspect ratio, adding letterbox bars if needed.parameters="designer.parameters"-- Binds the watch list parameters so they can be updated by zone clicks.
Step 2: Embed the SVG and Add Zone Bindings
Use the <ma-svg> component to load the SVG file from a Mango file store. Inside it, use <div> elements with the ma-selector attribute to target specific SVG groups by their ID.
<ma-svg ng-include="'/rest/latest/file-stores/default/floorplans/floor-0.svg'"
style="position: absolute; width: 1590px; height: 1074px; left: 0; top: 0;">
<!-- Zone FC001: hover highlights, click selects the zone -->
<div ma-selector="#FC001"
ng-style="styleFC001"
ng-click="designer.parameters = {fc: 'FC 0', dn: 'FC 001'}"
ng-mouseenter="styleFC001 = {'opacity': 0.5}"
ng-mouseleave="styleFC001 = {}">
</div>
<!-- Zone FC002 -->
<div ma-selector="#FC002"
ng-style="styleFC002"
ng-click="designer.parameters = {fc: 'FC 0', dn: 'FC 002'}"
ng-mouseenter="styleFC002 = {'opacity': 0.5}"
ng-mouseleave="styleFC002 = {}">
</div>
<!-- Repeat for each zone in your SVG -->
</ma-svg>
How this works:
ma-selector="#FC001"-- Targets the SVG element withid="FC001". The SVG file must contain groups or paths with these IDs.ng-mouseenter/ng-mouseleave-- Applies an opacity change on hover to visually highlight the zone.ng-click-- Updatesdesigner.parameterswith the zone's filter values, which causes the watch list to reload with points for that specific zone.
Step 3: Overlay Live Data Point Values
Position <ma-point-value> components absolutely over each zone on the floor plan. Each one binds to a specific data point by its XID and displays its current value.
<!-- Temperature overlay for zone FC001 -->
<ma-point-value
style="position: absolute;
left: 170px; top: 385px;
z-index: 1;
width: 75px; height: 35px;
background-color: rgb(51, 51, 51);
display: flex; justify-content: center;
border-radius: 5px;"
point-xid="DP_03_FC001">
</ma-point-value>
<!-- Temperature overlay for zone FC002 -->
<ma-point-value
style="position: absolute;
left: 300px; top: 750px;
z-index: 1;
width: 75px; height: 35px;
background-color: rgb(51, 51, 51);
display: flex; justify-content: center;
border-radius: 5px;"
point-xid="DP_03_FC002">
</ma-point-value>
<!-- Repeat for each zone, adjusting left/top to position over the zone -->
Tips for positioning:
- Use your SVG editor (Inkscape, Illustrator) to find the coordinates of each zone's center.
- The
leftandtopvalues are relative to the root container's 1920x1080 coordinate space. - Set
z-index: 1to ensure the value overlays appear above the SVG.
Step 4: Add a Zone Detail Card
Use an AngularJS Material card to display detailed controls for the currently selected zone. The card filters the watch list points by name to find the relevant data point for each control.
<md-card style="position: absolute; left: 1504px; top: 0; width: 408px; height: 415px;">
<md-toolbar class="md-whiteframe-1dp md-hue-3">
<div class="md-toolbar-tools" style="font-size: 24px; font-weight: bolder;">
<h2 flex="">
<span>Zone: {{designer.parameters.dn}}</span>
</h2>
</div>
</md-toolbar>
<md-card-content>
<md-list class="md-dense">
<!-- On/Off toggle switch -->
<md-list-item layout="">
On/Off
<span flex=""></span>
<ma-switch
point="designer.points
| filter:{name:'Puts the unit in shutdown mode (0=ON, 1=OFF)'}:true
| maFirst">
</ma-switch>
</md-list-item>
<!-- Live temperature reading -->
<md-list-item layout="">
Temperature
<span flex=""></span>
<ma-point-value
enable-popup="left"
point="designer.points
| filter:{name:'Room Temperature'}:true
| maFirst"
flash-on-change="true">
</ma-point-value>
</md-list-item>
<!-- Current operating mode -->
<md-list-item layout="">
Mode
<span flex=""></span>
<ma-point-value
point="designer.points
| filter:{name:'Current Control (0=OFF, 1=Heating, 2=Cooling)'}:true
| maFirst"
flash-on-change="true">
</ma-point-value>
</md-list-item>
<!-- Fan speed control -->
<md-list-item layout="">
Fan Speed
<span flex=""></span>
<ma-set-point-value
show-button="true"
set-on-change="false"
enable-popup="hide"
point="designer.points
| filter:{name:'Fan Mode (0=OFF, 1=FS1, 2=FS2, 3=FS3, 4=Auto)'}:true
| maFirst">
</ma-set-point-value>
</md-list-item>
<!-- Temperature setpoint control -->
<md-list-item layout="">
Setpoint
<span flex=""></span>
<ma-set-point-value
show-button="true"
set-on-change="false"
enable-popup="hide"
point="designer.points
| filter:{name:'Setpoint Displacement'}:true
| maFirst">
</ma-set-point-value>
</md-list-item>
</md-list>
</md-card-content>
</md-card>
Key patterns used in the detail card:
filter:{name:'...'}:true | maFirst-- Filters the watch list points array by the point name and takes the first match. This relies on your data points having descriptive, consistent names.<ma-switch>-- Renders a toggle switch for binary points.<ma-point-value>-- Displays a read-only live value. Theflash-on-change="true"attribute adds a brief visual flash when the value updates.<ma-set-point-value>-- Renders an editable control that lets the operator change the point's value.
Step 5: Putting It All Together
Combine all the pieces inside the root container. The complete structure is:
<ma-watch-list-get>-- Loads point data- Root
<div>withma-designer-root-- Establishes the coordinate system <ma-svg>with zone bindings -- The interactive floor plan<ma-point-value>overlays -- Live readings positioned on the map<md-card>-- Detail panel for the selected zone
When a user clicks a zone, designer.parameters updates, the watch list reloads with that zone's points, and the detail card shows the relevant controls.
Next Steps
- Add color-coded status indicators -- Use
ng-stylewith conditional expressions to change zone fill colors based on heating/cooling mode or alarm status. - Multi-floor navigation -- Create separate SVG files for each floor and use tabs or a dropdown to switch between them.
- Historical data -- Add a
<ma-point-values>component with a chart to show temperature trends for the selected zone. - Alarm integration -- Overlay alarm indicators on zones with active alarms using
<ma-get-point-value>and conditional visibility. - Custom SVG preparation -- When creating your SVG, assign meaningful IDs to zone groups (e.g.,
id="FC001") and keep the file clean of unnecessary metadata for best performance.
Related Pages
- Tutorials Index — Browse all developer tutorials
- Interactive SVG Graphics — Using the ma-svg component for data-bound SVG graphics
- SVG Development in Mango — Designing SVG assets in Adobe Illustrator for Mango dashboards