I'm trying to do an Matrix animation where I both scale and transpose a canvas at the same time. The only approach I found was using a MatrixTransform and MatrixAnimationUsingKeyFrames. Since there doesnt seem to be any interpolation for matrices built in (only for path/rotate) it seems the only choice is to try and build the interpolation and DiscreteMatrixKeyFrame's yourself.
I did a basic implementation of this but it isnt exactly smooth and I'm not sure if this is the best way and how to handle framerates etc. Anyone have suggestions for improvement? Here's the code:
MatrixAnimationUsingKeyFrames anim = new MatrixAnimationUsingKeyFrames();
int duration = 1;
anim.KeyFrames = Interpolate(new Point(0, 0), centerPoint, 1, factor,100,duration);
this.matrixTransform.BeginAnimation(MatrixTransform.MatrixProperty, anim,HandoffBehavior.Compose);
public MatrixKeyFrameCollection Interpolate(Point startPoint, Point endPoint, double startScale, double endScale, double framerate,double duration)
{
MatrixKeyFrameCollection keyframes = new MatrixKeyFrameCollection();
double steps = duration * framerate;
double milliSeconds = 1000 / framerate;
double timeCounter = 0;
double diffX = Math.Abs(startPoint.X- endPoint.X);
double xStep = diffX / steps;
double diffY = Math.Abs(startPoint.Y - endPoint.Y);
double yStep = diffY / steps;
double diffScale= Math.Abs(startScale- endScale);
double scaleStep = diffScale / steps;
if (endPoint.Y < startPoint.Y)
{
yStep = -yStep;
}
if (endPoint.X < startPoint.X)
{
xStep = -xStep;
}
if (endScale < startScale)
{
scaleStep = -scaleStep;
}
Point currentPoint = new Point();
double currentScale = startScale;
for (int i = 0; i < steps; i++)
{
keyframes.Add(new DiscreteMatrixKeyFrame(new Matrix(currentScale, 0, 0, currentScale, currentPoint.X, currentPoint.Y), KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(timeCounter))));
currentPoint.X += xStep;
currentPoint.Y += yStep;
currentScale += scaleStep;
timeCounter += milliSeconds;
}
keyframes.Add(new DiscreteMatrixKeyFrame(new Matrix(endScale, 0, 0, endScale, endPoint.X, endPoint.Y), KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(0))));
return keyframes;
}
In case of @pwlodek link will not reachable in the future and to not forget his awesome class, I copied into SO:
Sample usage for code behind:
I have implemented MatrixAnimation class which supports smooth translation, scaling and rotation animations. It also supports easing functions! Find it here
I like @LukeN answer. Works nice for simple translate/scale animations.
I added easing to this code (hand made though, not WPF native easing).
And then in
GetCurrentValue
doprogress = Sigmoid(progress)
orEaseIn(progress)
...One way I can think of is to convert the Matrix to a
TransformGroup
which containsScaleTransform
,RotateTransform
, and aTranslateTransform
, then animate these using normal animations, then once the animation is complete, create the Matrix back again from the values in each of the Transforms?Try this! As long as you aren't rotating/shearing it will do the trick.
Well, if you ask that in MSDN
http://msdn.microsoft.com/en-us/library/system.windows.media.animation.discretematrixkeyframe.aspx
you are getting the answer that DiscreteMatrixKeyFrame causes abrupt changes and that you should use LinearDoubleKeyFrame or SplineDoubleKeyFrame together with source code !
EDIT: Ah, I see, Matrix transformations supports only discrete transformations, so you have in fact a problem with jumps. So what I propose is using a RectAnimationUsingKeyFrames
Simply use a Linear or SplineRectKeyFrame, set the duration/Keytime and the values you need. To get the scale, you need to compute the end width/height and set it, but that shouldn't be a problem.