How to center image in MultiScaleImage
Found the function which position the image(s) in the multiscaleimage... but I'm not sure how to get the actual image width (for single or multiple) and change the _msi.ViewportOrigin x param based on that.
There are 2 lines which affect the image position... one is
_msi.ViewportOrigin = new Point(0, 0);
and the other is:
//if (layout == ImageLayout.Vertical) //single column
// X = ((_msi.ViewportWidth - subImages[i].Width) / 2);
I'm ok to change either of which.. but need some help with that.
The code where the above snippets are taken from:
private void ArrangeImagesTile(ImageLayout layout)
{
if (_msi.ActualWidth <= 0 || _msi.ActualHeight <= 0)
return;
_lastMousePos = new Point(0, 0);
_msi.ViewportOrigin = new Point(0, 0);
_msi.ViewportWidth = 1;
Storyboard moveStoryboard = initStoryboard();
double containerAspectRatio = this._msi.ActualWidth / this._msi.ActualHeigh开发者_StackOverflow社区t;
double spaceBetweenImages = 0.005;
List<SubImage> subImages = new List<SubImage>();
_imagesToShow.ForEach(subImage => subImages.Add(new SubImage(subImage)));
// Capture the total width of all images
double totalImagesWidth = 0.0;
subImages.ForEach(subImage => totalImagesWidth += subImage.Width);
// Calculate the total number of rows required to display all the images
int numRows = 1; // layout - horizontal
if (layout == ImageLayout.One)
numRows = 1; //(int)Math.Sqrt((totalImagesWidth / containerAspectRatio) + 1);
else if (layout == ImageLayout.Four) //.Vertical)
numRows = 2; // subImages.Count;
// Assign images to each row
List<Row> rows = new List<Row>(numRows);
for (int i = 0; i < numRows; i++)
rows.Add(new Row(spaceBetweenImages));
double widthPerRow = totalImagesWidth / numRows;
double imagesWidth = 0;
// Separate the images into rows. The total width of all images in a row should not exceed widthPerRow
for (int i = 0, j = 0; i < numRows; i++, imagesWidth = 0)
{
while (imagesWidth < widthPerRow && j < subImages.Count)
{
rows[i].AddImage(subImages[j]);
subImages[j].RowNum = i;
imagesWidth += subImages[j++].Width;
}
}
// At this point in time the subimage height is 1
// If we assume that the total height is also 1 we need to scale the subimages to fit within a total height of 1
// If the total height is 1, the total width is aspectRatio. Hence (aspectRatio)/(total width of all images in a row) is the scaling factor.
// Added later: take into account spacing between images
rows.ForEach(Row => Row.Scale(containerAspectRatio));
// Calculate the total height, with space between images, of the images across all rows
// Also adjust the colNum for each image
double totalImagesHeight = (numRows - 1) * spaceBetweenImages;
rows.ForEach(Row => totalImagesHeight += Row.Height);
// The totalImagesHeight should not exceed 1.
// if it does, we need to scale all images by a factor of (1 / totalImagesHeight)
if (totalImagesHeight > 1)
{
subImages.ForEach(subImage => subImage.Scale(1 / (totalImagesHeight + spaceBetweenImages)));
totalImagesHeight = (numRows - 1) * spaceBetweenImages;
rows.ForEach(Row => totalImagesHeight += Row.Height);
}
// Calculate the top and bottom margin
double margin = (1 - totalImagesHeight) / 2;
if (_imagesToHide != null)
{
// First hide all the images that should not be displayed
_imagesToHide.ForEach(subImage =>
{
//Do not use opacity for this as it slows down the animation after a few arranges
subImage.ViewportWidth = 0;
});
}
// 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);
//if (layout == ImageLayout.Vertical) //single column
// X = ((_msi.ViewportWidth - subImages[i].Width) / 2);
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(moveStoryboard, _imagesToShow[i], new Point(-(X / subImages[i].Width), -(Y / subImages[i].Width))); // for animation, use this statement instead of the next one
_imagesToShow[i].Opacity = 1.0;
}
if (ImagesRearranged != null)
{
ImagesRearranged(this, EventArgs.Empty);
}
// Play Storyboard
moveStoryboard.Begin();
}
Previous Code Reference which goes to the function above when opening the image in msi:
Backend:
private void RootMultiScaleImage_Loaded(object sender, RoutedEventArgs e)
{
// Use the mid point of the image to zoom from
var xx = (MultiScaleImage) sender;
xx.ZoomAboutLogicalPoint(1, 0.5, 0.5);
}
Front-end:
<ControlTemplate x:Key="DeepZoomerControlTemplate" TargetType="zoom:DeepZoomer">
<Grid>
<MultiScaleImage x:Name="RootMultiScaleImage" Loaded="RootMultiScaleImage_Loaded" />
I agree it's rather confusing, however playing with viewPortWidth and viewPortOrigin you should be able to do it.
First you have to check if ViewPortWidth is > 1 (this means your image is currently "narrower" with respect to is parent. If this is not the case, you can check if ViewPortHeight > 1 (the image is shorter and you have to center vertically).
Assuming you found that ViewPortWidth is > 1, i.e. you have empty space on the right and want to center the viewport horizontally, you set a negative value to ViewPortOrigin to move the viewport to the right.
Example: ViewPortWidth is 3. This means your image is filling 1/3 of the available width. You have to move it to the right one time its width. ViewportOrigin becomes (-1, 0).
Another example: ViewPortWidth is 4. Your image is filling 1/4 of the available width. If you set ViewPortOrigin to -1.5 the viewport is actually moved 1.5 times its width to the right and actually goes to the center.
The general formula* should be ViewPortOrigin.x = - (ViewPortWidth - 1) / 2
I suggest you look at the doc and draw some sketches on paper until you figure it out.
精彩评论