Hi,
Just wanted to contribute something back to the forums. I have created a tweening class which has been loosely based on some Javascript tweening classes. If you have any suggestions please post them here.
Credits go to http://jstween.blogspot.com/ and http://www.codeproject.com/csharp/tweencs.asp which provided some valuable starting points.
Note that I originally wrote this class for the standard windows forms library, just change the Tick implementation from the storyboard hack to a Forms Timer.
Still todo are implementing other tweens (color, text, etc tweens still to come).
And finally, Usage goes something like this ( check out the MotionType enum for other motions)
.....
Motion motion;
private void init()
{
motion = new Motion(new Coordinate(0, 0),
new Coordinate(100, 100),
new TimeSpan(0, 0, 0,3),
new TimeSpan(0, 0, 0, 0, 100),
MotionType.BackEaseIn,
this);
motion.RaiseTickEvent +=new EventHandler(motion_RaiseTickEvent);
}
private void motion_RaiseTickEvent(Object sender, EventArgs e)
{
SomeControl.SetValue(Canvas.TopProperty, motion.Current.X);
SomeControl.SetValue(Canvas.LeftProperty, motion.Current.Y);
}
.....
//---------------------------------- START CODE ------------------------------
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
namespace Harveys.Tween
{
public class Motion
{
private Coordinate start;
private Coordinate end;
private Coordinate current;
private TimeSpan timeframe;
private TimeSpan tickInterval;
private TimeSpan currentInterval;
private MotionType motion;
private Control parent;
private delegate double MotionFunction(double CurrentTime, double BeginState, double ChangeState, double Duration);
private MotionFunction func;
public Motion(Coordinate Start, Coordinate End, TimeSpan Timeframe, TimeSpan TickInterval, MotionType Motion, Control Parent)
{
start = Start;
end = End;
current = start;
timeframe = Timeframe;
tickInterval = TickInterval;
motion = Motion;
parent = Parent;
func = (MotionFunction)Delegate.CreateDelegate(typeof(MotionFunction), typeof(Tweener).GetMethod(Motion.ToString()));
parent.Loaded += new EventHandler(InitTick);
}
// Start Tick
private void InitTick(Object sender, EventArgs e)
{
Storyboard timerTimeline = new Storyboard();
timerTimeline.Duration = new Duration( tickInterval );
parent.Resources.Add(timerTimeline);
timerTimeline.Begin();
timerTimeline.Completed += new EventHandler(Tick);
}
private void Tick(Object sender, EventArgs e)
{
// Set current time and check is stop is required!
currentInterval += tickInterval;
if (currentInterval < timeframe) ((Storyboard)sender).Begin();
// Raise the Tick Event
OnRaiseTickEven(new EventArgs());
}
// Coordinate Changes Event
public delegate void OnTickEventHandler(Object sender, EventArgs e);
public event EventHandler RaiseTickEvent;
protected virtual void OnRaiseTickEven(EventArgs e)
{
EventHandler handler = RaiseTickEvent;
if (handler != null)
{
handler(this, e);
}
}
public Coordinate Current
{
get
{
double t = (double)currentInterval.TotalMilliseconds / 1000.0;
double d = (double)timeframe.TotalMilliseconds /1000.0;
current.X = func(t, start.X, end.X - start.X, d);
current.Y = func(t, start.Y, end.Y - start.Y, d);
return current;
}
}
}
public enum MotionType
{
RegularEaseIn,
RegularEaseOut,
RegularEaseInOut,
StrongEaseIn,
StrongEaseOut,
StrongEaseInOut,
BackEaseIn,
BackEaseOut,
BackEaseInOut,
ElasticEaseIn,
ElasticEaseOut,
ElasticEaseInOut,
BounceEaseOut,
BounceEaseIn,
BounceEaseInOut
}
public struct Coordinate
{
private double x, y;
public Coordinate(double X, double Y)
{
x = X;
y = Y;
}
public double X
{
get { return x; }
set { x = value; }
}
public double Y
{
get { return y; }
set { y = value; }
}
}
class Tweener
{
// t = Currrent Timeline Position (Seconds)
// b = Begining Value
// c = Relative Change ( Final Value - Begining Value )
// d = Final Timeline Value (Seconds)
public static double BackEaseIn(double t, double b, double c, double d)
{
double s = 1.70158;
return c*(t/=d)*t*((s+1)*t - s) + b;
}
public static double BackEaseOut(double t, double b, double c, double d)
{
double s = 1.70158;
return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b;
}
public static double BackEaseInOut(double t, double b, double c, double d)
{
double s = 1.70158;
if ((t/=d/2) < 1) return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b;
return c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b;
}
public static double ElasticEaseIn(double t, double b, double c, double d)
{
double s, p, a;
p = d * .3;
a = c;
s = p / 4;
if (t==0) return b;
if ((t/=d)==1) return b+c;
else s = p/(2*Math.PI) * Math.Asin(c/a);
return -(a*Math.Pow(2,10*(t-=1)) * Math.Sin( (t*d-s)*(2*Math.PI)/p )) + b;
}
public static double ElasticEaseOut(double t, double b, double c, double d)
{
double s, p, a;
p=d*.3;
a = c;
s = p / 4;
if (t==0) return b;
if ((t/=d)==1) return b+c;
else s = p/(2*Math.PI) * Math.Asin (c/a);
return (a*Math.Pow(2,-10*t) * Math.Sin( (t*d-s)*(2*Math.PI)/p ) + c + b);
}
public static double ElasticEaseInOut(double t, double b, double c, double d)
{
double s, p, a;
p=d*(.3*1.5);
a=c;
s=p/4;
if (t==0) return b;
if ((t/=d/2)==2) return b+c;
else s = p/(2*Math.PI) * Math.Asin (c/a);
if (t < 1) return -.5*(a*Math.Pow(2,10*(t-=1)) * Math.Sin( (t*d-s)*(2*Math.PI)/p )) + b;
return a*Math.Pow(2,-10*(t-=1)) * Math.Sin( (t*d-s)*(2*Math.PI)/p )*.5 + c + b;
}
public static double BounceEaseOut(double t, double b, double c, double d)
{
if ((t /= d) < (1 / 2.75))
{
return c * (7.5625 * t * t) + b;
}
else if (t < (2 / 2.75))
{
return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
}
else if (t < (2.5 / 2.75))
{
return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
}
else
{
return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
}
}
public static double BounceEaseIn(double t, double b, double c, double d)
{
return c - Tweener.BounceEaseOut(d - t, 0, c, d) + b;
}
public static double BounceEaseInOut(double t, double b, double c, double d)
{
if (t < d / 2) return Tweener.BounceEaseIn(t * 2, 0, c, d) * .5 + b;
else return Tweener.BounceEaseOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
}
public static double StrongEaseInOut(double t, double b, double c, double d)
{
return c * (t /= d) * t * t * t * t + b;
}
public static double RegularEaseIn(double t, double b, double c, double d)
{
return c*(t/=d)*t + b;
}
public static double RegularEaseOut(double t, double b, double c, double d)
{
return -c * (t /= d) * (t - 2) + b;
}
public static double RegularEaseInOut(double t, double b, double c, double d)
{
if ((t /= d / 2) < 1) return c / 2 * t * t + b;
return -c / 2 * ((--t) * (t - 2) - 1) + b;
}
public static double StrongEaseIn(double t, double b, double c, double d)
{
return c * (t /= d) * t * t * t * t + b;
}
public static double StrongEaseOut(double t, double b, double c, double d)
{
return c * ((t = t / d - 1) * t * t * t * t + 1) + b;
}
public static double strongEaseInOut(double t, double b, double c, double d)
{
if ((t /= d / 2) < 1) return c / 2 * t * t * t * t * t + b;
return c / 2 * ((t -= 2) * t * t * t * t + 2) + b;
}
}
}
//---------------------------------- END CODE ------------------------------