Início rápido: gestos e manipulações DOM (HTML)

[ Este artigo destina-se aos desenvolvedores do Windows 8.x e do Windows Phone 8.x que escrevem aplicativos do Windows Runtime. Se você estiver desenvolvendo para o Windows 10, consulte documentação mais recente]

Você pode personalizar a experiência do usuário para alguns dos gestos básicos descritos na linguagem de toque do Windows (como deslizamento, rotação e redimensionamento) por meio da manipulação básica de eventos de gestos DOM (Document Object Model).

Atualizações para Windows 8.1: O Windows 8.1 introduz uma série de atualizações e melhorias para as APIs de entrada de ponteiro. Para saber mais, veja Alterações de API para Windows 8.1.

Se você for iniciante no desenvolvimento de aplicativos em JavaScript: Leia estes tópicos para se familiarizar com as tecnologias discutidas aqui.

Criar seu primeiro aplicativo em JavaScript

Mapa para aplicativos usando JavaScript

Saiba mais sobre eventos com o Guia de início rápido: adicionando controles HTML e manipulando eventos

Recursos de aplicativos, do início ao fim:

Explore esse recurso mais profundamente como parte da nossa série sobre recursos para aplicativos, do início ao fim

Interação do usuário, do início ao fim (HTML)

Personalização da interação do usuário, do início ao fim (HTML)

Diretrizes de experiência do usuário:

As bibliotecas de controle de plataforma ( (HTML e XAML) fornecem a experiência de total interação do usuário, incluindo interações padrão, efeitos físicos animados e comentários visuais. Se não precisar de suporte para interação personalizada, use esses controles internos.

Se os controles de plataforma não forem suficientes, as diretrizes a seguir para interação do usuário podem ajudá-lo a proporcionar uma experiência de interação envolvente e imersiva, consistente entre os modos de entrada. Essas diretrizes têm como foco principal a entrada por toque, mas elas ainda são relevante para entrada por touchpad, mouse, teclado e caneta.

Exemplos: Veja essa funcionalidade em ação em nossos exemplos de aplicativos.

Exemplo de personalização da interação do usuário, do início ao fim

Amostra de rolagem, movimento panorâmico e aplicação de zoom em HTML

Entrada: amostra de manipulação de eventos de ponteiros DOM

Entrada: exemplo de gestos instanciáveis

Objetivo: aprender a ouvir, manipular e processar gestos básicos para conversão, rotação e colocação em escala usando entrada de toque, mouse, interações de caneta e eventos de gestos DOM.

Pré-requisitos

Reveja Guia de Início Rápido: Ponteiros.

Nós supomos que você possa criar um aplicativo básico em JavaScript que use o modelo da Biblioteca do Windows para JavaScript.

Para completar este tutorial, você precisa:

Tempo para conclusão: 30 minutos.

O que são eventos de gesto?

Um gesto é um ato ou movimento físico executado no ou pelo dispositivo de entrada (um ou mais dedos em uma superfície de toque, caneta digitalizadora, mouse, etc.). Essas interações naturais são mapeadas para operações de elementos no sistema e no seu aplicativo. Para saber mais, veja Gestos, manipulações e interações.

O Windows depende de um conjunto básico de gestos para interagir com a interface do usuário e manipulá-la.

GestoDescrição
ToqueGesto de tocar

Um único contato é detectado e suspenso imediatamente.

Tocar em um elemento invoca sua ação primária.

Pressionar e segurarGesto de pressionar e segurar

Um único contato é detectado e não é movido.

Pressionar e segurar faz com que informações detalhadas ou elementos visuais de ensino (por exemplo, uma dica de ferramenta ou um menu de contexto) sejam exibidos sem o compromisso de executar uma ação.

Deslizar o dedoGesto de deslizar o dedo

Um ou mais contatos são detectados e se movem na mesma direção.

Usamos o gesto de deslizar o dedo principalmente para interações panorâmicas, mas também pode ser usado para movimentar, desenhar ou escrever.

Passar o dedoGesto de passar o dedo

Um ou mais contatos são detectados e se movem na mesma direção por uma curta distância.

Passe o dedo para selecionar, comandar e mover.

VirarGesto de girar

Dois ou mais contatos são detectados e giram em um arco em sentido horário ou anti-horário.

Vire para girar.

PinçarGesto de pinçagem

Dois ou mais contatos são detectados e aproximados.

Pince para diminuir o zoom.

AmpliarGesto de ampliação

Dois ou mais contatos são detectados e afastados.

Estique para aumentar o zoom.

Para saber mais sobre esses gestos e como eles se relacionam à linguagem de toque do Windows, veja Design da interação por toque.

 

Você pode usar a detecção de gestos para estender o modelo de interação do seu aplicativo e basear-se nos eventos de ponteiro básicos descritos no Guia de Início Rápido: Manipulando a Entrada do Ponteiro. De fato, seu aplicativo provavelmente consumirá eventos de gesto (como manipulação de toques, movimentação panorâmica, gesto de deslizar o dedo, zoom com pinçagem e ampliação) e usará dados brutos de ponteiro para dar suporte à detecção e ao processamento de gestos.

Seu aplicativo pode processar vários gestos simultaneamente (como rotação e aplicação de zoom), agrupar contatos de ponteiro para direcionamento a um elemento específico (como associar todos os contatos ao destino do contato inicial, ou primário) e identificar os elementos específicos direcionados por um gesto ou contato de ponteiro específico.

Importante  Se você implementar seu próprio suporte para interação, tenha em mente que os usuários esperam uma experiência intuitiva que envolva a interação direta com os elementos de interface do usuário do seu aplicativo. Recomendamos que você modele as interações personalizadas nas bibliotecas de controles de plataforma (HTML e XAML) para manter tudo consistente e detectável. Os controles nessas bibliotecas fornecem uma experiência de interação completa para o usuário, incluindo interações padrão, efeitos físicos animados, comentários visuais e acessibilidade. Crie interações personalizadas somente se houver uma exigência clara e bem definida e se nenhuma das interações básicas for permitida no seu cenário.

 

Criar a interface do usuário

Para este exemplo, usamos um retângulo (target) como objeto de destino para a detecção e o processamento de gestos de entrada de ponteiro.

O retângulo atua como um misturador básico de cores. A cor do destino muda com base em uma seleção de cor RGB (vermelho, verde ou azul) e do ângulo de rotação do destino informados através do gesto de rotação. (Calculamos o valor de vermelho, verde ou azul a partir do ângulo de rotação.)

Exibimos detalhes para cada evento de ponteiro e gesto, além da matriz de transformação atual aplicada ao destino, dentro do objeto de destino.

Este é o HTML para este exemplo.

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

Estas são as CSS (Folhas de Estilos em Cascata) para este exemplo.

Observação  Eventos de ponteiro não são disparados durante uma interação de panorâmica ou zoom. Você pode desabilitar gestos de panorâmica e zoom por meio das propriedades msTouchAction, overflow e -ms-content-zooming da CSS.

 

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

Escutar eventos de gesto e ponteiro

Este código configura o misturador de cores e os seletores de cor e declara os vários ouvintes de eventos.

Na maioria dos casos, recomendamos que você obtenha informações sobre o ponteiro por meio do argumento de eventos dos manipuladores de eventos do ponteiro em sua estrutura de idioma escolhida.

Se o argumento não representar os detalhes de ponteiro exigidos pelo seu aplicativo, você poderá obter acesso a dados de ponteiro estendidos do argumento do evento por meio dos métodos getCurrentPoint e getIntermediatePoints ou das propriedades currentPoint e intermediatePoints. Nós recomendamos o uso dos métodos getCurrentPoint e getIntermediatePoints pois você pode especificar o contexto dos dados de ponteiro.

Em primeiro lugar, declaramos variáveis globais, definimos um objeto de dados (colorInfo) para rastrear o estado de destino e inicializamos o misturador de cores (target) e os seletores de cor 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();
}

Em seguida, configuramos o misturador de cores, associamos um reconhecedor de gestos (msGesture) ao objeto e declaramos os vários ouvintes de eventos.

Dica  Para este exemplo, há apenas um objeto associado a um reconhecedor de gestos. Se o seu aplicativo tiver uma grande quantidade de objetos que podem ser manipulados (como um quebra-cabeça), considere criar dinamicamente um reconhecedor de gestos apenas quando a entrada do ponteiro é detectada em um objeto de destino. O reconhecedor de gestos pode ser destruído quando a manipulação é concluída (veja um exemplo em Entrada: exemplo de gestos instanciáveis). Para evitar a sobrecarga da criação e destruição de reconhecedores de gestos, crie um pequeno pool de reconhecedores de gestos na inicialização e atribua-os dinamicamente conforme necessário.

 

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

Por fim, inicializamos os seletores de cor RGB (com ouvintes de evento) e o 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;
}

Manipular o evento de ponteiro para baixo

Em um evento de ponteiro para baixo, obtemos a cor RGB selecionada e associamos o ponteiro ao reconhecedor de gestos, chamando o método addPointer. Rastreamos a sequência e pointerType para reassociar o ponteiro e o reconhecedor de gestos, se necessário.

Se nenhuma cor estiver selecionada, iremos ignorar o evento de ponteiro.

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

Manipular o evento de gesto

Neste código, processamos os gestos de conversão (deslizar ou passar o dedo), rotação e dimensionamento (pinçar ou 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";
}

Manipular outros eventos, conforme necessário

Neste exemplo, relatamos somente os outros eventos manipulados aqui. Um aplicativo mais robusto pode fornecer funcionalidade 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";
}

Confira os Tópicos relacionados no final desta página para acessar links para exemplos mais complexos.

Exemplo completo

Veja Código completo de gestos e manipulações DOM.

Resumo e próximas etapas

Neste Guia de início rápido, você aprendeu a manipular eventos de gestos básicos em aplicativos da Windows Store em JavaScript.

O reconhecimento de gestos básicos e os eventos de ponteiro são úteis para o gerenciamento de interações simples, como conversão (deslizar ou passar o dedo), rotação e colocação em escala (pinçar ou ampliar).

Para tratar de interações mais elaboradas e fornecer uma experiência de interação do usuário totalmente personalizada, veja Guia de Início Rápido: Gestos Estáticos e Guia de Início Rápido: Gestos de Manipulação.

Para saber mais sobre a linguagem de toque do Windows 8, veja Design da interação por toque.

Tópicos relacionados

Desenvolvedores

Respondendo à interação do usuário

Desenvolvendo aplicativos da Windows Store (JavaScript e HTML)

Guia de início rápido: ponteiros

Guia de Início Rápido: Gestos Estáticos

Guia de início rápido: gestos de manipulação

Designers

Design de interação por toque