using System;
using System.Windows;
namespace Bro.Common.ImageCanvas
{
public partial class ZoomAndPanControl
{
#region Public Methods
///
/// Do an animated zoom to view a specific scale and rectangle (in content coordinates).
///
public void AnimatedZoomTo(double newScale, Rect contentRect)
{
AnimatedZoomPointToViewportCenter(newScale, new Point(contentRect.X + (contentRect.Width / 2), contentRect.Y + (contentRect.Height / 2)),
delegate
{
//
// At the end of the animation, ensure that we are snapped to the specified content offset.
// Due to zooming in on the content focus point and rounding errors, the content offset may
// be slightly off what we want at the end of the animation and this bit of code corrects it.
//
ContentOffsetX = contentRect.X;
ContentOffsetY = contentRect.Y;
});
}
///
/// Do an animated zoom to the specified rectangle (in content coordinates).
///
public void AnimatedZoomTo(Rect contentRect)
{
var scaleX = ContentViewportWidth / contentRect.Width;
var scaleY = ContentViewportHeight / contentRect.Height;
var contentFitZoom = InternalViewportZoom * Math.Min(scaleX, scaleY);
AnimatedZoomPointToViewportCenter(contentFitZoom, new Point(contentRect.X + (contentRect.Width / 2), contentRect.Y + (contentRect.Height / 2)), null);
}
///
/// Instantly zoom to the specified rectangle (in content coordinates).
///
public void ZoomTo(Rect contentRect)
{
var scaleX = ContentViewportWidth / contentRect.Width;
var scaleY = ContentViewportHeight / contentRect.Height;
var newScale = InternalViewportZoom * Math.Min(scaleX, scaleY);
ZoomPointToViewportCenter(newScale, new Point(contentRect.X + (contentRect.Width / 2), contentRect.Y + (contentRect.Height / 2)));
}
///
/// Instantly center the view on the specified point (in content coordinates).
///
public void SnapContentOffsetTo(Point contentOffset)
{
AnimationHelper.CancelAnimation(this, ContentOffsetXProperty);
AnimationHelper.CancelAnimation(this, ContentOffsetYProperty);
ContentOffsetX = contentOffset.X;
ContentOffsetY = contentOffset.Y;
}
///
/// Instantly center the view on the specified point (in content coordinates).
///
public void SnapTo(Point contentPoint)
{
AnimationHelper.CancelAnimation(this, ContentOffsetXProperty);
AnimationHelper.CancelAnimation(this, ContentOffsetYProperty);
ContentOffsetX = contentPoint.X - (ContentViewportWidth / 2);
ContentOffsetY = contentPoint.Y - (ContentViewportHeight / 2);
}
///
/// Use animation to center the view on the specified point (in content coordinates).
///
public void AnimatedSnapTo(Point contentPoint)
{
var newX = contentPoint.X - (ContentViewportWidth / 2);
var newY = contentPoint.Y - (ContentViewportHeight / 2);
AnimationHelper.StartAnimation(this, ContentOffsetXProperty, newX, AnimationDuration, UseAnimations);
AnimationHelper.StartAnimation(this, ContentOffsetYProperty, newY, AnimationDuration, UseAnimations);
}
///
/// Zoom in/out centered on the specified point (in content coordinates).
/// The focus point is kept locked to it's on screen position (ala google maps).
///
public void AnimatedZoomAboutPoint(double newContentZoom, Point contentZoomFocus)
{
newContentZoom = Math.Min(Math.Max(newContentZoom, MinimumZoomClamped), MaximumZoom);
AnimationHelper.CancelAnimation(this, ContentZoomFocusXProperty);
AnimationHelper.CancelAnimation(this, ContentZoomFocusYProperty);
AnimationHelper.CancelAnimation(this, ViewportZoomFocusXProperty);
AnimationHelper.CancelAnimation(this, ViewportZoomFocusYProperty);
ContentZoomFocusX = contentZoomFocus.X;
ContentZoomFocusY = contentZoomFocus.Y;
ViewportZoomFocusX = (ContentZoomFocusX - ContentOffsetX) * InternalViewportZoom;
ViewportZoomFocusY = (ContentZoomFocusY - ContentOffsetY) * InternalViewportZoom;
//
// When zooming about a point make updates to ViewportZoom also update content offset.
//
_enableContentOffsetUpdateFromScale = true;
AnimationHelper.StartAnimation(this, InternalViewportZoomProperty, newContentZoom, AnimationDuration,
(sender, e) =>
{
_enableContentOffsetUpdateFromScale = false;
ResetViewportZoomFocus();
}, UseAnimations);
}
///
/// Zoom in/out centered on the specified point (in content coordinates).
/// The focus point is kept locked to it's on screen position (ala google maps).
///
public void ZoomAboutPoint(double newContentZoom, Point contentZoomFocus)
{
newContentZoom = Math.Min(Math.Max(newContentZoom, MinimumZoomClamped), MaximumZoom);
var screenSpaceZoomOffsetX = (contentZoomFocus.X - ContentOffsetX) * InternalViewportZoom;
var screenSpaceZoomOffsetY = (contentZoomFocus.Y - ContentOffsetY) * InternalViewportZoom;
var contentSpaceZoomOffsetX = screenSpaceZoomOffsetX / newContentZoom;
var contentSpaceZoomOffsetY = screenSpaceZoomOffsetY / newContentZoom;
var newContentOffsetX = contentZoomFocus.X - contentSpaceZoomOffsetX;
var newContentOffsetY = contentZoomFocus.Y - contentSpaceZoomOffsetY;
AnimationHelper.CancelAnimation(this, InternalViewportZoomProperty);
AnimationHelper.CancelAnimation(this, ContentOffsetXProperty);
AnimationHelper.CancelAnimation(this, ContentOffsetYProperty);
InternalViewportZoom = newContentZoom;
ContentOffsetX = newContentOffsetX;
ContentOffsetY = newContentOffsetY;
RaiseCanExecuteChanged();
}
///
/// Zoom in/out centered on the viewport center.
///
public void AnimatedZoomTo(double viewportZoom)
{
var xadjust = (ContentViewportWidth - _content.ActualWidth) * InternalViewportZoom / 2;
var yadjust = (ContentViewportHeight - _content.ActualHeight) * InternalViewportZoom / 2;
var zoomCenter = (InternalViewportZoom >= FillZoomValue)
? new Point(ContentOffsetX + (ContentViewportWidth / 2), ContentOffsetY + (ContentViewportHeight / 2))
: new Point(_content.ActualWidth / 2 - xadjust, _content.ActualHeight / 2 + yadjust);
AnimatedZoomAboutPoint(viewportZoom, zoomCenter);
}
///
/// Zoom in/out centered on the viewport center.
///
public void AnimatedZoomToCentered(double viewportZoom)
{
var zoomCenter = new Point(_content.ActualWidth / 2, _content.ActualHeight / 2); ;
AnimatedZoomAboutPoint(viewportZoom, zoomCenter);
}
///
/// Zoom in/out centered on the viewport center.
///
public void ZoomTo(double viewportZoom)
{
var zoomCenter = new Point(ContentOffsetX + (ContentViewportWidth / 2), ContentOffsetY + (ContentViewportHeight / 2));
ZoomAboutPoint(viewportZoom, zoomCenter);
}
///
/// Do animation that scales the content so that it fits completely in the control.
///
public void AnimatedScaleToFit()
{
if (_content == null)
throw new ApplicationException("PART_Content was not found in the ZoomAndPanControl visual template!");
ZoomTo(FillZoomValue);
//AnimatedZoomTo(new Rect(0, 0, _content.ActualWidth, _content.ActualHeight));
}
///
/// Instantly scale the content so that it fits completely in the control.
///
public void ScaleToFit()
{
if (_content == null)
throw new ApplicationException("PART_Content was not found in the ZoomAndPanControl visual template!");
ZoomTo(FitZoomValue);
//ZoomTo(new Rect(0, 0, _content.ActualWidth, _content.ActualHeight));
}
///
/// Zoom to the specified scale and move the specified focus point to the center of the viewport.
///
private void AnimatedZoomPointToViewportCenter(double newContentZoom, Point contentZoomFocus, EventHandler callback)
{
newContentZoom = Math.Min(Math.Max(newContentZoom, MinimumZoomClamped), MaximumZoom);
AnimationHelper.CancelAnimation(this, ContentZoomFocusXProperty);
AnimationHelper.CancelAnimation(this, ContentZoomFocusYProperty);
AnimationHelper.CancelAnimation(this, ViewportZoomFocusXProperty);
AnimationHelper.CancelAnimation(this, ViewportZoomFocusYProperty);
ContentZoomFocusX = contentZoomFocus.X;
ContentZoomFocusY = contentZoomFocus.Y;
ViewportZoomFocusX = (ContentZoomFocusX - ContentOffsetX) * InternalViewportZoom;
ViewportZoomFocusY = (ContentZoomFocusY - ContentOffsetY) * InternalViewportZoom;
//
// When zooming about a point make updates to ViewportZoom also update content offset.
//
_enableContentOffsetUpdateFromScale = true;
AnimationHelper.StartAnimation(this, InternalViewportZoomProperty, newContentZoom, AnimationDuration,
delegate (object sender, EventArgs e)
{
_enableContentOffsetUpdateFromScale = false;
callback?.Invoke(this, EventArgs.Empty);
}, UseAnimations);
AnimationHelper.StartAnimation(this, ViewportZoomFocusXProperty, ViewportWidth / 2, AnimationDuration, UseAnimations);
AnimationHelper.StartAnimation(this, ViewportZoomFocusYProperty, ViewportHeight / 2, AnimationDuration, UseAnimations);
}
///
/// Zoom to the specified scale and move the specified focus point to the center of the viewport.
///
private void ZoomPointToViewportCenter(double newContentZoom, Point contentZoomFocus)
{
newContentZoom = Math.Min(Math.Max(newContentZoom, MinimumZoomClamped), MaximumZoom);
AnimationHelper.CancelAnimation(this, InternalViewportZoomProperty);
AnimationHelper.CancelAnimation(this, ContentOffsetXProperty);
AnimationHelper.CancelAnimation(this, ContentOffsetYProperty);
InternalViewportZoom = newContentZoom;
ContentOffsetX = contentZoomFocus.X - (ContentViewportWidth / 2);
ContentOffsetY = contentZoomFocus.Y - (ContentViewportHeight / 2);
}
#endregion
}
}