靜態手勢的完整程式碼 (HTML)
[ 本文的目標對象是撰寫 Windows 執行階段 App 的 Windows 8.x 和 Windows Phone 8.x 開發人員。如果您正在開發適用於 Windows 10 的 App,請參閱 最新文件 ]
這個主題提供快速入門:靜態手勢中使用的完整程式碼範例。
這個主題包含這些小節:
- 技術
- 需求
- 檢視程式碼 ()
下載位置
此範例不提供下載。
技術
程式語言 | C++ |
程式設計模型 | Windows Runtime |
需求
最低支援的用戶端 | Windows 8 |
最低支援的伺服器 | Windows Server 2012 |
最低需求的 SDK | Microsoft Visual Studio Express 2012 for Windows 8 |
檢視程式碼 ()
default.css
body {
/*
A manipulation-blocking element is defined as an element that explicitly
blocks direct manipulation via declarative markup, and instead fires gesture
events such as MSGestureStart, MSGestureChange, and MSGestureEnd.
*/
overflow: hidden;
position: absolute;
font-family: 'Segoe UI';
font-size: small;
touch-action: none;
background-color: black;
}
div #targetContainer {
position: relative;
height: fill-available;
width: fill-available;
}
div #inputBox {
position: relative;
width: 640px;
height: 640px;
color: black;
overflow: hidden;
background-color: darkgrey;
margin: 0px;
padding: 0px;
border-width: 1px;
border-color: white;
border-style: solid;
}
div #instructions {
position: relative;
width: 100%;
height: fit-content;
color: black;
background-color: white;
visibility: visible;
}
div #questions {
position: relative;
width: 100%;
height: fit-content;
color: white;
background-color: black;
visibility: visible;
}
div #answers {
position: relative;
width: 100%;
height: fit-content;
color: white;
background-color: black;
visibility: visible;
}
div #clues {
position: relative;
width: 100%;
height: 100%;
background-color: DimGray;
}
div #timerBox {
background-color: red;
color: black;
position: absolute;
width: 100%;
bottom: 0px;
height: 20px;
text-align: center;
}
div #answerFloater {
position: absolute;
visibility: hidden;
top: 0px;
left: 0px;
background-color: blue;
}
div #eventLog {
font-size: xx-small;
position: absolute;
left: 0px;
top: 0px;
width: 640px;
height: 50px;
overflow: auto;
overflow-style: auto;
}
default.html
<html>
<head>
<meta charset="utf-8" />
<title>js</title>
<!-- WinJS references -->
<link href="//Microsoft.WinJS.2.0/css/ui-dark.css" rel="stylesheet" />
<script src="//Microsoft.WinJS.2.0/js/base.js"></script>
<script src="//Microsoft.WinJS.2.0/js/ui.js"></script>
<!-- BasicGesture references -->
<link href="/css/default.css" rel="stylesheet" />
<script src="/js/default.js"></script>
<script src="/js/inputprocessor.js"></script>
<script src="/js/datamanager.js"></script>
<script src="/js/cluemanager.js"></script>
</head>
<body>
<div class="TargetContainer" id="targetContainer">
<div id="inputBox">
<div id="instructions">Tap gray box below: Double tap to start questions, tap for next question, press and hold to show clues.</div>
<div id="questions"> </div>
<div id="answers">
<label for="answer">Answer:</label>
<input type="text" id="answer" maxlength="30" size="30" style="z-index:1" />
<button id="submit">Submit</button>
<button id="stumped">Stumped</button>
</div>
<div id="clues">
</div>
<div id="timerBox"></div>
</div>
<div id="eventLog"></div>
<div id="answerFloater">
<p>Show answer?</p>
<button id="yes">Yes</button>
<button id="no">No</button>
</div>
</div>
</body>
</html>
default.js
"use strict";
var _applicationData;
var _localSettings;
var _data;
var _inputBox;
var _instructions;
var _answers;
var _questions;
var _clues;
var _eventLog;
var _floater;
function initialize() {
// Get our UI objects.
_inputBox = document.getElementById("inputBox");
_instructions = document.getElementById("instructions");
_questions = document.getElementById("questions");
_answers = document.getElementById("answers");
_clues = document.getElementById("clues");
_eventLog = document.getElementById("eventLog");
_floater = document.getElementById("answerFloater");
// Configure the target.
setTarget();
}
// Configure the interaction target.
function setTarget() {
// Set the position of the input target.
var inputLeft = (window.innerWidth - _inputBox.clientWidth) / 2.0;
var inputTop = (window.innerHeight - _inputBox.clientHeight) / 2.0;
var transform = (new MSCSSMatrix()).translate(inputLeft, inputTop);
_inputBox.style.msTransform = transform;
// Set the position of the event log.
transform = (new MSCSSMatrix()).translate(inputLeft, inputTop + _inputBox.clientHeight);
_eventLog.style.msTransform = transform;
// Associate interaction target with our input manager.
// Scope input to clue area only.
_clues.inputProcessor = new QandA.InputProcessor(_clues);
}
(function () {
document.addEventListener("DOMContentLoaded", initialize, false);
})();
inputprocessor.js
// Handle gesture recognition for this sample.
(function () {
"use strict";
var InputProcessor = WinJS.Class.define(
// Constructor
function InputProcessor_ctor(target) {
this._questionsStarted = false;
this._tapCount = 0;
// Create a clue manager.
this._clueManager = new QandA.ClueManager();
// Load xml data from file into local app settings.
var _dataObject = new QandA.DataManager();
_data = _dataObject.getData();
this._questionTotal = _data.selectNodes("questions/question").length;
this._doubleTap = false;
this._startTime;
this._intervalTimerId;
// Initialize the gesture recognizer.
this.gr = new Windows.UI.Input.GestureRecognizer();
// Turn off visual feedback for gestures.
// Visual feedback for pointer input is still displayed.
this.gr.showGestureFeedback = false;
// Configure gesture recognizer to process the following:
// double tap - start questions and timer.
// tap - move to next question.
// right tap - show answer.
// hold and hold with mouse - start clues.
this.gr.gestureSettings =
Windows.UI.Input.GestureSettings.tap |
Windows.UI.Input.GestureSettings.doubleTap |
Windows.UI.Input.GestureSettings.rightTap |
Windows.UI.Input.GestureSettings.hold |
Windows.UI.Input.GestureSettings.holdWithMouse;
//
// Set event listeners.
//
// Get our context.
var that = this;
// Register event listeners for these gestures.
this.gr.addEventListener('tapped', tappedHandler);
this.gr.addEventListener("holding", holdingHandler);
this.gr.addEventListener("righttapped", rightTappedHandler);
// The following functions are registered to handle DOM pointer events
//
// Basic pointer handling to highlight input area.
target.addEventListener("pointerover", function onPointerOver(eventInfo) {
eventInfo.stopImmediatePropagation = true;
_eventLog.innerText += "pointer over || ";
eventInfo.target.style.backgroundColor = "DarkGray";
}, false);
// Basic pointer handling to highlight input area.
target.addEventListener("pointerout", function onPointerOut(eventInfo) {
eventInfo.stopImmediatePropagation = true;
_eventLog.innerText += "pointer out || ";
eventInfo.target.style.backgroundColor = "DimGray";
}, false);
// Handle the pointer move event.
// The holding gesture is routed through this event.
// If pointer move is not handled, holding will not fire.
target.addEventListener("pointermove", function onPointerMove(eventInfo) {
eventInfo.stopImmediatePropagation = true;
// Get intermediate PointerPoints
var pps = eventInfo.intermediatePoints;
// Pass the array of PointerPoints to the gesture recognizer.
that.gr.processMoveEvents(pps);
}, false);
// Handle the pointer down event.
target.addEventListener("pointerdown", function onPointerDown(eventInfo) {
eventInfo.stopImmediatePropagation = true;
_eventLog.innerText += "pointer down || ";
// Hide the floater if visible.
_floater.style.visibility = "hidden";
// Get the PointerPoint for the pointer event.
var pp = eventInfo.currentPoint;
// Get whether this pointer down event is within
// the time threshold for a double tap.
that._doubleTap = that.gr.canBeDoubleTap(pp);
// Pass the PointerPoint to the gesture recognizer.
that.gr.processDownEvent(pp);
}, false);
// Handle the pointer up event.
target.addEventListener("pointerup", function onPointerUp(eventInfo) {
eventInfo.stopImmediatePropagation = true;
_eventLog.innerText += "pointer up || ";
// Get the current PointerPoint
var pp = eventInfo.currentPoint;
// Pass the PointerPoint to the gesture recognizer.
that.gr.processUpEvent(pp);
}, false);
// The following functions are registered to handle gesture events.
//
// This handler processes taps and double taps.
// Potential double taps are identified in the pointer down handler.
function tappedHandler(evt) {
// Single tap and questions started: Display next question.
if (!that._doubleTap && that._questionsStarted) {
_eventLog.innerText += "tapped || ";
_instructions.innerText = "Double tap to stop questions.";
_clues.innerText = "";
that._tapCount++;
that._clueManager.tapCount = that.tapCount;
if (that._tapCount > that._questionTotal) {
_questions.innerText = "No more questions.";
} else {
var xpath = "questions/question[" + (that._tapCount % (that._questionTotal + 1)) + "]/q";
// Read data from a simple setting
_questions.innerText = _data.selectSingleNode(xpath).innerText;
}
}
// Single tap and questions not started: Don't do much.
else if (!that._doubleTap && !that._questionsStarted) {
_eventLog.innerText += "tapped || ";
_instructions.innerText = "Double tap to start questions.";
}
// Double tap and questions not started: Display first question.
else if (that._doubleTap && !that._questionsStarted) {
_eventLog.innerText += "double-tapped || ";
// Return if last question displayed.
if (that._tapCount > that._questionTotal) {
_questions.innerText = "No more questions.";
return;
}
// Start questions.
that._questionsStarted = true;
_instructions.innerText = "Starting questions (double tap to stop questions).";
// Question number is based on tap count.
that._tapCount++;
// Select question from XML data object.
var xpath = "questions/question[" + (that._tapCount % (that._questionTotal + 1)) + "]/q";
_questions.innerText = _data.selectSingleNode(xpath).innerText;
// Display a basic timer once questions started.
that._startTime = new Date().getTime();
that._intervalTimerId = setInterval(displayTimer, 100);
}
// Double tap and questions started: Stop questions and timer.
else if (that._doubleTap && that._questionsStarted) {
_eventLog.innerText += "double-tapped || ";
_instructions.innerText = "Questions stopped (double tap to start questions).";
that._questionsStarted = false;
clearInterval(that._intervalTimerId);
}
};
// For this app, we display a basic timer once questions start.
// In a more robust app, could be used for achievements.
function displayTimer() {
var x = new Date().getTime();
timerBox.innerText = (x - that._startTime) / 1000;
}
// This handler processes right taps.
// For all pointer devices a right tap is fired on
// the release of a press and hold gesture.
// For mouse devices, righttapped is also fired on a right button click.
// For pen devices,
function rightTappedHandler(evt) {
if (!that._questionsStarted) {
return;
}
var transform = (new MSCSSMatrix()).
translate(
(window.innerWidth - _inputBox.clientWidth) / 2.0 + evt.position.x,
(window.innerHeight - _inputBox.clientHeight) / 2.0 + evt.position.y);
_floater.style.visibility = "visible";
_floater.style.msTransform = transform;
eventLog.innerText = "right-tap || ";
}
// The pointer move event must also be handled because the
// holding gesture is routed through this event.
// If pointer move is not handled, holding will not fire.
// A holding event is fired approximately one second after
// a pointer down if no subsequent movement is detected.
function holdingHandler(evt) {
if (!that._questionsStarted)
return;
if (evt.holdingState == Windows.UI.Input.HoldingState.started) {
_eventLog.innerText += "holding || ";
// Create a clue manager.
that._clueManager.tapCount = that._tapCount;
// Start displaying clues.
that._clueManager.displayClues();
} else if (evt.holdingState == Windows.UI.Input.HoldingState.completed) {
that._clueManager.destroy();
_eventLog.innerText += "holding completed || ";
} else {
_eventLog.innerText += "holding canceled || ";
}
}
},
{},
{});
WinJS.Namespace.define("QandA", {
InputProcessor: InputProcessor
});
})();
datamanager.js
// Handle data for this sample.
(function () {
"use strict";
var DataManager = WinJS.Class.define(
// Constructor
function DataManager_ctor(target) {
_applicationData = Windows.Storage.ApplicationData.current;
_localSettings = _applicationData.localSettings;
// This sample uses data/data.xml (Assume valid, set file properties: Package Action - Content / Copy to Output Directory - Always)
// Use default load settings.
Windows.ApplicationModel.Package.current.installedLocation.getFolderAsync("data").then(function (dataFolder) {
dataFolder.getFileAsync("data.xml").then(function (dataFile) {
Windows.Data.Xml.Dom.XmlDocument.loadFromFileAsync(dataFile).then(function (data) {
// Create a simple setting
try {
_localSettings.values["data"] = data.getXml();
} catch (e) {
_eventLog.innerText += e.description;
}
}, function (error) {
_eventLog.innerText += "Error: Unable to load XML file";
});
}, function (error) {
_eventLog.innerText += error.description;
});
}, function (error) {
_eventLog.innerText += error.description;
});
},
{
getData: function () {
var data = new Windows.Data.Xml.Dom.XmlDocument;
var xmlLoadSettings = new Windows.Data.Xml.Dom.XmlLoadSettings();
xmlLoadSettings.elementContentWhiteSpace = false;
data.loadXml(_localSettings.values["data"], xmlLoadSettings);
return data;
}
},
{});
WinJS.Namespace.define("QandA", {
DataManager: DataManager
});
})();
cluemanager.js
// Handle data for this sample.
(function () {
"use strict";
var ClueManager = WinJS.Class.define(
// Constructor
function ClueManager_ctor() {
this._clueTimerId = null;
},
{
displayClues: function () {
var clue;
var clueCount = 0;
var clueCollection = _data.selectNodes("questions/question[" + this.tapCount + "]/clues/clue");
this._clueTimerId = setInterval(function () {
clueCount++;
if (clueCount > clueCollection.length) {
_clues.innerText += "\nNo more clues.";
clearInterval(_clueTimerId);
return;
}
if (clueCount == 1)
clue = clueCollection.first();
_clues.innerText += "\n" + clue.current.innerText;
clue.moveNext();
}, 2000);
},
destroy: function () {
clearInterval(this._clueTimerId);
},
tapCount: {
get: function () {
return this._tapCount;
},
set: function (tapCount) {
this._tapCount = tapCount;
}
}
},
{});
WinJS.Namespace.define("QandA", {
ClueManager: ClueManager
});
})();