20,919,685Total Points24,106Total Sites23,382Cell Towers69,500Racks Monitored56,753HVAC Units Monitored31,322UPS Units Monitored24,788Generators Monitored20,919,685Total Points24,106Total Sites23,382Cell Towers69,500Racks Monitored56,753HVAC Units Monitored31,322UPS Units Monitored24,788Generators Monitored20,919,685Total Points24,106Total Sites23,382Cell Towers69,500Racks Monitored56,753HVAC Units Monitored31,322UPS Units Monitored24,788Generators Monitored

Chapter 6: Dashboards & Platform ManagerLesson 34 of 65

Creating Interactive SVG Graphics for Dashboards

How to use SVG graphics with dynamic data binding in Mango by Radix IoT dashboards, including floor plans, process diagrams, and animated visualizations.

  • 15 min read
  • Advanced
  • Mango 5.x

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

  1. Go to Platform management > File stores.
  2. Select the default store or create a dedicated store such as svg-graphics.
  3. Create a folder such as /floorplans/.
  4. 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

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-include path, 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-selector values 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, not ma-text.

Animation Flickers

  • Add will-change: transform to animated elements.
  • Animate simple shapes or groups rather than complex paths.
  • Verify transform-origin.

SVG Is Too Large or Has Extra Whitespace

  • Tighten the viewBox attribute 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-events is not set to none on the target or a parent.
  • Building a Full-Screen Kiosk Dashboard
  • Changing Dashboard Bar Colors Based on Point Values
  • Configuring the Meta Data Source for Derived Data Points

Get free access to all 65 Mango by Radix IoT training lessons

One short form unlocks every lesson and its video in this browser.

This form is hosted by Zoho. It loads only after you enable support cookies or choose to load it below.

We honored your browser’s Global Privacy Control signal — optional cookies are off and nothing is tracked.