Пример #1
0
 /// <summary>
 /// Constructor that sets delay, easing, effect and duration properties
 /// </summary>
 /// <param name="delay">delay as int</param>
 /// <param name="easing">easing as enum</param>
 /// <param name="effect">effect as enum</param>
 /// <param name="duration">duration as int</param>
 public DialogAnimate(int?delay = null, Easing?easing = null, Effect?effect = null, int?duration = null)
 {
     this.Delay    = delay;
     this.Effect   = effect;
     this.Easing   = easing;
     this.Duration = duration;
 }
Пример #2
0
        static void AnimateInternal <T>(IAnimatable self, string name, Func <double, T> transform, Action <T> callback,
                                        uint rate, uint length, Easing?easing, Action <T, bool>?finished, Func <bool>?repeat)
        {
            var key = new AnimatableKey(self, name);

            AbortAnimation(key);

            Action <double>       step  = f => callback(transform(f));
            Action <double, bool>?final = null;

            if (finished != null)
            {
                final = (f, b) => finished(transform(f), b);
            }


            var tweener = new Tweener(length, rate);

            tweener.Handle        = key;
            tweener.ValueUpdated += HandleTweenerUpdated;
            tweener.Finished     += HandleTweenerFinished;

            var info = new Info(rate, length, easing ?? Easing.Linear, tweener, step, new WeakReference <IAnimatable>(self));

            info.Finished     = final;
            info.Repeat       = repeat;
            s_animations[key] = info;

            info.Callback(0.0f);
            tweener.Start();
        }
Пример #3
0
        /// <summary> Gets a value between 0.0f and 1.0f that we should multiply against the XPerSecond or YPerSecond value to know how many units we should move in this Update frame. </summary>
        private float GetPerSecondFactor(Easing[] easings, float currentPercent)
        {
            if (easings == null || !easings.Any())
            {
                return(1.0f);
            }

            Easing?closestEasing = null;

            if (easings[0].StartPercent > currentPercent)
            {
                // We're before the first easing we have, so we'll use the first easing's initial speed.
                return(easings[0].StartPerSecondPercent);
            }

            foreach (var easing in easings)
            {
                if (easing.StartPercent <= currentPercent)
                {
                    if (easing.EndPercent >= currentPercent)
                    {
                        //return easing.EndPerSecondPercent;

                        // We're somewhere within this Easing, so let's get the specific percent of the PerSecond value we should be using.
                        // (Current - Start) / (End - Start)
                        // Example: 0.0 to 0.5, current at 0.2 -> (0.2 - 0.0) / (0.5 - 0.0) -> 0.2 / 0.5 = 0.4f
                        // Example: 0.5 to 0.75, current at 0.67 -> (0.67 - 0.5) / (0.75 - 0.5) -> 0.17 / 0.25 = 0.68f
                        // Taking this value gives us how much of the PerSecond we should be using for this round. However, the full PerSecond
                        // is also eased between the Start and End time slot, so we'll use the formula to determine how much of the full PerSecond
                        // we should be using.
                        var perSecondPercent = (currentPercent - easing.StartPercent) / (easing.EndPercent - easing.StartPercent);

                        // The below examples work for Acceleration and Deceleration)
                        //  Accel (0.25 to 0.8 at   0% time): 0.0f * (0.8 - 0.25) + 0.25 = 0.0 *  0.55f + 0.25 =  0.0f   + 0.25 = 0.25  = 25.0% of the YPerSecond for this frame.
                        //        (0.25 to 0.8 at  20% time): 0.2f * (0.8 - 0.25) + 0.25 = 0.2 *  0.55f + 0.25 =  0.11f  + 0.25 = 0.36  = 36.0% of the YPerSecond for this frame.
                        //        (0.25 to 0.8 at  50% time): 0.5f * (0.8 - 0.25) + 0.25 = 0.5 *  0.55f + 0.25 =  0.275f + 0.25 = 0.525 = 52.5% of the YPerSecond for this frame.
                        //        (0.25 to 0.8 at  80% time): 0.8f * (0.8 - 0.25) + 0.25 = 0.8 *  0.55f + 0.25 =  0.44f  + 0.25 = 0.69  = 69.0% of the YPerSecond for this frame.
                        //        (0.25 to 0.8 at 100% time): 1.0f * (0.8 - 0.25) + 0.25 = 1.0 *  0.55f + 0.25 =  0.55f  + 0.25 = 0.8   = 80.0% of the YPerSecond for this frame.
                        // Deccel (0.8 to 0.25 at   0% time): 0.0f * (0.25 - 0.8) + 0.8  = 0.0 * -0.55f + 0.8  =  0.0f   + 0.8  = 0.8   = 25.0% of the YPerSecond for this frame.
                        //        (0.8 to 0.25 at  20% time): 0.2f * (0.25 - 0.8) + 0.8  = 0.2 * -0.55f + 0.8  = -0.11f  + 0.8  = 0.69  = 69.0% of the YPerSecond for this frame.
                        //        (0.8 to 0.25 at  50% time): 0.5f * (0.25 - 0.8) + 0.8  = 0.5 * -0.55f + 0.8  = -0.275f + 0.8  = 0.525 = 52.5% of the YPerSecond for this frame.
                        //        (0.8 to 0.25 at  80% time): 0.8f * (0.25 - 0.8) + 0.8  = 0.8 * -0.55f + 0.8  = -0.44f  + 0.8  = 0.36  = 36.0% of the YPerSecond for this frame.
                        //        (0.8 to 0.25 at 100% time): 1.0f * (0.25 - 0.8) + 0.8  = 1.0 * -0.55f + 0.8  = -0.55f  + 0.8  = 0.25  = 25.0% of the YPerSecond for this frame.
                        return((perSecondPercent * (easing.EndPerSecondPercent - easing.StartPerSecondPercent)) + easing.StartPerSecondPercent);
                    }
                    else
                    {
                        // We're beyond the End of the easing, so this will be our new 'Closest' one to where we're at.
                        closestEasing = easing;
                    }
                }
            }

            // This easing is the last one where we passed the End but didn't fall into another bucket, so we'll go at the max of this easing bracket, if any. Otherwise, max speed.
            if (closestEasing.HasValue)
            {
                return(closestEasing.Value.EndPerSecondPercent);
            }
            return(1.0f);
        }
Пример #4
0
        public bool Equals(Easing?other)
        {
            if (ReferenceEquals(this, other))
            {
                return(true);
            }

            if (other is null)
            {
                return(false);
            }

            if (Type != other.Type)
            {
                return(false);
            }

            switch (Type)
            {
            case EasingType.Hold:
            case EasingType.Linear:
                // Linear and hold easings have no parameters, so they're all equivalent to each other.
                return(true);

            case EasingType.CubicBezier:
                var xCb = (CubicBezierEasing)this;
                var yCb = (CubicBezierEasing)other;
                return(xCb.Equals(yCb));

            default:
                throw Unreachable;
            }
        }
Пример #5
0
 /// <summary>
 /// Constructor that sets enable, delay, easing, effect and duration properties
 /// </summary>
 /// <param name="enable">enable as bool</param>
 /// <param name="delay">delay as int</param>
 /// <param name="easing">easing as enum</param>
 /// <param name="effect">effect as enum</param>
 /// <param name="duration">duration as int</param>
 public TabAnimate(bool?enable = null, int?delay = null, Easing?easing = null, Effect?effect = null, int?duration = null)
 {
     this.Enable   = enable;
     this.Delay    = delay;
     this.Easing   = easing;
     this.Effect   = effect;
     this.Duration = duration;
 }
Пример #6
0
 public virtual void SetCenter(double x, double y, long duration = 0, Easing?easing = default)
 {
     if (Map?.PanLock ?? false)
     {
         return;
     }
     _viewport.SetCenter(x, y, duration, easing);
     Limiter?.LimitExtent(_viewport, Map?.Extent);
 }
Пример #7
0
 public void SetCenter(MReadOnlyPoint center, long duration = 0, Easing?easing = default)
 {
     if (Map?.PanLock ?? false)
     {
         return;
     }
     _viewport.SetCenter(center, duration, easing);
     Limiter?.LimitExtent(_viewport, Map?.Extent);
 }
Пример #8
0
 public void SetRotation(double rotation, long duration = 0, Easing?easing = default)
 {
     if (Map?.RotationLock ?? false)
     {
         return;
     }
     _viewport.SetRotation(rotation, duration, easing);
     Limiter?.LimitExtent(_viewport, Map?.Extent);
 }
Пример #9
0
        /// <summary>
        /// Navigate to center and change resolution with animation
        /// </summary>
        /// <param name="center">New center to move to</param>
        /// <param name="resolution">New resolution to use</param>
        /// <param name="duration">Duration for animation in milliseconds.</param>
        /// <param name="easing">The type of easing function used to transform from begin tot end state</param>
        public void NavigateTo(MPoint center, double resolution, long duration = 0, Easing?easing = default)
        {
            if (center == null)
            {
                throw new ArgumentNullException(nameof(center));
            }

            _viewport.SetCenterAndResolution(center.X, center.Y, resolution, duration, easing);
            OnNavigated(duration, ChangeType.Discrete);
        }
Пример #10
0
        public void SetResolution(double resolution, long duration = 0, Easing?easing = default)
        {
            if (Map?.ZoomLock ?? true)
            {
                return;
            }
            if (Limiter != null)
            {
                resolution = Limiter.LimitResolution(resolution, _viewport.Width, _viewport.Height, Map.Resolutions, Map.Extent);
            }

            _viewport.SetResolution(resolution, duration, easing);
        }
Пример #11
0
        internal CompositionEasingFunction?CreateCompositionEasingFunction(Easing?easingFunction)
        {
            if (easingFunction is null)
            {
                return(null);
            }

            return(easingFunction.Type switch
            {
                Easing.EasingType.Linear => CreateLinearEasingFunction(),
                Easing.EasingType.CubicBezier => CreateCubicBezierEasingFunction((CubicBezierEasing)easingFunction),
                Easing.EasingType.Hold => CreateHoldThenStepEasingFunction(),
                _ => throw new InvalidOperationException(),
            });
Пример #12
0
        public AnimationEntry(object start, object end,
                              double animationStart = 0, double animationEnd = 1,
                              Easing?easing         = null,
                              bool repeat           = false,
                              Action <T, AnimationEntry <T>, double>?tick = null,
                              Action <T, AnimationEntry <T> >?final       = null)
        {
            AnimationStart = animationStart;
            AnimationEnd   = animationEnd;

            Start = start;
            End   = end;

            Easing = easing ?? Easing.Linear;
            Repeat = repeat;

            _animationDelta = AnimationEnd - AnimationStart;

            _tick  = tick;
            _final = final;
        }
Пример #13
0
        public static void Animate <T>(this IAnimatable self, string name, Func <double, T> transform, Action <T> callback,
                                       uint rate = 16, uint length = 250, Easing?easing = null,
                                       Action <T, bool>?finished = null, Func <bool>?repeat = null)
        {
            if (transform == null)
            {
                throw new ArgumentNullException(nameof(transform));
            }
            if (callback == null)
            {
                throw new ArgumentNullException(nameof(callback));
            }
            if (self == null)
            {
                throw new ArgumentNullException(nameof(self));
            }

            Action animate = () => AnimateInternal(self, name, transform, callback, rate, length, easing, finished, repeat);

            DoAction(self, animate);
        }
Пример #14
0
        public static Task <bool> ColorTo(this VisualElement element, Color color, uint length = 250u, Easing?easing = null)
        {
            _ = element ?? throw new ArgumentNullException(nameof(element));

            var animationCompletionSource = new TaskCompletionSource <bool>();

            new Animation
            {
                { 0, 1, new Animation(v => element.BackgroundColor = new Color(v, element.BackgroundColor.G, element.BackgroundColor.B, element.BackgroundColor.A), element.BackgroundColor.R, color.R) },
                { 0, 1, new Animation(v => element.BackgroundColor = new Color(element.BackgroundColor.R, v, element.BackgroundColor.B, element.BackgroundColor.A), element.BackgroundColor.G, color.G) },
                { 0, 1, new Animation(v => element.BackgroundColor = new Color(element.BackgroundColor.R, element.BackgroundColor.G, v, element.BackgroundColor.A), element.BackgroundColor.B, color.B) },
                { 0, 1, new Animation(v => element.BackgroundColor = new Color(element.BackgroundColor.R, element.BackgroundColor.G, element.BackgroundColor.B, v), element.BackgroundColor.A, color.A) },
            }.Commit(element, nameof(ColorTo), 16, length, easing, (d, b) => animationCompletionSource.SetResult(true));

            return(animationCompletionSource.Task);
        }
        static IEnumerable <PathGeometryGroupKeyFrames> CreateGroupRecords(
            IReadOnlyList <Animatable <PathGeometry> > pathData)
        {
            // Get enumerators for the key frames in each of the Animatable<PathGeometry>s.
            var enumerators = pathData.Select(EnumerateKeyFrames).ToArray();

            // Start enumerating.
            foreach (var enumerator in enumerators)
            {
                enumerator.MoveNext();
            }

            // Get the current value from each enumerator.
            var curs = enumerators.Select(en => en.Current).ToArray();

            // Keep looping until all of the enumerators have been consumed.
            while (curs.Any(cur => !cur.isCompleted))
            {
                // Get the lowest frame number from the enumerators that have not yet been consumed.
                var currentFrame = curs.Where(cur => !cur.isCompleted).Select(cur => cur.keyFrame.Frame).Min();

                // Yield a group for all of the key frames that have a value for this frame number.
                // The frame number is NaN if the value is non-animated. Non-animated values are
                // always output.
                Easing?preferredEasing = null;
                var    easingIsCorrect = true;
                var    geometries      = new KeyFrame <PathGeometry>?[pathData.Count];

                for (var i = 0; i < enumerators.Length; i++)
                {
                    var current     = enumerators[i].Current;
                    var frameNumber = current.keyFrame.Frame;
                    if (double.IsNaN(frameNumber))
                    {
                        // The value is non-animated.
                        geometries[i] = current.keyFrame;
                    }
                    else if (frameNumber == currentFrame)
                    {
                        // The value has a key frame at the current frame number.
                        geometries[i] = current.keyFrame;
                        if (preferredEasing is null)
                        {
                            // Use the first easing we come across. This is arbitrary -
                            // we need an easing, but the various paths may have different easings
                            // The first one we find is correct for that particular path, and it
                            // might be correct for the other paths. The only way to get this
                            // completely correct would be to write an interpolator.
                            preferredEasing = current.keyFrame.Easing;
                        }
                        else if (preferredEasing != current.keyFrame.Easing)
                        {
                            easingIsCorrect = false;
                        }
                    }
                }

                // There should always be at least one keyframe for each frame number, so we will
                // always end up with a non-null preferred easing here.
                Debug.Assert(preferredEasing != null, "Invariant");

                yield return(new PathGeometryGroupKeyFrames(currentFrame, geometries, preferredEasing !, easingIsCorrect));

                // Advance the enumerators that are on the current frame unless they are completed.
                // NOTE: we don't need to care about whether the enumerators are completed because
                //       they will continue to return the last value, but we might as well avoid
                //       some unnecessary work.
                for (var i = 0; i < enumerators.Length; i++)
                {
                    var enumerator = enumerators[i];
                    if (!enumerator.Current.isCompleted &&
                        enumerator.Current.keyFrame.Frame == currentFrame)
                    {
                        enumerator.MoveNext();
                        curs[i] = enumerator.Current;
                    }
                }
            }
        }
Пример #16
0
        public static Task <bool> LayoutTo(this VisualElement view, Rectangle bounds, uint length = 250, Easing?easing = null)
        {
            if (view == null)
            {
                throw new ArgumentNullException(nameof(view));
            }

            Rectangle start = view.Bounds;
            Func <double, Rectangle> computeBounds = progress =>
            {
                double x = start.X + (bounds.X - start.X) * progress;
                double y = start.Y + (bounds.Y - start.Y) * progress;
                double w = start.Width + (bounds.Width - start.Width) * progress;
                double h = start.Height + (bounds.Height - start.Height) * progress;

                return(new Rectangle(x, y, w, h));
            };

            return(AnimateTo(view, 0, 1, nameof(LayoutTo), (v, value) => v.Layout(computeBounds(value)), length, easing));
        }
Пример #17
0
        public static Task <bool> RelScaleTo(this VisualElement view, double dscale, uint length = 250, Easing?easing = null)
        {
            if (view == null)
            {
                throw new ArgumentNullException(nameof(view));
            }

            return(view.ScaleTo(view.Scale + dscale, length, easing));
        }
Пример #18
0
        static Task <bool> AnimateTo(this VisualElement view, double start, double end, string name,
                                     Action <VisualElement, double> updateAction, uint length = 250, Easing?easing = null)
        {
            if (easing == null)
            {
                easing = Easing.Linear;
            }

            var tcs = new TaskCompletionSource <bool>();

            var weakView = new WeakReference <VisualElement>(view);

            void UpdateProperty(double f)
            {
                if (weakView.TryGetTarget(out VisualElement? v))
                {
                    updateAction(v, f);
                }
            }

            new Animation(UpdateProperty, start, end, easing).Commit(view, name, 16, length, finished: (f, a) => tcs.SetResult(a));

            return(tcs.Task);
        }
Пример #19
0
        public static Task <bool> FadeTo(this VisualElement view, double opacity, uint length = 250, Easing?easing = null)
        {
            if (view == null)
            {
                throw new ArgumentNullException(nameof(view));
            }

            return(AnimateTo(view, view.Opacity, opacity, nameof(FadeTo), (v, value) => v.Opacity = value, length, easing));
        }
Пример #20
0
 /// <summary>
 /// Change center of viewport to X/Y coordinates
 /// </summary>
 /// <param name="x">X value of the new center</param>
 /// <param name="y">Y value of the new center</param>
 /// <param name="duration">Duration for animation in milliseconds.</param>
 /// <param name="easing">Function for easing</param>
 public void CenterOn(double x, double y, long duration = -1, Easing?easing = default)
 {
     CenterOn(new MPoint(x, y), duration, easing);
 }
Пример #21
0
        public static Task <bool> TranslateTo(this VisualElement view, double x, double y, uint length = 250, Easing?easing = null)
        {
            if (view == null)
            {
                throw new ArgumentNullException(nameof(view));
            }

            easing ??= Easing.Linear;

            var             tcs        = new TaskCompletionSource <bool>();
            var             weakView   = new WeakReference <VisualElement>(view);
            Action <double> translateX = f =>
            {
                if (weakView.TryGetTarget(out VisualElement? v))
                {
                    v.TranslationX = f;
                }
            };
            Action <double> translateY = f =>
            {
                if (weakView.TryGetTarget(out VisualElement? v))
                {
                    v.TranslationY = f;
                }
            };

            new Animation
            {
                { 0, 1, new Animation(translateX, view.TranslationX, x, easing: easing) },
                { 0, 1, new Animation(translateY, view.TranslationY, y, easing: easing) }
            }.Commit(view, nameof(TranslateTo), 16, length, null, (f, a) => tcs.SetResult(a));

            return(tcs.Task);
        }

        internal static IAnimationManager GetAnimationManager(this IAnimatable animatable)
Пример #22
0
 /// <summary>
 /// Change center of viewport
 /// </summary>
 /// <param name="center">New center point of viewport</param>
 /// <param name="duration">Duration for animation in milliseconds.</param>
 /// <param name="easing">Function for easing</param>
 public void CenterOn(MPoint center, long duration = 0, Easing?easing = default)
 {
     _viewport.SetCenter(center, duration, easing);
     OnNavigated(duration, ChangeType.Discrete);
 }
Пример #23
0
        public static List <AnimationEntry <Viewport> > Create(IViewport viewport, double centerX, double centerY, long duration, Easing?easing)
        {
            var animations = new List <AnimationEntry <Viewport> > {
                new AnimationEntry <Viewport>(
                    start: (viewport.CenterX, viewport.CenterY),
                    end: (centerX, centerY),
                    animationStart: 0,
                    animationEnd: 1,
                    easing: easing ?? Easing.SinOut,
                    tick: CenterTick,
                    final: CenterFinal
                    )
            };

            Animation.Start(animations, duration);

            return(animations);
        }
Пример #24
0
 /// <summary>
 /// Change resolution of viewport
 /// </summary>
 /// <param name="resolution">New resolution to use</param>
 /// <param name="duration">Duration for animation in milliseconds.</param>
 /// <param name="easing">The type of easing function used to transform from begin tot end state</param>
 public void ZoomTo(double resolution, long duration = 0, Easing?easing = default)
 {
     _viewport.SetResolution(resolution, duration, easing);
     OnNavigated(duration, ChangeType.Discrete);
 }
Пример #25
0
        /// <summary>
        /// Navigate center of viewport to center of extent and change resolution
        /// </summary>
        /// <param name="extent">New extent for viewport to show</param>
        /// <param name="scaleMethod">Scale method to use to determine resolution</param>
        /// <param name="duration">Duration for animation in milliseconds.</param>
        /// <param name="easing">The type of easing function used to transform from begin tot end state</param>
        public void NavigateTo(MRect?extent, ScaleMethod scaleMethod = ScaleMethod.Fit, long duration = -1, Easing?easing = default)
        {
            if (extent == null)
            {
                return;
            }

            var resolution = ZoomHelper.DetermineResolution(
                extent.Width, extent.Height, _viewport.Width, _viewport.Height, scaleMethod);

            NavigateTo(extent.Centroid, resolution, duration, easing);
        }
Пример #26
0
 /// <summary>
 /// Navigate to a resolution, so such the map uses the fill method
 /// </summary>
 /// <param name="scaleMethod">Scale method to use to determine resolution</param>
 /// <param name="duration">Duration for animation in milliseconds.</param>
 /// <param name="easing">The type of easing function used to transform from begin tot end state</param>
 public void NavigateToFullEnvelope(ScaleMethod scaleMethod = ScaleMethod.Fill, long duration = -1, Easing?easing = default)
 {
     if (_map.Extent != null)
     {
         NavigateTo(_map.Extent, scaleMethod, duration, easing);
     }
 }
Пример #27
0
        public static List <AnimationEntry <Viewport> > Create(Viewport viewport, double rotation, long duration, Easing?easing)
        {
            rotation = GetNearestRotation(viewport, rotation);

            var animations = new List <AnimationEntry <Viewport> > {
                new AnimationEntry <Viewport>(
                    start: viewport.Rotation,
                    end: rotation,
                    animationStart: 0,
                    animationEnd: 1,
                    easing: easing ?? Easing.SinInOut,
                    tick: (viewport, e, v) => viewport.Rotation = (double)e.Start + (((double)e.End - (double)e.Start) * e.Easing.Ease(v)),
                    final: (viewport, e) => viewport.Rotation   = (double)e.End
                    )
            };

            Animation.Start(animations, duration);

            return(animations);
        }
Пример #28
0
        public static Task <bool> RotateXTo(this VisualElement view, double rotation, uint length = 250, Easing?easing = null)
        {
            if (view == null)
            {
                throw new ArgumentNullException(nameof(view));
            }

            return(AnimateTo(view, view.RotationX, rotation, nameof(RotateXTo), (v, value) => v.RotationX = value, length, easing));
        }
Пример #29
0
        /// <summary>
        /// Zoom to a given resolution with a given point as center
        /// </summary>
        /// <param name="resolution">Resolution to zoom</param>
        /// <param name="centerOfZoom">Center of zoom in screen coordinates. This is the one point in the map that
        /// stays on the same location while zooming in. /// For instance, in mouse wheel zoom animation the position
        /// of the mouse pointer can be the center of zoom. Note, that the centerOfZoom is in screen coordinates not
        /// world coordinates, this is because this is most convenient for the main use case, zoom with the mouse
        /// position as center.</param>
        /// <param name="duration">Duration for animation in milliseconds.</param>
        /// <param name="easing">The easing of the animation when duration is > 0</param>
        public void ZoomTo(double resolution, MPoint centerOfZoom, long duration = 0, Easing?easing = default)
        {
            var(worldCenterOfZoomX, worldCenterOfZoomY) = _viewport.ScreenToWorldXY(centerOfZoom.X, centerOfZoom.Y);
            var animationEntries = ZoomAroundLocationAnimation.Create(_viewport, worldCenterOfZoomX, worldCenterOfZoomY, resolution,
                                                                      _viewport.CenterX, _viewport.CenterY, _viewport.Resolution, duration);

            AddFinalAction(animationEntries, () => OnNavigated(ChangeType.Discrete));
            _viewport.SetAnimations(animationEntries);
        }
Пример #30
0
        public static Task <bool> ScaleYTo(this VisualElement view, double scale, uint length = 250, Easing?easing = null)
        {
            if (view == null)
            {
                throw new ArgumentNullException(nameof(view));
            }

            return(AnimateTo(view, view.ScaleY, scale, nameof(ScaleYTo), (v, value) => v.ScaleY = value, length, easing));
        }