documentationfor yFiles for HTML 3.0.0.1

Changing the Z-order

To manage the z-order of elements in the view, you’ll typically interact with the GraphModelManager and its convenience methods.

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

One of the most common reasons to change the default z-order is to improve the rendering of node labels that are placed inside the bounds of their owner nodes. When two nodes overlap, both labels are fully visible on top of both nodes because by default all labels are drawn in front of all nodes. This can make it difficult to determine which label belongs to which node and users find this visually confusing. For this use case, it is sufficient to change the LabelLayerPolicy.

Effect of LabelLayerPolicy
SEPARATE_LAYER
AT_OWNER

Similar visual issues can arise with overlapping nodes and their ports, which can be resolved by changing the PortLayerPolicy, and with edges that cross through unrelated nodes and groups.

In general, instead of customizing the z-order, consider ways to avoid these overlaps to create a more readable diagram.

The default z-order implemented by GraphModelManager is suitable for almost all cases except those mentioned above. Specifically:

  • Rendering labels in the front ensures that their full text is readable, even with some unavoidable overlaps. This is usually the desired behavior for all edge labels and for node labels that are not placed inside their owner nodes.
  • When groups are present, edges are interleaved with the rendering of the groups. This ensures that the first and last segments of the edges are not covered by the groups of their source and target nodes. However, to maintain consistent rendering of nested groups and nodes, some edges might be forced to cross in front of (or behind) an unrelated group in a way that is not ideal.

The Default Z-order of Edges and Groups

It is intuitive that the children of a group should be rendered in front of the group instead of behind it. However, for edges, the situation is more complex. By default, edges are drawn behind nodes. When a node outside of a group has an edge to a node inside the group, or when the group node itself has an edge to one of its children, the edge can be obscured. This can make it unclear where the edge connects or even if an edge exists at all.

Because of this, yFiles for HTML by default interleaves the rendering order of nodes and edges to better support hierarchical structures. 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 hierarchicalNestingPolicy.

The Z-order of Graph Elements

The z-order of all visualized items is managed by an internal visual tree. This tree consists of hierarchically nested IRenderTreeGroup that have IRenderTreeElement implementations as leaf nodes. Each item that will be visualized is represented by an IRenderTreeElement or IRenderTreeGroup. The order of IRenderTreeElement in their IRenderTreeGroup corresponds to the z-order of the represented items.

The IRenderTreeGroup instances that are used, and in which IRenderTreeGroup an IRenderTreeElement is placed, is determined by the chosen HierarchicalNestingPolicy, PortLayerPolicy and LabelLayerPolicy.

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:

  1. portLabelGroup. It contains the visualization for the labels of ports.
  2. nodeLabelGroup. It contains the visualization for the labels of nodes.
  3. edgeLabelGroup. It contains the visualization for the labels of edges.
  4. portGroup. It contains the visualization for the ports.
  5. nodeGroup. By default it contains the visualizations for the nodes and edges.
  6. edgeGroup. It is unused by default and contains the visualizations for the edges if hierarchicalNestingPolicy is not set to NODES_AND_EDGES.
  7. groupNodeGroup. It is unused by default and contains the visualizations for group nodes if hierarchicalNestingPolicy is set to GROUP_NODES.

The following table describes which groups are used for nodes and edges, depending on the hierarchicalNestingPolicy:

Effect of HierarchicalNestingPolicy on the IRenderTreeGroup of nodes and edges
Policy Group Nodes Leaf Nodes Edges
NONEnodeGroupnodeGroupedgeGroup
NODESchild group of parent node in nodeGroupchild group of parent node in nodeGroupedgeGroup
NODES_AND_EDGESchild group of parent nodechild group of parent nodechild group of the common ancestor of the edge’s source and target node in nodeGroup
GROUP_NODESchild group of groupNodeGroup according to the nesting depthnodeGroupedgeGroup

The groups for ports and labels depend on the chosen PortLayerPolicy and LabelLayerPolicy:

Effect of PortLayerPolicy on the IRenderTreeGroup of ports
Policy Labels
AT_OWNERchild group of port owner
SEPARATE_LAYERportGroup
Effect of LabelLayerPolicy on the IRenderTreeGroup of labels
Policy Labels
AT_OWNERchild group of label owner
SEPARATE_LAYERnodeLabelGroup, edgeLabelGroup or portLabelGroup depending on the kind of label owner

Re-ordering Model Items

GraphModelManager provides methods that re-order IModelItem within their layer, which changes the order in which the elements of this layer are rendered. Re-ordering Model Items presents these methods and describes what they do.

With WebGL 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, 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, 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, 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, rendered in the back. The relative order of the elements is preserved.
raise(item: IModelItem): void
Changes the position 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 position 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 position 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 position 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’s 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. Therefore, n1 is the bottommost and n3 the topmost node.

Now we raise n2, so the rendering order is now n1, n3, n2, and n2 is topmost.

Raising n2
graphComponent.graphModelManager.raise(n2)

If we want n1 to be the topmost node, we simply move it to the end of the rendering order.

Bringing n1 to the front
graphComponent.graphModelManager.toFront(n1)
Changing the rendering order of nodes
Rendering order after node creation.
Raised n2 up …​
…​ and brought n1 to front.

For interactive scenarios, a common use case 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, 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, rendered in the back.
raiseSelection(): void
Changes the position 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 position 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 IRenderTreeElements of the model items, which can be retrieved using GraphModelManager's method getMainRenderTreeElement.

IRenderTreeElement offers two more methods that are especially handy to change the z-order of the graph element groups:

above(reference: IRenderTreeElement): IRenderTreeElement
Re-inserts this element after the given element in the rendering list, causing it to be rendered directly above the given element.
below(reference: IRenderTreeElement): IRenderTreeElement
Re-inserts this element before the given element in the rendering list, causing it to be rendered directly 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.

Changing the rendering order of edges and group nodes
Default rendering order
Changed rendering order

To achieve this, you just have to configure the GraphModelManager as shown in the following code snippet.

Drawing edges in front of group nodes
const graphModelManager = graphComponent.graphModelManager
// only nest nodes and draw all edges in a single layer
graphModelManager.hierarchicalNestingPolicy =
  HierarchicalNestingPolicy.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:

Z-order commands with their accepted parameter and effects
Command Accepted Parameter Effect
Command.RAISEIModelItemCalls raise(IModelItem)
IEnumerable<T>Calls raise(IEnumerable<IModelItem>)
nullIf selection is not empty, raiseSelection() is called. Otherwise if GraphEditorInputMode.useCurrentItemForCommands is enabled, calls raise for the currentItem.
Command.LOWERIModelItemCalls lower(IModelItem)
IEnumerable<T>Calls lower(IEnumerable<IModelItem>)
nullIf selection is not empty, lowerSelection() is called. Otherwise if GraphEditorInputMode.useCurrentItemForCommands is enabled, calls lower(IModelItem) for the currentItem.
Command.TO_FRONTIModelItemCalls toFront(IModelItem)
IEnumerable<T>Calls toFront(IEnumerable<IModelItem>)
nullIf selection is not empty, selectionToFront() is called. Otherwise if GraphEditorInputMode.useCurrentItemForCommands is enabled, calls toFront(IModelItem) for the currentItem.
Command.TO_BACKIModelItemCalls toBack(IModelItem)
IEnumerable<T>Calls toBack(IEnumerable<IModelItem>)
nullIf selection is not empty, selectionToBack() is called. Otherwise if GraphEditorInputMode.useCurrentItemForCommands is enabled, calls toBack(IModelItem) for the currentItem.

The Z-order of Indicators

Each of the three kinds of indication has its own dedicated render tree group. The main render tree groups lists these and the other predefined groups.

Reorder 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, reorder them in the corresponding group.

Completely Customize the Z-order

The approaches described above provide a comprehensive set of options for controlling the z-order of elements. However, to gain complete control, you can subclass GraphModelManager and override specific methods to implement your own z-order logic.

One approach involves overriding the factory methods for the IRenderTreeGroups. These imethods are responsible for creating each sub-group within the content group of the GraphComponent.

Alternatively, you can implement your own set of IRenderTreeGroups and override the methods that determine where each item should be placed. For example, you could override getNodeRenderTreeGroup(INode) to distribute nodes into different groups based on certain characteristics. Similar methods exist for other graph items as well.