SvgDiagram

Prev Next

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.

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.

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.
Into the options object, you can pass:

  • height: the height in pixels the SVG diagram will occupy vertically in the page.

  • viewportWidth: the width in pixels of the SVG viewport (default 1280).

  • viewportHeight: the height in pixels of the SVG viewport (default 720).


The SVG element will horizontally fill the parent widget.

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.
See SvgDiagram.makeDraggable() method.

foreignObject(id, x, y, w, h, html)

Embeds an HTML element into an SVG element as a foreign object.
Parameters:

  • id: the ID of the foreign object being created.

  • x,y,w,h: the coordinates and size of the foreign object.

  • html: the string representing the HTML element to append. When the HTML element is attached, you can manipulate it by using standard HTML functions or jQuery functions.

getById(id)

Retrieves an SVG object by ID.
If missing, null is returned.

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
AbstractWidget.loadResources(resources)

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.