Friday, April 3, 2009

How to Zoom In and Out with a Mouse Wheel in Silverlight

A known fact about Silverlight is that it does not currently listen to the mouse wheel; there are no events in XAML that return its status. The following code will allow you to monitor the mouse wheel by using events passed by the browser, and zoom in and out when the mouse wheel is turned.

The first section of code sets up Silverlight to listen to the browser for the OnMouseWheel event:


private void OnMouseWheel(object sender, HtmlEventArgs args)
{
HtmlPage.Window.AttachEvent("DOMMouseScroll", OnMouseWheel);
HtmlPage.Window.AttachEvent("onmousewheel", OnMouseWheel);
HtmlPage.Document.AttachEvent("onmousewheel", OnMouseWheel);
}


This next piece of code gets the delta for the mouse wheel, positive or negative. We don't care how much the wheel has turned, only if it was up/forward/positive or down/back/negative, translating this into a +1 or -1:


private void OnMouseWheel(object sender, HtmlEventArgs args)
{
double mouseDelta = 0;
ScriptObject e = args.EventObject;

// Mozilla and Safari
if (e.GetProperty("detail") != null)
{
mouseDelta = ((double)e.GetProperty("detail"));
}
// IE and Opera
else if (e.GetProperty("wheelDelta") != null)
mouseDelta = ((double)e.GetProperty("wheelDelta"));

double dSign = Math.Sign(mouseDelta);
//now change the scale of the activePage xaml element
//this is typically a canvas this is a child of the local root
ChangeScale(ActivePage, dSign);
}


The last piece of code uses this number to calculate and apply a scaling factor to the target XAML element.


private void ChangeScale(FrameworkElement oTarget, double dSign)

{
if(!(oTarget.RenderTransform is TransformGroup))
oTarget.RenderTransform = new TransformGroup();

TransformGroup oGroup = oTarget.RenderTransform as TransformGroup;
if (oGroup.Children.Count == 0)
{
oGroup.Children.Add(new ScaleTransform());
oTarget.RenderTransformOrigin = new Point(.5, .5);
}

m_dCurrentZoom += 0.1 * dSign;

ScaleTransform oScale = oGroup.Children[0] as ScaleTransform;
oScale.ScaleX = m_dCurrentZoom;
oScale.ScaleY = m_dCurrentZoom;
}


This code sets the focal point of the zoom to the center (.5, .5) of the XAML element that is passed in the function, typically a canvas. If you wanted to zoom in on something that is drawn on the canvas, like a shape or a button, you would need to calculate where that element is relative to the total width and height of the canvas (e.g. 30% of x, 70% of y = .3, .7).

No comments: