// -----------------------------------------------------------------------
//
// Copyright 2014 MIT Licence. See licence.md for more information.
//
// -----------------------------------------------------------------------
namespace Perspex.Animation
{
using System;
using System.Diagnostics;
using System.Linq;
using System.Reactive.Linq;
using Perspex.Threading;
///
/// Utilities for creating animations.
///
public static class Animate
{
///
/// The number of frames per second.
///
public const int FramesPerSecond = 60;
///
/// The time span of each frame.
///
private static readonly TimeSpan Tick = TimeSpan.FromSeconds(1.0 / FramesPerSecond);
///
/// Initializes static members of the class.
///
static Animate()
{
Stopwatch = new Stopwatch();
Stopwatch.Start();
Timer = Observable.Interval(Tick, PerspexScheduler.Instance)
.Select(_ => Stopwatch.Elapsed)
.Publish()
.RefCount();
}
///
/// The stopwatch used to track time.
///
///
/// The stopwatch used to track time.
///
public static Stopwatch Stopwatch
{
get;
private set;
}
///
/// Gets the animation timer.
///
///
/// The animation timer ticks times per second. The
/// parameter passed to a subsciber is the time span since the animation system was
/// initialized.
///
///
/// The animation timer.
///
public static IObservable Timer
{
get;
private set;
}
///
/// Gets a timer that fires every frame for the specified duration.
///
/// The duration of the animation.
///
/// An observable that notifies the subscriber of the progress along the animation.
///
///
/// 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.
///
public static IObservable 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));
}
///
/// Animates a .
///
/// The target object.
/// The target property.
/// The value of the property at the start of the animation.
/// The value of the property at the end of the animation.
/// The easing function to use.
/// The duration of the animation.
/// An that can be used to track or stop the animation.
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));
}
///
/// Animates a .
///
/// The property type.
/// The target object.
/// The target property.
/// The value of the property at the start of the animation.
/// The value of the property at the end of the animation.
/// The easing function to use.
/// The duration of the animation.
/// An that can be used to track or stop the animation.
public static Animation Property(
PerspexObject target,
PerspexProperty property,
T start,
T 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));
}
}
}