- Fixed the memory leak issue by getting rid of the Storyboard after it has achieved its purpose
- Used a single storyboard to animate multiple images. I don't know if this is better than multiple storyboards (one for each image) so it would be nice to hear some opinions
Code to animate the image
private void AnimateImage(MultiScaleSubImage currentImage, Point futurePosition)
{
// Create Keyframe
SplinePointKeyFrame endKeyframe = new SplinePointKeyFrame();
endKeyframe.Value = futurePosition;
endKeyframe.KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromSeconds(1));
KeySpline ks = new KeySpline();
ks.ControlPoint1 = new Point(0, 1);
ks.ControlPoint2 = new Point(1, 1);
endKeyframe.KeySpline = ks;
// Create Animation
PointAnimationUsingKeyFrames moveAnimation = new PointAnimationUsingKeyFrames();
moveAnimation.KeyFrames.Add(endKeyframe);
Storyboard.SetTarget(moveAnimation, currentImage);
Storyboard.SetTargetProperty(moveAnimation, "ViewportOrigin");
// Add the animation to the Storyboard
_moveStoryboard.Children.Add(moveAnimation);
}
Code to invoke the animation - I decided against animating the hidden images (like Hard Rock) since my goal is to work with large amount of images and I didn't want to incur the additional performance overhead
private Storyboard _moveStoryboard;
public void InitStoryboard()
{
_moveStoryboard = new Storyboard();
msi.Resources.Add(_moveStoryboard);
_moveStoryboard.Completed += (sender, e) => msi.Resources.Remove((Storyboard)sender);
}
public void ArrangeImages()
{
InitStoryboard();
...
// Then display the displayable images to scale
for (int i=0; i<_imagesToShow.Count; i++) {
double X = rows[subImages[i].RowNum].CalcX(subImages[i].ColNum);
double Y = margin;
for (int j=0; j<subImages[i].RowNum; j++)
Y += spaceBetweenImages + rows[j].Height;
_imagesToShow[i].ViewportWidth = containerAspectRatio / subImages[i].Width;
AnimateImage(_imagesToShow[i], new Point(-(X / subImages[i].Width), -(Y / subImages[i].Width)));
_imagesToShow[i].Opacity = 1.0;
}
// Play Storyboard
_moveStoryboard.Begin();
}
Code to Randomize the images. The code for the RandomizeListOfImages is lifted from the Expression Team blog
buttonRandomize.Click += (sender, e) => RandomizeAndArrange();
private void RandomizeAndArrange()
{
_imagesToShow = RandomizedListOfImages();
ArrangeImages();
}
private List<MultiScaleSubImage> RandomizedListOfImages()
{
List<MultiScaleSubImage> imageList = new List<MultiScaleSubImage>();
Random ranNum = new Random();
// Store List of Images
_imagesToShow.ForEach(subImage => imageList.Add(subImage));
// Randomize Image List
int numImages = imageList.Count;
for(int i=0; i<numImages; i++) {
MultiScaleSubImage tempImage = imageList[i];
imageList.RemoveAt(i);
int ranNumSelect = ranNum.Next(imageList.Count);
imageList.Insert(ranNumSelect, tempImage);
}
return imageList;
}
6 comments:
This is great stuff. Is there any chance you can post the source code for the complete project?
I am hoping you can help me out...
I am trying to do a Deep Zoom with thumbnails on the side, and when you click on the thumbnails, it zooms in on that picture in the deep zoom. However I want the picture to basically fill up the deep zoom screen. I am having the issue of it not centering correctly, so what I have it do is center AFTER the zooming is done, but it isn't as smooth as I want it to be, and takes longer than I want it to be, do you have any ideas?
You can see an example here:
http://people.rit.edu/~jld4460/Silverlight/DeepZoomGalleryTestPage.html
Thanks!
-Jess
P.S your blog has been very helpful !
Jessica,
I see what you mean. I will look into it when I get some time, hopefully sometime this week. In the meantime, if you do find a solution, please post it here.
Thanks
Wilfred
Jessica,
Tried this and it seems to work fine. Let me know if it works for you.
public void ZoomAndCenterImage(int subImageIndex, double zoomFactor)
{
Rect subImageRect = GetSubImageRect(subImageIndex);
DisplaySubImageCentered(subImageIndex);
msi.ZoomAboutLogicalPoint(zoomFactor, (subImageRect.Left+subImageRect.Right)/2, (subImageRect.Top+subImageRect.Bottom)/2);
}
Yes! That worked perfectly, thank you. I also added a line of code so that no matter what the zoom level is at, it will always zoom in to the max zoom level:
double zoomFactor = _maxZoomIn / _currentTotalZoom;
ZoomAndCenterImage(img.returnNum(), zoomFactor);
public void ZoomAndCenterImage(int subImageIndex, double zoomFactor)
{
if ((_currentTotalZoom * zoomFactor) < MaxZoomOut ||
(_currentTotalZoom * zoomFactor) > MaxZoomIn)
return;
Rect subImageRect = GetSubImageRect(subImageIndex);
DisplaySubImageCentered(subImageIndex);
msi.ZoomAboutLogicalPoint(zoomFactor, (subImageRect.Left + subImageRect.Right) / 2, (subImageRect.Top + subImageRect.Bottom) / 2);
_currentTotalZoom *= zoomFactor;
}
Thanks again!
-Jessica
Jessica,
Thanks for sharing your code. This works great in a scenario where all images are of the same dimensions.
I am working with different size images and hence needed a more generic solution. I figured out how to do this and decided to dedicate a post to it, since there might be others who might want a similar solution.
Thanks
Wilfred
Post a Comment