This is the second article about the network graph SAP UI5 control. The first
article, you can find it here.
In this article, we will discuss custom rendering. As of SAP UI5 version 1.58, we allow UI5 developers to completely customize node visualization by changing the positions of icons and nodes titles , as well as applying custom colors and different node shapes.
We will take a look at three types of custom nodes:
- Custom box node -- We will change the default locations of text and icons.
- Custom circular node -- We will put the text into the circle where the node icon is placed by default.
- Custom-shaped node.
The Architecture of Custom Rendering
To enable custom rendering, you need to override some of the node’s methods. Although you can override methods for each node’s instance, I recommend that you create your own custom node class and inherit it from the default node.
Here, as you can see, we are creating our own class with the method
calculateSizes. We will discuss this method later.
<custom:NetworkGraphCustomNode key="{key}"
title="{title}"
icon="{icon}"
shape="{shape}"
width="{width}"
height="{height}"
titleLineSize="{titleLineSize}"
status="{status}">
</custom:NetworkGraphCustomNode>
sap.ui.define([
"sap/ui/core/mvc/Controller",
"sap/ui/model/json/JSONModel",
"sap/suite/ui/commons/networkgraph/Node"
], function (Controller, JSONModel, Node) {
var oCustomNode = Node.extend("sap.suite.ui.commons.sample.NetworkGraphCustomRendering.NetworkGraphCustomNode", {
oCustomTitleSize: null,
oCustomTrimmedTextSize: null,
sBigFont: "BIG FONT TRIMMED TEXT",
calculateSizes: function () {
Text Wrapping
Before we start customization, there is a very important topic we need to discuss. For now, SVG doesn’t support wrapping text into multiple lines (the CSS equivalent is
white-space: normal). That’s why we have provided two methods:
- calculateSizes -- a method that calculates the number of lines of text.
- renderText -- a method for rendering such calculated lines of text.
In the network graph control, this is unfortunately more complicated, as we need to know the node’s dimensions
before the nodes are sent to the layout rendering processor.
That being said, without getting too deep into technical details, the node has a method
calculateSizes which by default calculates and positions all texts when the default rendering algorithm is used.
If you want to use custom rendering, you can override this function (best in your own class inheriting from the node) and do the calculation for your text yourself. There is another method that helps you calculate text size,
computeTextDimensions - you only need to specify the width of the text, the maximum number of lines (0 for unlimited), and, of course, the text itself.
calculateSizes: function () {
this.oCustomTitleSize = this.computeTextDimmensions({
text: this.getTitle(),
width: this.getWidth() - 10,
maxLines: this.getTitleLineSize()
});
this.oCustomTrimmedTextSize = this.computeTextDimmensions({
text: this.sBigFont,
width: this.getWidth() - 10,
attributes: {
"font-size": "20px"
},
maxLines: 1
});
}
The node title is split into multiple lines to fit the node’s width.The return parameter of this method is an object with two properties:
return {
text: // an array of strings that contains the text split into lines
lineHeight: // the height of a single line (different line sizes in are not supported
You can store this value (for example, in a closure) and then pass it to the
renderText method described below.
If you want to change the node’s height or width, now is the best moment for that. Since the
height property is used for the initial height of the node, we don’t want to change it directly, as it would grow indefinitely in multiple calls. Instead, you can use the method
setSize, which sets internal variables and doesn’t change the
height and
width properties.
this.setSize({
height: Math.floor(oTitle.lineHeight * oTitle.text.length + oTrimmedText.lineHeight + 25 + 50 /*icon*/)
});
Other Methods Used for Rendering
To streamline the creation of SVGs, you can use several methods that are available for network graph nodes.
But, of course, you can always create your own custom SVGs without using these methods.
- computeTextDimensions – this method helps you split the text into lines. As mentioned above, SVG doesn’t support text wrapping, so you need to split it manually, specifying the text to be displayed on each line.
Important: This method should be called from the calculateSizes method.
- renderText - if you have already split your text into lines or if you just want to render one single line, you can use this method to render text as SVG. Please note, though, that this method won’t split text into
- renderIcon – this method provides an easier way to render an icon, using the SAP icon font.
- renderElement – this method provides a simple function wrapper for rendering a single SVG element.
We support two basic approaches to handling node customization. We start with the easier one – node’s content customization.
Partial Customization: Node’s Content Customization
Nodes with customized content may look like this. The basic shape is predefined but you can change the rest to fit your needs.

The Network Graph will still render the node’s wrappers that allow the network graph to handle status changes, hover events, and selection events as well as keyboard navigation. Which means you can focus on proper content positioning only.
To customize the node’s content, you need to override the method
renderItemContent for each node you want to customize.
renderItemContent: function (mArguments) {
if (this.getShape() === "Custom") {
return Node.prototype.renderContent.call(this);
}
var sHtml = "";
if (this.getShape() === "Box") {
var y = 20;
if (this.oCustomTitleSize) {
sHtml += this.renderText({
x: 5,
y: y,
lineSize: this.oCustomTitleSize.lineHeight,
lines: this.oCustomTitleSize.text
});
y += this.oCustomTitleSize.lineHeight * this.oCustomTitleSize.text.length + 20;
if (this.oCustomTrimmedTextSize) {
// solo lane text
sHtml += this.renderText({
x: 5,
y: y,
lines: this.oCustomTrimmedTextSize.text,
attributes: {
"font-size": "20px"
}
});
y += this.oCustomTrimmedTextSize.lineHeight;
}
sHtml += this.renderIcon({
icon: this.getIcon(),
y: y + 30,
x: this.getWidth() / 2,
attributes: {
"text-anchor": "middle",
"font-size": "50px"
}
});
}
} else {
if (this.oCustomTitleSize) {
sHtml += this.renderText({
x: 30,
y: 35,
lineSize: this.oCustomTitleSize.lineHeight,
lines: this.oCustomTitleSize.text
});
}
}
return sHtml;
}
Then we can create an SVG string for the title, using the data we collected in the attached event
calculateSizes.
As you can see, we can create different content, based on whether the node is of the circle or box type. We can use helper methods to render SVG strings and adjust the text size, usinge the object we created with the
calculateSizes method
.
This method requires a return string that represents an SVG element.
Complete Customization: Adjusting the Node’s Shape and Content
You can, however, customize your node completely, exploring other shapes beyond the standard box and circle. How about a diamond shape like the one pictured
If you want tocustomize both the node’s shape and its content, follow these steps:
- Set the node’s shape property to Custom
- Override the method renderContent for the node you want to customize.
renderContent: function (mArguments) {
// size determination rendering is for default nodes using max-width or multiline titles
// there is no need to waste time rendering in this cycle as its destroyed anyway
if (mArguments.sizeDetermination) {
return;
}
Important: The rendering function is called even for calculating the text length (with parameter
sizeDetermination). Since we usually perform all text length calculations in a special event, it’s recommended that you skip the rendering in this case and save some computation time.
If you want the network graph to handle events for color changes, state changes, and hover states, you can do so by settings correct classes. For the top shape element, it’s sapSuiteUiCommonsNetworkInnerRect.
var FOCUS_OFFSET = 3;
var sHtml = "",
x = this.getX(),
y = this.getY(),
iHeight = 80,
iWidth = this.getWidth();
// set default classes if you want to have focus, hover and selected state handled by default
// otherwise you need to handle it yourself
sHtml += this.renderElement("path", {
stroke: "red",
"class": "sapSuiteUiCommonsNetworkInnerRect",
d: "M" + (x + iWidth / 2) + " " + y + " L " + (x + iWidth) + " " + ( y + iHeight / 2) +
" L " + (x + iWidth / 2) + " " + ( y + iHeight) +
" L " + (x) + " " + ( y + iHeight / 2) +
" L " + (x + iWidth / 2) + " " + ( y) + "Z"
});
This shape will be used for focus handling and keyboard navigation. If you want the network graph to take care of these, set the class to sapSuiteUiCommonsNetworkBoxFocus.
sHtml += this.renderElement("path", {
stroke: "red",
"class": "sapSuiteUiCommonsNetworkBoxFocus",
d: "M" + (x + iWidth / 2) + " " + (y + FOCUS_OFFSET) + " L " + (x + iWidth - FOCUS_OFFSET) + " " + ( y + iHeight / 2) +
" L " + (x + iWidth / 2) + " " + ( y + iHeight - FOCUS_OFFSET) +
" L " + (x + FOCUS_OFFSET) + " " + ( y + iHeight / 2) +
" L " + (x + iWidth / 2) + " " + ( y + FOCUS_OFFSET) + "Z"
});
Alternatively, you have can do this all in a different way, if it fits your needs better, in which case you don’t need to add the classes.
Finally, we can render the icon and the text that we split into lines earlier.
sHtml += this.renderIcon({
icon: this.getIcon(),
y: 65,
x: this.getWidth() / 2,
attributes: {
"text-anchor": "middle",
"font-size": "50px"
}
});
if (this.getTitle()) {
sHtml += this.renderText({
x: this.getWidth() / 2,
attributes: {
"text-anchor": "middle",
"pointer-events": "none"
},
y: iHeight + 20,
lineSize: oTitle.lineHeight,
lines: oTitle.text
});
}
Rendering of the Node’s Status Icon
Status icon is a part of the node’s shape.
If you override the
renderItemContent method to change only the inner content of the node, the status icon will be rendered automatically, which means you needn’t do anything yourself. In case you still want to change the status icon, you can override the method
renderStatusIcon. Please keep in mind that you will also have to take care of the colors for different states, such as node colors on select and on hover.
// render info box
sHtml += this.renderStatusIcon({
x: this.getWidth() / 2,
y: 0,
size: 15,
iconSize: 25
});
On the other hand, when you use complete customization, using the
renderContent method, the status icon is not rendered. You can use the already mentioned method
renderStatusIcon and call it directly (see the API reference for the available parameters) or create a completely different shape for this status icon. However, in this case you will again need to take care of the colors used for different node states.
In this tutorial, you’ve learned how to customize node shapes and their content in a network graph. For a more detailed example, see our
sample page.