Changing the Z-order
For most use cases you work with the GraphModelManager and its convenience methods to adjust the z-order of elements in the view to your needs.
The WebGL2 rendering mode and the associated WebGL2GraphModelManager support only some of the features described in this section.
In the following sections, we’ll discuss the benefits of the default z-order, introduce the general API to re-order objects, and describe how to change the z-order of graph elements and of the visualizations of selection, focus, and custom highlight. Finally, we describe how you can implement your own GraphModelManager for full control of the rendering order.
General Thoughts
In our experience, one of the most common reasons to change the default z-order is the rendering of node labels that are placed inside of the bounds of their owner nodes. If two nodes overlap, both labels are fully visible on top of both nodes since by default all labels are drawn in front of all nodes. This makes it hard to decide which label belongs to which node and in general just looks strange to many people. For this usecase it is sufficient to change the LabelLayerPolicy.
Similar confusion can arise for example for overlapping nodes and their ports, which can be solved by changing the PortLayerPolicy, and for edges that cross through unrelated nodes and groups.
For all these cases, we recommend considering ways to avoid the overlaps instead of spending time for customizing the z-order. The benefit will be a more readable diagram.
The default z-order realized by GraphModelManager works very well for almost all cases except for the ones mentioned above. In particular,
- Rendering labels in the front ensures that their full text is readable even if there are some unavoidable overlaps. This is typically the desired behavior for all edge labels and for node labels that are not placed inside their owner.
- If groups are present, edges are interleaved with the rendering of the groups to make sure that their first and last segments are not covered by the groups of their source and target nodes. Since in addition the rendering of nested groups and nodes must be consistent, some edges might be forced to cross in the front (or back) of an unrelated group in an undesired way.
The Default Z-order of Edges and Groups
Clearly, the children of a group should be rendered in front of the group instead of behind it. For edges, it’s more complicated. By default, edges are drawn behind nodes. However, when a node outside of a group has an edge to a node that is part of a group or if the group node itself has an edge to a child of his, then the edge is hidden in a way that makes it unclear where the edge connects to or if there is an edge at all.
Because of this, yFiles for HTML by default interleaves the rendering order of nodes and edge in such a way that hierarchical structures are considered. Edges that connect to nodes inside a group are drawn on a higher level than edges that connect nodes on the same level as the group node.
You can choose another preconfigured nesting policy by changing the property hierarchicNestingPolicy.
The Z-order of Graph Elements
The z-order of all visualized items is managed by an internal visual tree that consists of hierarchic nested ICanvasObjectGroup that have ICanvasObject implementations as leaf nodes. Each item that shall be visualized is represented by an ICanvasObject or ICanvasObjectGroup and the order of ICanvasObject in their ICanvasObjectGroup corresponds to the z-order or the represented items.
What ICanvasObjectGroup are used and in which ICanvasObjectGroup an ICanvasObject is placed is determined by the the chosen HierarchicNestingPolicy, PortLayerPolicy and LabelLayerPolicy.
With WebGL2 rendering, there is only one ICanvasObject that represents the complete WebGL2 rendering, and the described policy properties have no effect. You can however change the z-order of graph item types by reordering the sub-groups listed below.
The content group is a high-level group that contains a sub-group for each kind of graph element. Due to the chosen aforementioned policies, some of the groups might be unused.
From front to back, these groups are:
- portLabelGroup. It contains the visualization for the labels of ports.
- nodeLabelGroup. It contains the visualization for the labels of nodes.
- edgeLabelGroup. It contains the visualization for the labels of edges.
- portGroup. It contains the visualization for the ports.
- nodeGroup. By default it contains the visualizations for the nodes and edges.
- edgeGroup. It is unused by default and contains the visualizations for the edges if hierarchicNestingPolicy is not set to NODES_AND_EDGES.
- groupNodeGroup. It is unused by default and contains the visualizations for group nodes if hierarchicNestingPolicy is set to GROUP_NODES.
The following table describes which groups are used for nodes and edges depending on the hierarchicNestingPolicy:
Policy | Group Nodes | Leaf Nodes | Edges |
---|---|---|---|
The groups for ports and labels depends on the chosen PortLayerPolicy and LabelLayerPolicy:
Policy | Labels | |
---|---|---|
Policy | Labels | |
---|---|---|
Re-ordering Model Items
GraphModelManager provides methods that re-order IModelItem in their layer which changes the order in which the elements of this layer are rendered. Re-ordering Model Items presents the methods and what they do.
With WebGL2 rendering, the rendering order of individual elements cannot be changed in this way.
- Convenience Methods that change the order of model items in their layer.
- toFront(item: IModelItem): void
- Moves the element to the end of the rendering list, causing it to be drawn last and therefore to be rendered in the front.
- toFront(items: IEnumerable<IModelItem>): void
- Moves the elements to the end of the rendering list, causing them to be drawn last and therefore to be rendered in the front. The relative order of the elements is preserved.
- toBack(item: IModelItem): void
- Moves the element to the start of the rendering list, causing it to be drawn first and therefore to be rendered in the back. The relative order of the elements is preserved.
- toBack(items: IEnumerable<IModelItem>): void
- Moves the elements to the start of the rendering list, causing them to be drawn first and therefore to be rendered in the back. The relative order of the elements is preserved.
- raise(item: IModelItem): void
- Changes the place of this element with its successor in the list, causing it to be rendered in front of its former successor.
- raise(items: IEnumerable<IModelItem>): void
- Changes the place of the elements with their successor in the list, causing them to be rendered in front of their former successor. The relative order of the elements is preserved.
- lower(item: IModelItem): void
- Changes the place of this element with its predecessor in the list, causing it to be rendered behind its former predecessor.
- lower(items: IEnumerable<IModelItem>): void
- Changes the place of the elements with their predecessor in the list, causing them to be rendered behind their former predecessor. The relative order of the elements is preserved.
Let us illustrate changing the order with a simple example. We create three overlapping nodes:
first n1
, then n2
, and finally n3
. The rendering order is n1
, n2
, n3
, and therefore,
n1
is the undermost and n2
the topmost node.
Now we raise n2
, so the rendering order is now n1
, n3
, n2
, and n2
is topmost.
graphComponent.graphModelManager.getMainCanvasObject(n2).raise()
If we want n1
to be the topmost node, we simply move it to the end of the rendering order.
graphComponent.graphModelManager.getMainCanvasObject(n1).toFront()
n2
up …n1
to front.For interactive scenarios a common usecase is to change the z-order for all selected model items. GraphEditorInputMode provides the following methods for exactly this purpose:
- selectionToFront(): void
- Moves the selected elements to the end of the rendering list keeping their relative order and causing them to be drawn last and therefore to be rendered in the front.
- selectionToBack(): void
- Moves the selected elements to the start of the rendering list keeping their relative order and causing them to be drawn first and therefore to be rendered in the back.
- raiseSelection(): void
- Changes the place of the selected elements with their successor in the list keeping their relative order and causing them to be rendered in front of their former successor.
- lowerSelection(): void
- Changes the place of the selected elements with their predecessor in the list keeping their relative order and causing them to be rendered behind their former predecessor.
All these convenience methods change the order of the ICanvasObjects of the model items which can be retrieved using GraphModelManager's method getMainCanvasObject.
ICanvasObject offers two more methods that are especially handy to change the z-order of the graph element groups:
- above(reference: ICanvasObject): ICanvasObject
- Re-inserts this element after the given element in the rendering list, causing it to be rendered right above the given element.
- below(reference: ICanvasObject): ICanvasObject
- Re-inserts this element before the given element in the rendering list, causing it to be rendered right below the given element.
By default yFiles for HTML draws edges that cross group nodes behind the group nodes. A common use case is to change this behavior so that edges are drawn in front of group nodes.
To achieve this you just have to configure the GraphModelManager as shown in the following code snippet.
const graphModelManager = graphComponent.graphModelManager
// draw all edges in a single layer
graphModelManager.hierarchicNestingPolicy = HierarchicNestingPolicy.GROUP_NODES
// move the edge layer in front of the node layer
graphModelManager.edgeGroup.above(graphModelManager.nodeGroup)
Z-order Commands
The raise, lower, toFront and toBack methods described in Re-ordering Model Items can also be triggered by the following commands:
The Z-order of Indicators
There is a dedicated canvas object group for each of the three kinds of indication. The main canvas object groups lists these and the other predefined groups.
Re-order these groups to change the order in which the different kinds of decorations are drawn. To change the drawing order of decorations of the same kind, re-order them in the corresponding group.
Completely Customize the Z-order
All of the above mentioned approaches together offer a good set of possibilities to control the z-order of elements. However, you gain full control of the z-order by subclassing GraphModelManager and overriding a few methods. This way, you can implement your own Z-order for the elements.
One set of methods that can be overridden are the factory methods for the ICanvasObjectGroups. There is one factory method for each sub-group of the content group of the GraphComponent. Additionally, the factory method for the content group itself can be overridden on GraphComponent.
Another possibility is to implement your own set of ICanvasObjectGroups and override the methods that specify in which group an item should be placed. For example, getNodeCanvasObjectGroup can be overridden to distribute nodes to different groups by certain characteristics. There are also methods for the other items as well.