/// <summary> /// Calculates diff between 2 <see cref="PositionedGraph"/>s. /// The <see cref="GraphDiff"/> describes a matching between nodes in the graphs, added and removed nodes. /// </summary> public GraphDiff MatchGraphs(PositionedGraph oldGraph, PositionedGraph newGraph) { if (oldGraph == null) { if (newGraph == null) { return(new GraphDiff()); } else { GraphDiff addAllDiff = new GraphDiff(); foreach (PositionedNode newNode in newGraph.Nodes) { addAllDiff.SetAdded(newNode); } return(addAllDiff); } } else if (newGraph == null) { GraphDiff removeAllDiff = new GraphDiff(); foreach (PositionedNode oldNode in oldGraph.Nodes) { removeAllDiff.SetRemoved(oldNode); } return(removeAllDiff); } // none of the graphs is null GraphDiff diff = new GraphDiff(); Dictionary <int, PositionedNode> newNodeForHashCode = BuildHashToNodeMap(newGraph); Dictionary <PositionedNode, bool> newNodeMatched = new Dictionary <PositionedNode, bool>(); foreach (PositionedNode oldNode in oldGraph.Nodes) { PositionedNode matchingNode = MatchNode(oldNode, newNodeForHashCode); if (matchingNode != null) { diff.SetMatching(oldNode, matchingNode); newNodeMatched[matchingNode] = true; } else { diff.SetRemoved(oldNode); } } foreach (PositionedNode newNode in newGraph.Nodes) { if (!newNodeMatched.ContainsKey(newNode)) { diff.SetAdded(newNode); } } return(diff); }
public GraphDiff MatchGraphs(PositionedGraph oldGraph, PositionedGraph newGraph) { if (oldGraph == null) { if (newGraph == null) { return new GraphDiff(); } else { GraphDiff addAllDiff = new GraphDiff(); foreach (PositionedGraphNode newNode in newGraph.Nodes) addAllDiff.SetAdded(newNode); return addAllDiff; } } else if (newGraph == null) { GraphDiff removeAllDiff = new GraphDiff(); foreach (PositionedGraphNode oldNode in oldGraph.Nodes) removeAllDiff.SetRemoved(oldNode); return removeAllDiff; } // none of the graphs is null GraphDiff diff = new GraphDiff(); Dictionary<int, PositionedGraphNode> newNodeForHashCode = buildHashToNodeMap(newGraph); Dictionary<PositionedGraphNode, bool> newNodeMatched = new Dictionary<PositionedGraphNode, bool>(); foreach (PositionedGraphNode oldNode in oldGraph.Nodes) { PositionedGraphNode matchingNode = matchNode(oldNode, newNodeForHashCode); if (matchingNode != null) { diff.SetMatching(oldNode, matchingNode); newNodeMatched[matchingNode] = true; } else { diff.SetRemoved(oldNode); } } foreach (PositionedGraphNode newNode in newGraph.Nodes) { if (!newNodeMatched.ContainsKey(newNode)) { diff.SetAdded(newNode); } } return diff; }
/// <summary> /// Starts animation from oldGraph to newGraph. /// </summary> /// <param name="oldGraph"></param> /// <param name="newGraph"></param> /// <param name="diff"></param> public void StartAnimation(PositionedGraph oldGraph, PositionedGraph newGraph, GraphDiff diff) { // account for that the visual controls could have been reused (we are not reusing controls now - NodeControlCache does nothing) this.canvas.Width = newGraph.BoundingRect.Width; this.canvas.Height = newGraph.BoundingRect.Height; if (oldGraph == null) { Draw(newGraph); return; } var durationMove = new Duration(TimeSpan.FromSeconds(animationDurationSeconds)); var durationFade = durationMove; DoubleAnimation fadeOutAnim = new DoubleAnimation(1.0, 0.0, durationFade); DoubleAnimation fadeInAnim = new DoubleAnimation(0.0, 1.0, durationFade); foreach (UIElement drawing in canvas.Children) { var arrow = drawing as Path; if (arrow != null) { arrow.BeginAnimation(UIElement.OpacityProperty, fadeOutAnim); } } foreach (PositionedEdge edge in newGraph.Edges) { AddEdgeToCanvas(edge).BeginAnimation(UIElement.OpacityProperty, fadeInAnim); } foreach (PositionedNode removedNode in diff.RemovedNodes) { removedNode.NodeVisualControl.BeginAnimation(UIElement.OpacityProperty, fadeOutAnim); } foreach (PositionedNode addedNode in diff.AddedNodes) { AddNodeToCanvas(addedNode).BeginAnimation(UIElement.OpacityProperty, fadeInAnim); } bool first = true; foreach (PositionedNode node in diff.ChangedNodes) { var newNode = diff.GetMatchingNewNode(node); PointAnimation anim = new PointAnimation(); if (first) { anim.Completed += (o, e) => { Draw(newGraph); if (oldGraph != null) { foreach (var oldNode in oldGraph.Nodes) { oldNode.ReleaseNodeVisualControl(); } } }; first = false; } anim.From = node.LeftTop; anim.To = newNode.LeftTop; anim.DecelerationRatio = 0.3; anim.AccelerationRatio = 0.3; anim.Duration = durationMove; node.NodeVisualControl.BeginAnimation(CanvasLocationAdapter.LocationProperty, anim); } }
/// <summary> /// Starts animation from oldGraph to newGraph. /// </summary> /// <param name="oldGraph"></param> /// <param name="newGraph"></param> /// <param name="diff"></param> public void StartAnimation(PositionedGraph oldGraph, PositionedGraph newGraph, GraphDiff diff) { if (oldGraph != null) { foreach (var oldNode in oldGraph.Nodes) { foreach (var newNode in newGraph.Nodes) { if (oldNode.NodeVisualControl == newNode.NodeVisualControl) { ClearCanvas(); } } } } this.canvas.Width = newGraph.BoundingRect.Width; this.canvas.Height = newGraph.BoundingRect.Height; if (oldGraph == null) { Draw(newGraph); return; } double seconds = 0.5; var durationMove = new Duration(TimeSpan.FromSeconds(seconds)); var durationFade = durationMove; DoubleAnimation fadeOutAnim = new DoubleAnimation(1.0, 0.0, durationFade); DoubleAnimation fadeInAnim = new DoubleAnimation(0.0, 1.0, durationFade); foreach (UIElement drawing in canvas.Children) { var arrow = drawing as Path; if (arrow != null) { arrow.BeginAnimation(UIElement.OpacityProperty, fadeOutAnim); } } foreach (PositionedEdge edge in newGraph.Edges) { addEdgeToCanvas(edge).BeginAnimation(UIElement.OpacityProperty, fadeInAnim); } foreach (PositionedGraphNode removedNode in diff.RemovedNodes) { removedNode.NodeVisualControl.BeginAnimation(UIElement.OpacityProperty, fadeOutAnim); } foreach (PositionedGraphNode addedNode in diff.AddedNodes) { addNodeToCanvas(addedNode).BeginAnimation(UIElement.OpacityProperty, fadeInAnim); } bool first = true; foreach (PositionedGraphNode node in diff.ChangedNodes) { var newNode = diff.GetMatchingNewNode(node); PointAnimation anim = new PointAnimation(); if (first) { anim.Completed += new EventHandler((o, e) => { Draw(newGraph); }); first = false; } anim.From = node.LeftTop; anim.To = newNode.LeftTop; anim.DecelerationRatio = 0.3; anim.AccelerationRatio = 0.3; anim.Duration = durationMove; node.NodeVisualControl.BeginAnimation(CanvasLocationAdapter.LocationProperty, anim); } }