In the previous article about UWP Inking platform as input for advanced scenarios, we have been able to
- Use the InkCanvas to accept pen/touch/mouse drawing
- Convert the InkStrokes to XAML Lines
We are about to see how we can easily integrate a zoom functionality in our inking application.
The ScrollViewer control does 'almost' all the magic
You can start from the code explained in the previous blog post or from a blank UWP application.
We use the InkCanvas, but this time, we incorporate it inside a ScrollViewer:
<ScrollViewer x:Name="rootScrollViewer"
ZoomMode="Enabled" MaxZoomFactor="5" MinZoomFactor="0.5"
HorizontalScrollMode="Auto" HorizontalScrollBarVisibility="Auto"
VerticalScrollMode="Auto" VerticalScrollBarVisibility="Auto">
<InkCanvas x:Name="inkCanvas" />
</ScrollViewer>
The important properties there are:
- ZoomMode="Enabled" in order to be able to zoom (That means also that we can block the zoom at some point of time in the app if needed)
- MinZoomFactor and MaxZoomFactor to control the minimum and maximum zoom level we want
- HorizontalScrollMode and VerticalScrollMode for giving the ability to move inside the content
You can use the mouse wheel to make vary the zoom level, but the touch is much more friendly and the best interaction to use for tablets or Surface devices. The C# code provided for the sample of the previous article was also using touch for drawing; For this scenario, we have to allow only the mouse and the pen to dedicate the touch for the zoom gesture:
public MainPage()
{
this.InitializeComponent();
// Initialize the InkCanvas
inkCanvas.InkPresenter.InputDeviceTypes =
Windows.UI.Core.CoreInputDeviceTypes.Mouse |
Windows.UI.Core.CoreInputDeviceTypes.Pen;
}
Improving the zoom experience
Look at the following interactions about our sample. Do you notice the two limitations?
- The zoom is not focused on the area on which we do the zoom gesture (or not focused on the mouse cursor if we use the mouse wheel). The zoom always focus on the origin of the window
- We cannot move inside the zoomed content in doing right/left or top/bottom gestures
This not really usable for professional drawing or content creation apps, no? Let's use an extremely small magic joker: No code, no work! Just using a Viewbox control :party_popper: :
<Grid>
<ScrollViewer x:Name="rootScrollViewer"
ZoomMode="Enabled" MaxZoomFactor="5" MinZoomFactor="0.5"
HorizontalScrollMode="Auto" HorizontalScrollBarVisibility="Auto"
VerticalScrollMode="Auto" VerticalScrollBarVisibility="Auto">
<Viewbox x:Name="imageViewbox">
<Grid>
<Image x:Name="floorplanImage"
Source="assets/SplashScreen.scale-200.png"/>
<InkCanvas x:Name="inkCanvas" />
</Grid>
</Viewbox>
</ScrollViewer>
</Grid>
With this code, you can zoom/unzoom focusing on a specific area and move freely inside the drawing:
This sample XAML code is the shortest possible for being able to read it with simplicity. Feel free to use some RowDefinition/ColumnDefinition with fixed Height/Width to really control the surface on which you allow the user to draw. Here, the Viewbox provides all the functionalities we need to adapt the content to the available space in the Grid.
Considerations for pen/touch/mouse inputs
You have seen in this sample that we do not accept touch for drawing on the InkCanvas. We use the pen or the mouse for inking. You understand that you will have to make a choice for input types. For example, you can consider the following options.
- Allow only pen and mouse for drawing if you are using a device with a pen like Microsoft Surface; Then you dedicate the touch for zoom/move or other interactions.
- Allow touch all the time for drawing if the device does not have a pen; You provide a button/switch in order to go to a "zoom/move" mode to be able to navigate inside the window's content.
Just remember that at any time, you can change the inputs allowed. Here is an example to enable or disable touch:
private void EnableTouchDrawing(bool enable)
{
if (enable)
{
inkCanvas.InkPresenter.InputDeviceTypes =
CoreInputDeviceTypes.Mouse |
CoreInputDeviceTypes.Touch |
CoreInputDeviceTypes.Pen;
}
else
{
inkCanvas.InkPresenter.InputDeviceTypes =
CoreInputDeviceTypes.Mouse |
CoreInputDeviceTypes.Pen;
}
}
Wrapping up
Ink strokes or XAML Shapes that you are displaying on Canvas are vectorial shapes. Implementing functionalities to be able to move the 'sheet' on which you draw or zoom for a better visualization/precision is almost mandatory for inking applications. Define a strategy for handling and switching inputs is also key to provide the best user experience.
--
As always, the source code of the sample is on GitHub - https://github.com/microsoft/Windows-AppConsult-Samples-UWP/
@sbovo for the AppConsult team.
Inking series' articles
This article is part of a series exploring concepts about inking and XAML Shapes. Here are all links:
-
Handling zoom in Inking applications ⇐ You are here
- Free your mind: Start manipulating XAML Shapes
References
- Source code of this article - https://github.com/microsoft/Windows-AppConsult-Samples-UWP/
- ScrollViewer control - https://docs.microsoft.com/en-us/uwp/api/windows.ui.xaml.controls.scrollviewer
- ScrollViewer UX Guidance - https://docs.microsoft.com/en-us/windows/uwp/design/controls-and-patterns/scroll-controls
- Viewbox - https://docs.microsoft.com/en-us/uwp/api/windows.ui.xaml.controls.viewbox