Overview
SVG files are XML-based vector images that can be embedded in Mango by Radix IoT dashboard pages and bound to live data. With the <ma-svg> element and ng-include, colors, opacity, rotation, and text can respond to point values in real time. The same graphic can also provide navigation, tooltips, and setpoint controls.
Prerequisites
- Mango 5.x with Dashboard Designer or Page Editor access
- A vector editor such as Inkscape, Adobe Illustrator, or Affinity Designer
- Active data points to bind to the graphic
- Basic knowledge of SVG/XML and AngularJS template syntax
- Familiarity with Mango custom pages
Step 1: Design the SVG
Plan the layout, dynamic elements, point bindings, and user interactions before opening the vector editor.
Create the graphic with shapes, paths, groups, and text. Organize elements into clearly named layers and groups so they remain easy to identify in the exported XML.
Assign Element IDs
Every element controlled by Mango needs a unique, descriptive ID such as zone1-fill, pump-status, or temp-label.
In Inkscape, select an element and open Object > Object Properties, then set ID. In Adobe Illustrator, rename the element in the Layers panel.
Tip
Use a consistent convention such as zone1-fill, zone1-label, zone2-fill, and zone2-label.
Export the result as Plain SVG rather than an editor-specific format.
Step 2: Upload the SVG
- Go to Platform management > File stores.
- Select the
defaultstore or create a dedicated store such assvg-graphics. - Create a folder such as
/floorplans/. - Upload the SVG.
Note
The File stores page is superadmin-only, and write access to the default store is superadmin-only unless the Core filestore write permission has been granted to another role. Read access to default is granted to the user role by default, so anyone who can open the dashboard can load the graphic.
A file in the default store might be available at:
/rest/latest/file-stores/default/floorplans/building-floor1.svg
Step 3: Embed the SVG
Create or edit a custom page under Platform management > Edit pages, then load the SVG inline:
<ma-svg
ng-include="'/rest/latest/file-stores/default/floorplans/building-floor1.svg'">
<!-- Selectors bind to SVG elements by ID -->
</ma-svg>
Warning
<ma-svg> is an element, not an attribute. Use <ma-svg ng-include="...">, not <div ma-svg ng-include="...">.
The SVG is inserted into the DOM, allowing AngularJS to bind to its internal elements. A normal <img> tag would not provide the same access.
Step 4: Bind Point Values
Retrieve each point outside the <ma-svg> element. That is not a style preference: <ma-svg> empties its own children at compile time and keeps only their attributes, so a <ma-get-point-value> placed inside is discarded before it ever runs.
<ma-get-point-value
point-xid="DP_Zone1_Temp"
point="zone1Temp">
</ma-get-point-value>
<ma-get-point-value
point-xid="DP_Zone2_Temp"
point="zone2Temp">
</ma-get-point-value>
<ma-get-point-value
point-xid="DP_Pump1_Status"
point="pump1Status">
</ma-get-point-value>
<ma-get-point-value
point-xid="DP_Fan1_Speed"
point="fanSpeed">
</ma-get-point-value>
<ma-get-point-value
point-xid="DP_Valve1_Toggle"
point="togglePoint">
</ma-get-point-value>
<ma-get-point-value
point-xid="DP_Alarm_Point"
point="alarmPoint">
</ma-get-point-value>
<ma-get-point-value
point-xid="DP_Fan1_Running"
point="fanRunning">
</ma-get-point-value>
Inside <ma-svg>, use ma-selector to target elements. Its value is any CSS selector, so an ID works and so does a descendant selector such as #zone1-label tspan.
Change Fill Color
<div ma-selector="#zone1-fill" ng-style="{
'fill': zone1Temp.value > 76 ? '#ff4444' :
zone1Temp.value > 72 ? '#ffaa00' :
'#44cc44'
}"></div>
Update Text
<div
ma-selector="#zone1-label tspan"
ng-bind="zone1Temp.renderedValue">
</div>
Warning
ma-text is not a Mango attribute. Use AngularJS ng-bind. Most SVG editors place the text content inside a <tspan>, so target that inner element. renderedValue is the value as formatted by the point’s text renderer, including its configured suffix — which is the engineering unit only when Use unit symbol as suffix is ticked on the Analog renderer. It is not ticked by default, so a new numeric point renders a bare number.
Control Opacity
<div
ma-selector="#pump1-running-indicator"
ng-style="{'opacity': pump1Status.value ? 1 : 0.2}">
</div>
Apply Rotation
<div ma-selector="#fan-blade" ng-style="{
'transform': 'rotate(' + (fanSpeed.value * 3.6) + 'deg)',
'transform-origin': 'center center'
}"></div>
Step 5: Add Interactivity
Navigate on Click
Use ui-sref with a state defined by your page/menu configuration:
<div
ma-selector="#zone1-fill"
ui-sref="ui.zoneDetail({zone: 'zone1'})"
ng-mouseenter="zone1Hover = true"
ng-mouseleave="zone1Hover = false"
ng-style="{
'fill': zone1Hover ? '#5555ff' : '#44cc44',
'cursor': 'pointer'
}">
</div>
Replace ui.zoneDetail with the actual state name. ui-sref is preferable to calling $state.go(...) because $state is not guaranteed to be exposed on a custom page’s scope.
Show a Tooltip
ma-selector copies attributes onto the matched SVG element — it cannot insert a child element. Give the shape a <title> child in the vector editor, then bind that element the same way you bind a <tspan>. Browsers render an SVG <title> as a native hover tooltip.
<div
ma-selector="#zone1-fill title"
ng-bind="'Zone 1: ' + zone1Temp.renderedValue">
</div>
Warning
Do not use md-tooltip here. Angular Material’s tooltip is an element directive — <md-tooltip md-direction="top">...</md-tooltip> placed inside the element it annotates — so it cannot be delivered as an attribute through ma-selector.
If you need a richer readout than a native tooltip, track hover state on a selector element and render the detail outside the graphic:
<div
ma-selector="#zone1-hotspot"
ng-mouseenter="hoverZone = 'zone1'"
ng-mouseleave="hoverZone = null"
style="cursor: pointer;">
</div>
<div ng-if="hoverZone === 'zone1'" class="ma-svg-readout">
Zone 1: <ma-point-value point="zone1Temp"></ma-point-value>
</div>
Warning
Each ma-selector string may appear only once inside a given <ma-svg>. Mango keys the selector elements by their selector text, so a second element with the same string silently replaces the first. Put every attribute for one target on a single element, or use distinct selectors such as #DAS-ON and #DAS-ON rect.
Set a Point Value
<div
ma-selector="#valve1-handle"
ng-click="togglePoint.toggleValue()"
style="cursor: pointer;">
</div>
.toggleValue() flips a Binary point. .setValue(x) writes a specific value and works on any settable point — setValue(true) and setValue(false) are the usual way to build separate ON and OFF hotspots, and Multistate and Alphanumeric points use the same call. Ensure the user has permission to set the point.
Step 6: Add CSS Animations
Add animation styles to the custom page:
@keyframes pulse {
0% { opacity: 1; }
50% { opacity: 0.4; }
100% { opacity: 1; }
}
@keyframes spin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
.alarm-active {
animation: pulse 1s ease-in-out infinite;
fill: #ff4444;
}
.fan-spinning {
animation: spin 2s linear infinite;
transform-origin: center center;
}
Toggle the classes from point values:
<div
ma-selector="#alarm-indicator"
ng-class="{'alarm-active': alarmPoint.value === true}">
</div>
<div
ma-selector="#fan-graphic"
ng-class="{'fan-spinning': fanRunning.value === true}">
</div>
Step 7: Scale the Graphic
Wrap the graphic in a scaling container:
<div ma-scale-to="ma-ui-page-view" style="width: 1920px; height: 1080px;">
<ma-svg
ng-include="'/rest/latest/file-stores/default/floorplans/building-floor1.svg'">
<!-- Selectors here -->
</ma-svg>
</div>
ma-scale-to scales the fixed-size inner container while maintaining its aspect ratio. You can also overlay <ma-point-value> elements with absolute positioning.
Verification
- The SVG loads without a rendering or 404 error.
- Dynamic elements update when point values change.
- Colors correspond to the intended thresholds.
- Text displays live formatted values through
ng-bind. - Clicks navigate or set values correctly.
- Animations activate and stop with equipment state.
- The graphic scales correctly at different viewport sizes.
Troubleshooting
SVG Does Not Appear
- Verify the
ng-includepath, including case. - Use
/rest/latest/file-stores/<store>/<path>. - Keep single quotes around the path inside the AngularJS expression.
- Check the browser console for 404 errors.
Data Bindings Do Not Work
- Save the file as Plain SVG.
- Confirm element IDs match
ma-selectorvalues exactly. - Put
<ma-get-point-value>elements outside<ma-svg>. - Use
<ma-svg>as an element.
Text Does Not Update
- Target the inner
<tspan>where appropriate. - Use
ng-bind, notma-text.
Animation Flickers
- Add
will-change: transformto animated elements. - Animate simple shapes or groups rather than complex paths.
- Verify
transform-origin.
SVG Is Too Large or Has Extra Whitespace
- Tighten the
viewBoxattribute around the content in a text editor. - Remove hidden layers and unused elements left behind by the design tool.
Clicks Do Not Register
- Inspect for invisible overlapping SVG elements.
- Confirm
pointer-eventsis not set tononeon the target or a parent.
Related Guides
- Building a Full-Screen Kiosk Dashboard
- Changing Dashboard Bar Colors Based on Point Values
- Configuring the Meta Data Source for Derived Data Points