/// <summary> /// Event handler that is triggered when a group is closed interactively. /// </summary> /// <remarks>This method performs an incremental layout on the newly collapsed group node.</remarks> /// <param name="source"></param> /// <param name="evt"></param> private async void NavigationInputMode_GroupCollapsed(object source, ItemEventArgs <INode> evt) { incrementalNodes.Clear(); incrementalEdges.Clear(); // we mark the group node and its adjacent edges as incremental incrementalNodes.Add(evt.Item); incrementalEdges.UnionWith(graphControl.Graph.EdgesAt(evt.Item)); // rescue the original node bounds which are needed for a correct layout INode groupNode = evt.Item; fixedGroupNodeLayout.Clear(); fixedGroupNodeLayout[groupNode] = groupNode.Layout.ToRectD(); // retrieve the state of the view node *before* the grouping operation INode master = foldingView.GetMasterItem(groupNode); // and set these bounds so that the animation will move it to the correct location graphControl.Graph.SetNodeLayout(groupNode, master.Layout.ToRectD()); // reset adjacent edge paths to get smoother layout transitions foreach (var edge in graphControl.Graph.EdgesAt(groupNode)) { graphControl.Graph.ClearBends(edge); } await ApplyLayout(); }
/// <summary> /// Apply the algorithm which is appropriate for the selected graph. /// </summary> /// <param name="sampleSelectedIndex">The index to use.</param> private async Task ApplyAlgorithmForKey(int sampleSelectedIndex) { ResetStyles(); if (CurrentConfig != null && CurrentConfig.IncrementalElements != null && CurrentConfig.IncrementalElements.Entries.Any()) { incrementalElements.Clear(); CurrentConfig.IncrementalElements = incrementalElements; CurrentConfig.EdgeRemoved = false; } // run the layout if the layout combo box is already correct var algorithmSelectedIndex = algorithmComboBox.SelectedIndex; if (!mIsInitializing) { preventLayout = true; // otherwise, change the selection and indirectly trigger the layout algorithmComboBox.SelectedIndex = sampleSelectedIndex; // changing the algorithm will trigger a layout run } else { UpdateGraphInformation(); } preventLayout = false; // run a layout from scratch (i.e. for a new graph), clear the undo queue and apply an analysis algorithm await RunLayout(false, true, true); }
/// <summary> /// Creates a mapping to specify the components which should not be modified by <see cref="ClearAreaLayout"/>. /// </summary> private void UpdateComponents() { components.Clear(); if (subtree.NewParent != null) { foreach (var edge in Graph.OutEdgesAt(subtree.NewParent)) { var siblingSubtree = new Subtree(Graph, edge.GetTargetNode()); foreach (var node in siblingSubtree.Nodes) { components[node] = siblingSubtree; } } } }
public void Clear() { backingMapper.Clear(); }
/// <summary> /// Run a layout and an analysis algorithm if wanted. /// </summary> /// <param name="incremental">Whether to run in incremental mode, i.e. only moving new items.</param> /// <param name="clearUndo">Whether to clear the undo queue after the layout.</param> /// <param name="runAlgorithm">Whether to apply the <see cref="CurrentConfig">current analysis algorithm</see>, too.</param> /// <returns></returns> private async Task RunLayout(bool incremental, bool clearUndo, bool runAlgorithm) { // the actual organic layout var layout = new OrganicLayout { Deterministic = true, ConsiderNodeSizes = true, Scope = incremental ? Scope.MainlySubset : Scope.All, LabelingEnabled = false, PreferredEdgeLength = 100, MinimumNodeDistance = 10 }; ((ComponentLayout)layout.ComponentLayout).Style = ComponentArrangementStyles.None | ComponentArrangementStyles.ModifierNoOverlap; OrganicLayoutData layoutData = null; if (incremental && incrementalNodesMapper != null) { layoutData = new OrganicLayoutData(); layoutData.AffectedNodes.Mapper = incrementalNodesMapper; } inLayout = true; SetUiDisabled(true); // run the layout in an asynchronous, animated fashion await graphControl.MorphLayout(layout, TimeSpan.FromSeconds(0.5), layoutData); // run algorithm if (runAlgorithm) { // apply graph algorithms after layout ApplyAlgorithm(); var algorithm = algorithmComboBox.SelectedItem as Algorithm; if (algorithm != null && algorithm.DisplayName.EndsWith("Centrality")) { // since centrality changes the node sizes, node overlaps need to be removed await graphControl.MorphLayout(new OrganicRemoveOverlapsStage(), TimeSpan.FromSeconds(0.2)); } } // labeling: place labels after the layout and the analysis (which might have generated or changed labels) var labeling = new GenericLabeling { PlaceEdgeLabels = true, PlaceNodeLabels = false, Deterministic = true }; var labelingData = new LabelingData { EdgeLabelPreferredPlacement = { Delegate = label => { var preferredPlacementDescriptor = new PreferredPlacementDescriptor(); if ("Centrality".Equals(label.Tag)) { preferredPlacementDescriptor.SideOfEdge = LabelPlacements.OnEdge; } else { preferredPlacementDescriptor.SideOfEdge = LabelPlacements.RightOfEdge | LabelPlacements.LeftOfEdge; preferredPlacementDescriptor.DistanceToEdge = 5; } preferredPlacementDescriptor.Freeze(); return(preferredPlacementDescriptor); } } }; await graphControl.MorphLayout(labeling, TimeSpan.FromSeconds(0.2), labelingData); // cleanup if (clearUndo) { graphControl.Graph.GetUndoEngine().Clear(); } // clean up data provider incrementalNodesMapper.Clear(); // enable the UI's buttons ReleaseLocks(); SetUiDisabled(false); UpdateUiState(); }