A cross-platform UI framework for .NET
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

135 lines
5.2 KiB

// -----------------------------------------------------------------------
// <copyright file="Animate.cs" company="Steven Kirk">
// Copyright 2014 MIT Licence. See licence.md for more information.
// </copyright>
// -----------------------------------------------------------------------
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
{
/// <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)
.Publish()
.RefCount();
}
/// <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="Animation"/> that can be used to track or stop the animation.</returns>
public static Animation Property(
PerspexObject target,
PerspexProperty property,
object start,
object finish,
IEasing easing,
TimeSpan duration)
{
var o = GetTimer(duration).Select(progress => easing.Ease(progress, start, finish));
return new Animation(o, 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="Animation"/> that can be used to track or stop the animation.</returns>
public static Animation<T> Property<T>(
PerspexObject target,
PerspexProperty<T> property,
T start,
T finish,
IEasing<T> easing,
TimeSpan duration)
{
var o = GetTimer(duration).Select(progress => easing.Ease(progress, start, finish));
return new Animation<T>(o, target.Bind(property, o, BindingPriority.Animation));
}
}
}