Language: HTML | XAML

Quickstart: Capturing ink data (HTML)

Applies to Windows only

This Quickstart walks you through capturing ink data from an input digitizer.

Updates for Windows 8.1:  Windows 8.1 introduces a number of updates and improvements to the pointer input APIs. See API changes for Windows 8.1 for more info.

Objective: After completing this Quickstart you will understand how to use the ink platform to detect and capture input from a pointer device (mouse, pen/stylus, or touch) in a Windows Store app using JavaScript.

Prerequisites

We assume that you can create a basic Windows Store app using JavaScript that uses the Windows Library for JavaScript template.

To complete this tutorial, you need to:

Instructions

1. Set up a drawing surface in your UI

This sample uses an HTML 5 Canvas element as the ink drawing and rendering surface. A canvas is an HTML5 element that acts as a surface for dynamically drawing, rendering, and manipulating graphical elements in a Windows Store app using JavaScript.

Note  A Scalable Vector Graphics (SVG) object can also be used.

Here we declare a canvas element with an id of inkCanvas that you'll use to reference the element in JavaScript.


<body>
<div id="applicationTitle">Ink sample</div>
<div>
    <canvas id="inkCanvas"></canvas>
    <div>
        <button id="load">Load</button>
        <button id="save">Save</button>
        <button id="draw">Draw</button>
        <button id="select">Select</button>
        <button id="selectall">Select all</button>
        <button id="erase">Erase</button>
        <button id="eraseAll">Erase all</button>
        <button id="recognize" value="selected">Handwriting recognition</button>
    </div>
</div>
<div id="modeMessage"></div>
<div id="deviceMessage"></div>
<div id="statusMessage"></div>
</body>


2. Create an ink manager

Initialize an InkManager object that will process and manipulate the ink-related data obtained from the pointer input.


        // Create an ink manager.
        // InkManager is documented at http://go.microsoft.com/fwlink/?LinkID=260648.
        var inkManager = new Windows.UI.Input.Inking.InkManager();


3. Connect your app to the drawing surface

To work with the canvas and its child elements, you need to define two variables. The first is assigned a reference to the canvas element, inkCanvas, using getElementById and the other is assigned the drawing context (a 2-D surface in this case) for the canvas element by calling the getContext method.


// Obtain reference to the specified element.
function get(elementId)
{
    return document.getElementById(elementId);
}



inkCanvas = get("inkCanvas");
inkContext = inkCanvas.getContext("2d");


4. Attach input event listeners to the drawing surface

Using the reference to the canvas element, attach the following three PointerEvent listeners for pointer device input. (The event handler functions identified in this example are discussed later in this Quickstart.)

  • pointerdown fires when a user presses down on the digitizer surface with a pen or finger, or they click the left button on a mouse.
  • pointermove fires when the pointer associated with the pointerdown event moves across the canvas.
  • pointerup fires when the user lifts the pen or finger from the digitizer surface, or they release the left mouse button.

// Set up the handlers for input processing.
inkCanvas.addEventListener("pointerdown", onPointerDown, false);
inkCanvas.addEventListener("pointermove", onPointerMove, false);
inkCanvas.addEventListener("pointerup", onPointerUp, false);


5. Define the event handler functions

In this section, we define the event handlers to be associated with the event listeners that you added in the previous step.

  • pointerdown is the event that is used to initiate ink capture.

    In this example, the beginPath and moveTo methods are used to set the location in screen coordinates at which to begin displaying the ink data. (Capturing ink and displaying it are two separate actions.) The pointerdown event is then processed through inkManager by passing the pointer data (currentPoint) of the event to ProcessPointerDown.

    The global variable, penID, is used to store the pointerId of the input pointer associated with this event. We'll discuss the need for this later.

    Note  This example filters the pointer input (using the pointerType property) so that ink capture is performed for pen/stylus input and mouse input only when the left button is pressed. Touch input is reserved for manipulating the UI of the app.

    
        function getPointerDeviceType(pId)
        {
            var pointerDeviceType;
            var pointerPoint = Windows.UI.Input.PointerPoint.getCurrentPoint(pId);
            switch (pointerPoint.pointerDevice.pointerDeviceType)
            {
                case Windows.Devices.Input.PointerDeviceType.touch:
                    pointerDeviceType = "Touch";
                    break;
    
                case Windows.Devices.Input.PointerDeviceType.pen:
                    pointerDeviceType = "Pen";
                    break;
    
                case Windows.Devices.Input.PointerDeviceType.mouse:
                    pointerDeviceType = "Mouse";
                    break;
                default:
                    pointerDeviceType = "Undefined";
            }
            deviceMessage.innerText = pointerDeviceType;
            return pointerDeviceType;
        }
    
    
    
    
        // Occurs when the pointer (touch, pen, mouse) is detected by the canvas.
        // Each stroke begins with onPointerDown.
        function onPointerDown(evt)
        {
            // Get the device type for the pointer input.
            pointerDeviceType = getPointerDeviceType(evt.pointerId);
    
            // Process pen and mouse (with left button) only. Reserve touch for manipulations.
            if ((pointerDeviceType === "Pen") || ((pointerDeviceType === "Mouse") && (evt.button === 0)))
            {
                statusMessage.innerText = pointerDeviceType + " pointer down: Start stroke. "
    
                // Process one pointer at a time.
                if (pointerId === -1)
                {
                    var current = evt.currentPoint;
    
                    // Start drawing the stroke.
                    inkContext.beginPath();
                    inkContext.lineWidth = strokeWidth;
                    inkContext.strokeStyle = strokeColor;
    
                    inkContext.moveTo(current.position.x, current.position.y);
    
                    // Add current pointer to the ink manager (begin stroke).
                    inkManager.processPointerDown(current);
    
                    // The pointer id is used to restrict input processing to the current stroke.
                    pointerId = evt.pointerId;
                }
            }
            else
            {
                // Process touch input.
            }
        }
    
    
    
  • Ink data is captured when an pointermove event occurs.

    In the following example, the global variable, penId, is used to ensure that the pointerId for this event is identical to that of the associated pointerdown event. If it's not, the input is ignored and no ink data is captured. This is useful, for example, to filter input from a mouse that is moved accidentally during a pen stroke.

    The lineTo (using the RawPosition of the pointer as reported by the digitizer) and stroke methods are called to draw and display the ink data immediately as discrete line segments. (Capturing ink and displaying it are two separate actions.) The pointermove event is then processed through inkManager by passing the pointer data (currentPoint) of the event to ProcessPointerUpdate.

    
        // Mouse: Occurs when the pointer moves.
        // Pen/Touch: Occurs at a steady rate (approx. 100 messages/second) whether the pointer moves or not.
        function onPointerMove(evt)
        {
            // Process pen and mouse (with left button) only. Reserve touch for manipulations.
            if ((pointerDeviceType === "Pen") || ((pointerDeviceType === "Mouse") && (evt.button === -1)))
            {
                statusMessage.innerText = pointerDeviceType + " pointer move: Draw stroke as lines. "
                // The pointer Id is used to restrict input processing to the current stroke.
                // pointerId is updated in onPointerDown().
                if (evt.pointerId === pointerId)
                {
                    var current = evt.currentPoint;
    
                    // Draw stroke in real time.
                    inkContext.lineTo(current.rawPosition.x, current.rawPosition.y);
                    inkContext.stroke();
    
                    // Add current pointer to the ink manager (update stroke).
                    inkManager.processPointerUpdate(current);
                }
            }
            else
            {
                // Process touch input.
            }
        }
    
    
    
  • Ink data capture is complete when an pointerup event occurs.

    As in the previous example, this function uses the global variable, penId, to ensure that the pointerId for this event is identical to that of the associated pointerdown and pointermove events. If it's not, the input is ignored and no ink data is captured.

    The lineTo, stroke, and closePath methods are called to complete and close the path created in the handlePointerDown function. The pointerup event is then processed through inkManager by passing the pointer data (currentPoint) of the event to ProcessPointerUp.

    The renderAllStrokes function in this example is optional and is called to process the ink data and render the raw stroke segments on the canvas element as smooth curves (See How to How to render ink data).

    
    // Occurs when the pointer (touch, pen, mouse) is lifted from the canvas.
    // Each stroke ends with onPointerUp.
    function onPointerUp(evt)
    {
        // Process pen and mouse (with left button) only. Reserve touch for manipulations.
        if ((pointerDeviceType === "Pen") || ((pointerDeviceType === "Mouse") && (evt.button === 0)))
        {
            statusMessage.innerText = pointerDeviceType + " pointer up: Finish stroke. "
            if (evt.pointerId === pointerId) {
                // Add current pointer to the ink manager (end stroke).
                inkManager.processPointerUp(evt.currentPoint);
    
                // End live drawing.
                inkContext.closePath();
    
                // Render strokes using bezier curves.
                renderAllStrokes();
    
                // Reset pointer Id.
                pointerId = -1;
            }
        }
        else
        {
            // Process touch input.
        }
    }
    
    
    

See Related topics at the bottom of this page for links to more complex samples.

6. Complete example

See Capturing ink data complete code.

Summary

You now have a basic idea of how to capture ink data with your Windows Store app.

To see this code in action, build and run the following ink samples at the Windows Store app sample home page:

  • Input: simplified ink sample - this sample demonstrates ink functionality such as saving and loading ink, selecting and deleting ink, and converting ink strokes to text through handwriting recognition.
  • Input: ink sample - in addition to the functionality demonstrated in Input: simplified ink sample, this sample provides a richer UI and demonstrates how to search within recognition results.

Related topics

Conceptual
Responding to pen and stylus input
Reference
Windows.Devices.Input
Windows.UI.Core
Windows.UI.Input
Windows.UI.Input.Inking
Samples (DOM)
Input: DOM pointer event handling sample
Samples (Windows Store app APIs)
Input: Device capabilities sample
Input: Ink sample
Input: Simplified ink sample

 

 

Show:
© 2014 Microsoft