The yFiles FLEX server library provides support for hierarchically organized graphs. To get a brief review over the concepts of grouping and folding see the corresponding chapter describing the client library.
Analogous to the client the hierarchy of nodes is managed by the interface INodeHierarchy. This interface provides convenient utility methods for querying and manipulating a LayoutGraph's hierarchical structure:
Node getParent(Node child) |
|
Description | Get a node's parent. |
void setParent(Node child, Node parent) |
|
Description | Set a node's parent. |
void setParent(NodeList children, Node parent) |
|
Description | Add a list of nodes to a parent |
setGroupNode( Node node, boolean isGroupNode ) |
|
Description | Set whether the node should be considered a group node |
boolean isGroupNode(Node node) |
|
Description | Returns whether the node is considered a group node |
NodeList getChildren(Node parent) |
|
Description | Get the children of a group node |
The INodeHierarchy of a graph can be obtained using StyledLayoutGraph's method getNodeHierarchy(). Note that GraphRoundtripSupport's method createRoundtripGraph() always returns a StyledLayoutGraph.
Example 7.7, “Creating a Grouped Graph on the Server” demonstrates how the grouped graph structure shown in Figure 7.1, “Example grouped graph” can be created on the server using a LayoutGraph instance with the yFiles FLEX server API.
Figure 7.1. Example grouped graph
The hierarchic graph structure created in Example 7.7, “Creating a Grouped Graph on the Server”, after a hierarchic layout has been applied. |
Example 7.7. Creating a Grouped Graph on the Server
/** * Create a simple graph hierarchy containing * nested group nodes */ private void createGroupNodes(StyledLayoutGraph graph) { // createGroupNode assigns a distinct style // and label model to nodes that will be used as group nodes. Node outerGroup = createGroupNode(graph, "Outer Group"); Node innerGroup = createGroupNode(graph, "Inner Group"); // createLeafNode assigns a distinct style // and label model to nodes that will be used as leaf nodes. Node leafNode1 = createLeafNode(graph,"Leaf Node"); Node leafNode2 = createLeafNode(graph,"Leaf Node"); Node leafNode3 = createLeafNode(graph,"Leaf Node"); Node leafNode4 = createLeafNode(graph,"Leaf Node"); // So far, we have a flat graph - no hierarchy // has been defined yet. // Now, we define the hierarchy. INodeHierarchy nodeHierarchy = graph.getNodeHierarchy(); nodeHierarchy.setParent(leafNode1, outerGroup); nodeHierarchy.setParent(innerGroup, outerGroup); nodeHierarchy.setParent(leafNode2, innerGroup); nodeHierarchy.setParent(leafNode3, innerGroup); nodeHierarchy.setParent(leafNode4, outerGroup); // Add some edges. graph.createEdge(leafNode2, leafNode1); graph.createEdge(leafNode3, leafNode2); graph.createEdge(leafNode3, leafNode4); } /** * Create a node that will be used as leaf node, * using a BevelNodeStyle and a centered label. */ private Node createLeafNode(StyledLayoutGraph graph, String labelText) { Node node = graph.createNode(); graph.setSize(node, 60, 40); BevelNodeStyle style = new BevelNodeStyle(); style.setColor(new Color(255, 140, 0)); graph.setStyle(node, style); if (null != labelText) { InteriorLabelModel labelModel = new InteriorLabelModel(); ILabelModelParameter parameter = new InteriorLabelModel.ModelParameter(labelModel, InteriorLabelModel.POSITION_CENTER); graph.addLabel(node, new Label(labelText, parameter)); } return node; } /** * Create a node that will be used as a group node, * using a PanelNodeStyle and * a label that is stretched to the node's width. */ private Node createGroupNode( StyledLayoutGraph graph, String labelText ) { Node groupNode = graph.createNode(); InteriorLabelModel labelModel = new InteriorLabelModel(); ILabelModelParameter parameter = new InteriorLabelModel.ModelParameter(labelModel, InteriorLabelModel.POSITION_NORTH); Label label = new Label(labelText, parameter); graph.addLabel(groupNode, label); PanelNodeStyle style = new PanelNodeStyle(); style.setColor(new Color(128, 128, 128)); style.setLabelInsetsColor(new Color(192, 192, 192)); graph.setStyle(groupNode, style); // Define some insets for the group node, // that will be considered by layout algorithms. DataProvider insetsProvider = graph.getDataProvider(GroupingKeys.GROUP_NODE_INSETS_DPKEY); if (null != insetsProvider && insetsProvider instanceof DataMap) { ((DataMap) insetsProvider).set(groupNode, new Insets(25, 5, 5, 5)); } return groupNode; }
Folding, i.e. expanding and collapsing group nodes, is an important means in breaking large graphs into smaller units. yFiles FLEX supports folding at the client as well as at the server side.
Folding is supported by FoldedLayoutGraph, which is a subclass of StyledLayoutGraph. GraphRoundtripSupport's method createRoundtripGraph() returns a FoldedLayoutGraph if folding is enabled. Folding support is not enabled by default but has to be enabled by setting setFoldingEnabled() to true.
Generally, there are two ways to send a folded graph to the client:
Sending the folder nodes as folders together with their nested graphs (the folder contents). This allows to open and close the folders on the client side without contacting the server again. On the other hand, transferring the nested graphs can increase the size of the transferred GraphML significantly, which affects roundtrip time and network traffic.
This mode can be enabled by setting setLocalViewMode() on GraphRoundtripSupport to false (the default).
Note that folding has to be enabled on the client.
Sending the closed folder nodes as "normal" nodes. With this option opening a folder requires a new roundtrip to the server. On the other hand, the transferred GraphML will be kept small which results in shorter roundtrip times and less network traffic.
This mode can be enabled by setting setLocalViewMode() on GraphRoundtripSupport to true.
Folding is managed by the FoldedLayoutGraph which provides convenient utility methods for expanding and collapsing groups:
void collapse(Node node) |
|
Description | collapse (close) a group node, hiding its children from the current view |
void expand(Node node) |
|
Description | expand (open) a group node, revealing its children |
void isExpanded(Node node) |
|
Description | whether the given node is expanded |
void setLocalRoot(Node node) |
|
Description | "enter" the given group node, i.e. let the folded graph reflect only the contents of the group |
A group node can be opened or closed using the methods expand(Node node) and collapse(Node node), respectively. Closing the "innerGroup" node from Example 7.7, “Creating a Grouped Graph on the Server” is shown in Example 7.8, “Closing a group node”.
Example 7.8. Closing a group node
// modify the method createGroupNodes in the // "create a grouped graph" example to apply folding: private void createGroupNodes(FoldedLayoutGraph graph) { ... // insert the new line at the end graph.collapse(innerGroup); }
Figure 7.2. Closed group node
The inner group node from Figure 7.1, “Example grouped graph” was closed as shown in Example 7.8, “Closing a group node”. |
The server-side folded graph also supports the concept of a virtual "local root" through the setLocalRoot(Node node) method of FoldedlayoutGraph. When a graph layout is calculated for the folded graph, the layout will be applied to the contents of the group node that is set as the local root.
When reading a graph from a HttpServletRequest GraphRoundtripSupport will set the local root automatically if folding is enabled and the request is sent with a "localRoot" parameter. The local root will be set to the node identified by the id given with that parameter.
As discussed in the section called “Folding-related State Across Views”, closed folder nodes and inter-edges (edges between hidden contents of a closed folder and nodes outside the folder) can have different visual representations. Class NodeViewState keeps the visual information such as labels, style, and layout for a dummy node. Class EdgeViewState keeps the visual information such as labels, styles, bends, and source and target ports for a dummy edge. FoldedLayoutGraph's methods to access the view states are listed below.
NodeViewState getNodeViewState(DummyNodeId nodeId) |
|
Description | // get the view state of a collapsed group node |
EdgeViewState getEdgeViewState(DummyEdgeId edgeId) |
|
Description | // get the view state of a dummy edge |
If a folder node should have a different label, style and size than in its open state, a view state has to be assigned as shown in Example 7.9, “Setting a view state”. Note that collapsing a group node will not automatically create view states for the collapsed state of the group node and for the inter edges resutling from the collapse operation. However, when a view state of a collapsed node or interedge is queried from the FoldedLayoutGraph using getEdgeViewState(DummyEdgeId edgeId) / getNodeViewState(DummyNodeId nodeId), and no view state instance has been assigned to the collapsed node or interedge yet, a new view state instance will be created and returned. The default implementations of createNodeViewState(DummyNodeId nodeId) and createEdgeViewState(DummyEdgeId edgeId) will copy the visual properties of the corresponding master node or master edge to the view state instance.
Example 7.9. Setting a view state
// get the nodeViewState for the innerGroup NodeViewState nodeViewState = graph.getNodeViewState(new DummyNodeId(innerGroup)); // add a different label nodeViewState.getLabels().add(new Label("Collapsed node", InteriorLabelModel.center)); // set a different style nodeViewState.setStyle(new BevelNodeStyle()); // make it smaller nodeViewState.setLayout(new YRectangle(0, 0, 60, 40));
Figure 7.3. Folder node with different view state
The closed group node with the different view state created in Example 7.9, “Setting a view state”. |
When applying an automatic layout the layouter does not know about the folding state by default. FoldedLayoutGraph offers a convenience method to configure the graph and the layouter and apply the layout: doLayout(Layouter layouter), see also Example 7.10, “Applying a layout on a folded graph”. Its overload doLayout(Layouter layouter, Node root, boolean recursive, byte dummyEdgeMode) allows further configurations. See the API documentation for details.
The following servlets which can be found in subpackages of com.yworks.yfiles.server.graphml.demo demonstrate aspects of working with Hierarchies on a yFiles Java Server:
Copyright ©2007-2015, yWorks GmbH. All rights reserved. |