Inicio rápido: gestos y manipulaciones de DOM (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 ciertos gestos básicos descritos en el lenguaje táctil de Windows (como deslizar, girar o cambiar el tamaño) a través del control de eventos de gestos básicos de Document Object Model (DOM).

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: Puedes ver esta funcionalidad en acción en nuestras muestras de aplicaciones.

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

Muestra de desplazamiento, movimiento panorámico y zoom HTML

Entrada: muestra de control de eventos de puntero de DOM

Entrada: muestra de gestos instanciables

Objetivo: aprender a escuchar, controlar y procesar gestos básicos para trasladar, girar y escalar elementos mediante entradas de interacciones táctiles, del mouse, de lápiz o pluma y eventos de gestos de DOM.

Requisitos previos

Revisa el tema de inicio rápido: punteros.

Damos por sentado 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:

Tiempo para finalizar: 30 minutos.

¿Qué son los eventos de gesto?

Un gesto es el acto físico o movimiento ejecutado en el dispositivo de entrada o por él (uno o varios dedos en una superficie táctil, un digitalizador de pluma o lápiz, un mouse, etc.). 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.

Windows usa un conjunto básico de gestos para manipular la interfaz de usuario e interactuar con ella.

GestoDescripción
PulsarGesto de pulsar

Se detecta un solo contacto que se levanta de inmediato.

La pulsación sobre un elemento invoca esta acción primaria.

Pulsar y sostenerGesto de pulsar y sostener

Se detecta un solo contacto que no se mueve.

Pulsar y sostener hace que se muestre información detallada o elementos visuales didácticos (por ejemplo, información sobre herramientas o un menú contextual) sin confirmar una acción.

DeslizarGesto de deslizar

Se detecta un contacto o más, y se mueven en la misma dirección.

El gesto de deslizar se usa principalmente para interacciones de desplazamiento lateral, pero también puede usarse para mover, dibujar o escribir.

Deslizar rápidamenteGesto de deslizar rápidamente

Se detecta un contacto o más, y se mueven una corta distancia en la misma dirección.

Desliza rápidamente para seleccionar, ordenar y mover.

GirarGesto de girar

Se detectan dos contactos o más, y se gira en el sentido de las agujas del reloj o en el sentido contrario a las agujas del reloj.

Gira para rotar.

ReducirGesto de reducir

Se detectan dos o más contactos, y se acercan.

Acerca los dedos para alejar.

AmpliarGesto de ampliar

Se detectan dos o más contactos, y se alejan.

Aleja los dedos para acercar.

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

 

Puedes usar la detección de gestos para extender el modelo de interacción de tu aplicación y basarte en los eventos de puntero básicos descritos en el tema de inicio rápido: controlar entrada de puntero. De hecho, es muy probable que tu aplicación consuma eventos de gestos (como controlar pulsaciones, realizar un desplazamiento lateral o movimiento con el gesto de deslizar, y ajustar el zoom con los gestos de reducir y ampliar) y use datos de puntero sin procesar para admitir el procesamiento y la detección de gestos.

Tu aplicación puede procesar múltiples gestos al mismo tiempo (como zoom y giro), agrupar los contactos de puntero para apuntar a un elemento específico (como asociar todos los contactos con el destino del contacto inicial, o primario) e identificar los elementos específicos a los que apunta un contacto de puntero o gesto en particular.

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

Para este ejemplo, usamos un rectángulo (target) como el objeto de destino de la entrada de puntero y el procesamiento y la detección de gestos.

El rectángulo actúa como un mezclador de colores básico. El color del destino cambia según una selección de colores RGB (rojo, verde o azul) y su ángulo de giro en función de lo que haya informado el gesto de giro. (Calculamos el valor de rojo, verde o azul desde el ángulo de giro).

Mostramos detalles para cada evento de gesto y de puntero, junto con la matriz de transformación actual aplicada al destino dentro del objeto de destino.

Este es el HTML para este ejemplo.

<html>
<head>
    <meta charset="utf-8" />
    <title>PointerInput</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>
</head>
<body>
    <div class="TargetContainer" id="targetContainer">
        <div id="colorMixer">
            <input type="radio" name="color" value="R" title="Red" id="red" class="Red" /><label for="red" id="labelRed">Red</label>
            <input type="radio" name="color" value="G" title="Green" id="green" class="Green" /><label for="green" id="labelGreen">Green</label>
            <input type="radio" name="color" value="B" title="Blue" id="blue" class="Blue" /><label for="blue" id="labelBlue">Blue</label>
            <div id="targetLog"></div>
            <div id="eventLog"></div>
        </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 desplazamiento lateral en una región a través de las propiedades de CSS msTouchAction, overflow y -ms-content-zooming.

 

body {
    overflow: hidden;
    position: relative;
}

div #targetContainer {
/*
Set the width and height properties of the target container to fill the viewport. 
You can set these properties to 100%, but we use 100vw (viewport width) and 100vh (viewport height).
See https://go.microsoft.com/fwlink/?LinkID=301480 for more detail on CSS units supported by Internet Explorer.
*/
    height: 100vw;
    width: 100vh;
    overflow: hidden;
    position: absolute;
}

div #colorMixer {
/*
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;
    -ms-transform-origin: 0px 0px;
    position: absolute;
    background-color: black;
    border-color: white;
    border-width: thick;
    border-style: solid;
}

div #colorSelector {
    position: relative;
}

div #eventLog {
    -ms-overflow-style:scrollbar;
}

input.Red {
    background-color: rgb(255,0,0);
}

input.Green {
    background-color: rgb(0,255,0);
}

input.Blue {
    background-color: rgb(0,0,255);
}

Escuchar eventos de gesto y puntero

Este código establece los selectores de colores y el mezclador de colores, y declara los diversos agentes de escucha de eventos.

En muchos casos, te aconsejamos que obtengas información de puntero a través del argumento de eventos de los controladores de eventos de puntero en el marco del 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, que permiten especificar el contexto de los datos de puntero.

Primero, declaramos variables globales, definimos un objeto de datos (colorInfo) para realizar un seguimiento del estado del destino e inicializamos tanto el mezclador de colores (target) como los selectores de colores RGB.

var _width = 640;
var _height = 640;

var _pointerInfo;
var _targetLog;

var _selectedColor;
var _colorRed, _colorGreen, _colorBlue;

// Color-specific data object.
//   value: The color value (r, g, or b)
//   rotation: The rotation value used to calculate color value.
//   matrix: The transform matrix of the target.
function colorInfo(value, rotation, matrix) {
    this.value = value;
    this.rotation = rotation;
    this.matrix = matrix;
}

function initialize() {
    // Configure the target.
    setTarget();

    // Initialize color tracking.
    setColors();
}

Después establecemos el mezclador de colores, asociamos un reconocedor de gestos (msGesture) con el objeto y declaramos los diversos agentes de escucha de eventos.

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.

 

// Configure the interaction target.
function setTarget() {
    //  Set up the target position, size, and transform.
    colorMixer.style.width = _width + "px";
    colorMixer.style.height = _height + "px";
    colorMixer.style.msTransform = (new MSCSSMatrix()).
        translate((window.innerWidth - parseInt(colorMixer.style.width)) / 2.0,
        (window.innerHeight - parseInt(colorMixer.style.height)) / 2.0);

    // Create gesture recognizer.
    var msGesture = new MSGesture();
    msGesture.target = colorMixer;
    colorMixer.gesture = msGesture;
    // Expando property for handling multiple pointer devices.
    colorMixer.gesture.pointerType = null;

    // Expando property to track pointers.
    colorMixer.pointers = [];

    // Declare event handlers.
    colorMixer.addEventListener("pointerdown", onPointerDown, false);
    colorMixer.addEventListener("pointerup", onPointerUp, false);
    colorMixer.addEventListener("pointercancel", onPointerCancel, false);
    colorMixer.addEventListener("lostpointercapture", onLostPointerCapture, false);
    colorMixer.addEventListener("MSGestureChange", onMSGestureChange, false);
    colorMixer.addEventListener("MSGestureTap", onMSGestureTap, false);
    colorMixer.addEventListener("MSGestureEnd", onMSGestureEnd, false);
    colorMixer.addEventListener("MSGestureHold", onMSGestureHold, false);
}

Finalmente inicializamos los selectores de colores RGB (con agentes de escucha de eventos) y el objeto colorInfo.

// Initialize values and event listeners for color tracking.
function setColors() {
    var m = new MSCSSMatrix(colorMixer.style.msTransform);
    _colorRed = new colorInfo(0, 0, m);
    _colorGreen = new colorInfo(0, 0, m);
    _colorBlue = new colorInfo(0, 0, m);

    document.getElementById("red").addEventListener("click", onColorChange, false);
    document.getElementById("green").addEventListener("click", onColorChange, false);
    document.getElementById("blue").addEventListener("click", onColorChange, false);
}

// Re-draw target based on transform matrix associated with color selection.
function onColorChange(e) {
    switch (e.target.id) {
        case "red":
            colorMixer.style.msTransform = _colorRed.matrix;
            break;
        case "green":
            colorMixer.style.msTransform = _colorGreen.matrix;
            break;
        case "blue":
            colorMixer.style.msTransform = _colorBlue.matrix;
            break;
    }
    _selectedColor = e.target.id;

    eventLog.innerText = "Color change";
    targetLog.innerText = colorMixer.style.msTransform;
}

Controlar el evento de puntero abajo

En un evento de puntero abajo, obtenemos el color RGB seleccionado y asociamos el puntero con el reconocedor de gestos llamando al método addPointer. Realizamos un seguimiento de la secuencia y de pointerType para reasociar el reconocedor de gestos y puntero, si fuera necesario.

Si no hay ningún color seleccionado, ignoramos el evento de puntero.

// Pointer down handler: Attach the pointer to a gesture object.
function onPointerDown(e) {
    // Do not attach pointer if no color selected.
    if (_selectedColor === undefined)
        return;
    _selectedColor = getSelectedColor();

    // Process pointer.
    if (e.target === this) {
        this.style.borderStyle = "double";
        //  Attach first contact and track device.
        if (this.gesture.pointerType === null) {
            this.gesture.addPointer(e.pointerId);
            this.gesture.pointerType = e.pointerType;
        }
            // Attach subsequent contacts from same device.
        else if (e.pointerType === this.gesture.pointerType) {
            this.gesture.addPointer(e.pointerId);
        }
            // New gesture recognizer for new pointer type.
        else {
            var msGesture = new MSGesture();
            msGesture.target = e.target;
            e.target.gesture = msGesture;
            e.target.gesture.pointerType = e.pointerType;
            e.target.gesture.addPointer(e.pointerId);
        }
    }
    eventLog.innerText = "Pointer down";
}

// Get the current color.
function getSelectedColor() {
    var colorSelection = document.getElementsByName("color");
    for (var i = 0; i < colorSelection.length; i++) {
        if (colorSelection[i].checked)
            return colorSelection[i].id;
    }
}

Controlar el evento de gesto

En este código, procesamos los gestos de traducción (deslizar rápidamente o deslizar), giro y ajuste de escala (reducir o ampliar).

// Gesture change handler: Process gestures for translation, rotation, and scaling.
// For this example, we don't track pointer movements.
function onMSGestureChange(e) {
    // Get the target associated with the gesture event.
    var elt = e.gestureObject.target;
    // Get the matrix transform for the target.
    var matrix = new MSCSSMatrix(elt.style.msTransform);

    // Process gestures for translation, rotation, and scaling.
    e.target.style.msTransform = matrix.
        translate(e.offsetX, e.offsetY).
        translate(e.translationX, e.translationY).
        rotate(e.rotation * 180 / Math.PI).
        scale(e.scale).
        translate(-e.offsetX, -e.offsetY);

    // Mix the colors based on rotation value.
    switch (_selectedColor) {
        case "red":
            _colorRed.rotation += ((e.rotation * 180 / Math.PI));
            _colorRed.rotation = _colorRed.rotation % 360;
            targetLog.innerText = _colorRed.rotation.toString();
            if (_colorRed.rotation >= 0)
                _colorRed.value = parseInt(Math.abs(_colorRed.rotation) * (256 / 360));
            else
                _colorRed.value = parseInt((360 - Math.abs(_colorRed.rotation)) * (256 / 360));
            document.getElementById("labelRed").innerText = _colorRed.value.toString();
            _colorRed.matrix = matrix;
            break;
        case "green":
            _colorGreen.rotation += ((e.rotation * 180 / Math.PI));
            _colorGreen.rotation = _colorGreen.rotation % 360;
            targetLog.innerText = _colorGreen.rotation.toString();
            if (_colorGreen.rotation >= 0)
                _colorGreen.value = parseInt(Math.abs(_colorGreen.rotation) * (256 / 360));
            else
                _colorGreen.value = parseInt((360 - Math.abs(_colorGreen.rotation)) * (256 / 360));
            document.getElementById("labelGreen").innerText = _colorGreen.value.toString();
            _colorGreen.matrix = matrix;
            break;
        case "blue":
            _colorBlue.rotation += ((e.rotation * 180 / Math.PI));
            _colorBlue.rotation = _colorBlue.rotation % 360;
            if (_colorBlue.rotation >= 0)
                _colorBlue.value = parseInt(Math.abs(_colorBlue.rotation) * (256 / 360));
            else
                _colorBlue.value = parseInt((360 - Math.abs(_colorBlue.rotation)) * (256 / 360));
            document.getElementById("labelBlue").innerText = _colorBlue.value.toString();
            _colorBlue.matrix = matrix;
            break;
    }
    e.target.style.backgroundColor = "rgb(" + _colorRed.value + ", " + _colorGreen.value + ", " + _colorBlue.value + ")";
    targetLog.innerText = e.target.style.msTransform;
    eventLog.innerText = "Gesture change";
}

Controlar otros eventos, según la necesidad

En este ejemplo, simplemente informamos sobre los eventos controlados aquí. Una aplicación más eficaz proporcionaría funcionalidad adicional.

// Tap gesture handler: Display event.
// The touch language described in Touch interaction design (https://go.microsoft.com/fwlink/?LinkID=268162),
// specifies that the tap gesture should invoke an elements primary action (such as launching an application 
// or executing a command). 
// The primary action in this sample (color mixing) is performed through the rotation gesture.
function onMSGestureTap(e) {
    eventLog.innerText = "Gesture tap";
}

// Gesture end handler: Display event.
function onMSGestureEnd(e) {
    if (e.target === this) {
        this.style.borderStyle = "solid";
    }
    eventLog.innerText = "Gesture end";
}

// Hold gesture handler: Display event.
function onMSGestureHold(e) {
    eventLog.innerText = "Gesture hold";
}

// Pointer up handler: Display event.
function onPointerUp(e) {
    eventLog.innerText = "Pointer up";
}

// Pointer cancel handler: Display event.
function onPointerCancel(e) {
    eventLog.innerText = "Pointer canceled";
}

// Pointer capture lost handler: Display event.
function onLostPointerCapture(e) {
    eventLog.innerText = "Pointer capture lost";
}

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 y manipulaciones de DOM

Resumen y siguientes pasos

En este inicio rápido, aprendiste acerca del control de eventos de gesto básicos en aplicaciones de la Tienda Windows con JavaScript.

El reconocimiento de gestos básicos, junto con los eventos de puntero, es útil para administrar interacciones simples, como trasladar (deslizar o deslizar rápidamente), girar y escalar (reducir o ampliar).

Para controlar interacciones más elaboradas y proporcionar una experiencia de interacción del usuario totalmente personalizada, consulta los temas de inicio rápido: gestos estáticos y de inicio rápido: gestos de manipulación.

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 estáticos

Inicio rápido: gestos de manipulación

Diseñadores

Diseño de la interacción táctil