一次开发过程中遇到一个需求,需要以鼠标为中心点,利用鼠标滚轮对图片进行缩放。网上的资源还是很多的:
参考了如下一篇文档的缩放算法:尊重作者原创,附原文地址:
https://www.cnblogs.com/kongxianghai/archive/2012/06/26/2562966.html
给这篇blog点赞,实现的效果不错!
private void Window_MouseWheel(object sender, MouseWheelEventArgs e) {
if (e.Delta == 0) return;
double d = e.Delta / Math.Abs(e.Delta);
if (_scaleValue < 0.5 && d < 0) return;
if (_scaleValue > 20 && d > 0) return;
_scaleValue += d * .2;
//获取鼠标在缩放之前的目标上的位置
Point targetZoomFocus1 = e.GetPosition(target);
//获取目标在缩放之前的Rect
//Rect beforeScaleRect =
// target.RenderTransform.TransformBounds(new Rect(target.RenderSize));
//缩放的中心点为左上角(0,0)
scaler.ScaleX = _scaleValue;
scaler.ScaleY = _scaleValue;
//获取鼠标在缩放之后的目标上的位置
Point targetZoomFocus2 = new Point(targetZoomFocus1.X * (1 + d * .2), targetZoomFocus1.Y * (1 + d * .2));
//获取目标在缩放之后的Rect
Rect afterScaleRect = target.RenderTransform.TransformBounds(new Rect(target.RenderSize));
//算的缩放前后鼠标的位置间的差
Vector v = targetZoomFocus2 - targetZoomFocus1;
if (afterScaleRect.Size.Width <= _viewportSize.Width) {
//缩放之后居中
double widthHalfDelta = (Container.RenderSize.Width - afterScaleRect.Width) / 2;
translater.X = widthHalfDelta;
}
else if (afterScaleRect.X - v.X > 0) {
//目标左边界与可视左边界对齐
translater.X = 0;
}
else if (afterScaleRect.X + afterScaleRect.Width - v.X < Container.RenderSize.Width) {
//目标右边界与可视右边界对齐
translater.X = Container.RenderSize.Width - afterScaleRect.Size.Width;
}
else {
//减去鼠标点在缩放前后之间的差值,实际上就是以鼠标点为中心进行缩放
translater.X -= v.X;
}
if (afterScaleRect.Size.Height <= _viewportSize.Height) {
double heightHalfDleta = (Container.RenderSize.Height - afterScaleRect.Height) / 2;
translater.Y = heightHalfDleta;
}
else if (afterScaleRect.Y - v.Y > 0) {
translater.Y = 0;
}
else if (afterScaleRect.Y + afterScaleRect.Height - v.Y < Container.RenderSize.Height) {
translater.Y = Container.RenderSize.Height - afterScaleRect.Size.Height;
}
else {
translater.Y -= v.Y;
}
}
实际在项目运用中用此方法碰见了2个问题:
问题1:缩放时放大的元素脱离了布局,缩放超过了父容器的限制,遮挡了界面中其他的布局,此问题多半是布局造成的bug,调整先后顺序可以解决此问题,
问题2:
//获取鼠标在缩放之后的目标上的位置
Point targetZoomFocus2 = new Point(targetZoomFocus1.X * (1 + d * .2), targetZoomFocus1.Y * (1 + d * .2));
bug发现 targetZoomFocus2 的x,y 坐标永远是(0,0)
解决此问题的办法是:
_scaleValue += d * .2;
Point targetZoomFocus1 = e.GetPosition(this);
//ScaleTransform scaler = new ScaleTransform(_scaleValue,_scaleValue,0,0);
Matrix mt = translater.Value;
mt.M11 = _scaleValue;
mt.M22 = _scaleValue;
this.RenderTransform.Matrix = mt;
bug出现前的代码为:
_scaleValue += d * .2;
Point targetZoomFocus1 = e.GetPosition(this);
ScaleTransform scaler = new ScaleTransform(_scaleValue,_scaleValue,0,0);
**this.RenderTransform.Matrix = scaler.Value;**
Point targetZoomFocus2 = new Point(targetZoomFocus1.X * (1 + d * .2), targetZoomFocus1.Y * (1 + d * .2));
//Point pt= (this.Parent as Canvas).TransformToAncestor(App.Current.MainWindow).Transform(new Point(0, 0));
Rect afterScaleRect = this.RenderTransform.TransformBounds(new Rect(this.RenderSize));
即在缩放前需要对平移变化也要赋值,具体问题本质还不是特别清楚,但问题经过调试,通过对代码改进解决了缩放的问题。记录于此,供日后参阅方便!