/// <summary> /// This basically just sets the value of <see cref="Northwoods.GoXam.Node.Position"/>, /// but with animated movement. /// </summary> /// <param name="node"></param> /// <param name="newpos">a new position in model coordinates</param> /// <remarks> /// There is no animation if <see cref="Animated"/> is false, /// if the <see cref="AnimationTime"/> is very small, or /// if the original position and the new position are very near to each other /// or offscreen. /// </remarks> public void MoveAnimated(Node node, Point newpos) { if (node == null) { return; } VerifyAccess(); Point oldloc = node.Location; Rect oldb = node.Bounds; //Diagram.Debug("LayoutManager.MoveAnimated: " + Diagram.Str(node) + " " + Diagram.Str(node.Position) + " -- > " + Diagram.Str(newpos)); // always move the node node.Position = newpos; if (this.Story != null) { // if MoveAnimated is called more than once for a Node, remove any previous saved animation PointAnimation anim = null; if (this.Animations.TryGetValue(node, out anim)) { //Diagram.Debug(" removed animation for " + node.ToString()); this.Story.Children.Remove(anim); } } // try not to bother with animations that won't be visibly useful if (!this.Animated) { return; } if (this.AnimationTime <= 10) { return; } // two pixels or more (but that's in model coordinates) if (Math.Abs(newpos.X - oldb.X) < 2 && Math.Abs(newpos.Y - oldb.Y) < 2) { return; } FrameworkElement elt = node.VisualElement; if (elt == null) { return; } // only do animation for nodes whose new or old bounds are visible in the view //?? this doesn't work reliably: Diagram diagram = this.Diagram; if (diagram == null || diagram.Panel == null) { return; } Rect nearRect = diagram.Panel.InflatedViewportBounds; Rect newb = new Rect(newpos.X, newpos.Y, oldb.Width, oldb.Height); if (!Geo.Intersects(nearRect, oldb) && !Geo.Intersects(nearRect, newb)) { return; } // start an animation //Diagram.Debug(" MoveAnimated " + Diagram.Str(new Point(oldb.X, oldb.Y)) + Diagram.Str(node.Position)); if (Double.IsNaN(oldloc.X)) { oldloc.X = this.DefaultLocation.X; } if (Double.IsNaN(oldloc.Y)) { oldloc.Y = this.DefaultLocation.Y; } PointAnimation a = new PointAnimation(); a.From = oldloc; a.Duration = this.AnimationDuration; Storyboard.SetTarget(a, elt); Storyboard.SetTargetProperty(a, new PropertyPath(Node.LocationProperty)); Storyboard story = this.Story; if (story == null) // when called from outside of DoLayoutDiagram { Storyboard singlestory = new Storyboard(); singlestory.Children.Add(a); StartStoryboard(singlestory); } else { StartingLayoutAnimation(); story.Children.Add(a); // collect animations for later action, all at once this.Animations[node] = a; } }