Pointers complete code (HTML)

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

This topic contains these sections:

  • Technologies
  • Requirements
  • View the code ()

Download location

This sample is not available for download.

Technologies

Programming languages CSS, HTML, JavaScript
Programming models Windows Runtime

Requirements

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

View the code ()

default.css

body {
    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 */
}

default.html

Note  Windows Store apps

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

Note  Windows Phone Store apps

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

default.js

(function () {
    "use strict";
    var app = WinJS.Application;
    var activation = Windows.ApplicationModel.Activation;


    app.onactivated = function (args) {
        if (args.detail.kind === activation.ActivationKind.launch) {
            if (args.detail.previousExecutionState !== activation.ApplicationExecutionState.terminated) {
                // TODO: This application has been newly launched. Initialize
                // your application here.
                initialize();
            } else {
                // TODO: This application has been reactivated from suspension.
                // Restore application state here.
            }
            args.setPromise(WinJS.UI.processAll());
        }
    };

    app.oncheckpoint = function (args) {
        // TODO: This application is about to be suspended. Save any state
        // that needs to persist across suspensions here. You might use the
        // WinJS.Application.sessionState object, which is automatically
        // saved and restored across suspension. If you need to complete an
        // asynchronous operation before your application is suspended, call
        // args.setPromise().
    };

    app.start();

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

    // Handles pointers that are in contact and moved within the boundary of the target. 
    // 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). 
    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);
    }

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

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

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

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


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

})();