Inicio rápido: gestos de manipulación (HTML)

[ Este artículo está destinado a desarrolladores de Windows 8.x y Windows Phone 8.x que escriben aplicaciones de Windows en tiempo de ejecución. Si estás desarrollando para Windows 10, consulta la documentación más reciente

Puedes personalizar la experiencia del usuario para los gestos de manipulación descritos en el lenguaje táctil de Windows, como deslizar, deslizar rápidamente, girar, reducir y ampliar. Para lograrlo, controlas los eventos de gestos de Windows en tiempo de ejecución en tu aplicación de Windows en tiempo de ejecución con JavaScript.

La mayoría de las aplicaciones procesa los gestos (girar, zoom y arrastrar) y no hace prácticamente nada con los datos de puntero sin procesar, salvo pasarlos a la detección de gestos. En esta muestra, usamos estos datos de puntero sin procesar para admitir el procesamiento y el control de gestos de manipulación. Esto amplía el modelo de interacción de la aplicación y se basa en los eventos de puntero básicos descritos en Inicio rápido: punteros.

Actualizaciones para Windows 8.1: Windows 8.1 incorpora varias actualizaciones y mejoras para las API para entrada de puntero. Para obtener más información, consulta el tema sobre cambios en las API para Windows 8.1.

Si no estás familiarizado con el desarrollo de aplicaciones con JavaScript: Echa un vistazo a estos temas para familiarizarte con las tecnologías que se mencionan aquí.

Crear tu primera aplicación con JavaScript

Guía básica para aplicaciones con JavaScript

Obtén información acerca de los eventos con Inicio rápido: agregar controles HTML y controlar eventos

Funciones de la aplicación, de principio a fin:

Consulta esta funcionalidad con más detalle como parte de la serie Funciones de la aplicación, de principio a fin

Interacción del usuario, de principio a fin (HTML)

Personalización de la interacción del usuario, de principio a fin (HTML)

Directrices sobre la experiencia del usuario:

Las bibliotecas de control de la plataforma (HTML y XAML) proporcionan una experiencia de interacción del usuario completa, incluidas interacciones estándar, efectos físicos animados y comentarios visuales. Si no necesitas compatibilidad para interacción personalizada, usa estos controles integrados.

Si los controles de la plataforma no son suficientes, estas directrices para la interacción del usuario te pueden ayudar a proporcionar una experiencia de interacción atractiva y envolvente que sea coherente en todos los modos de entrada. Estas instrucciones se centran principalmente en la entrada táctil, pero también son válidas para entradas de panel táctil, mouse, teclado y lápiz.

Muestras: Verás esta funcionalidad en acción en nuestras muestras de aplicaciones.

Personalización de la interacción del usuario, muestra de principio a fin

Entrada: muestra de control de eventos de puntero de DOM

Entrada: muestra de manipulaciones y gestos (JavaScript)

Objetivo: Para aprender a detectar, controlar y procesar gestos de manipulación mediante entradas de interacciones táctiles, del mouse, de lápiz o pluma y eventos de gestos de Windows en tiempo de ejecución,

Requisitos previos

repasa Inicio rápido: punteros, Inicio rápido: gestos y manipulaciones de DOM y Inicio rápido: gestos estáticos.

Además, damos por hecho que puedes crear una aplicación básica con JavaScript que use la plantilla de la Biblioteca de Windows para JavaScript.

Para completar este tutorial, necesitas:

¿Qué son los eventos de gesto?

Un gesto es el acto físico o movimiento ejecutado en el dispositivo de entrada o por él. Se incluyen, entre otros, uno o varios dedos en una superficie táctil, un digitalizador de pluma o lápiz o un mouse. Estas interacciones naturales se asignan a operaciones en elementos tanto del sistema como de tu aplicación. Para más información, consulta el tema sobre gestos, manipulaciones e interacciones.

La siguiente tabla identifica los gestos de manipulación que se abordan en este inicio rápido. Consulta Inicio rápido: gestos estáticos para obtener compatibilidad con gestos estáticos, como pulsar y mantener presionado.

GestoDescripción
DeslizarGesto de deslizar

Uno o más contactos que traspasan un umbral de distancia.

Si el movimiento panorámico no está habilitado y el primer contacto se produce dentro de los límites de un elemento, al deslizar se moverá el elemento.

Si el movimiento panorámico está habilitado, el primer contacto, se produce dentro de los límites de un elemento y la dirección de deslizamiento es perpendicular con respecto al eje panorámico, al deslizar se moverá el elemento. De lo contrario, se iniciará el movimiento panorámico.

  • Estado de entrada: se detectan uno o más contactos.
  • Movimiento: el arrastre/deslizamiento traspasa el umbral de distancia.
  • Estado de salida: el último contacto se libera o finaliza.
Deslizar rápidamenteGesto de deslizar rápidamente

Uno o más contactos que se mueven dentro de un umbral de distancia (breve gesto de deslizar). El deslizamiento rápido no es un gesto basado en la rapidez o el tiempo.

Si la aplicación no habilita el movimiento panorámico, y el primer contacto se produce dentro de los límites de un elemento, al deslizar rápidamente, se moverá el elemento.

Si la aplicación habilita el movimiento panorámico, el primer contacto se produce dentro de los límites de un elemento y la dirección del deslizamiento rápido es perpendicular con respecto al eje panorámico, al deslizar rápidamente, se moverá el elemento. De lo contrario, el deslizamiento rápido inicia un movimiento panorámico.

  • Estado de entrada: se detectan uno o más contactos.
  • Movimiento: el arrastre/deslizamiento no traspasa el umbral de distancia.
  • Estado de salida: el último contacto se libera o finaliza.
Reducir y ampliarGesto de reducir y ampliar

Dos o más contactos que convergen o divergen para acercar o alejar, respectivamente.

Se suele usar para cambiar el tamaño de un objeto, acercar o alejar una vista o para el zoom semántico.

  • Estado de entrada: se han detectado dos o más contactos dentro de los límites rectangulares de un objeto.
  • Movimiento: arrastre/deslizamiento con los contactos convergiendo o divergiendo.
  • Estado de salida: menos de dos contactos detectados.
GirarGesto de girar

Al girar con uno o más dedos, el objeto gira. Al girar el dispositivo, gira toda la pantalla.

Dos o más contactos que se mueven en círculo alrededor de un centro (o punto) de giro.

Se suele usar para girar un objeto.

  • Estado de entrada: se han detectado dos o más contactos dentro de los límites rectangulares de un objeto.
  • Movimiento: arrastre/deslizamiento de uno o más contactos en un movimiento circular.
  • Estado de salida: menos de dos contactos detectados.

Para obtener más información sobre estos gestos y cómo se relacionan con el lenguaje táctil de Windows 8, consulta el tema acerca del diseño de la interacción táctil.

 

Importante  Si implementas tu propia compatibilidad con la interacción, ten presente que los usuarios esperan una experiencia intuitiva en la que interactúen en forma directa con los elementos de la interfaz de usuario de tu aplicación. Te recomendamos que modeles tus interacciones personalizadas sobre la biblioteca de controles de la plataforma (HTML y XAML) para que todo sea coherente y pueda detectarse. Los controles de estas bibliotecas proporcionan una experiencia de interacción de usuario completa, incluidas interacciones estándar, efectos físicos animados, comentarios visuales y accesibilidad. Crea únicamente interacciones personalizadas si existe un requisito claro y bien definido y no hay ninguna interacción básica que sea compatible con el escenario.

 

Crear la interfaz de usuario

En este ejemplo se explica cómo habilitar un solo gesto de manipulación (un giro para rotar) en un elemento de interfaz de usuario básico. Un cuadrado (target) sirve de objeto de destino para la entrada y detección de puntero. Estos datos de puntero se pasan a un objeto GestureRecognizer que procesa los datos de un gesto de girar para crear una manipulación de rotación con comportamiento de inercia estándar.

La aplicación proporciona las siguientes funciones de interacción del usuario:

  • Giro: rota el objeto, con inercia cuando los contactos de puntero finalizan. Este comportamiento de interacción respeta las directrices para información visual y las recomendaciones del lenguaje táctil de Windows. De acuerdo con estas recomendaciones, el gesto de girar debe estar limitado a la rotación de los elementos de la interfaz de usuario. Nota  Este ejemplo se puede modificar sin problemas para admitir el gesto de arrastrar para zoom, proceso en el que nos centraremos más adelante en este inicio rápido.  

Este es el HTML para este ejemplo.

<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>

Esta es la hoja de estilo CSS para este ejemplo.

Nota  Los eventos de puntero no se desencadenan durante una interacción de zoom o desplazamiento lateral. Puedes deshabilitar el zoom y el movimiento panorámico en una región mediante las propiedades de CSS msTouchAction, overflow y -ms-content-zooming.

 

html,body {
    overflow: hidden;
    position: relative;
    height: 100%;
}

div #Container {
/*
This element permits no default touch behaviors.
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.
*/
    touch-action: none;
    display: -ms-grid;
    -ms-grid-rows: 200px 1fr 50px;
    -ms-grid-columns: 1fr;
    overflow: hidden;
    position: absolute;
    padding: 0px;
    margin: 0px;
    border-width: 0px;
    border-collapse: collapse;
}

div #targetTitle {
    touch-action: none;
    -ms-grid-row: 1;
    -ms-grid-column: 1;
    background-color: black;
    color: white;
    padding: 0px;
    margin: 0px;
    border-width: 0px;
    border-collapse: collapse;
    font-family: 'Segoe UI';
    font-size: large;
}
div #targetContainer {
    touch-action: none;
    -ms-grid-row: 2;
    -ms-grid-column: 1;
    background-color: white;
    padding: 0px;
    margin: 0px;
    border-width: 0px;
    border-collapse: collapse;
}
div #targetFooter {
    touch-action: none;
    -ms-grid-row: 3;
    -ms-grid-column: 1;
    background-color: black;
    color: white;
    padding: 0px;
    margin: 0px;
    border-width: 0px;
    border-collapse: collapse;
    font-family: 'Segoe UI';
    font-size: large;
}

div #target {
    -ms-transform-origin: 0px 0px;
    position: absolute;
    width: 300px;
    height: 300px;
    background-color: black;
    padding: 0px;
    margin: 0px;
    border-width: 0px;
    border-collapse: collapse;
}

Inicializar la aplicación

Configura el destino, su contenedor y el control de manipulación del destino cuando la aplicación se inicie.

Aquí inicializamos el elemento de destino (y otros objetos de interfaz de usuario) dentro del contenedor y configuramos un controlador para las manipulaciones.

/// <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);
}

Controlar la entrada de puntero y configurar el reconocedor de gestos

En este ejemplo usamos una clase contenedora básica (InputProcessor) para definir los controladores de eventos de puntero junto con el objeto GestureRecognizer que usa la entrada de puntero.

En la mayoría de los casos, te recomendamos obtener información de puntero mediante el argumento de eventos de los controladores de eventos de puntero en el marco de lenguaje que hayas elegido.

Si el argumento de evento no expone los detalles de puntero que necesita tu aplicación, puedes acceder a los datos extendidos de puntero del argumento de evento con los métodos getCurrentPoint y getIntermediatePoints, o las propiedades currentPoint y intermediatePoints. Te recomendamos usar los métodos getCurrentPoint y getIntermediatePoints, porque te permiten especificar el contexto de los datos de puntero.

Sugerencia  Para este ejemplo, hay un solo objeto asociado con un reconocedor de gestos. Si tu aplicación contiene una gran cantidad de objetos que pueden manipularse (como un puzzle), considera crear un reconocedor de gestos en forma dinámica solo cuando se detecte una entrada de puntero en un objeto de destino. El reconocedor de gestos puede destruirse cuando finaliza la manipulación (consulta Entrada: muestra de gestos instanciables para ver un ejemplo). Para evitar la sobrecarga de crear y destruir reconocedores de gestos, crea un grupo pequeño de reconocedores de gestos en la inicialización y asígnalos en forma dinámica según sea necesario.

 

Aquí, el reconocedor de gestos (_gestureRecognizer) detecta y controla todos los eventos de gestos y de puntero.

/// <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();
            }
        })
    });
})();

Procesar la manipulación

Aquí usamos una clase de administrador de manipulación (ManipulationManager) para definir los comportamientos y limitaciones de manipulación para el objeto GestureRecognizer. Este es el objeto que se definió en el InputProcessor (_inputProcessor) descrito en el paso anterior.

/// <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;
                }
            }),
        })
    });
})();

Consulta Temas relacionados en la parte inferior de esta página para obtener vínculos a muestras más complejas.

Ejemplo completo

Consulta Código completo de gestos de manipulación.

Resumen y siguientes pasos

En este inicio rápido has aprendido a controlar los eventos de gesto de manipulación en aplicaciones de la Tienda Windows con JavaScript.

Los gestos de manipulación resultan prácticos a la hora de admitir y administrar interacciones complejas, como deslizarse para hacer un movimiento panorámico, reorganizar/mover, hacer zoom o girar.

Consulta Entrada: muestra de gestos instanciables para ver un ejemplo más complejo del control de gestos.

Nota  Esta muestra no cumple con las directrices del lenguaje táctil de Windows en cuanto a las interacciones personalizadas. Algunos de los gestos estáticos se han redefinido para fines instructivos.

 

Para administrar las interacciones estáticas (como deslizar, deslizar rápidamente, girar, reducir y ampliar), consulta Inicio rápido: gestos estáticos.

Para obtener más información sobre el lenguaje táctil de Windows 8, consulta Diseño de interacción táctil.

Temas relacionados

Desarrolladores

Responder a la interacción del usuario

Desarrollar aplicaciones de la Tienda Windows (JavaScript y HTML)

Inicio rápido: punteros

Inicio rápido: gestos y manipulaciones de DOM

Inicio rápido: gestos estáticos

Diseñadores

Diseño de la interacción táctil