快速入門:擷取筆跡資料 (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 市集應用程式。
若要完成這個教學課程,您需要:
- 安裝 Windows 8
- 安裝 Microsoft Visual Studio。
- 取得開發人員授權。如需相關指示,請參閱使用 Visual Studio 2013 開發。
- 使用 JavaScript 建立您的第一個 Windows 市集應用程式。
- 若要了解 WinJS 物件與控制項,請檢閱快速入門:新增 WinJS 控制項與樣式。
指示
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 和它的子元素,您需要定義兩個變數。
使用 getElementById 將 canvas 元素的參考 "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 是用來起始筆跡擷取的事件。
在這個範例中,是使用 beginPath 和 moveTo 方法設定開始顯示筆跡資料的螢幕座標位置 (擷取筆跡和顯示筆跡是兩個獨立的動作)。然後,會將事件 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
來確保這個事件與相關的 pointerdown 和 pointermove 事件三者的 pointerId 相同。如果不是,就會略過輸入,而不會擷取任何筆跡資料。系統會呼叫 lineTo、stroke 以及 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 市集應用程式範例首頁的以下筆跡資料:
- 輸入:簡化的筆跡範例 - 本範例示範筆跡功能,例如儲存和載入筆跡、選取和刪除筆跡,以及透過手寫辨識將筆跡筆觸轉換成文字。
- 輸入:筆跡範例 - 除了輸入:簡化的筆跡範例示範的功能外,本範例還提供非常豐富的 UI,以及示範如何在辨識結果中搜尋資料。
相關主題
概念
參考
範例 (DOM)
範例 (Windows 市集應用程式 API)