/// <summary> /// Applies the layout. /// </summary> /// <remarks> /// Uses an <see cref="HierarchicLayout"/>. If single graph /// items are created or removed, the incremental mode of this layout /// algorithm is used to keep most of the current layout of the graph /// unchanged. /// </remarks> /// <param name="incremental">if set to <see langword="true"/> [incremental].</param> /// <param name="incrementalNodes">The incremental nodes.</param> private async Task ApplyLayout(bool incremental, params EntityData[] incrementalNodes) { var layout = new HierarchicLayout { IntegratedEdgeLabeling = true, OrthogonalRouting = true }; HierarchicLayoutData layoutData = null; if (!incremental) { layout.LayoutMode = LayoutMode.FromScratch; } else { layout.LayoutMode = LayoutMode.Incremental; if (incrementalNodes.Any()) { // we need to add hints for incremental nodes layoutData = new HierarchicLayoutData { IncrementalHints = { IncrementalLayeringNodes = { Source = incrementalNodes.Select(graphSource.GetNode) } } }; } } await graphControl.MorphLayout(layout, TimeSpan.FromSeconds(1), layoutData); }
private void ApplyHierarchicLayout(LayoutGraph graph) { HierarchicLayout hl = new HierarchicLayout(); hl.OrthogonalRouting = true; hl.RecursiveGroupLayering = false; hl.ComponentLayoutEnabled = false; hl.FromScratchLayerer = new BackLoopLayerer(); hl.MinimumLayerDistance = MinimumNodeDistance; hl.NodeToNodeDistance = MinimumNodeDistance; ((SimplexNodePlacer)hl.NodePlacer).BarycenterMode = true; ((SimplexNodePlacer)hl.NodePlacer).StraightenEdges = true; hl.LayoutOrientation = LayoutOrientation == LayoutOrientation.LeftToRight ? Layout.LayoutOrientation.LeftToRight : Layout.LayoutOrientation.TopToBottom; hl.HierarchicLayoutCore.PortConstraintOptimizer = new BalancingPortOptimizer(new PortCandidateOptimizer()); if (Scope == Scope.SelectedElements) { hl.FixedElementsLayerer = new AsIsLayerer { MaximumNodeSize = 5 }; hl.LayoutMode = LayoutMode.Incremental; } hl.ApplyLayout(graph); }
/// <summary> /// Perform a hierarchic layout that also configures the tables /// </summary> /// <remarks>Table support is automatically enabled in <see cref="LayoutExecutor"/>. The layout will: /// <list type="bullet"> /// <item> /// Arrange all leaf nodes in a hierarchic layout inside their respective table cells /// </item> /// <item>Resize all table cells to encompass their child nodes. Optionally, <see cref="TableLayoutConfigurator.Compaction"/> allows to shrink table cells, other wise, table cells /// can only grow.</item> /// </list> /// </remarks> private async void LayoutButton_Click(object sender, EventArgs e) { var hl = new HierarchicLayout { ComponentLayoutEnabled = false, LayoutOrientation = LayoutOrientation.LeftToRight, OrthogonalRouting = true, RecursiveGroupLayering = false }; ((SimplexNodePlacer)hl.NodePlacer).BarycenterMode = true; //We use Layout executor convenience method that already sets up the whole layout pipeline correctly var layoutExecutor = new LayoutExecutor(graphControl, hl) { //Table layout is enabled by default already... ConfigureTableLayout = true, Duration = TimeSpan.FromMilliseconds(500), AnimateViewport = true, UpdateContentRect = true, TargetBoundsInsets = graphEditorInputMode.ContentRectMargins, RunInThread = true, //Table cells may only grow by an automatic layout. TableLayoutConfigurator = { Compaction = false } }; await layoutExecutor.Start(); }
static PartialLayoutForm() { SubGraphLayouts[LayoutIncremental] = new HierarchicLayout(); SubGraphLayouts[LayoutOrganic] = new OrganicLayout(); SubGraphLayouts[LayoutOrthogonal] = new OrthogonalLayout(); SubGraphLayouts[LayoutCircular] = new CircularLayout(); SubGraphLayouts[LayoutUnchanged] = null; }
/// <summary> /// Gets the layout algorithm selected by the user. /// </summary> /// <returns></returns> private ILayoutAlgorithm GetLayoutAlgorithm() { var graph = graphControl.Graph; var item = layoutChooserBox.SelectedItem as ComboBoxItem; var layoutName = item != null ? item.Tag as String: null; ILayoutAlgorithm layout = new HierarchicLayout(); if (layoutName != null) { if (layoutName == "hierarchic") { layout = new HierarchicLayout(); } else if (layoutName == "organic") { layout = new OrganicLayout { PreferredEdgeLength = 1.5 * Math.Max(graph.NodeDefaults.Size.Width, graph.NodeDefaults.Size.Height) }; } else if (layoutName == "orthogonal") { layout = new OrthogonalLayout(); } else if (layoutName == "circular") { layout = new CircularLayout(); } else if (layoutName == "tree") { layout = new TreeReductionStage(new TreeLayout()) { NonTreeEdgeRouter = new OrganicEdgeRouter() }; } else if (layoutName == "balloon") { layout = new TreeReductionStage(new BalloonLayout()) { NonTreeEdgeRouter = new OrganicEdgeRouter() }; } else if (layoutName == "radial") { layout = new RadialLayout(); } else if (layoutName == "router-polyline") { layout = new EdgeRouter(); } else if (layoutName == "router-organic") { layout = new OrganicEdgeRouter { EdgeNodeOverlapAllowed = false }; } } return(layout); }
/// <summary> /// Gets the layout algorithm selected by the user. /// </summary> /// <returns></returns> private ILayoutAlgorithm GetLayoutAlgorithm() { var graph = graphControl.Graph; var layoutName = layoutBox.SelectedItem as string; ILayoutAlgorithm layout = new HierarchicLayout(); if (layoutName != null) { if (layoutName == "Layout: Hierarchic") { layout = new HierarchicLayout(); } else if (layoutName == "Layout: Organic") { layout = new OrganicLayout { PreferredEdgeLength = 1.5 * Math.Max(graph.NodeDefaults.Size.Width, graph.NodeDefaults.Size.Height) }; } else if (layoutName == "Layout: Orthogonal") { layout = new OrthogonalLayout(); } else if (layoutName == "Layout: Circular") { layout = new CircularLayout(); } else if (layoutName == "Layout: Tree") { layout = new TreeReductionStage(new TreeLayout()) { NonTreeEdgeRouter = new OrganicEdgeRouter() }; } else if (layoutName == "Layout: Balloon") { layout = new TreeReductionStage(new BalloonLayout()) { NonTreeEdgeRouter = new OrganicEdgeRouter() }; } else if (layoutName == "Layout: Radial") { layout = new RadialLayout(); } else if (layoutName == "Routing: Polyline") { layout = new EdgeRouter(); } else if (layoutName == "Routing: Organic") { layout = new OrganicEdgeRouter { EdgeNodeOverlapAllowed = false }; } } return(layout); }
/// <summary> /// Performs the layout operation after applying all required constraints /// </summary> private async Task DoLayout() { // layout starting, disable button runButton.Enabled = false; // we want to use the hl var hl = new HierarchicLayout() { OrthogonalRouting = true }; // we only configure sequence constraints, so we can just use a new SequenceConstraintData // if HierarchicLayout should be configured further, we could also use HierarchicLayoutData.SequenceConstraintData var scData = new SequenceConstraintData { // we provide the item Values directly as IComparable instead of using the Add* methods on SequenceConstraintData ItemComparables = { Delegate = item => { // get the constraints info for the item // Note that 'item' can be an INode or IEdge but we only use SequenceConstraintsInfo for nodes var data = (item).Tag as SequenceConstraintsInfo; if (data != null && data.Constraints) { // the item shall be constrained so we use its Value as comparable return(data.Value); } // otherwise we don't add constraints for the item return(null); } } }; // additionally enforce all nodes with a SequenceConstraintInfo.Value of 0 or 7 to be placed at head/tail foreach (var node in graphControl.Graph.Nodes) { var data = node.Tag as SequenceConstraintsInfo; if (data != null && data.Constraints) { if (data.Value == 0) { // add constraint to put this node at the head scData.PlaceAtHead(node); } else if (data.Value == 7) { // add constraint to put this node at the tail scData.PlaceAtTail(node); } } } // do the layout await graphControl.MorphLayout(hl, TimeSpan.FromSeconds(1), scData); // enable button again runButton.Enabled = true; }
/// <summary> /// Populates the layout combo box. /// </summary> private void PopulateLayoutComboBox() { layouts["Hierarchic Layout"] = new HierarchicLayout(); layouts["Organic Layout"] = new OrganicLayout { MinimumNodeDistance = 40 }; layouts["Orthogonal Layout"] = new OrthogonalLayout(); layoutComboBox.Items.AddRange(layouts.Keys.ToArray()); }
private static ILayoutAlgorithm CreateHierarchicLayout(LayoutOrientation layoutOrientation) { var hl = new HierarchicLayout { IntegratedEdgeLabeling = true, LayoutOrientation = layoutOrientation }; DisableAutoFlipping(hl); return(hl); }
///<inheritdoc/> protected override void ConfigureLayout() { OptionGroup layoutGroup = Handler.GetGroupByName(GENERAL); var partialLayout = new PartialLayout { MinimumNodeDistance = (int)layoutGroup[MIN_NODE_DIST].Value, ConsiderNodeAlignment = (bool)layoutGroup[CONSIDER_SNAPLINES].Value, SubgraphPlacement = subgraphPlacementStrategies[ (string)layoutGroup[SUBGRAPH_POSITION_STRATEGY].Value] }; string componentAssignmentStr = (string)layoutGroup[MODE_COMPONENT_ASSIGNMENT].Value; partialLayout.ComponentAssignmentStrategy = componentAssignment[componentAssignmentStr]; partialLayout.LayoutOrientation = layoutOrientation[(string)layoutGroup[ORIENTATION_MAIN_GRAPH].Value]; partialLayout.EdgeRoutingStrategy = routingStrategies[(string)layoutGroup[ROUTING_TO_SUBGRAPH].Value]; ILayoutAlgorithm subgraphLayout = null; if (componentAssignmentStr != MODE_COMPONENT_SINGLE) { var subGraphLayoutStr = (string)layoutGroup[SUBGRAPH_LAYOUT].Value; switch (subGraphLayoutStr) { case SUBGRAPH_LAYOUT_IHL: subgraphLayout = new HierarchicLayout(); break; case SUBGRAPH_LAYOUT_ORGANIC: subgraphLayout = new OrganicLayout(); break; case SUBGRAPH_LAYOUT_CIRCULAR: subgraphLayout = new CircularLayout(); break; case SUBGRAPH_LAYOUT_ORTHOGONAL: subgraphLayout = new OrthogonalLayout(); break; default: break; } } partialLayout.CoreLayout = subgraphLayout; LayoutAlgorithm = partialLayout; }
///<summary> /// Creates a new instance of <c>ThreeTierLayout</c>. ///</summary> /// <param name="fromSketch"/> Whether the <see cref="HierarchicLayout"/> shall be run in incremental layout mode. public ThreeTierLayout(bool fromSketch) { HierarchicLayout hl = new HierarchicLayout { LayoutOrientation = LayoutOrientation.LeftToRight, LayoutMode = fromSketch ? LayoutMode.Incremental : LayoutMode.FromScratch, }; var rgl = new RecursiveGroupLayout(hl) { AutoAssignPortCandidates = true, FromSketchMode = true }; CoreLayout = rgl; }
/// <summary> /// Creates the core layouts and populates the layouts box /// </summary> private void InitializeCoreLayouts() { coreLayouts = new Dictionary <string, ILayoutAlgorithm>(); coreLayouts["Hierarchic"] = new HierarchicLayout { ConsiderNodeLabels = true, IntegratedEdgeLabeling = true, OrthogonalRouting = true }; coreLayouts["Circular"] = new CircularLayout(); coreLayouts["Compact Orthogonal"] = new CompactOrthogonalLayout(); coreLayouts["Organic"] = new OrganicLayout { MinimumNodeDistance = 10, Deterministic = true }; coreLayouts["Orthogonal"] = new OrthogonalLayout(); coreLayoutComboBox.ItemsSource = coreLayouts.Keys; coreLayoutComboBox.SelectedIndex = 0; }
public TableLayout(bool fromSketch) { // incremental hierarchic layout is used for the core layout that connects the table nodes var hl = new HierarchicLayout { LayoutOrientation = LayoutOrientation.LeftToRight, LayoutMode = fromSketch ? LayoutMode.Incremental : LayoutMode.FromScratch, OrthogonalRouting = true }; var rgl = new RecursiveGroupLayout(hl) { AutoAssignPortCandidates = true, FromSketchMode = true }; CoreLayout = rgl; }
/// <summary> /// Creates and configures the <see cref="HierarchicLayout"/> and the <see cref="HierarchicLayoutData"/> /// such that node types are considered. /// </summary> private Sample CreateHierarchicSample() { // create hierarchic layout - no further settings on the algorithm necessary to support types var layout = new HierarchicLayout(); // the node types are specified as delegate on the nodeTypes property of the layout data var layoutData = new HierarchicLayoutData { NodeTypes = { Delegate = node => GetNodeType(node) } }; return(new Sample { Name = "Hierarchic", File = "hierarchic", Layout = layout, LayoutData = layoutData, IsDirected = true }); }
/// <summary> /// Creates a configured hierarchic layout data. /// </summary> /// <param name="incremental"><code>true</code> in case the layout should be calculated incrementally.</param> public HierarchicLayout GetHierarchicLayout(bool incremental) { var layout = new HierarchicLayout { OrthogonalRouting = true, NodeToEdgeDistance = 50, MinimumLayerDistance = 40, LabelingEnabled = false, IntegratedEdgeLabeling = true, ConsiderNodeLabels = true, GridSpacing = 10 }; if (incremental) { layout.LayoutMode = LayoutMode.Incremental; } return(layout); }
/// <inheritdoc /> protected override ILayoutAlgorithm CreateConfiguredLayout(GraphControl graphControl) { var layout = new PartialLayout(); layout.ConsiderNodeAlignment = AlignNodesItem; layout.MinimumNodeDistance = MinimumNodeDistanceItem; layout.SubgraphPlacement = SubgraphPlacementItem; layout.ComponentAssignmentStrategy = ComponentAssignmentStrategyItem; layout.LayoutOrientation = OrientationItem; layout.EdgeRoutingStrategy = RoutingToSubgraphItem; layout.AllowMovingFixedElements = MoveFixedElementsItem; ILayoutAlgorithm subgraphLayout = null; if (ComponentAssignmentStrategyItem != ComponentAssignmentStrategy.Single) { switch (SubgraphLayoutItem) { case EnumSubgraphLayouts.Hierarchic: subgraphLayout = new HierarchicLayout(); break; case EnumSubgraphLayouts.Organic: subgraphLayout = new OrganicLayout(); break; case EnumSubgraphLayouts.Circular: subgraphLayout = new CircularLayout(); break; case EnumSubgraphLayouts.Orthogonal: subgraphLayout = new OrthogonalLayout(); break; } } layout.CoreLayout = subgraphLayout; return(layout); }
public HierarchicLayout ConfigureHierarchicLayout(bool fromSketchMode) { var hierarchicLayout = new HierarchicLayout { LayoutOrientation = LayoutOrientation.LeftToRight, LayoutMode = fromSketchMode ? LayoutMode.Incremental : LayoutMode.FromScratch, NodeToNodeDistance = 30, BackLoopRouting = true, EdgeLayoutDescriptor = { MinimumFirstSegmentLength = 120, MinimumLastSegmentLength = 120, }, }; // a port border gap ratio of zero means that ports can be placed directly on the corners of the nodes var portBorderRatio = 1; hierarchicLayout.NodeLayoutDescriptor.PortBorderGapRatios = portBorderRatio; // configures the generic labeling algorithm which produces more compact results, here var genericLabeling = (GenericLabeling)hierarchicLayout.Labeling; genericLabeling.ReduceAmbiguity = false; genericLabeling.PlaceNodeLabels = false; genericLabeling.PlaceEdgeLabels = true; hierarchicLayout.LabelingEnabled = true; // for Sankey diagrams, the nodes should be adjusted to the incoming/outgoing flow (enlarged if necessary) // -> use NodeResizingStage for that purpose var nodeResizingStage = new NodeResizingStage(hierarchicLayout); nodeResizingStage.LayoutOrientation = hierarchicLayout.LayoutOrientation; nodeResizingStage.PortBorderGapRatio = portBorderRatio; hierarchicLayout.PrependStage(nodeResizingStage); return(hierarchicLayout); }
private async Task DoLayout() { // layout starting, disable button layoutButton.IsEnabled = false; // create a new layout algorithm var hl = new HierarchicLayout { OrthogonalRouting = true, FromScratchLayeringStrategy = LayeringStrategy.HierarchicalTopmost, IntegratedEdgeLabeling = true }; // and layout data for it var hlData = new HierarchicLayoutData { ConstraintIncrementalLayererAdditionalEdgeWeights = { Delegate = GetEdgeWeight } }; // we provide the LayerConstraintData.Values directly as IComparable instead of using the Add* methods on LayerConstraintData var layerConstraintData = hlData.LayerConstraints; layerConstraintData.NodeComparables.Delegate = node => { var data = node.Tag as LayerConstraintsInfo; if (data != null && data.Constraints) { // the node shall be constrained so we use its Value as comparable return(data.Value); } // otherwise we don't add constraints for the node return(null); }; INode[] layerRep = new INode[8]; // additionally enforce all nodes with a LayerConstraintInfo.Value of 0 or 7 to be placed at top/bottom // and all nodes with the same Value in the same layer foreach (var node in graphControl.Graph.Nodes) { var data = node.Tag as LayerConstraintsInfo; if (data != null && data.Constraints) { if (data.Value == 0) { // add constraint to put this node at the top layerConstraintData.PlaceAtTop(node); } else if (data.Value == 7) { // add constraint to put this node at the bottom layerConstraintData.PlaceAtBottom(node); } if (layerRep[data.Value] == null) { // this is the first node found having this data.Value so we store it as representative layerRep[data.Value] = node; } else { // add constraint to put this node in the same layer as its representative layerConstraintData.PlaceInSameLayer(layerRep[data.Value], node); } } } // perform the layout operation await graphControl.MorphLayout(hl, TimeSpan.FromSeconds(1), hlData); // code is executed once the layout operation is finished // enable button again layoutButton.IsEnabled = true; }
public static void Main() { DefaultLayoutGraph graph = new DefaultLayoutGraph(); //construct graph. assign sizes to nodes Node v1 = graph.CreateNode(); graph.SetSize(v1, 30, 30); Node v2 = graph.CreateNode(); graph.SetSize(v2, 30, 30); Node v3 = graph.CreateNode(); graph.SetSize(v3, 30, 30); // add a label to one node var nodeLabelLayoutModel = new DiscreteNodeLabelLayoutModel(DiscreteNodeLabelPositions.InternalMask, 4); var labelLayoutFactory = LayoutGraphUtilities.GetLabelFactory(graph); labelLayoutFactory.AddLabelLayout(v1, labelLayoutFactory.CreateLabelLayout(v1, new YOrientedRectangle(0, 0, 80, 20), nodeLabelLayoutModel)); Edge e1 = graph.CreateEdge(v1, v2); Edge e2 = graph.CreateEdge(v1, v3); // add a label to an edge var edgeLabelLayoutModel = new SliderEdgeLabelLayoutModel(SliderMode.Side); labelLayoutFactory.AddLabelLayout(e1, labelLayoutFactory.CreateLabelLayout(e1, new YOrientedRectangle(0, 0, 80, 20), edgeLabelLayoutModel, PreferredPlacementDescriptor.NewSharedInstance(LabelPlacements.LeftOfEdge))); //optionally setup some port constraints for HierarchicLayout IEdgeMap spc = graph.CreateEdgeMap(); IEdgeMap tpc = graph.CreateEdgeMap(); //e1 shall leave and enter the node on the right side spc.Set(e1, PortConstraint.Create(PortSide.East, false)); //additionally set a strong port constraint on the target side. tpc.Set(e1, PortConstraint.Create(PortSide.East, true)); //ports with strong port constraints will not be reset by the //layout algorithm. So we specify the target port right now to connect //to the upper left corner of the node graph.SetTargetPointRel(e1, new YPoint(15, -15)); //e2 shall leave and enter the node on the top side spc.Set(e2, PortConstraint.Create(PortSide.North, false)); tpc.Set(e2, PortConstraint.Create(PortSide.North, false)); graph.AddDataProvider(PortConstraintKeys.SourcePortConstraintDpKey, spc); graph.AddDataProvider(PortConstraintKeys.TargetPortConstraintDpKey, tpc); HierarchicLayout layout = new HierarchicLayout(); layout.IntegratedEdgeLabeling = true; layout.ConsiderNodeLabels = true; layout.LayoutMode = LayoutMode.FromScratch; new BufferedLayout(layout).ApplyLayout(graph); Console.WriteLine("\n\nGRAPH LAID OUT HIERARCHICALLY FROM SCRATCH"); Console.WriteLine("v1 center position = " + graph.GetCenter(v1)); Console.WriteLine("v2 center position = " + graph.GetCenter(v2)); Console.WriteLine("v3 center position = " + graph.GetCenter(v3)); Console.WriteLine("e1 path = " + graph.GetPath(e1)); Console.WriteLine("e2 path = " + graph.GetPath(e2)); //display the graph in a simple viewer GraphViewer gv = new GraphViewer(); gv.AddLayoutGraph(new CopiedLayoutGraph(graph), "Before Addition"); // now add a node and two edges incrementally... Node v4 = graph.CreateNode(); graph.SetSize(v4, 30, 30); Edge e4 = graph.CreateEdge(v4, v2); Edge e3 = graph.CreateEdge(v1, v4); //mark elements as newly added so that the layout algorithm can place //them nicely. IIncrementalHintsFactory ihf = layout.CreateIncrementalHintsFactory(); IDataMap map = Maps.CreateHashedDataMap(); map.Set(v4, ihf.CreateLayerIncrementallyHint(v4)); map.Set(e3, ihf.CreateSequenceIncrementallyHint(e3)); map.Set(e4, ihf.CreateSequenceIncrementallyHint(e4)); graph.AddDataProvider(HierarchicLayout.IncrementalHintsDpKey, map); layout.LayoutMode = LayoutMode.Incremental; new BufferedLayout(layout).ApplyLayout(graph); Console.WriteLine("\n\nGRAPH AFTER ELEMENTS HAVE BEEN ADDED INCREMENTALLY"); Console.WriteLine("v1 center position = " + graph.GetCenter(v1)); Console.WriteLine("v2 center position = " + graph.GetCenter(v2)); Console.WriteLine("v3 center position = " + graph.GetCenter(v3)); Console.WriteLine("v4 center position = " + graph.GetCenter(v4)); Console.WriteLine("e1 path = " + graph.GetPath(e1)); Console.WriteLine("e2 path = " + graph.GetPath(e2)); Console.WriteLine("e3 path = " + graph.GetPath(e3)); Console.WriteLine("e4 path = " + graph.GetPath(e4)); //clean up data maps graph.RemoveDataProvider(HierarchicLayout.IncrementalHintsDpKey); //display the graph in a simple viewer gv.AddLayoutGraph(new CopiedLayoutGraph(graph), "After Addition"); Application.Run(gv); }
private void SetupLayouts() { //using hierarchical layout style HierarchicLayout hierarchicLayout = new HierarchicLayout(); hierarchicLayout.EdgeLayoutDescriptor.RoutingStyle = new yWorks.Layout.Hierarchic.RoutingStyle( yWorks.Layout.Hierarchic.EdgeRoutingStyle.Orthogonal); CurrentLayout = hierarchicLayout; layouts.Add("Hierarchic", hierarchicLayout); //using organic layout style OrganicLayout organic = new OrganicLayout { QualityTimeRatio = 1.0, NodeOverlapsAllowed = false, NodeEdgeOverlapAvoided = true, MinimumNodeDistance = 10, PreferredEdgeLength = 50, }; layouts.Add("Organic", organic); //using orthogonal layout style OrthogonalLayout orthogonal = new OrthogonalLayout { GridSpacing = 15, OptimizePerceivedBends = true }; layouts.Add("Orthogonal", orthogonal); //using circular layout style CircularLayout circular = new CircularLayout(); circular.BalloonLayout.MinimumEdgeLength = 50; circular.BalloonLayout.CompactnessFactor = 0.1; layouts.Add("Circular", circular); // a tree layout algorithm TreeLayout treeLayout = new TreeLayout { ConsiderNodeLabels = true }; treeLayout.AppendStage(new TreeReductionStage() { NonTreeEdgeRouter = new OrganicEdgeRouter(), NonTreeEdgeSelectionKey = OrganicEdgeRouter.AffectedEdgesDpKey, }); layouts.Add("Tree", treeLayout); //using Polyline Router var polylineRouter = new EdgeRouter { Grid = new Grid(0, 0, 10), PolylineRouting = true, Rerouting = true }; polylineRouter.DefaultEdgeLayoutDescriptor.PenaltySettings.BendPenalty = 3; polylineRouter.DefaultEdgeLayoutDescriptor.PenaltySettings.EdgeCrossingPenalty = 5; layouts.Add("Polyline Edge Router", polylineRouter); }
protected override LayoutData CreateConfiguredLayoutData(GraphControl graphControl, ILayoutAlgorithm layout) { var layoutData = new HierarchicLayoutData(); var incrementalLayout = SelectedElementsIncrementallyItem; var selection = graphControl.Selection; var selectedElements = selection.SelectedEdges.Any() || selection.SelectedNodes.Any(); if (incrementalLayout && selectedElements) { // configure the mode var ihf = ((HierarchicLayout)layout).CreateIncrementalHintsFactory(); layoutData.IncrementalHints.Delegate = item => { // Return the correct hint type for each model item that appears in one of these sets if (item is INode && selection.IsSelected(item)) { return(ihf.CreateLayerIncrementallyHint(item)); } if (item is IEdge && selection.IsSelected(item)) { return(ihf.CreateSequenceIncrementallyHint(item)); } return(null); }; } if (RankingPolicyItem == LayeringStrategy.Bfs) { layoutData.BfsLayererCoreNodes.Delegate = selection.IsSelected; } if (GridEnabledItem) { var nld = ((HierarchicLayout)layout).NodeLayoutDescriptor; layoutData.NodeLayoutDescriptors.Delegate = node => { var descriptor = new NodeLayoutDescriptor(); descriptor.LayerAlignment = nld.LayerAlignment; descriptor.MinimumDistance = nld.MinimumDistance; descriptor.MinimumLayerHeight = nld.MinimumLayerHeight; descriptor.NodeLabelMode = nld.NodeLabelMode; // anchor nodes on grid according to their alignment within the layer descriptor.GridReference = new YPoint(0.0, (nld.LayerAlignment - 0.5) * node.Layout.Height); descriptor.PortAssignment = this.GridPortAssignmentItem; return(descriptor); }; } if (EdgeDirectednessItem) { layoutData.EdgeDirectedness.Delegate = edge => { if (edge.Style is IArrowOwner && !Equals(((IArrowOwner)edge.Style).TargetArrow, Arrows.None)) { return(1); } return(0); }; } if (EdgeThicknessItem) { layoutData.EdgeThickness.Delegate = edge => { var style = edge.Style as PolylineEdgeStyle; if (style != null) { return(style.Pen.Thickness); } return(1); }; } if (SubComponentsItem) { // layout all siblings with label 'TL' separately with tree layout var treeLayout = new TreeLayout { DefaultNodePlacer = new LeftRightNodePlacer() }; foreach (var listOfNodes in FindSubComponents(graphControl.Graph, "TL")) { layoutData.SubComponents.Add(treeLayout).Items = listOfNodes; } // layout all siblings with label 'HL' separately with hierarchical layout var hierarchicLayout = new HierarchicLayout { LayoutOrientation = LayoutOrientation.LeftToRight }; foreach (var listOfNodes in FindSubComponents(graphControl.Graph, "HL")) { layoutData.SubComponents.Add(hierarchicLayout).Items = listOfNodes; } // layout all siblings with label 'OL' separately with organic layout var organicLayout = new OrganicLayout { PreferredEdgeLength = 100, Deterministic = true }; foreach (var listOfNodes in FindSubComponents(graphControl.Graph, "OL")) { layoutData.SubComponents.Add(organicLayout).Items = listOfNodes; } } if (HighlightCriticalPath) { // highlight the longest path in the graph as critical path // since the longest path algorithm only works for acyclic graphs, // feedback edges and self loops have to be excluded here var feedbackEdgeSetResult = new FeedbackEdgeSet().Run(graphControl.Graph); var longestPath = new LongestPath { SubgraphEdges = { Excludes = { Delegate = edge => feedbackEdgeSetResult.FeedbackEdgeSet.Contains(edge) || edge.IsSelfloop() } } }.Run(graphControl.Graph); if (longestPath.Edges.Any()) { layoutData.CriticalEdgePriorities.Delegate = edge => { if (longestPath.Edges.Contains(edge)) { return(10); } return(1); }; } } if (AutomaticBusRouting) { var allBusNodes = new HashSet <INode>(); foreach (var node in graphControl.Graph.Nodes) { if (!graphControl.Graph.IsGroupNode(node) && !allBusNodes.Contains(node)) { // search for good opportunities for bus structures rooted at this node if (graphControl.Graph.InDegree(node) >= 4) { var busDescriptor = new BusDescriptor(); var busEdges = GetBusEdges(graphControl.Graph, node, allBusNodes, graphControl.Graph.InEdgesAt(node)); if (busEdges.Any()) { layoutData.Buses.Add(busDescriptor).Items = busEdges; } } if (graphControl.Graph.OutDegree(node) >= 4) { var busDescriptor = new BusDescriptor(); var busEdges = GetBusEdges(graphControl.Graph, node, allBusNodes, graphControl.Graph.OutEdgesAt(node)); if (busEdges.Any()) { layoutData.Buses.Add(busDescriptor).Items = busEdges; } } } } } return(layoutData.CombineWith( CreateLabelingLayoutData( graphControl.Graph, LabelPlacementAlongEdgeItem, LabelPlacementSideOfEdgeItem, LabelPlacementOrientationItem, LabelPlacementDistanceItem ) )); }
public static void Main() { DefaultLayoutGraph graph = new DefaultLayoutGraph(); //construct graph and assign sizes to its nodes Node[] nodes = new Node[16]; for (int i = 0; i < 16; i++) { nodes[i] = graph.CreateNode(); graph.SetSize(nodes[i], 30, 30); } graph.CreateEdge(nodes[0], nodes[1]); graph.CreateEdge(nodes[0], nodes[2]); graph.CreateEdge(nodes[0], nodes[3]); graph.CreateEdge(nodes[0], nodes[14]); graph.CreateEdge(nodes[2], nodes[4]); graph.CreateEdge(nodes[3], nodes[5]); graph.CreateEdge(nodes[3], nodes[6]); graph.CreateEdge(nodes[3], nodes[9]); graph.CreateEdge(nodes[4], nodes[7]); graph.CreateEdge(nodes[4], nodes[8]); graph.CreateEdge(nodes[5], nodes[9]); graph.CreateEdge(nodes[6], nodes[10]); graph.CreateEdge(nodes[7], nodes[11]); graph.CreateEdge(nodes[8], nodes[12]); graph.CreateEdge(nodes[8], nodes[15]); graph.CreateEdge(nodes[9], nodes[13]); graph.CreateEdge(nodes[10], nodes[13]); graph.CreateEdge(nodes[10], nodes[14]); graph.CreateEdge(nodes[12], nodes[15]); GraphViewer gv = new GraphViewer(); //using organic layout style OrganicLayout organic = new OrganicLayout(); organic.QualityTimeRatio = 1.0; organic.NodeOverlapsAllowed = false; organic.MinimumNodeDistance = 10; organic.PreferredEdgeLength = 40; new BufferedLayout(organic).ApplyLayout(graph); LayoutGraphUtilities.ClipEdgesOnBounds(graph); gv.AddLayoutGraph(new CopiedLayoutGraph(graph), "Organic Layout Style"); //using orthogonal edge router (node positions stay fixed) EdgeRouter router = new EdgeRouter(); new BufferedLayout(router).ApplyLayout(graph); gv.AddLayoutGraph(new CopiedLayoutGraph(graph), "Polyline Edge Router"); //using orthogonal layout style OrthogonalLayout orthogonal = new OrthogonalLayout(); orthogonal.GridSpacing = 15; orthogonal.OptimizePerceivedBends = true; new BufferedLayout(orthogonal).ApplyLayout(graph); gv.AddLayoutGraph(new CopiedLayoutGraph(graph), "Orthogonal Layout Style"); //using circular layout style CircularLayout circular = new CircularLayout(); circular.BalloonLayout.MinimumEdgeLength = 20; circular.BalloonLayout.CompactnessFactor = 0.1; new BufferedLayout(circular).ApplyLayout(graph); LayoutGraphUtilities.ClipEdgesOnBounds(graph); gv.AddLayoutGraph(new CopiedLayoutGraph(graph), "Circular Layout Style"); //using hierarchical layout style var hierarchic = new HierarchicLayout(); new BufferedLayout(hierarchic).ApplyLayout(graph); gv.AddLayoutGraph(graph, "Hierarchical Layout Style"); var application = new System.Windows.Application(); application.Run(gv); }
/// <summary> /// Creates a small graph and applies a hierarchic group layout to it. /// The output of the calculated coordinates will be displayed in the /// console. /// </summary> public void Run() { DefaultLayoutGraph graph = new DefaultLayoutGraph(); //construct graph. assign sizes to nodes Node v1 = graph.CreateNode(); graph.SetSize(v1, 30, 30); Node v2 = graph.CreateNode(); graph.SetSize(v2, 30, 30); Node v3 = graph.CreateNode(); graph.SetSize(v3, 30, 30); Node v4 = graph.CreateNode(); graph.SetSize(v4, 30, 30); Node groupNode = graph.CreateNode(); graph.SetSize(groupNode, 100, 100); Edge e1 = graph.CreateEdge(v1, v2); Edge e2 = graph.CreateEdge(v4, groupNode); Edge e3 = graph.CreateEdge(v1, v3); Edge e4 = graph.CreateEdge(v1, v1); Edge e5 = graph.CreateEdge(v2, groupNode); Edge e6 = graph.CreateEdge(groupNode, v2); //optionally setup some edge groups IEdgeMap spg = graph.CreateEdgeMap(); IEdgeMap tpg = graph.CreateEdgeMap(); graph.AddDataProvider(PortConstraintKeys.SourceGroupIdDpKey, spg); graph.AddDataProvider(PortConstraintKeys.TargetGroupIdDpKey, tpg); spg.Set(e1, "SGroup1"); spg.Set(e3, "SGroup1"); tpg.Set(e1, "TGroup1"); tpg.Set(e3, "TGroup1"); //optionally setup the node grouping INodeMap nodeId = graph.CreateNodeMap(); INodeMap parentNodeId = graph.CreateNodeMap(); INodeMap groupKey = graph.CreateNodeMap(); graph.AddDataProvider(GroupingKeys.NodeIdDpKey, nodeId); graph.AddDataProvider(GroupingKeys.ParentNodeIdDpKey, parentNodeId); graph.AddDataProvider(GroupingKeys.GroupDpKey, groupKey); //mark a node as a group node groupKey.SetBool(groupNode, true); // add ids for each node nodeId.Set(v1, "v1"); nodeId.Set(v2, "v2"); nodeId.Set(v3, "v3"); nodeId.Set(v4, "v4"); nodeId.Set(groupNode, "groupNode"); // set the parent for each grouped node parentNodeId.Set(v2, "groupNode"); parentNodeId.Set(v3, "groupNode"); HierarchicLayout layout = new HierarchicLayout(); layout.MinimumLayerDistance = 0; layout.EdgeLayoutDescriptor.MinimumDistance = 10; new BufferedLayout(layout).ApplyLayout(graph); Console.WriteLine("\n\nGRAPH LAID OUT USING HIERARCHICLAYOUT"); Console.WriteLine("v1 center position = " + graph.GetCenter(v1)); Console.WriteLine("v2 center position = " + graph.GetCenter(v2)); Console.WriteLine("v3 center position = " + graph.GetCenter(v3)); Console.WriteLine("v4 center position = " + graph.GetCenter(v4)); Console.WriteLine("group center position = " + graph.GetCenter(groupNode)); Console.WriteLine("group size = " + graph.GetSize(groupNode)); Console.WriteLine("e1 path = " + graph.GetPath(e1)); Console.WriteLine("e2 path = " + graph.GetPath(e2)); Console.WriteLine("e3 path = " + graph.GetPath(e3)); Console.WriteLine("e4 path = " + graph.GetPath(e4)); Console.WriteLine("e5 path = " + graph.GetPath(e5)); Console.WriteLine("e6 path = " + graph.GetPath(e4)); //display the result in a simple viewer Application.Run(new Demo.yWorks.LayoutGraphViewer.GraphViewer(graph, "Hierarchical Group Layout")); }
///<inheritdoc/> protected override void ConfigureLayout() { LayoutGraph graph = CurrentLayoutGraph; HierarchicLayout hl = new HierarchicLayout(); LayoutAlgorithm = hl; // mark incremental elements if required IDataMap incrementalElements; OptionGroup generalGroup = (OptionGroup)Handler.GetGroupByName(GENERAL); OptionGroup currentGroup = (OptionGroup)generalGroup.GetGroupByName(INTERACTION); OptionGroup groupingGroup = (OptionGroup)Handler.GetGroupByName(GROUPING); bool fromSketch = (bool)currentGroup[USE_DRAWING_AS_SKETCH].Value; bool incrementalLayout = (bool)currentGroup[SELECTED_ELEMENTS_INCREMENTALLY].Value; bool selectedElements = !IsEdgeSelectionEmpty() || !IsNodeSelectionEmpty(); if (incrementalLayout && selectedElements) { // create storage for both nodes and edges incrementalElements = Maps.CreateHashedDataMap(); // configure the mode hl.LayoutMode = LayoutMode.Incremental; IIncrementalHintsFactory ihf = hl.CreateIncrementalHintsFactory(); foreach (Node node in graph.Nodes) { if (IsSelected(node)) { incrementalElements.Set(node, ihf.CreateLayerIncrementallyHint(node)); } } foreach (Edge edge in graph.Edges) { if (IsSelected(edge)) { incrementalElements.Set(edge, ihf.CreateSequenceIncrementallyHint(edge)); } } graph.AddDataProvider(HierarchicLayout.IncrementalHintsDpKey, incrementalElements); } else if (fromSketch) { hl.LayoutMode = LayoutMode.Incremental; } else { hl.LayoutMode = LayoutMode.FromScratch; } // cast to implementation simplex var np = (SimplexNodePlacer)hl.NodePlacer; np.BarycenterMode = (bool)generalGroup[SYMMETRIC_PLACEMENT].Value; np.StraightenEdges = (bool)Handler.GetValue(EDGE_SETTINGS, EDGE_STRAIGHTENING_OPTIMIZATION_ENABLED); hl.ComponentLayoutEnabled = (bool)generalGroup[LAYOUT_COMPONENTS_SEPARATELY].Value; currentGroup = (OptionGroup)generalGroup.GetGroupByName(MINIMUM_DISTANCES); hl.MinimumLayerDistance = (double)currentGroup[MINIMUM_LAYER_DISTANCE].Value; hl.NodeToEdgeDistance = (double)currentGroup[NODE_TO_EDGE_DISTANCE].Value; hl.NodeToNodeDistance = (double)currentGroup[NODE_TO_NODE_DISTANCE].Value; hl.EdgeToEdgeDistance = (double)currentGroup[EDGE_TO_EDGE_DISTANCE].Value; NodeLayoutDescriptor nld = hl.NodeLayoutDescriptor; EdgeLayoutDescriptor eld = hl.EdgeLayoutDescriptor; currentGroup = (OptionGroup)Handler.GetGroupByName(EDGE_SETTINGS); hl.AutomaticEdgeGrouping = (bool)currentGroup[AUTOMATIC_EDGE_GROUPING_ENABLED].Value; string edgeRoutingChoice = (string)currentGroup[EDGE_ROUTING].Value; eld.RoutingStyle = edgeRoutingEnum[edgeRoutingChoice]; eld.MinimumFirstSegmentLength = (double)currentGroup[MINIMUM_FIRST_SEGMENT_LENGTH].Value; eld.MinimumLastSegmentLength = (double)currentGroup[MINIMUM_LAST_SEGMENT_LENGTH].Value; eld.MinimumDistance = (double)currentGroup[MINIMUM_EDGE_DISTANCE].Value; eld.MinimumLength = (double)currentGroup[MINIMUM_EDGE_LENGTH].Value; eld.MinimumSlope = (double)currentGroup[MINIMUM_SLOPE].Value; eld.SourcePortOptimization = (bool)currentGroup[PC_OPTIMIZATION_ENABLED].Value; eld.TargetPortOptimization = (bool)currentGroup[PC_OPTIMIZATION_ENABLED].Value; var isIncrementalModeEnabled = (fromSketch || (incrementalLayout && selectedElements)); var recursiveRoutingMode = Handler.GetValue(EDGE_SETTINGS, RECURSIVE_EDGE_ROUTING); if (!isIncrementalModeEnabled && recursiveRoutingMode == RECURSIVE_EDGE_ROUTING_DIRECTED) { eld.RecursiveEdgeStyle = RecursiveEdgeStyle.Directed; } else if (!isIncrementalModeEnabled && recursiveRoutingMode == RECURSIVE_EDGE_ROUTING_UNDIRECTED) { eld.RecursiveEdgeStyle = RecursiveEdgeStyle.Undirected; } else { eld.RecursiveEdgeStyle = RecursiveEdgeStyle.Off; } nld.MinimumDistance = Math.Min(hl.NodeToNodeDistance, hl.NodeToEdgeDistance); nld.MinimumLayerHeight = 0; OptionGroup rankGroup = (OptionGroup)Handler.GetGroupByName(RANKS); string layerAlignmentChoice = (string)rankGroup[LAYER_ALIGNMENT].Value; nld.LayerAlignment = alignmentEnum[layerAlignmentChoice]; ol = (OrientationLayout)hl.OrientationLayout; string orientationChoice = (string)generalGroup[ORIENTATION].Value; ol.Orientation = orientEnum[orientationChoice]; OptionGroup labelingGroup = (OptionGroup)Handler.GetGroupByName(LABELING); currentGroup = (OptionGroup)labelingGroup.GetGroupByName(LABELING_EDGE_PROPERTIES); string el = (string)currentGroup[EDGE_LABELING].Value; if (!el.Equals(EDGE_LABELING_NONE)) { if (el.Equals(EDGE_LABELING_GENERIC)) { var la = new GenericLabeling(); la.MaximumDuration = 0; la.PlaceNodeLabels = false; la.PlaceEdgeLabels = true; la.AutoFlipping = true; la.ProfitModel = new SimpleProfitModel(); hl.PrependStage(la); } else if (el.Equals(EDGE_LABELING_HIERARCHIC)) { bool copactEdgeLabelPlacement = (bool)currentGroup[COMPACT_EDGE_LABEL_PLACEMENT].Value; if (hl.NodePlacer is SimplexNodePlacer) { np.LabelCompaction = copactEdgeLabelPlacement; } hl.IntegratedEdgeLabeling = true; } } else { hl.IntegratedEdgeLabeling = false; } currentGroup = (OptionGroup)labelingGroup.GetGroupByName(NODE_PROPERTIES); if ((bool)currentGroup[CONSIDER_NODE_LABELS].Value) { hl.ConsiderNodeLabels = true; hl.NodeLayoutDescriptor.NodeLabelMode = NodeLabelMode.ConsiderForDrawing; } else { hl.ConsiderNodeLabels = false; } string rp = (string)rankGroup[RANKING_POLICY].Value; hl.FromScratchLayeringStrategy = rankingPolicies[rp]; if (rp.Equals(BFS_LAYERS)) { CurrentLayoutGraph.AddDataProvider(BFSLayerer.CoreNodesDpKey, new SelectedNodesDP(this)); } hl.ComponentArrangementPolicy = componentAlignmentEnum[(string)rankGroup[COMPONENT_ARRANGEMENT_POLICY].Value]; //configure AsIsLayerer Object layerer = (hl.LayoutMode == LayoutMode.FromScratch) ? hl.FromScratchLayerer : hl.FixedElementsLayerer; // if (layerer is OldLayererWrapper) { // layerer = ((OldLayererWrapper)layerer).OldLayerer; // } if (layerer is AsIsLayerer) { AsIsLayerer ail = (AsIsLayerer)layerer; currentGroup = (OptionGroup)rankGroup.GetGroupByName(FROM_SKETCH_PROPERTIES); ail.NodeHalo = (double)currentGroup[HALO].Value; ail.NodeScalingFactor = (double)currentGroup[SCALE].Value; ail.MinimumNodeSize = (double)currentGroup[MINIMUM_SIZE].Value; ail.MaximumNodeSize = (double)currentGroup[MAXIMUM_SIZE].Value; } //configure grouping np.GroupCompactionStrategy = groupHorizCompactionEnum[(string)groupingGroup[GROUP_HORIZONTAL_COMPACTION].Value]; if (!fromSketch && groupStrategyEnum[(string)groupingGroup[GROUP_LAYERING_STRATEGY].Value]) { GroupAlignmentPolicy alignmentPolicy = groupAlignmentEnum[(string)groupingGroup[GROUP_ALIGNMENT].Value]; hl.GroupAlignmentPolicy = alignmentPolicy; hl.CompactGroups = (bool)groupingGroup[GROUP_ENABLE_COMPACTION].Value; hl.RecursiveGroupLayering = true; } else { hl.RecursiveGroupLayering = false; } OptionGroup swimGroup = (OptionGroup)Handler.GetGroupByName(SWIMLANES); if ((bool)swimGroup[TREAT_ROOT_GROUPS_AS_SWIMLANES].Value) { TopLevelGroupToSwimlaneStage stage = new TopLevelGroupToSwimlaneStage(); stage.OrderSwimlanesFromSketch = (bool)swimGroup[USE_ORDER_FROM_SKETCH].Value; stage.Spacing = (double)swimGroup[SWIMLANE_SPACING].Value; hl.AppendStage(stage); } hl.BackLoopRouting = (bool)Handler.GetValue(EDGE_SETTINGS, BACKLOOP_ROUTING); hl.MaximumDuration = ((int)Handler.GetValue(GENERAL, MAXIMUM_DURATION)) * 1000; bool gridEnabled = (bool)Handler.GetValue(GRID, GRID_ENABLED); if (gridEnabled) { hl.GridSpacing = (double)Handler.GetValue(GRID, GRID_SPACING); String portAssignment = (string)Handler.GetValue(GRID, GRID_PORT_ASSIGNMENT); PortAssignmentMode gridPortAssignment; switch (portAssignment) { case GRID_PORT_ASSIGNMENT_ON_GRID: gridPortAssignment = PortAssignmentMode.OnGrid; break; case GRID_PORT_ASSIGNMENT_ON_SUBGRID: gridPortAssignment = PortAssignmentMode.OnSubgrid; break; default: gridPortAssignment = PortAssignmentMode.Default; break; } graph.AddDataProvider(HierarchicLayoutCore.NodeLayoutDescriptorDpKey, new NodeLayoutDescriptorAdapter(hl.NodeLayoutDescriptor, graph, gridPortAssignment)); } }
public static void Main() { DefaultLayoutGraph graph = new DefaultLayoutGraph(); //construct graph. assign sizes to nodes Node v1 = graph.CreateNode(); graph.SetSize(v1, 30, 30); Node v2 = graph.CreateNode(); graph.SetSize(v2, 30, 30); Node v3 = graph.CreateNode(); graph.SetSize(v3, 30, 30); Edge e1 = graph.CreateEdge(v1, v2); Edge e2 = graph.CreateEdge(v2, v3); Edge e3 = graph.CreateEdge(v1, v3); //optionally setup some port constraints for HierarchicLayout IEdgeMap spc = graph.CreateEdgeMap(); IEdgeMap tpc = graph.CreateEdgeMap(); //e1 shall leave and enter the node on the right side spc.Set(e1, PortConstraint.Create(PortSide.East)); //additionally set a strong port constraint on the target side. tpc.Set(e1, PortConstraint.Create(PortSide.East, true)); //ports with strong port constraints will not be reset by the //layout algorithm. So we specify the target port right now to connect //to the upper left corner of the node graph.SetTargetPointRel(e1, new YPoint(15, -15)); //e2 shall leave and enter the node on the top side spc.Set(e2, PortConstraint.Create(PortSide.North)); tpc.Set(e2, PortConstraint.Create(PortSide.North)); //e3 uses no port constraints, i.e. layout will choose best side graph.AddDataProvider(PortConstraintKeys.SourcePortConstraintDpKey, spc); graph.AddDataProvider(PortConstraintKeys.TargetPortConstraintDpKey, tpc); //setup two edge labels for edge e1. The size of the edge labels will be set to //80x20. Usually the size of the labels will be determined by //calculaing the bounding box of a piece text that is displayed //with a specific font. var labelFactory = LayoutGraphUtilities.GetLabelFactory(graph); graph.SetLabelLayout(e1, new[] { CreateEdgeLabelLayout(labelFactory, e1, new SliderEdgeLabelLayoutModel(SliderMode.Center), PreferredPlacementDescriptor.NewSharedInstance(LabelPlacements.AtCenter)), CreateEdgeLabelLayout(labelFactory, e1, new SliderEdgeLabelLayoutModel(SliderMode.Side), PreferredPlacementDescriptor.NewSharedInstance(LabelPlacements.LeftOfEdge)) }); var layout = new HierarchicLayout(); layout.LabelingEnabled = true; layout.Labeling = new GenericLabeling(); new BufferedLayout(layout).ApplyLayout(graph); Console.WriteLine("\n\nGRAPH LAID OUT USING GENERIC EDGE LABELING"); Console.WriteLine("v1 center position = " + graph.GetCenter(v1)); Console.WriteLine("v2 center position = " + graph.GetCenter(v2)); Console.WriteLine("v3 center position = " + graph.GetCenter(v3)); Console.WriteLine("e1 path = " + graph.GetPath(e1)); Console.WriteLine("e2 path = " + graph.GetPath(e2)); Console.WriteLine("e3 path = " + graph.GetPath(e3)); Console.WriteLine("ell1 upper left location = " + GetEdgeLabelLocation(graph, e1, CreateEdgeLabelLayout(labelFactory, e1, new SliderEdgeLabelLayoutModel(SliderMode.Center), PreferredPlacementDescriptor.NewSharedInstance(LabelPlacements.AtCenter)))); Console.WriteLine("ell2 upper left location = " + GetEdgeLabelLocation(graph, e1, graph.GetLabelLayout(e1)[1])); GraphViewer gv = new GraphViewer(); gv.AddLayoutGraph(new CopiedLayoutGraph(graph), "Layout with Generic Labeling"); var freeModel = new FreeEdgeLabelLayoutModel(); graph.SetLabelLayout(e1, new[] { CreateEdgeLabelLayout(labelFactory, e1, freeModel, PreferredPlacementDescriptor.NewSharedInstance(LabelPlacements.AtCenter)), CreateEdgeLabelLayout(labelFactory, e1, freeModel, PreferredPlacementDescriptor.NewSharedInstance(LabelPlacements.LeftOfEdge)) }); layout.LabelingEnabled = true; layout.Labeling = new LabelLayoutTranslator(); new BufferedLayout(layout).ApplyLayout(graph); Console.WriteLine("\n\nGRAPH LAID OUT USING HIERACHIC LAYOUT SPECIFIC EDGE LABELING"); Console.WriteLine("v1 center position = " + graph.GetCenter(v1)); Console.WriteLine("v2 center position = " + graph.GetCenter(v2)); Console.WriteLine("v3 center position = " + graph.GetCenter(v3)); Console.WriteLine("e1 path = " + graph.GetPath(e1)); Console.WriteLine("e2 path = " + graph.GetPath(e2)); Console.WriteLine("e3 path = " + graph.GetPath(e3)); Console.WriteLine("ell1 upper left location = " + GetEdgeLabelLocation(graph, e1, CreateEdgeLabelLayout(labelFactory, e1, new SliderEdgeLabelLayoutModel(SliderMode.Center), PreferredPlacementDescriptor.NewSharedInstance(LabelPlacements.AtCenter)))); Console.WriteLine("ell2 upper left location = " + GetEdgeLabelLocation(graph, e1, graph.GetLabelLayout(e1)[1])); //display the result in a simple viewer gv.AddLayoutGraph(graph, "Layout with Integrated Labeling"); var application = new System.Windows.Application(); application.Run(gv); }
/// <summary> /// Perform the layout operation /// </summary> private async Task ApplyLayout() { // layout starting, disable button layoutButton.IsEnabled = false; // create the layout algorithm var layout = new HierarchicLayout { OrthogonalRouting = true, LayoutOrientation = LayoutOrientation.TopToBottom }; // do the layout await graphControl.MorphLayout(layout, TimeSpan.FromSeconds(1), new HierarchicLayoutData { //Automatically determine port constraints for source and target NodePortCandidateSets = { Delegate = node => { var candidateSet = new PortCandidateSet(); // iterate the port descriptors var descriptors = PortDescriptor.CreatePortDescriptors(((FlowChartNodeStyle)node.Style).FlowChartType); foreach (var portDescriptor in descriptors) { PortCandidate candidate; // isn't a fixed port candidate (location is variable) if (portDescriptor.X == int.MaxValue) { // create a port candidate at the specified side (east, west, north, south) and apply a cost to it candidate = PortCandidate.CreateCandidate(portDescriptor.Side, portDescriptor.Cost); } else { // create a candidate at a fixed location and side var x = portDescriptor.X - node.Layout.Width / 2; var y = portDescriptor.Y - node.Layout.Height / 2; candidate = PortCandidate.CreateCandidate(x, y, portDescriptor.Side, portDescriptor.Cost); } candidateSet.Add(candidate, portDescriptor.Capacity); } return(candidateSet); } }, SourceGroupIds = { Delegate = edge => { // create bus-like edge groups for outgoing edges at Start nodes var sourceNode = edge.SourcePort.Owner as INode; if (sourceNode != null && ((((FlowChartNodeStyle)sourceNode.Style).FlowChartType)) == FlowChartType.Start) { return(sourceNode); } return(null); } }, TargetGroupIds = { Delegate = edge => { // create bus-like edge groups for incoming edges at Branch nodes var targetNode = edge.TargetPort.Owner as INode; if (targetNode != null && (((FlowChartNodeStyle)targetNode.Style).FlowChartType) == FlowChartType.Branch) { return(targetNode); } return(null); } } }); // enable button again layoutButton.IsEnabled = true; }
protected override LayoutData CreateConfiguredLayoutData(GraphControl graphControl, ILayoutAlgorithm layout) { var layoutData = new HierarchicLayoutData(); var incrementalLayout = SelectedElementsIncrementallyItem; var selection = graphControl.Selection; var selectedElements = selection.SelectedEdges.Any() || selection.SelectedNodes.Any(); if (incrementalLayout && selectedElements) { // configure the mode var ihf = ((HierarchicLayout)layout).CreateIncrementalHintsFactory(); layoutData.IncrementalHints.Delegate = item => { // Return the correct hint type for each model item that appears in one of these sets if (item is INode && selection.IsSelected(item)) { return(ihf.CreateLayerIncrementallyHint(item)); } if (item is IEdge && selection.IsSelected(item)) { return(ihf.CreateSequenceIncrementallyHint(item)); } return(null); }; } if (RankingPolicyItem == LayeringStrategy.Bfs) { layoutData.BfsLayererCoreNodes.Delegate = selection.IsSelected; } if (GridEnabledItem) { var nld = ((HierarchicLayout)layout).NodeLayoutDescriptor; layoutData.NodeLayoutDescriptors.Delegate = node => { var descriptor = new NodeLayoutDescriptor(); descriptor.LayerAlignment = nld.LayerAlignment; descriptor.MinimumDistance = nld.MinimumDistance; descriptor.MinimumLayerHeight = nld.MinimumLayerHeight; descriptor.NodeLabelMode = nld.NodeLabelMode; // anchor nodes on grid according to their alignment within the layer descriptor.GridReference = new YPoint(0.0, (nld.LayerAlignment - 0.5) * node.Layout.Height); descriptor.PortAssignment = this.GridPortAssignmentItem; return(descriptor); }; } if (EdgeDirectednessItem) { layoutData.EdgeDirectedness.Delegate = edge => { if (edge.Style is IArrowOwner && !Equals(((IArrowOwner)edge.Style).TargetArrow, Arrows.None)) { return(1); } return(0); }; } if (EdgeThicknessItem) { layoutData.EdgeThickness.Delegate = edge => { var style = edge.Style as PolylineEdgeStyle; if (style != null) { return(style.Pen.Width); } return(1); }; } if (SubComponentsItem) { var treeLayout = new TreeLayout { DefaultNodePlacer = new LeftRightNodePlacer() }; layoutData.SubComponents.Add(treeLayout).Delegate = node => node.Labels.Any() && node.Labels.First().Text == "TL"; var hierarchicLayout = new HierarchicLayout { LayoutOrientation = LayoutOrientation.LeftToRight }; layoutData.SubComponents.Add(hierarchicLayout).Delegate = node => node.Labels.Any() && node.Labels.First().Text == "HL"; var organicLayout = new OrganicLayout { PreferredEdgeLength = 100, Deterministic = true }; layoutData.SubComponents.Add(organicLayout).Delegate = node => node.Labels.Any() && node.Labels.First().Text == "OL"; } if (BusesItem) { // Group edges ending at a node with the label "Bus" into a bus layoutData.Buses.Add(new BusDescriptor()).Delegate = edge => edge.GetTargetNode().Labels.Count > 0 && edge.GetTargetNode().Labels[0].Text == "Bus"; } return(layoutData); }
/// <inheritdoc /> protected override ILayoutAlgorithm CreateConfiguredLayout(GraphControl graphControl) { var layout = new HierarchicLayout(); // mark incremental elements if required var fromSketch = UseDrawingAsSketchItem; var incrementalLayout = SelectedElementsIncrementallyItem; var selectedElements = graphControl.Selection.SelectedEdges.Any() || graphControl.Selection.SelectedNodes.Any(); if (incrementalLayout && selectedElements) { layout.LayoutMode = LayoutMode.Incremental; } else if (fromSketch) { layout.LayoutMode = LayoutMode.Incremental; } else { layout.LayoutMode = LayoutMode.FromScratch; } ((SimplexNodePlacer)layout.NodePlacer).BarycenterMode = SymmetricPlacementItem; layout.ComponentLayoutEnabled = LayoutComponentsSeparatelyItem; layout.MinimumLayerDistance = MinimumLayerDistanceItem; layout.NodeToEdgeDistance = NodeToEdgeDistanceItem; layout.NodeToNodeDistance = NodeToNodeDistanceItem; layout.EdgeToEdgeDistance = EdgeToEdgeDistanceItem; var nld = layout.NodeLayoutDescriptor; var eld = layout.EdgeLayoutDescriptor; layout.AutomaticEdgeGrouping = AutomaticEdgeGroupingEnabledItem; eld.RoutingStyle = new RoutingStyle(EdgeRoutingItem); eld.RoutingStyle.CurveShortcuts = CurveShortcutsItem; eld.RoutingStyle.CurveUTurnSymmetry = CurveUTurnSymmetryItem; eld.MinimumFirstSegmentLength = MinimumFirstSegmentLengthItem; eld.MinimumLastSegmentLength = MinimumLastSegmentLengthItem; eld.MinimumDistance = MinimumEdgeDistanceItem; eld.MinimumLength = MinimumEdgeLengthItem; eld.MinimumSlope = MinimumSlopeItem; eld.SourcePortOptimization = PcOptimizationEnabledItem; eld.TargetPortOptimization = PcOptimizationEnabledItem; eld.RecursiveEdgeStyle = RecursiveEdgeStyleItem; nld.MinimumDistance = Math.Min(layout.NodeToNodeDistance, layout.NodeToEdgeDistance); nld.MinimumLayerHeight = 0; nld.LayerAlignment = LayerAlignmentItem; var ol = (OrientationLayout)layout.OrientationLayout; ol.Orientation = OrientationItem; if (ConsiderNodeLabelsItem) { layout.ConsiderNodeLabels = true; layout.NodeLayoutDescriptor.NodeLabelMode = NodeLabelMode.ConsiderForDrawing; } else { layout.ConsiderNodeLabels = false; } if (EdgeLabelingItem != EnumEdgeLabeling.None) { if (EdgeLabelingItem == EnumEdgeLabeling.Generic) { layout.IntegratedEdgeLabeling = false; var labeling = new GenericLabeling { PlaceNodeLabels = false, PlaceEdgeLabels = true, AutoFlipping = true, ReduceAmbiguity = ReduceAmbiguityItem, ProfitModel = new SimpleProfitModel(), }; layout.LabelingEnabled = true; layout.Labeling = labeling; } else if (EdgeLabelingItem == EnumEdgeLabeling.Integrated) { layout.IntegratedEdgeLabeling = true; ((SimplexNodePlacer)layout.NodePlacer).LabelCompaction = CompactEdgeLabelPlacementItem; } } else { layout.IntegratedEdgeLabeling = false; } layout.FromScratchLayeringStrategy = RankingPolicyItem; layout.ComponentArrangementPolicy = ComponentArrangementPolicyItem; ((SimplexNodePlacer)layout.NodePlacer).NodeCompaction = NodeCompactionItem; ((SimplexNodePlacer)layout.NodePlacer).StraightenEdges = StraightenEdgesItem; //configure AsIsLayerer var layerer = layout.LayoutMode == LayoutMode.FromScratch ? layout.FromScratchLayerer : layout.FixedElementsLayerer; var ail = layerer as AsIsLayerer; if (ail != null) { ail.NodeHalo = HaloItem; ail.NodeScalingFactor = ScaleItem; ail.MinimumNodeSize = MinimumSizeItem; ail.MaximumNodeSize = MaximumSizeItem; } //configure grouping ((SimplexNodePlacer)layout.NodePlacer).GroupCompactionStrategy = GroupHorizontalCompactionItem; if (!fromSketch && GroupLayeringStrategyItem == GroupLayeringStrategyOptions.LayoutGroups) { layout.GroupAlignmentPolicy = GroupAlignmentItem; layout.CompactGroups = GroupEnableCompactionItem; layout.RecursiveGroupLayering = true; } else { layout.RecursiveGroupLayering = false; } if (TreatRootGroupAsSwimlanesItem) { var stage = new TopLevelGroupToSwimlaneStage { OrderSwimlanesFromSketch = UseOrderFromSketchItem, Spacing = SwimlineSpacingItem }; layout.AppendStage(stage); } layout.BackLoopRouting = BackloopRoutingItem; layout.BackLoopRoutingForSelfLoops = BackloopRoutingForSelfLoopsItem; layout.MaximumDuration = MaximumDurationItem * 1000; if (GridEnabledItem) { layout.GridSpacing = GridSpacingItem; } return(layout); }
private async Task DoLayout() { // layout starting, disable button runButton.Enabled = false; // create a new layout algorithm var hl = new HierarchicLayout { OrthogonalRouting = true, FromScratchLayeringStrategy = LayeringStrategy.HierarchicalTopmost, IntegratedEdgeLabeling = true }; // and layout data for it var hlData = new HierarchicLayoutData { ConstraintIncrementalLayererAdditionalEdgeWeights = { Delegate = GetEdgeWeight } }; // we provide the LayerConstraintData.Values directly as IComparable instead of using the Add* methods on LayerConstraintData var layerConstraintData = hlData.LayerConstraints; layerConstraintData.NodeComparables.Delegate = node => { var data = node.Tag as LayerConstraintsInfo; if (data != null && data.Constraints) { // the node shall be constrained so we use its Value as comparable return(data.Value); } // otherwise we don't add constraints for the node return(null); }; INode[] layerRep = new INode[8]; // additionally enforce all nodes with a LayerConstraintInfo.Value of 0 or 7 to be placed at top/bottom // and register the value in the NodeComparables Mapper for all other constrained nodes foreach (var node in graphControl.Graph.Nodes) { var data = node.Tag as LayerConstraintsInfo; if (data != null && data.Constraints) { if (data.Value == 0) { // add constraint to put this node at the top layerConstraintData.PlaceAtTop(node); } else if (data.Value == 7) { // add constraint to put this node at the bottom layerConstraintData.PlaceAtBottom(node); } else { // for every node in between we record its value with the mapper, assuring that there // will be no layer with different values and monotonically growing values per layer layerConstraintData.NodeComparables.Mapper[node] = data.Value; } } } // perform the layout operation await graphControl.MorphLayout(hl, TimeSpan.FromSeconds(1), hlData); // code is executed once the layout operation is finished // enable button again runButton.Enabled = true; }
public static void Main() { DefaultLayoutGraph graph = new DefaultLayoutGraph(); //construct graph. assign sizes to nodes Node v1 = graph.CreateNode(); graph.SetSize(v1, 30, 30); Node v2 = graph.CreateNode(); graph.SetSize(v2, 30, 30); Node v3 = graph.CreateNode(); graph.SetSize(v3, 30, 30); Node v4 = graph.CreateNode(); graph.SetSize(v4, 30, 30); // create some edges... Edge e1 = graph.CreateEdge(v1, v2); Edge e2 = graph.CreateEdge(v1, v3); Edge e3 = graph.CreateEdge(v2, v4); // create swim lane descriptors for two lanes var sl1 = new SwimlaneDescriptor(1); var sl2 = new SwimlaneDescriptor(2); // create a map to store the swim lane descriptors INodeMap slMap = graph.CreateNodeMap(); // assign nodes to lanes slMap.Set(v1, sl1); slMap.Set(v2, sl2); slMap.Set(v3, sl2); slMap.Set(v4, sl1); // register the information graph.AddDataProvider(HierarchicLayout.SwimlaneDescriptorDpKey, slMap); // create the layout algorithm HierarchicLayout layout = new HierarchicLayout(); // start the layout new BufferedLayout(layout).ApplyLayout(graph); Console.WriteLine("\n\nGRAPH LAID OUT HIERARCHICALLY IN SWIMLANES"); Console.WriteLine("v1 center position = " + graph.GetCenter(v1)); Console.WriteLine("v2 center position = " + graph.GetCenter(v2)); Console.WriteLine("v3 center position = " + graph.GetCenter(v3)); Console.WriteLine("v4 center position = " + graph.GetCenter(v4)); Console.WriteLine("e1 path = " + graph.GetPath(e1)); Console.WriteLine("e2 path = " + graph.GetPath(e2)); Console.WriteLine("e3 path = " + graph.GetPath(e3)); Console.WriteLine("SwimLane 1 index = " + sl1.ComputedLaneIndex); Console.WriteLine("SwimLane 1 position = " + sl1.ComputedLanePosition); Console.WriteLine("SwimLane 1 width = " + sl1.ComputedLaneWidth); Console.WriteLine("SwimLane 2 index = " + sl2.ComputedLaneIndex); Console.WriteLine("SwimLane 2 position = " + sl2.ComputedLanePosition); Console.WriteLine("SwimLane 2 width = " + sl2.ComputedLaneWidth); //clean up data maps graph.DisposeNodeMap(slMap); graph.RemoveDataProvider(HierarchicLayout.SwimlaneDescriptorDpKey); //display the graph in a simple viewer var viewer = new GraphViewer(); viewer.AddLayoutGraph(graph, "Swimlane Demo"); var application = new System.Windows.Application(); application.Run(viewer); }