CHAPTER 12
As mentioned in the section on transformations, the entire view can be zoomed in or out using a simple Scale matrix. We will attach an event to the DirectXRenderer page that captures the mouse wheel (if the user is using a Windows 8 desktop), and allow the wheel to alter the zoom of our chart.
We already have a scale matrix being applied to our data, but its task is to flip the y-axis, so we are not drawing our chart upside down. To create a zoom capability, we can add an additional multiplication to the values in the parameters of this matrix. I have used two member floats to hold the zoom coefficients, and I have used #define to specify some limits, avoid zooming in too far, and to avoid division by zero errors that can occur when zooming out so far that it underflows the 32-bit floats. I've made the changes to the GraphRenderer.h file.
// Member variables for displaying FPS float m_timeDelta; // Time since last update call float m_timeTotal; // Total time of application // Member variables and constants for zooming #define MIN_ZOOM (0.01f) // Smallest zoom value is 1% #define MAX_ZOOM (100.0f) // Largest zoom value is 10,000% float m_zoomX; // The amount the x-axis is scaled by float m_zoomY; // The amount the y-axis is scaled by Microsoft::WRL::ComPtr<ID2D1SolidColorBrush> m_blackBrush; Microsoft::WRL::ComPtr<IDWriteTextFormat> m_textFormat; |
Initialize the floats we just defined in the constructor of the GraphRenderer in the GraphRenderer.cpp file.
GraphRenderer::GraphRenderer(): m_zoomX(1.0f), m_zoomY(1.0f) { |
Add a public, internal Zoom method prototype to the GraphRenderer class so we can call it from the DirectXPage class. I have placed this prototype directly after the GetLine method prototype.
internal: LineChart* GetLine() { return (LineChart*) m_lineChart; } // Zooming method void Zoom(float amount); |
The body for the function in the GraphRenderer.cpp file is very basic. We multiply the axis zooms by the parameter passes, and make sure they are within the limits MAX_ZOOM and MIN_ZOOM. Place the following code in the GraphRenderer.cpp file. It can be placed at the end after the Render method.
void GraphRenderer::Zoom(float amount) { // Multiply the zooms m_zoomX *= amount; m_zoomY *= amount; // Make sure the new zooms are still within the limits: if(m_zoomX < MIN_ZOOM) m_zoomX = MIN_ZOOM; else if(m_zoomX > MAX_ZOOM) m_zoomX = MAX_ZOOM; if(m_zoomY < MIN_ZOOM) m_zoomY = MIN_ZOOM; else if(m_zoomY > MAX_ZOOM) m_zoomY = MAX_ZOOM; } |
Next, we need to add an event handler to capture when the mouse wheel is changed. Open the DirectXPage.xaml file, find the line describing the SwapChainBackground panel, and add a PointerWheelChanged event to the XAML code.
<SwapChainBackgroundPanel x:Name="SwapChainPanel" PointerWheelChanged="OnPointerWheelChanged" PointerMoved="OnPointerMoved" PointerReleased="OnPointerReleased"> |
Right-click on the event name in the XAML code (I've used OnPointerWheelChanged) and click Navigate to Event Handler on the context menu which appears.

Visual Studio will write the event handler code for us, and take us directly there so we can specify what is to happen when the mouse wheel changes. All we need to do is check which way the wheel was rotated, and call the GraphRenderer::Zoom method with appropriate values. I have used 1.2f to zoom in and 0.8f to zoom out. These values mean the zooming will be fairly smooth at around 20%. Here is the code for the DirectXPage::OnPointerWheelChangedEvent.
void DirectXPage::OnPointerWheelChanged(Platform::Object^ sender, Windows::UI::Xaml::Input::PointerRoutedEventArgs^ e) { Windows::UI::Input::PointerPoint ^p = e->GetCurrentPoint(this); if(p->Properties->MouseWheelDelta > 0) m_renderer->Zoom(1.2f); else m_renderer->Zoom(0.8f); } |
Add the additional multiplication of our new axis zoom values to the scale matrix in the GraphRenderer::Render method.
// The scale matrix inverts the y-axis Matrix3x2F scale = Matrix3x2F::Scale( 1.0f * m_zoomX, // Multiply by x-axis zoom -1.0f * m_zoomY, // Flip and multiply by y-axis zoom D2D1::Point2F(0.0f, 0.0f)); |
Upon running the application, you should find that you can now zoom in and out of the chart using the mouse wheel. The Axes class is no longer rendering properly. First, the thickness of the axis lines is being altered by the scale matrix. When the user zooms in, the axis lines become thicker. When the user zooms out, they become thinner and disappear altogether. Figure 35 is a screenshot zoomed into the meeting point of the axes, the origin.

Zooming into Origin
The other problem is that when the chart is zoomed out, the axes’ lines no longer span the entire window. This destroys the illusion that they are infinite since the ends are clearly visible. See Figure 36.

Zooming Out
We can fix both of these problems by multiplying by the m_zoomX and m_zoomY in the m_axes::Render method call.
// The pan matrix still pans but it also adds the height of the screen Matrix3x2F panMatrix = Matrix3x2F::Translation(m_pan.X, m_pan.Y + m_d2dContext->GetSize().height); // Apply the scale first m_d2dContext->SetTransform(scale*panMatrix*m_orientationTransform2D); // Draw the axes m_axes->Render(m_d2dContext, m_pan.X, m_pan.Y, m_zoomX*1.0f, m_zoomY*-1.0f); // // Draw objects here // |
Upon making this change, you should be able to run the application and zoom in and out without altering the thickness of the axis lines, and without making their ends visible. See Figure 37.

Zooming with Scaling Axes