Reputation: 1668
I am using the scroll wheel to zoom in and out on an object using the following method:
void OnPreviewMouseWheel(object sender, MouseWheelEventArgs e)
{
lastMousePositionOnTarget = Mouse.GetPosition(grid);
double max = 255;
double min = .005;
var deltaScale = Math.Max(Math.Log(scaleTransform.ScaleX), double.Epsilon);
var delta = e.Delta > 0 ? Math.Max(e.Delta * deltaScale, .5) : Math.Min(e.Delta * deltaScale, -.5);
double newScale = Math.Max(Math.Min((delta / 250d) + scaleTransform.ScaleX, max), min);
scaleTransform.ScaleX = newScale;
scaleTransform.ScaleY = newScale;
System.Diagnostics.Debug.WriteLine(newScale);
e.Handled = true;
}
I want to have it zoom more slowly when it is zoomed in closer to the max, and faster when the number is closer to the minimum. What I currently have sort of works but not very well. How can I fix this to do what I want?
Upvotes: 1
Views: 404
Reputation: 1668
This is my final answer, I wouldn't have been able to come up with it if not for GEEF & Pawel so a big thanks to them for giving it their best shot.
void OnPreviewMouseWheel(object sender, MouseWheelEventArgs e)
{
double max = 255;
double min = .005;
double scaler = 4;
var deltaScale = Math.Min(Math.Max(scaler * scaleTransform.ScaleX / max, min),1) * Math.Sign(e.Delta);
double newScale = Math.Max(Math.Min(deltaScale + scaleTransform.ScaleX, max), min);
scaleTransform.ScaleX = newScale;
scaleTransform.ScaleY = newScale;
e.Handled = true;
}
I use a ratio of the current scale to the max to get the slope -- and don't allow it to go to fast (max 1) or too slow, min == the min scale. Works OK.
Upvotes: 2
Reputation: 853
First of all I would not use value e.Delta for calculations (sign is of course needed). This value is not very reliable - in my experience it was close to random noise. Instead use constant value or some counter like how many times in a row zoom in was invoked and how many times in a row zoom out was invoked.
So my first try (with constant value) would look somehow like this.
void OnPreviewMouseWheel(object sender, MouseWheelEventArgs e)
{
lastMousePositionOnTarget = Mouse.GetPosition(grid);
double max = 255;
double min = .005;
var deltaScale = Math.Max(Math.Log(scaleTransform.ScaleX), double.Epsilon);
var delta = e.Delta > 0 ? Math.Max(1 * deltaScale, .5) : Math.Min(1 * deltaScale, -.5);
double newScale = Math.Max(Math.Min((delta / 250d) + scaleTransform.ScaleX, max), min);
scaleTransform.ScaleX = newScale;
scaleTransform.ScaleY = newScale;
System.Diagnostics.Debug.WriteLine(newScale);
e.Handled = true;
}
Version with counters would look something like this.
private double counter=0;
private bool isZoomIn=true;
void OnPreviewMouseWheel(object sender, MouseWheelEventArgs e)
{
lastMousePositionOnTarget = Mouse.GetPosition(grid);
if( (e.Delta > 0 && isZoomIn) || (e.Delta < 0 && !isZoomIn))
IncreaseCounter(counter);//is another one in a row
else
counter=1;
isZoomIn = e.Delta > 0;//we set this flag for next time
double max = 255;
double min = .005;
var deltaScale = Math.Max(Math.Log(scaleTransform.ScaleX), double.Epsilon);
var delta = e.Delta > 0 ? Math.Max(counter * deltaScale, .5) : Math.Min(counter * deltaScale, -.5);
double newScale = Math.Max(Math.Min((delta / 250d) + scaleTransform.ScaleX, max), min);
scaleTransform.ScaleX = newScale;
scaleTransform.ScaleY = newScale;
System.Diagnostics.Debug.WriteLine(newScale);
e.Handled = true;
}
Note that I used pseudofunction IncreaceCounter instead of just incrementaion because you may want something else than just linear increase.
Upvotes: 1
Reputation: 1185
Assuming I understand this right, you want your deltaScale
to be large when zoomed in, but small when zoomed out. Thereby giving you fast zooming when close and slow zooming when far.
If scaletransform.ScaleX
gets smaller as you're zoomed in, try something like this:
var deltaScale = Math.Max(K * 1/(scaleTransform.ScaleX), double.Epsilon);
where K is just some const you mess around with until it feels right.
If scaletransform.ScaleX
gets larger as you're zoomed in, then try something like like your log, with a larger coefficient than 1:
var deltaScale = Math.Max(5*Math.Log(scaleTransform.ScaleX), double.Epsilon);
Upvotes: 4