共用方式為


快速入門:擷取筆跡資料 (HTML)

[ 本文的目標對象是撰寫 Windows 執行階段 App 的 Windows 8.x 和 Windows Phone 8.x 開發人員。如果您正在開發適用於 Windows 10 的 App,請參閱 最新文件 ]

這個快速入門會引導您如何從輸入數位板擷取筆跡資料。

注意  本主題使用的程式碼來自功能完善的 Microsoft Visual Studio 2013 JavaScript 專案。雖然專案不提供下載,但可以在擷取筆跡資料的完整程式碼中找到完整的階層式樣式表 (CSS)、HTML 和 JavaScript 檔案。

 

Windows 8.1 的更新: Windows 8.1 對指標輸入 API 引入了數種更新及改進。如需詳細資訊,請參閱 Windows 8.1 的 API 變更

目標: 完成這個快速入門之後,您將了解如何在使用 JavaScript 的 Windows 市集應用程式中,使用筆跡平台來偵測及擷取來自指標裝置 (滑鼠、畫筆/手寫筆或觸控) 的輸入。

先決條件

我們假設您可以利用 JavaScript,以適用於 JavaScript 的 Windows Library 範本來建立基本的 Windows 市集應用程式。

若要完成這個教學課程,您需要:

指示

1. 在 Visual Studio 建立新的 "空白應用程式" 專案,並加入 HTML、CSS 和 JavaScript 檔案。

在這個範例中,我們有一個 HTML 檔案 ("InkPage.html")、一個 CSS 檔案 ("InkPage.css"),以及一個 JavaScript 檔案 ("InkPage.js")。

您可以在擷取筆跡資料的完整程式碼中找到完整的 CSS、HTML 和 JavaScript 檔案。

2. 在使用者介面中設定繪圖介面

這個範例使用 Canvas 元素當作筆跡繪圖及轉譯的表面。

canvas 是一個用來做為介面的 HTML5 元素,可以讓使用者在使用 JavaScript 的 Windows 市集應用程式中,進行動態繪圖、轉譯以及操作圖形元素。

注意  也可以使用可縮放向量圖形 (SVG) 物件。

 

在 HTML 檔案中,宣告 canvas 元素,然後給予它 "inkCanvas" 的 id。使用此 id 來參考 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>

3. 建立筆跡管理員

InkManager 物件會處理和操作從指標輸入取得的筆跡相關資料。

在 JavaScript 檔案中,建立筆跡管理員。這個範例的 InkManager 物件是全域物件。

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

4. 將應用程式連接至繪圖介面

若要使用 canvas 和它的子元素,您需要定義兩個變數。

使用 getElementByIdcanvas 元素的參考 "inkCanvas" 指派給第一個變數 (inkCanvas)。使用 getContext 方法將 canvas 元素 (在此例中為 2D 表面) 的繪製內容指派給第二個變數 (inkContext)。

// Obtain reference to the specified element.
function get(elementId)
{
    return document.getElementById(elementId);
}
inkCanvas = get("inkCanvas");
inkContext = inkCanvas.getContext("2d");

5. 定義事件處理函式

在這個區段中,我們定義了指標輸入所需的各種事件處理常式。這些必須與下一個步驟中新增的事件接聽程式建立關聯。

  • pointerdown 是用來起始筆跡擷取的事件。

    在這個範例中,是使用 beginPathmoveTo 方法設定開始顯示筆跡資料的螢幕座標位置 (擷取筆跡和顯示筆跡是兩個獨立的動作)。然後,會將事件 pointerdown 的指標資料 (currentPoint) 傳送給 ProcessPointerDown,透過 inkManager 處理該事件。

    全域變數 penID 是用來儲存與這個事件關聯之輸入指標的 pointerId。我們稍後會討論此需求。

    注意  這個範例會篩選指標輸入 (使用 pointerType 屬性),以執行畫筆/手寫筆輸入的筆跡擷取,以及滑鼠輸入 (僅限按下左鍵時) 的筆跡擷取。觸控輸入則保留用於操作應用程式的 UI。

     

        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.
            }
        }
    
  • 發生 pointermove 事件時,會擷取筆跡資料。

    在下列範例中,全域變數 penId 是用來確保這個事件與相關 pointerdown 事件兩者的 pointerId 會相同。如果不是,就會略過輸入,而不會擷取任何筆跡資料。例如,可以篩選出筆觸間不小心的滑鼠移動輸入,非常實用。

    系統會呼叫 lineTo (使用數位板回報之指標的 RawPosition) 和 stroke 方法,立即繪製筆跡資料並顯示成不同的線段。(擷取筆跡和顯示筆跡是兩個獨立的動作)。然後,會將事件 pointermove 的指標資料 (currentPoint) 傳送給 ProcessPointerUpdate,透過 inkManager 處理該事件。

        // 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.
            }
        }
    
  • 發生 pointerup 事件時,表示筆跡資料擷取完成。

    如同前述範例,這個函式使用全域變數 penId 來確保這個事件與相關的 pointerdownpointermove 事件三者的 pointerId 相同。如果不是,就會略過輸入,而不會擷取任何筆跡資料。

    系統會呼叫 lineTostroke 以及 closePath 方法,以完成並封閉 handlePointerDown 函式中建立的路徑。然後,會將事件 pointerup 的指標資料 (currentPoint) 傳送給 ProcessPointerUp,透過 inkManager 處理該事件。

    本範例中的 renderAllStrokes 函式是選用的,而且呼叫它之後,就可以處理筆跡資料以及在 canvas 元素上,將原始筆劃線段顯示成平滑的曲線 (請參閱如何轉譯筆跡資料)。

    // 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.
        }
    }
    

如需較複雜範例的連結,請參閱本頁面下方的相關主題。

6. 將輸入事件接聽程式連結至繪圖介面

使用 canvas 元素的參考,附加 PointerEvent 接聽程式並將它們與上個步驟定義的指標事件處理常式建立關聯。

  • 當使用者用手寫筆或手指按下數位板表面,或是按一下滑鼠左鍵時,會引發 pointerdown
  • 當與 pointerdown 事件關聯的指標在 canvas 上移動時,會引發 pointermove
  • 當使用者從數位板表面上提起手寫筆或手指,或是放開滑鼠右鍵時,會引發 pointerup
// Set up the handlers for input processing.
inkCanvas.addEventListener("pointerdown", onPointerDown, false);
inkCanvas.addEventListener("pointermove", onPointerMove, false);
inkCanvas.addEventListener("pointerup", onPointerUp, false);

摘要

您現在已經具備使用 Windows 市集應用程式擷取筆跡資料的基本概念。

如果想試試看本程式碼的執行結果,請建置並執行 Windows 市集應用程式範例首頁的以下筆跡資料:

相關主題

概念

回應畫筆和手寫筆輸入

參考

Windows.Devices.Input

Windows.UI.Core

Windows.UI.Input

Windows.UI.Input.Inking

範例 (DOM)

輸入:DOM 指標事件處理範例

範例 (Windows 市集應用程式 API)

輸入:裝置功能範例

輸入:筆跡範例

輸入:簡化的筆跡範例