C

FoldingManager

This class adds folding support to IGraph implementations.
Inheritance Hierarchy

Remarks

Folding is an extension to the grouping concept. It adds the functionality of collapsing (closing) and expanding (opening) group nodes. Collapsing a group node means that its content is hidden and the group node itself becomes a normal (i.e. non-group or leaf) node.

In yFiles, folding works with two graph instances: a masterGraph which is the fully expanded graph and the so-called view graph which supports collapsing and expanding. This view graph is a modified and managed copy of the master graph. To make sure that the state of both graphs is correctly synchronized, yFiles provides the types FoldingManager and the IFoldingView.

The FoldingManager holds the masterGraph and synchronizes changes between the master graph and the different IFoldingViews. Therefore, it also serves as see factory for instances of IFoldingView. In turn, each IFoldingView instance manages an IGraph implementation that provides a view of a subset of the masterGraph where group nodes can appear as collapsed group nodes with their contents hidden. The views are synchronized with the masterGraph, but may contain additional view state.

Creating a graph where nodes can be collapsed and expanded
// first create the manager
const manager = new FoldingManager()
// the manager serves as factory to create views
const foldingView = manager.createFoldingView()
// each view contains a folding-enabled graph: the view graph
const viewGraph = foldingView.graph
// the view graph is the graph which should actually be displayed
graphComponent.graph = viewGraph

Collapsed group nodes in a view, as well as their adjacent edges, maintain a separate set of labels, ports, bends, and geometry. This view-local state is shared between all views that have been created by the same manager. It can be obtained and modified via the methods getFoldingEdgeState for folding edges and getFolderNodeState for folder nodes. The FoldingManager manages the varying states nodes and edges can have in different views and during different collapsed/expanded states of the nodes. Group nodes can appear as collapsed group nodes with their contents hidden. Edges that connect to elements inside collapsed group nodes can be configured to be represented by folding edges in the views. The process of converting one or more true edges from the masterGraph to zero or more folding edges can be customized, as well as the process of converting an expanded group node to a collapsed group node.

See Also

Class FoldingManager's central role for folding support is discussed in the section Folding Revisited. A brief description of the class's API, set-up, etc. is given in the section Working with Folding.

Developer's Guide

API

IFoldingView, createFoldingView

Demos

Shows the graph editing features of the graph component.

Members

No filters for this type

Constructors

Creates a new manager with a default backing graph implementation.

Use createFoldingView to create a view that supports the IFoldingView interface for displaying and working with a collapsible graph structure.

This constructor will set a new empty Graph as masterGraph.

Parameters

Examples

Setting up folding with a new graph instance
const manager = new FoldingManager()
graphComponent.graph = manager.createFoldingView().graph
Setting up folding, reusing a given graph instance
const manager = new FoldingManager(graphComponent.graph)
graphComponent.graph = manager.createFoldingView().graph

See Also

API
createFoldingView, masterGraph
Creates a manager instance for the given masterGraph to create views on top of it that support folding operations.
The given masterGraph may already contain nodes.

Parameters

masterGraph: IGraph
The graph to use as the masterGraph.

Throws

Exception ({ name: 'ArgumentError' })
masterGraph is null.

Examples

Setting up folding with a new graph instance
const manager = new FoldingManager()
graphComponent.graph = manager.createFoldingView().graph
Setting up folding, reusing a given graph instance
const manager = new FoldingManager(graphComponent.graph)
graphComponent.graph = manager.createFoldingView().graph

Properties

Gets or sets the IFolderNodeConverter implementation that is used to create/convert and modify the folder nodes inside the view instances.
The converter instance will be used to create the initial and change the appearance of the folder nodes as soon as they appear in a view.
final

Examples

const defaultFolderNodeConverter = new FolderNodeConverter()
// set a gray rectangle to initialize a freshly collapsed group node with
defaultFolderNodeConverter.folderNodeDefaults.style = new ShapeNodeStyle({
  stroke: 'gray',
})
// use the same instance for all folders
defaultFolderNodeConverter.folderNodeDefaults.shareStyleInstance = true
// configure label handling: copy the labels
defaultFolderNodeConverter.folderNodeDefaults.copyLabels = true

// initialize labels on a freshly collapsed group node with a default style
defaultFolderNodeConverter.folderNodeDefaults.labels.style =
  new LabelStyle()
// share the same style instance
defaultFolderNodeConverter.folderNodeDefaults.labels.shareStyleInstance = true
// copy all properties from the group node labels to the folder node labels
defaultFolderNodeConverter.folderNodeDefaults.labels.initializeOptions =
  FoldingSynchronizationOptions.ALL
// copy all properties from the group node labels to the folder node labels
defaultFolderNodeConverter.folderNodeDefaults.labels.updateFoldingOptions =
  FoldingSynchronizationOptions.LABEL_TEXT
// upon subsequent collapse and expand: only synchronize the text
defaultFolderNodeConverter.folderNodeDefaults.labels.updateMasterOptions =
  FoldingSynchronizationOptions.LABEL_TEXT
// adjust the preferred size to the new text
defaultFolderNodeConverter.folderNodeDefaults.labels.autoAdjustPreferredSize = true

manager.folderNodeConverter = defaultFolderNodeConverter

See Also

Developer's Guide
API
FolderNodeConverter
Gets or sets the IFoldingEdgeConverter implementation that is used to create/convert and modify the folding edges inside the view instances.
The converter instance will be used to create the initial and change the appearance of the folding edges as soon as they appear in a view.
final

Throws

Exception ({ name: 'ArgumentError' })
value is null.

Examples

const defaultFoldingEdgeConverter = new FoldingEdgeConverter()
// initialize the new edges with a gray style
defaultFoldingEdgeConverter.foldingEdgeDefaults.style =
  new PolylineEdgeStyle({ stroke: 'gray' })
defaultFoldingEdgeConverter.foldingEdgeDefaults.copyLabels = true

// initialize the labels with a new style
defaultFoldingEdgeConverter.foldingEdgeDefaults.labels.style =
  new LabelStyle()
defaultFoldingEdgeConverter.foldingEdgeDefaults.labels.shareStyleInstance = true

// initialize all label properties (the default)
// but synchronize only the text after initialization
defaultFoldingEdgeConverter.foldingEdgeDefaults.labels.updateFoldingOptions =
  FoldingSynchronizationOptions.LABEL_TEXT
defaultFoldingEdgeConverter.foldingEdgeDefaults.labels.updateMasterOptions =
  FoldingSynchronizationOptions.LABEL_TEXT
defaultFoldingEdgeConverter.foldingEdgeDefaults.labels.autoAdjustPreferredSize = true
manager.foldingEdgeConverter = defaultFoldingEdgeConverter

Sample Graphs

ShownSetting: Expanded node

See Also

Developer's Guide
API
FoldingEdgeConverter
Gets the master IGraph instance that holds the complete model in expanded group node state.
This graph contains all non-folding edges and expanded group nodes, no folding edges and no collapsed group nodes.
readonlyfinal

See Also

Developer's Guide
Gets all currently known view instances that are managed by this instance.
readonlyfinal

See Also

API
graph

Methods

Creates a separate view instance of the masterGraph which is a synchronized copy of a subset of the items from the master graph.

This method will create a new instance of an IGraph that is constructed as a synchronized copy of the masterGraph. That instance can be obtained from the graph property of the returned IFoldingView implementation. The graph instance will provide an IFoldingView instance in its lookup mechanism:

This instance can be used to gain access to this manager instance and the folding operations.

Note that the entities that are contained in the returned graph instance are not the same instances as the original "master" entities in the masterGraph. However, they share the same properties (style, tag, parameters, and geometry). For collapsed group nodes and view edges, there is a separate set of properties available for each possible state combination. The getFoldingEdgeState method for edges and the getFolderNodeState method for nodes provide access to that state while it is not being displayed in a view.

final

Parameters

root?: INode
A group node or the root of the masterGraph whose contents will be displayed in the view.
isExpanded?: function(INode): boolean

A predicate that can be provided to the view that will be used as a callback to determine the initial expansion state in the view when a group node is created on the master graph.

In the graph of a folding view, creating groups, as opposed to creating a FolderNode via createFolderNode, always creates a group even if the isExpanded predicate is specified in the FoldingManager.createFoldingView method. Create the group on the master graph if you want the predicate to be respected.

Return Value

IFoldingView
A new graph instance that represents a synchronized view on the masterGraph.

Examples

Create a folding enabled graph
// first create the manager
const manager = new FoldingManager()
// the manager serves as factory to create views
const foldingView = manager.createFoldingView()
// each view contains a folding-enabled graph: the view graph
const viewGraph = foldingView.graph
// the view graph is the graph which should actually be displayed
graphComponent.graph = viewGraph

If the masterGraph already contains graph elements, the created view and its view graph will contain these initially, too.

Create a folding enabled graph with initial elements
const manager = new FoldingManager(graphComponent.graph)
graphComponent.graph = manager.createFoldingView().graph

All group nodes are expanded by default. The isExpanded parameter allows for providing a predicate function which can decide for each node whether it is expanded or collapsed. The following example uses a predicate which returns false for all nodes. Therefore, all nodes in the view graph will be collapsed initially.

Create a folding enabled graph with all groups being collapsed initially
const manager = new FoldingManager(graphComponent.graph)
graphComponent.graph = manager.createFoldingView({
  isExpanded: (node) => false,
}).graph

See Also

Developer's Guide
Disposes of this instance.
This will disconnect the masterGraph from the previously created managed views. Also each view will be disposed.
final
Returns the FoldingEdgeStateIds of all edges whose folding state would change if the groupNode would be collapsed.

The return value is only a snapshot and considers the expansion states of nodes in the view except for the groupNode which is considered to be collapsed. This way, the returned edge state IDs can be used to adjust the corresponding FoldingEdgeStates before they become part of the view.

The groupNode may be part of the masterGraph or of the view graph. The master edges of the returned IDs may or may not currently have a corresponding view edge.

final

Parameters

view: IFoldingView
The folding view that is used to determine the expansion state of group nodes.
groupNode: INode
The group node that should be considered as collapsed.

Return Value

IEnumerable<FoldingEdgeStateId>
The FoldingEdgeStateIds of all edges whose folding state would change if the groupNode would be collapsed.

Examples

geim.navigationInputMode.addEventListener(
  'group-collapsing',
  clearBendsOfFoldingEdges,
)
function clearBendsOfFoldingEdges(e: InputModeItemEventArgs<INode>) {
  const groupNode = e.item
  const foldingView = graph.foldingView!
  const edgeStateIds = foldingView.isExpanded(groupNode)
    ? foldingView.manager.getEdgesChangedAfterCollapse(
        foldingView,
        groupNode,
      )
    : foldingView.manager.getEdgesChangedAfterExpand(foldingView, groupNode)
  edgeStateIds.forEach((edgeStateId) => {
    if (!edgeStateId.sourceIsCollapsed && !edgeStateId.targetIsCollapsed) {
      // if neither source nor target node is collapsed, edgeStateId represents the unfolded master edge
      // so the bends also have to be cleared on the master graph
      foldingView.manager.masterGraph.clearBends(edgeStateId.masterEdge)
    } else {
      // otherwise the bends are cleared on the corresponding FoldingEdgeState
      foldingView.manager.getFoldingEdgeState(edgeStateId).clearBends()
    }
  })
}

See Also

API
FoldingEdgeState
Returns the FoldingEdgeStateIds of all edges whose folding state would change if the groupNode would be expanded.

The return value is only a snapshot and considers the expansion states of nodes in the view except for the groupNode which is considered to be expanded. This way, the returned edge state IDs can be used to adjust the corresponding FoldingEdgeStates before they become part of the view.

The groupNode may be part of the masterGraph or of the view graph. The master edges of the returned IDs may or may not currently have a corresponding view edge.

final

Parameters

view: IFoldingView
The folding view that is used to determine the expansion state of group nodes.
groupNode: INode
The group node that should be considered as expanded.

Return Value

IEnumerable<FoldingEdgeStateId>
The FoldingEdgeStateIds of all edges whose folding state would change if the groupNode would be expanded.

Examples

geim.navigationInputMode.addEventListener(
  'group-expanding',
  clearBendsOfFoldingEdges,
)
function clearBendsOfFoldingEdges(e: InputModeItemEventArgs<INode>) {
  const groupNode = e.item
  const foldingView = graph.foldingView!
  const edgeStateIds = foldingView.isExpanded(groupNode)
    ? foldingView.manager.getEdgesChangedAfterCollapse(
        foldingView,
        groupNode,
      )
    : foldingView.manager.getEdgesChangedAfterExpand(foldingView, groupNode)
  edgeStateIds.forEach((edgeStateId) => {
    if (!edgeStateId.sourceIsCollapsed && !edgeStateId.targetIsCollapsed) {
      // if neither source nor target node is collapsed, edgeStateId represents the unfolded master edge
      // so the bends also have to be cleared on the master graph
      foldingView.manager.masterGraph.clearBends(edgeStateId.masterEdge)
    } else {
      // otherwise the bends are cleared on the corresponding FoldingEdgeState
      foldingView.manager.getFoldingEdgeState(edgeStateId).clearBends()
    }
  })
}

See Also

API
FoldingEdgeState
Provides access to the folder node state of a node.
This method can be used to query the collapsed state of a node, even if the node is currently not present in any managed view or the node is in fact expanded in all views.
final

Parameters

masterNode: INode
The node in the masterGraph for which the state should be returned.

Return Value

FolderNodeState
A state holder implementation of a node, which is not part of any graph.

Throws

Exception ({ name: 'ArgumentError' })
The master node does not belong to the managed graph.

Examples

const state = manager.getFolderNodeState(masterNode)
state.style = new GroupNodeStyle()

See Also

Developer's Guide
Return a data container implementation that is not part of any actual IGraph that describes the state of the edge for the given FoldingEdgeStateId.
This method can be used to query the state of an edge that is either not currently visible in any view or connects to different source and target nodes because of the collapsed states of the nodes and their parents in the view.
final

Parameters

id: FoldingEdgeStateId
The ID of the folding edge for which the folding state should be returned.

Return Value

FoldingEdgeState
A FoldingEdgeState that can be used to query and change the properties of the edge.

Throws

Exception ({ name: 'ArgumentError' })
if the id doesn't represent a dummy edge state which is managed by this manager.

Examples

const state = manager.getFoldingEdgeState(
  new FoldingEdgeStateId(
    masterEdge,
    masterSource,
    true,
    masterTarget,
    false,
  ),
)
state.style = new PolylineEdgeStyle({ stroke: Stroke.RED })
const state = manager.getFoldingEdgeState(
  new FoldingEdgeStateId(
    masterEdge,
    masterSource,
    true,
    masterTarget,
    false,
  ),
)
const portState = state.sourcePort
portState.locationParameter = FreeNodePortLocationModel.RIGHT

Sample Graphs

ShownSetting: Fully Expanded: no view state

See Also

Developer's Guide
API
getFolderNodeState, FoldingEdgeStateId
Returns the master nodes of the descendants of the groupNode that would be represented in the view if the groupNode would be expanded.

The return value is only a snapshot and considers the expansion states of nodes in the view except for the groupNode which is considered to be expanded. This way, the returned nodes can be adjusted before they become part of the view.

The groupNode may be part of the masterGraph or of the view graph. The returned descendants all belong to the masterGraph and may currently have no corresponding view item.

final

Parameters

view: IFoldingView
The folding view that is used to determine the expansion state of group nodes.
groupNode: INode
The group node that should be considered as expanded.

Return Value

IEnumerable<INode>
The master nodes of the descendants of the group node that would be represented in the view if the group node would be expanded.

Examples

geim.navigationInputMode.addEventListener(
  'group-expanding',
  onGroupExpanding,
)
function onGroupExpanding(e: InputModeItemEventArgs<INode>) {
  // move the center of the expanded group node (together with all descendants) to the center of the folder
  const groupNode = e.item
  const foldingView = graph.foldingView!
  const masterItem = foldingView.getMasterItem(groupNode)!
  // calculate the delta by which the group node and its descendants have to be moved
  const delta = groupNode.layout.center.subtract(masterItem.layout.center)

  const masterGraph = foldingView.manager.masterGraph
  masterGraph.setNodeCenter(masterItem, groupNode.layout.center)
  const descendents = foldingView.manager.getNodesRevealedAfterExpand(
    foldingView,
    groupNode,
  )
  descendents.forEach((descendent) =>
    masterGraph.setNodeCenter(
      descendent,
      descendent.layout.center.add(delta),
    ),
  )
}
Determines whether for the given masterNode this manager has stored associated folder node state.
The manager does not necessarily have folder node state for folder nodes if that specific state has never been requested by a view because it has never been visualized. This method indicates whether there is state information available for the given master node.
final

Parameters

masterNode: INode
The master node for which the state is requested.

Return Value

boolean
Whether getFolderNodeState would return existing state information.

See Also

API
getFolderNodeState
Determines whether for the given FoldingEdgeStateId this manager has stored associated view local state.
The manager does not necessarily have a FoldingEdgeState for folding elements if that specific state has never been requested by a IFoldingView because it has never been visualized. This method indicates whether there is state information available for the given id.
final

Parameters

id: FoldingEdgeStateId
The id for which state is requested.

Return Value

boolean
Whether getFoldingEdgeState would return existing state information.

See Also

API
getFoldingEdgeState
Triggers a call to updateFolderNodeState for all view nodes that represent the given masterNode in its collapsed state.

In all views that are currently showing the node in collapsed state, the view-local state will be updated via a call to the IFolderNodeConverter's updateFolderNodeState method.

Note that all views share the same FolderNodeState for the masterNode.

This method is useful in situations where a change in the data on the master graph did not automatically trigger a call to the converter. Using this method, the state of the collapsed nodes in the views can be synchronized according to the logic in the IFolderNodeConverter implementation.

final

Parameters

masterNode: INode
The master node that belongs to the masterGraph.

Throws

Exception ({ name: 'ArgumentError' })
If the provided master node does not belong to the master graph.

See Also

API
updateFoldingEdgeStates
Triggers a call to updateFoldingEdgeState for all folder edges that represent the given masterEdge.

In all views that are currently showing the view edge for the provided master edge, the view-local state will be updated via a call to the IFoldingEdgeConverter's updateFoldingEdgeState method.

This method is useful in situations where a change in the data on the master graph did not automatically trigger a call to the converter. Using this method, the state of the representing edges in the views can be synchronized according to the logic in the IFoldingEdgeConverter implementation.

final

Parameters

masterEdge: IEdge
The master edge that belongs to the masterGraph.

Throws

Exception ({ name: 'ArgumentError' })
If the provided master edge does not belong to the master graph.

See Also

API
updateFolderNodeState