|
|
|
@ -7,48 +7,126 @@ |
|
|
|
namespace Perspex.Animation |
|
|
|
{ |
|
|
|
using System; |
|
|
|
using System.Diagnostics; |
|
|
|
using System.Linq; |
|
|
|
using System.Reactive.Linq; |
|
|
|
using Perspex.Threading; |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Utilities for creating animations.
|
|
|
|
/// </summary>
|
|
|
|
public static class Animate |
|
|
|
{ |
|
|
|
private const int FramesPerSecond = 30; |
|
|
|
/// <summary>
|
|
|
|
/// The number of frames per second.
|
|
|
|
/// </summary>
|
|
|
|
public const int FramesPerSecond = 60; |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// The time span of each frame.
|
|
|
|
/// </summary>
|
|
|
|
private static readonly TimeSpan Tick = TimeSpan.FromSeconds(1.0 / FramesPerSecond); |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Initializes the static class.
|
|
|
|
/// </summary>
|
|
|
|
static Animate() |
|
|
|
{ |
|
|
|
Stopwatch = new Stopwatch(); |
|
|
|
Stopwatch.Start(); |
|
|
|
Timer = Observable.Interval(Tick, PerspexScheduler.Instance).Select(_ => Stopwatch.Elapsed); |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// The stopwatch used to track time.
|
|
|
|
/// </summary>
|
|
|
|
public static Stopwatch Stopwatch |
|
|
|
{ |
|
|
|
get; |
|
|
|
private set; |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Gets the animation timer.
|
|
|
|
/// </summary>
|
|
|
|
/// <remarks>
|
|
|
|
/// The animation timer ticks <see cref="FramesPerSecond"/> times per second. The
|
|
|
|
/// parameter passed to a subsciber is the time span since the animation system was
|
|
|
|
/// initialized.
|
|
|
|
/// </remarks>
|
|
|
|
public static IObservable<TimeSpan> Timer |
|
|
|
{ |
|
|
|
get; |
|
|
|
private set; |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Gets a timer that fires every frame for the specified duration.
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="duration">The duration of the animation.</param>
|
|
|
|
/// <returns>
|
|
|
|
/// An observable that notifies the subscriber of the progress along the animation.
|
|
|
|
/// </returns>
|
|
|
|
/// <remarks>
|
|
|
|
/// The parameter passed to the subscriber is the progress along the animation, with
|
|
|
|
/// 0 being the start and 1 being the end. The observable is guaranteed to fire 0
|
|
|
|
/// immediately on subscribe and 1 at the end of the duration.
|
|
|
|
/// </remarks>
|
|
|
|
public static IObservable<double> GetTimer(TimeSpan duration) |
|
|
|
{ |
|
|
|
var startTime = Stopwatch.Elapsed.Ticks; |
|
|
|
var endTime = (startTime + duration.Ticks); |
|
|
|
return Timer |
|
|
|
.TakeWhile(x => x.Ticks < endTime) |
|
|
|
.Select(x => (x.Ticks - startTime) / (double)duration.Ticks) |
|
|
|
.StartWith(0.0) |
|
|
|
.Concat(Observable.Return(1.0)); |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Animates a <see cref="PerspexProperty"/>.
|
|
|
|
/// </summary>
|
|
|
|
/// <typeparam name="T">The property type.</typeparam>
|
|
|
|
/// <param name="target">The target object.</param>
|
|
|
|
/// <param name="property">The target property.</param>
|
|
|
|
/// <param name="start">The value of the property at the start of the animation.</param>
|
|
|
|
/// <param name="finish">The value of the property at the end of the animation.</param>
|
|
|
|
/// <param name="easing">The easing function to use.</param>
|
|
|
|
/// <param name="duration">The duration of the animation.</param>
|
|
|
|
/// <returns>An <see cref="IDisposable"/> that can be used to stop the animation.</returns>
|
|
|
|
public static IDisposable Property( |
|
|
|
PerspexObject target, |
|
|
|
PerspexProperty property, |
|
|
|
object start, |
|
|
|
object finish, |
|
|
|
IEasing easing, |
|
|
|
TimeSpan duration, |
|
|
|
double repeats = 1) |
|
|
|
TimeSpan duration) |
|
|
|
{ |
|
|
|
var startTime = Environment.TickCount; |
|
|
|
var runningTime = (double)duration.TotalMilliseconds; |
|
|
|
var endTime = Environment.TickCount + (runningTime * repeats); |
|
|
|
|
|
|
|
var o = Observable.Interval(Tick, PerspexScheduler.Instance) |
|
|
|
.Select(_ => Environment.TickCount) |
|
|
|
.TakeWhile(tick => tick < endTime) |
|
|
|
.Select(tick => easing.Ease((tick - startTime) / runningTime, start, finish)) |
|
|
|
.StartWith(start) |
|
|
|
.Concat(Observable.Return(finish)); |
|
|
|
|
|
|
|
var o = GetTimer(duration).Select(progress => easing.Ease(progress, start, finish)); |
|
|
|
return target.Bind(property, o, BindingPriority.Animation); |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Animates a <see cref="PerspexProperty"/>.
|
|
|
|
/// </summary>
|
|
|
|
/// <typeparam name="T">The property type.</typeparam>
|
|
|
|
/// <param name="target">The target object.</param>
|
|
|
|
/// <param name="property">The target property.</param>
|
|
|
|
/// <param name="start">The value of the property at the start of the animation.</param>
|
|
|
|
/// <param name="finish">The value of the property at the end of the animation.</param>
|
|
|
|
/// <param name="easing">The easing function to use.</param>
|
|
|
|
/// <param name="duration">The duration of the animation.</param>
|
|
|
|
/// <returns>An <see cref="IDisposable"/> that can be used to stop the animation.</returns>
|
|
|
|
public static IDisposable Property<T>( |
|
|
|
PerspexObject target, |
|
|
|
PerspexProperty<T> property, |
|
|
|
T start, |
|
|
|
T finish, |
|
|
|
IEasing easing, |
|
|
|
IEasing<T> easing, |
|
|
|
TimeSpan duration) |
|
|
|
{ |
|
|
|
return Property(target, (PerspexProperty)property, start, finish, easing, duration); |
|
|
|
var o = GetTimer(duration).Select(progress => easing.Ease(progress, start, finish)); |
|
|
|
return target.Bind(property, o, BindingPriority.Animation); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|