Manipulation gestures complete code (HTML)

This topic provides the complete code sample used in Quickstart: Manipulation gestures.

This topic contains these sections:

  • Technologies
  • Requirements
  • View the code ()

Download location

This sample is not available for download.

Technologies

Programming languages C++
Programming models Windows Runtime

Requirements

Minimum supported client Windows 8
Minimum supported server Windows Server 2012
Minimum required SDK Microsoft Visual Studio Express 2012 for Windows 8

View the code ()

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>Manipulation Gestures</title>
    
    <!-- WinJS references -->
    <link rel="stylesheet" href="//Microsoft.WinJS.2.0/css/ui-light.css" />
    <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/InputProcessor.js"></script>
    <script src="/js/ManipulationManager.js"></script>
    <script src="/js/default.js"></script>
</head>
<body>
    <div class="Container" id="Container">
        <div id="targetTitle">Manipulation gestures (rotation)</div>
        <div class="TargetContainer" id="targetContainer">
            <div id="target" draggable="false"></div>
        </div>
        <div id="targetFooter">&nbsp;</div>
    </div>
</body>
</html>

default.js

(function () {
    "use strict";

    /// <summary> 
    /// Initializes the target and manipulation handling.
    /// </summary>
    function initialize() {
        var container = document.getElementById("targetContainer");
        var target = document.getElementById("target");
        var title = document.getElementById("targetTitle");
        var footer = document.getElementById("targetFooter");
        // Set the height of the target container for initial positioning of the target.
        var containerHeight = window.innerHeight - title.clientHeight - footer.clientHeight;
        container.style.height = containerHeight + "px";
        // Set the initial position of the target.
        target.style.msTransform = (new MSCSSMatrix()).
            translate((container.clientWidth - parseInt(target.clientWidth)) / 2.0,
            (containerHeight - parseInt(target.clientHeight)) / 2.0);
        // Configure manipulation handling.
        var manipulable = new Manipulator.ManipulationManager();
        // The configuration function can support all manipulations.
        // For this example, we limit manipulation support to rotation with inertia.
        manipulable.configure(false,
                              true, // Rotation.
                              false,
                              true, // Inertia.
                              1,
                              0,
                              {
                                  x: (container.clientWidth - parseInt(target.clientWidth)) / 2.0,
                                  y: (containerHeight - parseInt(target.clientHeight)) / 2.0
                              });
        manipulable.setElement(target);
        manipulable.setParent(container);
        // Handler for transforms related to the manipulation.
        manipulable.registerMoveHandler({
            x: (container.clientWidth / 2.0),
            y: (containerHeight / 2.0)
        }, Manipulator.ManipulationManager.FixPivot.MoveHandler);
    }

    document.addEventListener("DOMContentLoaded", initialize, false);
})();

InputProcessor.js

/// <summary> 
/// InputProcessor is a thin wrapper for pointer event handling and gesture detection.
/// Defines an InputProcessor class that takes all pointer event data and feeds it to
/// a GestureRecognizer for processing of the manipulation gestures 
/// as configured in ManipulationManager.js.
/// </summary>
(function () {
    "use strict";
    WinJS.Namespace.define("Manipulator", {
        InputProcessor: WinJS.Class.define(function () {
            // Constructor.
            this._gestureRecognizer = new Windows.UI.Input.GestureRecognizer();
            this._downPoint = null;
            this._lastState = null;
        }, {
            // Instance members.
            element: {
                /// <summary> 
                /// The manipulable element.
                /// </summary>
                get: function () {
                    if (!this._element) {
                        return null;
                    }
                    return this._element;
                },
                set: function (value) {
                    this._element = value;
                    this._setupElement();
                }
            },
            parent: {
                /// <summary> 
                /// The container that defines the coordinate space used
                /// for transformations during manipulation of the target.
                /// </summary>
                get: function () {
                    if (!this._parent) {
                        return null;
                    }
                    return this._parent;
                },
                set: function (value) {
                    this._parent = value;
                }
            },
            getRecognizer: function () {
                /// <summary>
                /// The gesture recognition object.
                /// </summary>
                return this._gestureRecognizer;
            },
            getDown: function () {
                /// <summary>
                /// The pointer data for the pointerdown event.
                /// </summary>
                return this._downPoint;
            },
            _setupElement: function () {
                /// <summary> 
                /// Declare the event listeners for the pointer events on the target.
                /// </summary>
                var that = this;
                this._element.addEventListener("pointerdown",
                    function (evt) { Manipulator.InputProcessor._handleDown(that, evt); },
                    false);
                this._element.addEventListener("pointermove",
                    function (evt) { Manipulator.InputProcessor._handleMove(that, evt); },
                    false);
                this._element.addEventListener("pointerup",
                    function (evt) { Manipulator.InputProcessor._handleUp(that, evt); },
                    false);
                this._element.addEventListener("pointercancel",
                    function (evt) { Manipulator.InputProcessor._handleCancel(that, evt); },
                    false);
                this._element.addEventListener("wheel",
                    function (evt) { Manipulator.InputProcessor._handleMouse(that, evt); },
                    false);
            }
        }, {
            // Static members.
            _handleDown: function (that, evt) {
                /// <summary> 
                /// Handler for the pointerdown event.
                /// </summary>
                /// <param name="that" type="Object">
                /// The InputProcessor object handling this event.
                /// </param>
                /// <param name="evt" type="Event">
                /// The event object.
                /// </param>
                var pp = evt.getCurrentPoint(that._parent);
                that._element.setPointerCapture(pp.pointerId);
                that._gestureRecognizer.processDownEvent(pp);

                // Prevent propagation of this event to additional event handlers.
                evt.stopImmediatePropagation();

                // Capture the pointer location for this event.
                that._downPoint = { x: pp.position.x, y: pp.position.y };
            },
            _handleMove: function (that, evt) {
                /// <summary> 
                /// Handler for the pointermove event.
                /// </summary>
                /// <param name="that" type="Object">
                /// The InputProcessor object handling this event.
                /// </param>
                /// <param name="evt" type="Event">
                /// The event object.
                /// </param>
                var pps = evt.getIntermediatePoints(that._parent);
                that._gestureRecognizer.processMoveEvents(pps);

                // Prevent propagation of this event to additional event handlers.
                evt.stopImmediatePropagation();
            },
            _handleUp: function (that, evt) {
                /// <summary> 
                /// Handler for the pointerup event.
                /// </summary>
                /// <param name="that" type="Object">
                /// The InputProcessor object handling this event.
                /// </param>
                /// <param name="evt" type="Event">
                /// The event object.
                /// </param>
                var pp = evt.getCurrentPoint(that._parent);
                that._gestureRecognizer.processUpEvent(pp);

                // Prevent propagation of this event to additional event handlers.
                evt.stopImmediatePropagation();
            },
            _handleCancel: function (that, evt) {
                /// <summary> 
                /// Handler for the pointercancel event.
                /// </summary>
                /// <param name="that" type="Object">
                /// The InputProcessor object handling this event.
                /// </param>
                /// <param name="evt" type="Event">
                /// The event object.
                /// </param>
                that._gestureRecognizer.completeGesture();

                // Prevent propagation of this event to additional event handlers.
                evt.stopImmediatePropagation();
            },
            _handleMouse: function (that, evt) {
                /// <summary> 
                /// Handler for the mouse wheel event.
                /// </summary>
                /// <param name="that" type="Object">
                /// The InputProcessor object handling this event.
                /// </param>
                /// <param name="evt" type="Event">
                /// The event object.
                /// </param>
                var pp = evt.getCurrentPoint(that._parent);
                that._gestureRecognizer.processMouseWheelEvent(pp, evt.shiftKey, evt.ctrlKey);

                // Prevent propagation of this event to additional event handlers.
                evt.stopImmediatePropagation();
                evt.preventDefault();
            }
        })
    });
})();

ManipulationManager.js

/// <summary> 
/// ManipulationManager is the manipulation processing engine for the 
/// GestureRecognizer object defined in InputProcessor.js.
/// Different components and behaviors of manipulation (rotate, translate, zoom, 
/// and inertia) can be enabled, disabled, and customized as required.
/// </summary>
(function () {
    "use strict";
    WinJS.Namespace.define("Manipulator", {
        ManipulationManager: WinJS.Class.define(function () {
            // Constructor.
            // Create an input processor.
            this._inputProcessor = new Manipulator.InputProcessor();
            // Initialize the manipulation movement and end handlers.
            this._endHandler = null;
            this._moveHandler = null;
            // Create the transform matrices used for manipulating
            // and resetting the target.
            this._currentTransform = new MSCSSMatrix();
            this._initialTransform = new MSCSSMatrix();
            // Initialize the transform matrices values.
            this._initialTransformParams = {
                translation: { x: 0, y: 0 },
                rotation: 0,
                scale: 1
            };
            this._currentTransformParams = {
                translation: { x: 0, y: 0 },
                rotation: 0,
                scale: 1
            };
        }, {
            // Instance members.
            configure: function (scale, rotate, translate, inertia,
                                initialScale, initialRotate, initialTranslate) {
                /// <summary> 
                /// Define the behaviors of the ManipulationManager object.
                /// </summary>
                /// <param name="scale" type="Boolean">
                /// True if scaling is enabled.
                /// </param>
                /// <param name="rotate" type="Boolean">
                /// True if rotation is enabled.
                /// </param>
                /// <param name="translate" type="Boolean">
                /// True if translation is enabled.
                /// </param>
                /// <param name="inertia" type="Boolean">
                /// True if inertia is enabled.
                /// </param>
                /// <param name="initialScale" type="Number">
                /// The initial scale factor.
                /// </param>
                /// <param name="initialRotate" type="Number">
                /// The initial rotation value.
                /// </param>
                /// <param name="initialTranslate" type="Object">
                /// The initial translation values (x,y).
                /// </param>

                // Get the GestureRecognizer associated with this manipulation manager.
                var gr = this._inputProcessor.getRecognizer();
                // Set the manipulations supported by the GestureRecognizer if the
                // interaction is not already being processed.
                if (!gr.isActive) {
                    var settings = 0;
                    if (scale) {
                        settings |= Windows.UI.Input.GestureSettings.manipulationScale;
                        if (inertia) {
                            settings |= Windows.UI.Input.GestureSettings.manipulationScaleInertia;
                        }
                    }
                    if (rotate) {
                        settings |= Windows.UI.Input.GestureSettings.manipulationRotate;
                        if (inertia) {
                            settings |= Windows.UI.Input.GestureSettings.manipulationRotateInertia;
                        }
                    }
                    if (translate) {
                        settings |= Windows.UI.Input.GestureSettings.manipulationTranslateX |
                            Windows.UI.Input.GestureSettings.manipulationTranslateY;
                        if (inertia) {
                            settings |= Windows.UI.Input.GestureSettings.manipulationTranslateInertia;
                        }
                    }

                    // Cache a reference to the current object.
                    var that = this;

                    // If any manipulation is supported, declare the manipulation event listeners.
                    if (scale || rotate || translate) {
                        gr.addEventListener('manipulationstarted',
                            function (evt) { Manipulator.ManipulationManager._manipulationStarted(that, evt); },
                            false);
                        gr.addEventListener('manipulationupdated',
                            function (evt) { Manipulator.ManipulationManager._manipulationUpdated(that, evt); },
                            false);
                        gr.addEventListener('manipulationended',
                            function (evt) { Manipulator.ManipulationManager._manipulationEnded(that, evt); },
                            false);
                    }

                    gr.gestureSettings = settings;

                    // Initialize the transform matrices.
                    this._currentTransformParams.scale = initialScale;
                    this._currentTransformParams.rotation = initialRotate;
                    this._currentTransformParams.translation = initialTranslate;

                    this._initialTransformParams.scale = initialScale;
                    this._initialTransformParams.rotation = initialRotate;
                    this._initialTransformParams.translation = initialTranslate;

                    // Set the transformation values.
                    if (initialRotate) {
                        this._initialTransform = this._initialTransform.rotate(initialRotate);
                    }
                    else {
                        this._currentTransformParams.rotation = 0;
                        this._initialTransformParams.rotation = 0;
                    }
                    if (initialTranslate) {
                        this._initialTransform = this._initialTransform.translate(initialTranslate.x, initialTranslate.y);
                    }
                    else {
                        this._currentTransformParams.translation = { x: 0, y: 0 };
                        this._initialTransformParams.translation = { x: 0, y: 0 };
                    }
                    if (initialScale) {
                        this._initialTransform = this._initialTransform.scale(initialScale);
                    }
                    else {
                        this._currentTransformParams.scale = 1;
                        this._initialTransformParams.scale = 1;
                    }

                    this._currentTransform = this._initialTransform;
                }
            },
            setElement: function (elm) {
                /// <summary> 
                /// Set the manipulable object.
                /// </summary>
                /// <param name="elm" type="Object">
                /// The object that supports manipulation.
                /// </param>
                this._inputProcessor.element = elm;
                // Set the transform origin for rotation and scale manipulations.
                this._inputProcessor.element.style.msTransformOrigin = "0 0";
            },
            setParent: function (elm) {
                /// <summary> 
                /// Set the parent of the manipulable object.
                /// </summary>
                /// <param name="elm" type="Object">
                /// The parent of the object that supports manipulation.
                /// </param>
                this._inputProcessor.parent = elm;
            },
            registerEndHandler: function (handler) {
                /// <summary> 
                /// Register handler to be called after the manipulation is complete.
                /// </summary>
                /// <param name="handler" type="Function">
                /// The manipulationended event handler.
                /// </param>
                this._endHandler = handler;
            },
            registerMoveHandler: function (arg, handler) {
                /// <summary> 
                /// Register handler to be called when manipulation is under way.
                /// </summary>
                /// <param name="args">
                /// Arguments passed to the move handler function.
                /// </param>
                /// <param name="handler" type="Function">
                /// The manipulationupdated event handler.
                /// </param>
                this._moveHandlerArg = arg;
                this._moveHandler = handler;
            },
            resetAllTransforms: function () {
                /// <summary> 
                /// Reset the ManipulationManager object to its initial state.
                /// </summary>

                // Check that the element has been registered before before attempting to reset.
                if (this._inputProcessor.element) {
                    // Reapply the initial transform
                    this._inputProcessor.element.style.transform = this._initialTransform.toString();
                    this._currentTransform = this._initialTransform;

                    // Reset the current transform parameters to their initial values.
                    this._currentTransformParams.translation = this._initialTransformParams.translation;
                    this._currentTransformParams.rotation = this._initialTransformParams.rotation;
                    this._currentTransformParams.scale = this._initialTransformParams.scale;
                }
            },

            _applyMotion: function (pivot, translation, rotation, scaling) {
                /// <summary> 
                /// Apply the manipulation transform to the target.
                /// </summary>
                /// <param name="pivot" type="Object">
                /// The X,Y values for the rotation and scaling pivot point.
                /// </param>
                /// <param name="translation" type="Object">
                /// The X,Y values for the translation delta.
                /// </param>
                /// <param name="rotation" type="Number">
                /// The angle of rotation.
                /// </param>
                /// <param name="scaling" type="Number">
                /// The scaling factor.
                /// </param>

                // Create the transform, apply parameters, and multiply by the current transform matrix.
                var transform = new MSCSSMatrix().translate(pivot.x, pivot.y).
                    translate(translation.x, translation.y).
                    rotate(rotation).
                    scale(scaling).
                    translate(-pivot.x, -pivot.y).multiply(this._currentTransform);

                this._inputProcessor.element.style.transform = transform.toString();
                this._currentTransform = transform;
            },

            _updateTransformParams: function (delta) {
                /// <summary> 
                /// Update the current transformation parameters based on the new delta.
                /// </summary>
                /// <param name="that" type="Object">
                /// The change in rotation, scaling, and translation.
                /// </param>
                this._currentTransformParams.translation.x = this._currentTransformParams.translation.x + delta.translation.x;
                this._currentTransformParams.translation.y = this._currentTransformParams.translation.y + delta.translation.y;
                this._currentTransformParams.rotation = this._currentTransformParams.rotation + delta.rotation;
                this._currentTransformParams.scale = this._currentTransformParams.scale * delta.scale;
            }
        }, {
            // Static members.
            _manipulationStarted: function (that, evt) {
                /// <summary> 
                /// The manipulationstarted event handler.
                /// </summary>
                /// <param name="that" type="Object">
                /// ManipulationManager object on which the event was performed.
                /// </param>
                /// <param name="evt" type="Event">
                /// The event data.
                /// </param>
                Manipulator.ManipulationManager._manipulationHelper(that, evt);
            },
            _manipulationUpdated: function (that, evt) {
                /// <summary> 
                /// The manipulationupdated event handler.
                /// </summary>
                /// <param name="that" type="Object">
                /// ManipulationManager object on which the event was performed.
                /// </param>
                /// <param name="evt" type="Event">
                /// The event data.
                /// </param>
                Manipulator.ManipulationManager._manipulationHelper(that, evt);
            },
            _manipulationEnded: function (that, evt) {
                /// <summary> 
                /// The manipulationended event handler.
                /// </summary>
                /// <param name="that" type="Object">
                /// ManipulationManager object on which the event was performed.
                /// </param>
                /// <param name="evt" type="Event">
                /// The event data.
                /// </param>
                // Pass the event to the manipulation helper function.
                Manipulator.ManipulationManager._manipulationHelper(that, evt);

                // Call the manipulationended handler, if registered.
                if (that._endHandler) {
                    that._endHandler();
                }
            },
            _manipulationHelper: function (that, evt) {
                /// <summary> 
                /// Helper function for calculating and applying the transformation parameter deltas.
                /// </summary>
                /// <param name="that" type="Object">
                /// ManipulationManager object on which the event was performed.
                /// </param>
                /// <param name="evt" type="Event">
                /// The event data.
                /// </param>

                if (evt.delta) {
                    // Rotation/scaling pivot point.
                    var pivot = { x: evt.position.x, y: evt.position.y };

                    // Translation values.
                    var translation = { x: evt.delta.translation.x, y: evt.delta.translation.y };

                    // Rotation angle.
                    var rotation = evt.delta.rotation;

                    // Scale factor.
                    var scale = evt.delta.scale;

                    // Group the transformation parameter deltas.
                    var delta = {
                        pivot: pivot,
                        translation: translation,
                        rotation: rotation,
                        scale: scale
                    };

                    // Apply the manipulation movement constraints.
                    if (that._moveHandler) {
                        delta = that._moveHandler(that._moveHandlerArg, delta, that._currentTransformParams, that._currentTransform);
                    }

                    // Update the transformation parameters with fresh deltas.
                    that._updateTransformParams(delta);

                    // Apply the transformation.
                    that._applyMotion(delta.pivot, delta.translation, delta.rotation, delta.scale);
                }
            },
            FixPivot: WinJS.Class.define(function () {
            /// <summary>
            /// Constrain the center of manipulation (or pivot point) to a set of X,Y coordinates,  
            /// instead of the centroid of the pointers associated with the manipulation.
            /// <param name="pivot" type="Object">
            /// The pivot coordinates for the ManipulationManager object.
            /// </param>
            /// <param name="delta" type="Object">
            /// The transformation parameter deltas (pivot, delta, rotation, scale).
            /// </param>
            /// </summary>
            }, {
            }, {
                MoveHandler: function (pivot, delta) {
                    delta.pivot = pivot;
                    return delta;
                }
            }),
        })
    });
})();