Краткое руководство: указатели (HTML)

[ Эта статья адресована разработчикам приложений среды выполнения Windows для Windows 8.x и Windows Phone 8.x. При разработке приложений для Windows 10 см. раздел последняя документация]

В приложениях на JavaScript взаимодействия при помощи сенсорного экрана, мыши или пера принимаются, обрабатываются и управляются как ввод с использованием указателя.

Обновления в Windows 8.1: В Windows 8.1 появилось множество обновлений и усовершенствований API ввода с помощью указателя. Подробнее: Изменения API для Windows 8.1.

Если у вас нет опыта в разработке приложений на JavaScript: Чтобы получить представление о технологиях, о которых пойдет речь, ознакомьтесь с этими разделами:

Создание первого приложения Магазина Windows на JavaScript

Схема создания приложений Магазина Windows на JavaScript

Дополнительные сведения о событиях см. в разделе Краткое руководство: добавление элементов управления HTML и обработка событий.

Компоненты приложения от начала до конца:

Дополнительные сведения об этой функциональности см. в нашей серии Компоненты приложения от начала до конца.

Взаимодействие с пользователем от А до Я (HTML)

Настройка взаимодействия с пользователем от А до Я (HTML)

Рекомендации по взаимодействию с пользователем:

Библиотеки элементов управления платформы (HTML и XAML) предоставляют все механизмы взаимодействия с пользователем, используемые в Windows, в том числе стандартные взаимодействия, анимированные физические эффекты и визуальную обратную связь. Если вы не планируете настраивать механизмы поддержки взаимодействий, используйте стандартные элементы управления.

Если элементов управления, предоставляемых платформой, недостаточно, то, чтобы обеспечить привлекательный и современный единый механизм взаимодействия для всех режимов ввода, вы можете воспользоваться следующими рекомендациями. В основном эти рекомендации описывают сенсорный ввод, но также применимы к вводу с сенсорной панели, мыши, клавиатуры и пера.

Примеры: Примеры использования этой функциональности см. в коллекции примеров приложений.

Пример настройки взаимодействия с пользователем

Пример прокрутки, сдвига и масштабирования в HTML

Ввод: пример обработки событий указателя DOM

Ввод: пример пользовательских жестов

Ввод: пример рукописного ввода

Ввод: пример управления и жестов (JavaScript)

Ввод: пример упрощенного рукописного ввода

Цель: Пособие по ожиданию и обработке ввода с использованием указателя.

Необходимые условия

Предполагается, что вы умеете создавать простые приложения на JavaScript с использованием шаблона библиотеки Windows для JavaScript.

Для выполнения этого руководства вам необходимо:

Время для завершения: 30 мин.

Инструкции

Что представляет собой ввод с использованием указателя?

Если ввод при помощи мыши, пера и касаний пальцами представить как абстрактный ввод с использованием указателя, то приложение сможет обрабатывать взаимодействия с пользователем без привязки к конкретному устройству ввода.

Объект указателя представляет собой один уникальный "контакт" ввода (PointerPoint) от устройства ввода, например мышью, пером, одним или несколькими пальцами. Система создает указатель при первом обнаружении контакта и уничтожает его, когда указатель выходит из зоны обнаружения или отменяется. При наличии нескольких устройств или мультисенсорного ввода каждый контакт считается уникальным указателем.

Существует большое количество API ввода на базе указателя, которые могут перехватывать вводимые данные непосредственно с различных устройств. Обрабатывая события указателя, можно получать как основную информацию, например о расположении и типе устройства, так и дополнительную, например о давлении и геометрии контакта. В большинстве случаев приложения должны реагировать на разные режимы ввода по-разному, поэтому доступны также свойства конкретных устройств — какую кнопку мыши нажал пользователь или использует ли он стирающий конец пера, к примеру. Скажем, чтобы обеспечить поддержку таких взаимодействий, как сдвиг и прокрутка, можно использовать касания, а для задач, требующих точности, таких как рукописный ввод и рисование, больше подходят мышь и перо. Если ваше приложение должно различать устройства ввода и их возможности, см. Краткое руководство: определение типов устройств ввода.

Если вы реализуете собственную поддержку взаимодействий, помните: пользователи ожидают, что способ взаимодействия с элементами вашего приложения будет интуитивно понятным. Мы рекомендуем моделировать взаимодействие на платформенных элементах управления, чтобы обеспечить единообразие и узнаваемость интерфейса. Создавайте пользовательские взаимодействия, только если это действительно необходимо и ни один стандартный механизм взаимодействия не подходит для вашего случая.

Создание пользовательского интерфейса

В этом примере в качестве целевого объекта для ввода от указателя мы используем прямоугольник (target). Цвет целевого объекта изменяется при изменении состояния указателя.

Подробные сведения для каждого указателя отображаются во всплывающем текстовом блоке, который находится рядом с указателем и следует за движениями указателя. Сообщения о конкретных событиях указателя выводятся по правому краю экрана. На следующем снимке экрана показан пользовательский интерфейс для данного примера.

Снимок экрана пользовательского интерфейса приложения из данного примера.

HTML-код для этого примера.

Примечание  Приложения Магазина Windows

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>PointerInput_Universal.Windows</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>

    <!-- PointerInput_Universal.Windows references -->
    <link href="/css/default.css" rel="stylesheet" />
    <script src="/js/default.js"></script>
</head>
<body class="windows">
    <div id="grid">
        <div id="targetContainer">
            <div id="target"></div>
        </div>
        <div id="bottom">
        </div>
        <div id="eventLog"></div>
    </div>
</body>
</html>

Примечание  Приложения Магазина Windows Phone

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>PointerInput_Universal.WindowsPhone</title>

    <!-- WinJS references -->
    <!-- At runtime, ui-themed.css resolves to ui-themed.light.css or ui-themed.dark.css 
    based on the user’s theme setting. This is part of the MRT resource loading functionality. -->
    <link href="/css/ui-themed.css" rel="stylesheet" />
    <script src="//Microsoft.Phone.WinJS.2.1/js/base.js"></script>
    <script src="//Microsoft.Phone.WinJS.2.1/js/ui.js"></script>

    <!-- PointerInput_Universal.Phone references -->
    <link href="/css/default.css" rel="stylesheet" />
    <script src="/js/default.js"></script>
</head>
<body class="phone">
    <div id="grid">
        <div id="targetContainer">
            <div id="target"></div>
        </div>
        <div id="bottom">
        </div>
        <div id="eventLog"></div>
    </div>
</body>
</html>

Код каскадных таблиц стилей (CSS) для этого примера.

Примечание  События указателя не генерируются в процессе взаимодействий сдвига или масштабирования. Сдвиг и масштабирование для области можно отключить при помощи таких свойств CSS, как msTouchAction, overflow и -ms-content-zooming.

 

body {
    overflow: hidden;
    position: relative;
}

#grid {
    display: -ms-grid;
    height: 100vh; /* 100% of viewport height */
    -ms-grid-columns: 4fr 1fr; /* 2 columns */
    -ms-grid-rows: 1fr 320px 1fr;  /* 3 rows */
    /*touch-action: none;*/ /* Disable panning and zooming */
}
#targetContainer {
    border:solid;
    border-width:thin;
    border-color: red;
    -ms-grid-row: 2;
    -ms-grid-column: 1;
    -ms-grid-row-align: center;
    -ms-grid-column-align: center;
    /*touch-action: none; /* Disable panning and zooming */*/
}
#eventLog {
    -ms-grid-row: 1;
    -ms-grid-column: 2; 
    -ms-grid-row-span: 3;
    padding-right: 10px;
    background-color: black;
    color: white;
}
.phone #target {
    width: 200px;
    height: 300px;
    border: none;
    padding: 0px;
    margin: 0px;
    -ms-transform-origin: 0% 0%;
    /*touch-action: none; /* Disable panning and zooming */*/
}
.windows #target {
    width: 400px;
    height: 200px;
    border: none;
    padding: 0px;
    margin: 0px;
    -ms-transform-origin: 0% 0%;
    touch-action: none; /* Disable panning and zooming */
}

Ожидание событий указателя

В большинстве случаев мы рекомендуем получать информацию указателя через аргумент событий обработчиков событий указателя в выбранной языковой платформе.

Если аргумент события не предоставляет сведения об указателе, необходимые вашему приложению, вы можете получить доступ к расширенным сведениям об указателе из аргумента события с помощью методов getCurrentPoint и getIntermediatePoints или свойств currentPoint иintermediatePoints. Рекомендуется использовать методы getCurrentPoint и getIntermediatePoints, так как для них можно указать контекст указателя данных.

Следующий снимок экрана показывает целевую область с данными указателя мыши из данного примера.

Снимок целевой области указателя.

Здесь мы задаем экранное расположение и прослушиватели событий для целевой области.

Сначала объявляются глобальные переменные, инициализируется целевой объект и область данных указателя, а также определяется журнал событий.

// For this example, we track simultaneous contacts in case the 
// number of contacts has reached the maximum supported by the device.
// Depending on the device, additional contacts might be ignored 
// (PointerPressed not fired). 
var numActiveContacts = 0;

// The input target.
var target;

// Target background colors corresponding to various pointer states.
var pointerColor = {
    hover: "rgb(255, 255, 102)",
    down: "rgb(0, 255, 0)",
    up: "rgb(255, 0, 0)",
    cancel: "rgb(0,0,0)",
    out: "rgb(127,127,127)",
    over: "rgb(0,0,255)"
};

// The event log (updated on each event).
var eventLog;

function initialize() {
    /// <summary>Set up the app.</summary>
    eventLog = document.getElementById("eventLog");
    target = document.getElementById("target");
    setTarget();
}

Затем нужно задать целевой объект и объявить слушатели различных событий указателя для этого целевого объекта.

function setTarget() {
    /// <summary>Set up the target and interaction event handlers.</summary>

    // Initial color of target.
    target.style.backgroundColor = pointerColor.out;

    // Expando dictionary property to track active contacts. 
    // An entry is added during pointer down/hover/over events 
    // and removed during pointer up/cancel/out/lostpointercapture events.
    target.pointers = [];

    // Declare pointer event handlers.
    target.addEventListener("pointerdown", onPointerDown, true);
    target.addEventListener("pointerover", onPointerOver, true);
    target.addEventListener("pointerup", onPointerUp, true);
    target.addEventListener("pointerout", onPointerOut, true);
    target.addEventListener("pointercancel", onPointerCancel, true);
    target.addEventListener("lostpointercapture", onLostPointerCapture, true);
    target.addEventListener("pointermove", onPointerMove, true);
    target.addEventListener("wheel", onMouseWheel, false);
}

И наконец, необходимо задать область данных указателя.

function createInfoPop(e) {
    /// <summary>
    /// Create and insert DIV into the DOM for displaying pointer details.
    /// </summary>
    /// <param name="e" type="Event">The event argument.</param>
    var infoPop = document.createElement("div");
    infoPop.setAttribute("id", "infoPop" + e.pointerId);

    // Set screen position of DIV.
    var transform = (new MSCSSMatrix()).translate(e.offsetX + 20, e.offsetY + 20);
    infoPop.style.msTransform = transform;
    target.appendChild(infoPop);

    infoPop.innerText = queryPointer(e);
}

function updateInfoPop(e) {
    /// <summary>
    /// Update pointer details in UI.
    /// </summary>
    /// <param name="e" type="Event">The event argument.</param>
    var infoPop = document.getElementById("infoPop" + e.pointerId);
    if (infoPop === null)
        return;

    // Set screen position of DIV.
    var transform = (new MSCSSMatrix()).translate(e.offsetX + 20, e.offsetY + 20);
    infoPop.style.msTransform = transform;
    infoPop.innerText = queryPointer(e);
}

Обработка событий указателя

Далее мы воспользуемся обратной связью от пользовательского интерфейса для демонстрации обработчиков основных событий указателя.

  • Этот обработчик управляет событием контакта от указателя (опущено, нажато). Мы добавляем это событие в журнал событий, добавляем указатель в массив указателей, используемый для отслеживания интересующих нас указателей, и отображаем данные указателя.

    Примечание  События pointerdown и pointerup не всегда генерируются парами. Приложение должно ожидать и обрабатывать любые события, которые могут содержать действие указателя "вниз" (например, pointerup, pointerout, pointercancel и lostpointercapture).

     

    function onPointerDown(e) {
        /// <summary>
        /// Occurs for mouse when at least one mouse button is pressed or 
        /// for touch and pen when there is physical contact with the digitizer.
        /// For input devices that do not support hover, the pointerover event is 
        /// fired immediately before the pointerdown event.  
        /// Here, we  filter pointer input based on the first pointer type detected. 
        /// </summary>
        /// <param name="e" type="Event">The event argument.</param>
    
        // pointerdown and pointerup events do not always occur in pairs. 
        // Listen for and handle any event that might conclude a pointer down action 
        // (such as pointerup, pointerout, pointercancel, and lostpointercapture).
        //
        // For this example, we track the number of contacts in case the 
        // number of contacts has reached the maximum supported by the device.
        // Depending on the device, additional contacts might be ignored 
        // (PointerPressed not fired). 
    
        // Prevent the next handler in the hierarchy from receiving the event.
        e.cancelBubble = true;
    
        // Check if the number of supported contacts is exceeded.
        var touchCapabilities = new Windows.Devices.Input.TouchCapabilities();
        if ((touchCapabilities.touchPresent != 0) & (numActiveContacts > touchCapabilities.contacts)) {
            return;
        }
    
        // Update event details and target UI.
        eventLog.innerText += "\nDown: " + e.pointerId;
        target.style.backgroundColor = pointerColor.down;
    
        // Check if pointer already exists (if hover/over occurred prior to down).
        for (var i in target.pointers) {
            if (target.pointers[i].id = e.pointerId) {
                return;
            }
        }
    
        // Push new pointer Id onto expando target pointers array.
        target.pointers.push({ id: e.pointerId, type: e.pointerType });
    
        // Ensure that the element continues to receive PointerEvents 
        // even if the contact moves off the element. 
        // Capturing the current pointer can improve usability by reducing 
        // the touch precision required when interacting with an element.
        // Note: Only the assigned pointer is affected. 
        target.setPointerCapture(e.pointerId);
    
        // Display pointer details.
        createInfoPop(e);
    }
    
  • Этот обработчик управляет событием ввода указателя (над объектом) для указателя, коснувшегося и перемещенного в границах цели. Мы добавляем это событие в журнал событий, добавляем указатель в массив указателей и отображаем данные указателя.

    См. событие pointermove для обработки состояния наведения указателя, который не касается объекта, но находится в границах цели (обычно это устройство типа "перо").

    function onPointerOver(e) {
        /// <summary>
        /// Occurs when a pointer is detected within the hit test boundaries 
        /// of an element.
        /// Also occurs prior to a pointerdown event for devices that do not 
        /// support hover.  
        /// This event type is similar to pointerenter, but bubbles. 
        /// See the pointermove event for handling the hover state of a pointer 
        /// that is not in contact but is within the boundary of the target 
        /// (typically a pen/stylus device). 
        /// </summary>
        /// <param name="e" type="Event">The event argument.</param>
    
        // Prevent the next handler in the hierarchy from receiving the event.
        e.cancelBubble = true;
    
        // Update event details and target UI.
        eventLog.innerText += "\nOver: " + e.pointerId;
    
        if (target.pointers.length === 0) {
            // Change background color of target when pointer contact detected.
            if (e.getCurrentPoint(e.currentTarget).isInContact) {
                // Pointer down occured outside target.
                target.style.backgroundColor = pointerColor.down;
            } else {
                // Pointer down occured inside target.
                target.style.backgroundColor = pointerColor.over;
            }
        }
    
        // Check if pointer already exists.
        for (var i in target.pointers) {
            if (target.pointers[i].id = e.pointerId) {
                return;
            }
        }
    
        // Push new pointer Id onto expando target pointers array.
        target.pointers.push({ id: e.pointerId, type: e.pointerType });
    
        // Ensure that the element continues to receive PointerEvents 
        // even if the contact moves off the element. 
        // Capturing the current pointer can improve usability by reducing 
        // the touch precision required when interacting with an element.
        // Note: Only the assigned pointer is affected. 
        target.setPointerCapture(e.pointerId);
    
        // Display pointer details.
        createInfoPop(e);
    }
    
  • Этот обработчик управляет событием перемещения указателя. Мы добавляем это событие в журнал событий и обновляем сведения об указателе (для наведения мы также добавляем указатель в массив указателя).

    MSPointerHover в Windows 8.1 использовать не рекомендуется. Чтобы определить состояние наведения, используйте свойства указателя pointermove и IsInContact.

    Примечание   В этом обработчике также обрабатываются несколько одновременных нажатий кнопки мыши. Ввод мыши связывается с отдельным указателем, назначаемым при первом обнаружении ввода мыши. Нажатие дополнительных кнопок мыши (левой, правой или колеса) в ходе взаимодействия создает вторичные связи между этими кнопками и указателем через событие нажатия указателя. Событие отпускания указателя происходит только после отпускания последней кнопки мыши, связанной с взаимодействием (не обязательно первой нажатой кнопки). Из-за этого другие щелчки кнопок мыши обрабатываются с помощью события движения указателя.

     

     function onPointerMove(e) {
         /// <summary>
         /// Occurs when a pointer moves within the hit test boundaries 
         /// of an element.
         /// </summary>
         /// <param name="e" type="Event">The event argument.</param>
    
         // NOTE: Multiple, simultaneous mouse button inputs are processed here.
         // Mouse input is associated with a single pointer assigned when 
         // mouse input is first detected. 
         // Clicking additional mouse buttons (left, wheel, or right) during 
         // the interaction creates secondary associations between those buttons 
         // and the pointer through the pointer pressed event. 
         // The pointer released event is fired only when the last mouse button 
         // associated with the interaction (not necessarily the initial button) 
         // is released. 
         // Because of this exclusive association, other mouse button clicks are 
         // routed through the pointer move event.  
    
         // Prevent the next handler in the hierarchy from receiving the event.
         e.cancelBubble = true;
    
         if (e.pointerType == "mouse") {
             // Mouse button states are extended PointerPoint properties.
             var pt = e.getCurrentPoint(e.currentTarget);
             var ptProperties = pt.properties;
             if (ptProperties.isLeftButtonPressed) {
                 eventLog.innerText += "\nLeft button: " + e.pointerId;
             }
             if (ptProperties.isMiddleButtonPressed) {
                 eventLog.innerText += "\nWheel button: " + e.pointerId;
             }
             if (ptProperties.isRightButtonPressed) {
                 eventLog.innerText += "\nRight button: " + e.pointerId;
             }
         }
         // Handle hover state of a pointer that is not in contact but is within 
         // the boundary of the target (typically a pen/stylus device). 
         if (e.pointerType == "pen") {
             var pt = e.getCurrentPoint(e.currentTarget);
             if (pt.isInContact == false) {
                 // Update event details and target UI.
                 target.style.backgroundColor = pointerColor.hover;
                 eventLog.innerText = "\nHover: " + e.pointerId;
    
                 // Check if pointer already exists.
                 for (var i in target.pointers) {
                     if (target.pointers[i].id = e.pointerId) {
                         updateInfoPop(e);
                         return;
                     }
                 }
    
                 target.pointers.push({ id: e.pointerId, type: e.pointerType });
    
                 // Ensure that the element continues to receive PointerEvents 
                 // even if the contact moves off the element. 
                 // Capturing the current pointer can improve usability by reducing 
                 // the touch precision required when interacting with an element.
                 // Note: Only the assigned pointer is affected. 
                 target.setPointerCapture(e.pointerId);
             }
         }
    
         // Display pointer details.
         updateInfoPop(e);
     }
    
  • Этот обработчик управляет событием колесика мыши (вращение). Мы добавляем это событие в журнал событий, при необходимости добавляем указатель в массив указателей и отображаем данные указателя.

    function onMouseWheel(e) {
        /// <summary>  
        /// Occurs when the mouse wheel is rotated. 
        /// </summary> 
        /// <param name="e" type="Event">The event argument.</param>
        // Check if a mouse pointer already exists.
        for (var i in target.pointers) {
            // Ensure existing pointer type registered with pointerover is mouse. 
            if (target.pointers[i].type === "mouse") {
                e.pointerId = target.pointers[i].id;
                break;
            }
        }
        eventLog.innerText += "\nMouse wheel: " + e.pointerId;
        // For this example, we fire a corresponding pointer down event.
        onPointerDown(e);
    }
    
  • Этот обработчик управляет событием выхода (с потерей контакта с устройством) указателя из активной области. Мы добавляем это событие в журнал событий, удаляем указатель из массива указателей и обновляем данные указателя.

    function onPointerUp(e) {
        /// <summary>
        /// Occurs for mouse at transition from at least one button pressed 
        /// to no buttons pressed.
        /// Occurs for touch and pen when contact is removed from the digitizer. 
        /// For input devices that do not support hover, the pointerout event 
        /// is fired immediately after the pointerup event.  
        /// </summary>
        /// <param name="e" type="Event">The event argument.</param>
    
        // Prevent the next handler in the hierarchy from receiving the event.
        e.cancelBubble = true;
    
        // Update event details.
        eventLog.innerText += "\nUp: " + e.pointerId;
    
        // If event source is mouse pointer and the pointer is still 
        // over the target, retain pointer and pointer details.
        // Return without removing pointer from pointers dictionary.
        // For this example, we assume a maximum of one mouse pointer.
        if ((e.pointerType === "mouse") &
            (document.elementFromPoint(e.x, e.y) === target)) {
            target.style.backgroundColor = pointerColor.up;
            return;
        }
    
        // Ensure capture is released on a pointer up event.
        target.releasePointerCapture(e.pointerId);
    
        // Remove pointer from pointers dictionary.
        var targetPointers = target.pointers;
        for (var i in targetPointers) {
            if (target.pointers[i].id === e.pointerId) {
                target.pointers.splice(i, 1);
                var pointerInfoPop = document.getElementById("infoPop" + e.pointerId);
                if (pointerInfoPop === null)
                    return;
                pointerInfoPop.removeNode(true);
            }
        }
    
        // Update target UI.
        if (target.pointers.length === 0) {
            target.style.backgroundColor = pointerColor.up;
        }
    }
    
  • Этот обработчик управляет событием выхода (без потери контакта с устройством) указателя из активной области. Мы добавляем это событие в журнал событий, удаляем указатель из массива указателей и обновляем данные указателя.

    function onPointerOut(e) {
        /// <summary>
        /// Occurs when a pointer (in contact or not) moves out of the 
        /// target hit test boundary, after a pointerup event for a device 
        /// that does not support hover, and after a pointercancel event. 
        /// This event type is similar to pointerleave, but bubbles.  
        /// Note: Pointer capture is maintained until pointer up event.
        /// </summary>
        /// <param name="e" type="Event">The event argument.</param>
    
        // Prevent the next handler in the hierarchy from receiving the event.
        e.cancelBubble = true;
    
        // Update event details.
        eventLog.innerText += "\nPointer out: " + e.pointerId;
    
        // Remove pointer from pointers dictionary.
        var targetPointers = target.pointers;
        for (var i in targetPointers) {
            if (target.pointers[i].id === e.pointerId) {
                target.pointers.splice(i, 1);
                var pointerInfoPop = document.getElementById("infoPop" + e.pointerId);
                if (pointerInfoPop === null)
                    return;
                pointerInfoPop.removeNode(true);
    
                // Update target UI.
                if (target.pointers.length === 0) {
                    target.style.backgroundColor = pointerColor.out;
                }
            }
        }
    }
    
  • Этот обработчик управляет событием отмены указателя. Мы добавляем это событие в журнал событий, удаляем указатель из массива указателей и обновляем данные указателя.

    function onPointerCancel(e) {
        /// <summary>
        /// Occurs when a pointer is removed.
        /// The app will not receive subsequent events for that pointer, including pointerup.  
        /// </summary>
        /// <param name="e" type="Event">The event argument.</param>
    
        // A pointer can be canceled as a result of one of the following:
        //    - A touch contact is canceled when a pen is detected.
        //    - More than 100ms has passed since the device reported
        //      an active contact.
        //    - The desktop is locked or the user logged off. 
        //    - The number of simultaneous contacts exceeds the number 
        //      supported by the device.
        //    - The system has determined that a pointer is unlikely to 
        //      continue to produce events (for example, due to a hardware event).
        //    - After a pointerdown event, the pointer is subsequently used to 
        //      manipulate the page viewport (for example, panning or zooming).  
    
        // Prevent the next handler in the hierarchy from receiving the event.
        e.cancelBubble = true;
    
        // Update event details.
        eventLog.innerText += "\nPointer canceled: " + e.pointerId;
    
        // Ensure capture is released on a pointer cancel event.
        target.releasePointerCapture(e.pointerId);
    
        // Update target UI.
        if (target.pointers.length === 0) {
            target.style.backgroundColor = pointerColor.cancel;
        }
    
        // Remove pointer from pointers dictionary.
        var targetPointers = target.pointers;
        for (var i in targetPointers) {
            if (target.pointers[i].id === e.pointerId) {
                target.pointers.splice(i, 1);
                var pointerInfoPop = document.getElementById("infoPop" + e.pointerId);
                if (pointerInfoPop === null)
                    return;
                pointerInfoPop.removeNode(true);
    
                // Update target UI.
                if (target.pointers.length === 0) {
                    target.style.backgroundColor = pointerColor.out;
                }
            }
        }
    }
    
  • Этот обработчик управляет событием потери захвата указателя. Мы добавляем это событие в журнал событий, удаляем указатель из массива указателей и обновляем данные указателя.

    Примечание  Событие lostpointercapture может произойти вместо события pointerup. Захват указателя может быть потерян в результате взаимодействий пользователя, из-за захвата программой другого указателя или намеренного высвобождения текущего захвата указателя.

     

    function onLostPointerCapture(e) {
        /// <summary>
        /// Occurs after pointer capture is released for the pointer.  
        /// </summary>
        /// <param name="e" type="Event">The event argument.</param>
    
        // lostpointercapture can fire instead of pointerup. 
    
        // Pointer capture can be lost as a result of one of the following:
        //    - User interactions
        //    - Programmatic caputre of another pointer
        //    - Captured pointer was deliberately released
    
        // Prevent the next handler in the hierarchy from receiving the event.
        e.cancelBubble = true;
    
        // Update event details.
        eventLog.innerText += "\nLost pointer capture: " + e.pointerId;
    
        // We need the device type to handle lost pointer capture from mouse input.
        // Use the getCurrentPoint method over currentPoint property to ensure
        // the coordinate space is in relation to the target element.
        // Note: getCurrentPoint and currentPoint are only available in the 
        // local compartment, they are not available in the web compartment.
        var ptTarget = e.getCurrentPoint(e.currentTarget);
        var ptContainer = e.getCurrentPoint(document.getElementsByTagName("body")[0]);
    
        // If event source is mouse pointer and the pointer is still over 
        // the target, retain pointer and pointer details.
        // For this example, we assume only one mouse pointer.
        if ((ptTarget.pointerDevice.pointerDeviceType === Windows.Devices.Input.PointerDeviceType.mouse) &
            (document.elementFromPoint(ptContainer.position.x, ptContainer.position.y) === target)) {
            target.setPointerCapture(e.pointerId);
            return;
        }
    
        // Remove pointer from pointers dictionary.
        var targetPointers = target.pointers;
        for (var i in targetPointers) {
            if (target.pointers[i].id === e.pointerId) {
                target.pointers.splice(i, 1);
                var pointerInfoPop = document.getElementById("infoPop" + e.pointerId);
                if (pointerInfoPop === null)
                    return;
                pointerInfoPop.removeNode(true);
            }
        }
    
        // Update target UI.
        if (target.pointers.length === 0) {
            target.style.backgroundColor = pointerColor.cancel;
        }
    }
    

Получение свойств указателя

Выбранная вами для приложения языковая платформа определяет способ получения свойств указателя. Многие свойства предоставляются напрямую через объект событий указателя. Как было отмечено выше, дополнительную информацию об указателе можно получить через методы getCurrentPoint и getIntermediatePoints или свойства currentPoint и intermediatePoints аргумента события. Рекомендуется использовать методы getCurrentPoint и getIntermediatePoints, так как для них можно указать контекст указателя данных.

Здесь мы запрашиваем различные свойства указателя напрямую из объекта события и расширенные свойства, доступные только через объекты PointerPoint и PointerPointProperties.

function queryPointer(e) {
    /// <summary>
    /// Get extended pointer data.
    /// </summary>
    /// <param name="e" type="Event">The event argument.</param>

    // We get the extended pointer info through the getCurrentPoint method
    // of the event argument. (We recommend using getCurrentPoint 
    // to ensure the coordinate space is in relation to the target.)
    // Note: getCurrentPoint and currentPoint are only available in the 
    // local compartment, they are not available in the web compartment.

    var pt = e.getCurrentPoint(e.currentTarget);
    var ptTargetProperties = pt.properties;

    var details = "Pointer Id: " + e.pointerId;
    switch (e.pointerType) {
        case "mouse":
            details += "\nPointer type: mouse";
            details += "\nLeft button: " + ptTargetProperties.isLeftButtonPressed;
            details += "\nRight button: " + ptTargetProperties.isRightButtonPressed;
            details += "\nWheel button: " + ptTargetProperties.isMiddleButtonPressed;
            details += "\nX1 button: " + ptTargetProperties.isXButton1Pressed;
            details += "\nX2 button: " + ptTargetProperties.isXButton2Pressed;
            break;
        case "pen":
            details += "\nPointer type: pen";
            if (pt.isInContact) {
                details += "\nPressure: " + ptTargetProperties.pressure;
                details += "\nrotation: " + ptTargetProperties.rotation;
                details += "\nTilt X: " + ptTargetProperties.xtilt;
                details += "\nTilt Y: " + ptTargetProperties.ytilt;
                details += "\nBarrel button pressed: " + ptTargetProperties.isBarrelButtonPressed;
            }
            break;
        case "touch":
            details += "\nPointer type: touch";
            details += "\nPressure: " + ptTargetProperties.pressure;
            details += "\nrotation: " + ptTargetProperties.rotation;
            details += "\nTilt X: " + ptTargetProperties.xtilt;
            details += "\nTilt Y: " + ptTargetProperties.ytilt;
            break;
        default:
            details += "\nPointer type: " + "n/a";
            break;
    }
    details += "\nPointer location (target): " + e.offsetX + ", " + e.offsetY;
    details += "\nPointer location (screen): " + e.screenX + ", " + e.screenY;

    return details;
}

См. ссылки на более сложные примеры в разделе "Связанные темы" в нижней части страницы.

Полный пример

См. Полный код указателей.

Краткая сводка и дальнейшие действия

Из этого краткого руководства вы узнали о вводе с использованием указателя в приложениях на JavaScript.

События указателя могут быть полезны для управления простыми взаимодействиями — касаниями, скольжениями и другими определяемыми конкретными устройствами взаимодействиями, в том числе вводом с использованием дополнительных клавиш мыши, колеса мыши, кнопки пера и ластика на конце пера.

Для обработки более сложных взаимодействий, например жестов, описанных в языке касаний Windows 8, см. Краткое руководство: жесты и манипуляции DOM, Краткое руководство: статические жесты и Краткое руководство: жесты управления.

Дополнительные сведения о языке касаний Windows 8 см. в разделе Взаимодействие с помощью сенсорного ввода.

Связанные разделы

Разработчикам

Реакция на взаимодействие с пользователем

Разработка приложений Магазина Windows (JavaScript и HTML)

Краткое руководство: жесты и манипуляции модели DOM

Краткое руководство: статические жесты

Краткое руководство: жесты манипуляций

Конструкторам

Взаимодействие с помощью сенсорного ввода