Scalable Vector Graphics (SVG) is a powerful and flexible format for displaying complex and dynamic diagrams on the web.
Unlike images, SVGs are resolution-independent and can be manipulated through CSS, JavaScript, and even create interactive and adaptive visualizations.
This article explores how SVG can be used to build complex diagrams that update dynamically based on metric data, also in real-time.
Adding SVG to widgets
When defining a widget, you can leverage a built-in JavaScript SvgDiagram class based on the public SVG.js (v3.2.4) library, which provides a rich set of functions for creating and manipulating SVG elements.
To start using this class, you must include it in your widgetās Dependencies.
.png?sv=2022-11-02&spr=https&st=2025-12-14T20%3A03%3A41Z&se=2025-12-14T20%3A16%3A41Z&sr=c&sp=r&sig=UJrHmZLoUBb5FUpjpMmxNqJgWzEczioKtY5K43mr12Y%3D)
In the following widget code example, you can see how to use the SvgDiagram class to create and update an SVG diagram.
class MySchemaWidget extends AbstractWidget {
constructor(config) {
config = config || {};
config.height = config.height || "480px";
config.width = config.width || "640px";
super(config);
}
onInit(context) {
let widget = this;
this.svgDiagram = new SvgDiagram();
let promises = [];
promises.push(super.onInit(context));
// load SVG.js resources
promises.push(this.loadResources(this.svgDiagram.getSvgResources()));
promises.push(this.loadMetricDefinitions(context));
return Promise.all(promises).then(function() {
widget.createOrUpdateSchema(context);
widget.setLoaderVisible(false);
}).catch(error => {
console.error(error);
widget.showError({ "message": "Error initializing SVG diagram" });
widget.setLoaderVisible(false);
});
}
createOrUpdateSchema(context) {
let widget = this;
let metricValue = parseInt(context.data[context.metrics[0].name].value) || 0;
let radius = metricValue * 10;
console.log(JSON.stringify(context.data));
console.log(context.metrics[0].name + ": " + radius);
if(!this.svgDiagram.draw){
// create the SVG root element
let draw = this.svgDiagram.createSvg(context.htmlElement, { 'height': parseInt(widget.config.height), 'viewportWidth': parseInt(widget.config.width), 'viewportHeight': parseInt(widget.config.height) });
// add the SVG elements
draw.line(0, 240, 640, 240).stroke({ width: 5, color: "#28a745"});
this.circle = draw.circle(radius).cx(320).cy(240).stroke({ width: 2, color: "#28a745"}).fill("#ffc107");
this.text = draw.text(metricValue.toString()).font({size: 24, color: "#28a745"}).cx(320).cy(240);
} else {
// update SVG elements
this.circle.radius(radius);
this.text.text(metricValue.toString()).cx(320).cy(240);
}
}
onDataUpdated(context) {
this.createOrUpdateSchema(context);
}
onInputUpdated(context) {
// handle inputs and update schema
}
onDestroy(context) {
super.onDestroy(context);
}
}Running the code above will result in an SVG as follows.
.png?sv=2022-11-02&spr=https&st=2025-12-14T20%3A03%3A41Z&se=2025-12-14T20%3A16%3A41Z&sr=c&sp=r&sig=UJrHmZLoUBb5FUpjpMmxNqJgWzEczioKtY5K43mr12Y%3D)
If your widget needs to be updated frequently on the page, we recommend that you cache the SVG elements instead of recreating them each time an update occurs.
For instance, the method createOrUpdateSchema() creates a new SVG element the first time, but the next times it is invoked (e.g., a metric is updated), the elements are already available and can therefore be directly updated. If the widget is destroyed, e.g., by navigating to another page, the associated SVG elements are destroyed along with it.
SvgDiagram Class Reference
The SvgDiagram class has the following methods.
createSvg(htmlElement, options) | Creates a new SVG element attached to the given htmlElement.
This method returns the SVG Draw object instance, which you can use to create SVG elements. |
enableDrag(element, enabled) | Enables or disables dragging on an SVG element. |
foreignObject(id, x, y, w, h, html) | Embeds an HTML element into an SVG element as a foreign object.
|
getById(id) | Retrieves an SVG object by ID. |
getSvgResources() | Returns the list of additional resources (SVG.js) to be loaded by the page when the widget is displayed for the very first time. You can use this array of URLs as input to the following method |
makeDraggable(element, onDragged) | Add the draggable feature to an SVG element. When dragging terminates, the onDragged callback is invoked, passing the new X and Y coordinates. |