• Html5 touch event


    HTML5 for the Mobile Web: Touch Events

    Finger touching feather

    POSTED BY RUADHAN - 15 AUG 2013
    Twitter share iconFacebook share iconGoogle Plus share icon

    With the widespread adoption of touchscreen devices, HTML5 brings to the table, among many other things, a set of touch-based interaction events. Mouse-based events such as hover, mouse in, mouse out etc. aren’t able to adequately capture the range of interactions possible via touchscreen, so touch events are a welcome and necessary addition to the web developer's toolbox.

    Use cases for the touch events API include gesture recognition, multi-touch, drag and drop, and any other touch-based interfaces.

    The Touch Events API

    We'll get some of the technical details of the API out of the way first, before moving on to some real examples. The API is defined in terms of Touches, TouchEvents, and TouchLists.

    Each Touch describes a touch point, and has the following attributes:

    AttributeDescription
    identifier unique numeric identifier
    target the DOM element that is the event target of the touch, even if the touch has moved outside of this element
    screenX horizontal coordinate relative to screen
    screenY vertical coordinate relative to screen
    clientX horizontal coordinate of point relative to viewport, excluding scroll offset
    clientY vertical coordinate of point relative to viewport, excluding scroll offset
    pageX horizontal coordinate of point relative to page, including scroll offset
    pageY vertical coordinate of point relative to page, including scroll offset

    The main touch events defined in the specification are outlined in the table below. The target of the event is the element in which the touch was detected, even if the touch has moved outside this element.

    EventDescription
    touchstart triggered when a touch is detected
    touchmove triggered when a touch movement is detected
    touchend triggered when a touch is removed e.g. the user’s finger is removed from the touchscreen
    touchcancel triggered when a touch is interrupted, e.g. if touch moves outside of the touch-capable area

    Three lists of touches, TouchLists, are associated with each of the events. These are:

    ListDescription
    touches all current touches on the screen
    targetTouches all current touches that started on the target element of the event
    changedTouches all touches involved in the current event

    Touch Events example

    We’ll cover just the basics in this example. There are plenty of more complex examples to be found on the web already, such as the canvas fingerpaint demo by Paul Irish et al. Here we demonstrate simply how to capture and inspect a touch event. Of the available data from the API, we'll use only the touchstart event, and the pageX and pageY attributes.

    First, some HTML. We define a touch-sensitive div to which we will attach an event listener. We also define a div at the top where we will display the screen coordinates of the most recent touch.

      <div id="coords"></div>
      <div id="touchzone"></div>

    Next we add some JavaScript to register the event listener, and add a handler function to do something with the touch data:

    function init() {
      // Get a reference to our touch-sensitive element
      var touchzone = document.getElementById("touchzone");
      // Add an event handler for the touchstart event
      touchzone.addEventListener("touchstart", touchHandler, false);
    }

    So, here we’re simply identifying the touchzone div, attaching a listener for the touchstart event, and registering a handler function: touchHandler.

    In the touchHandler function we grab the x and y coordinates of the touch, and write them to the coords div:

    function touchHandler(event) {
      // Get a reference to our coordinates div
      var coords = document.getElementById("coords");
      // Write the coordinates of the touch to the div
      coords.innerHTML = 'x: ' + event.touches[0].pageX + ', y: ' + event.touches[0].pageY;
    }

    And now we’re ready to go. If you are viewing this page on a device which supports touch events, you should be able to see the screen coordinates of your touches below.

    Live Demo - display touch coordinates

    Click the area to the right to activate the live demo. Depending on your device, you should be able to see the the coordinates of your touch points.

    (Note: this demo, and the other demos on this page, are listening for touch AND mouse events, and so they should also work on non-touch enabled devices).

     
    x: 686, y: 2201

    Display touches on screen

    So now we know how to grab and display some basic touch data. Let's go one step further and display the touch position information visually, by displaying a dot on the screen at the point where it was touched.

    There are a couple of extra things we need to do to get this working. For the display, we'll make use of another HTML5 feature: the canvas element. For now, all we need to say about canvas is that it facilitates drawing graphics in a web page without much difficulty.

    To define the canvas element, we use the following (we've set the size, and added a border too):

      <canvas id="mycanvas" width="662" height="373" style="border: 1px solid #ccc">
        Canvas element not supported<br />
      </canvas>

    We also need to modify the handler function from the last example, so that we now draw on this canvas element. To do this, we need to:

    1. Find the canvas element in the DOM
          var canvas = document.getElementById('mycanvas');
    2. Get the 2D drawing context from the canvas element; this provides the methods and properties we need to draw on the canvas
          var ctx = canvas.getContext("2d");
    3. Use the drawing context to draw something; we'll draw a small rectangle
          ctx.fillRect(event.touches[0].pageX-offset.left, event.touches[0].pageY-offset.top, 5, 5);

    That's it! The full code is displayed below:

    <!DOCTYPE html>
    <html>
      <head>
        <title>HTML5 input </title>
        <script>
     
        function init() {
          var touchzone = document.getElementById("mycanvas");
          touchzone.addEventListener("touchstart", draw, false);
        }
     
        function draw() {
          var canvas = document.getElementById('mycanvas');
     
          if(canvas.getContext) {
            var ctx = canvas.getContext("2d");
            ctx.fillRect (event.touches[0].pageX, event.touches[0].pageY, 5, 5);
          }
        }
        </script>
     
      </head>
      <body onload="init()">
        <canvas id="mycanvas" width="500" height="500">
          Canvas element not supported.
        </canvas>
      </body>
    </html>

    Touch the image below to activate the live demo, and then touch the area below to display your touches!

    Touch coordinate and screen coordinate conversion

    A short note on coordinates and element positions. There is a small trick - to do with coordinate frames - that was glossed over in the above example. The above example will work fine if the canvas element is the only element on the page, and it is aligned with the top left of the page. However, most of the time in your webapps the element that you are interested in will not benefit for the luxury of sitting in this top-leftmost position - more likely it will be embedded in the page some distance down and across. That is, it will be offset by a certain amount from the left of the viewport, and a certain amount from the top of the viewport. We can call these values offsetLeft and offsetTop respectively.

    These values must be taken into account when we want to convert the reported touch event coordinates to usable screen coordinates. Incorporating the offset is quite simple; we use something like touch.pageX-offsetLeft, andtouch.pageY-offsetTop. So how do we get the offsets? To do this, I refer to the method outlined on the Quirskmode blog. The trick is to start with the element we are interested in, and to traverse up the DOM tree, accumulating the offset of each element from its parent until the top is reached. Then we have the total offset that we can use in our app.

    A function to compute this offset looks like this:

    function getOffset(obj) {
      var offsetLeft = 0;
      var offsetTop = 0;
      do {
        if (!isNaN(obj.offsetLeft)) {
          offsetLeft += obj.offsetLeft;
        }
        if (!isNaN(obj.offsetTop)) {
          offsetTop += obj.offsetTop;
        }   
      } while(obj = obj.offsetParent );
      return {left: offsetLeft, top: offsetTop};
    }

    From single touches to swipes and gestures: the touchmove event

    In the last example we saw how we could visualise single touches as dots, using the canvas element and the touchstart event. Now we'll take a look at what we can do when we add the touchmove event into the mix. The touchstart event was useful to capture single point touches. But with touchmove we can capture swipes and other gestures.

    The first thing we can try is to simply use the touchmove event in place of the touchstart event, and leave the rest of our code the same. So, each time the touchmove event is fired during a touch, we will draw a dot (small rectangle) at the point reported by the event. This should, in theory, trace out the entire touch as a path on the screen.

    In our init function, we will have:

        canvas.addEventListener("touchmove", draw, false);

    Wavey path made of dots

    So we can now draw freeform shapes. However, because we are only drawing points, if we move too fast, then the result will be a broken path, as depicted in the image on the right.

    If we want instead a nice continuous path, we need to be a little smarter. Instead of simply drawing a dot at the reported touch position, we draw a line between the last two touchpoints. This should fill the gaps we saw in the image above. We can achieve this with the code below:

          ctx.beginPath();
          // Start at previous point
          ctx.moveTo(lastPt.x, lastPt.y);
          // Line to latest point
          ctx.lineTo(e.touches[0].pageX, e.touches[0].pageY);
          // Draw it!
          ctx.stroke();
     
          //Store latest touchpoint
          lastPt = {x:e.touches[0].pageX, y:e.touches[0].pageY};

    Three green wavey lines

    Finally, we don't want to continue the path we are drawing across separate touches where the finger has been lifted from the screen, or we will end up with all paths joined up - as shown in the image to the right, in which there are three separate paths that are incorrectly joined. For this, we need to figure out when the touch has ended, and to terminate the path we are drawing. Enter the touchend event!

    First, we will register a handler function for thetouchend event. In this function, we need to perform any necessary actions that should occur at the end of the touch. In this case we are drawing the path of the touches on the screen, so for the touchendevent, we need to terminate the current path, and to ensure that it is not associated with the next touch that occurs.

    So, to attach the handler:

      touchzone.addEventListener("touchend", endTouch, false);

    In our example, whenever the touchmove event is triggered, we store the last point so that we can join up the last two points. So, to end the path of a touch, we simply forget about the last point by setting it to null:

      function endTouch(e) {
        e.preventDefault();
        lastPt=null;
      }

    The full code then for the example is:

    <!DOCTYPE html>
    <html>
      <head>
        <title>HTML5 Touch Tracing </title>
        <script>
          var canvas;
          var ctx;
          var lastPt=null;
     
          function init() {
            var touchzone = document.getElementById("mycanvas");
            touchzone.addEventListener("touchmove", draw, false);
            touchzone.addEventListener("touchend", end, false);
            ctx = touchzone.getContext("2d");
          }
     
          function draw(e) {
            e.preventDefault();
            if(lastPt!=null) {
              ctx.beginPath();
              ctx.moveTo(lastPt.x, lastPt.y);
              ctx.lineTo(e.touches[0].pageX, e.touches[0].pageY);
              ctx.stroke();
            }
            lastPt = {x:e.touches[0].pageX, y:e.touches[0].pageY};
          }
     
          function end(e) {
            e.preventDefault();
            // Terminate touch path
            lastPt=null;
          }
        </script>
      </head>
      <body onload="init()">
        <canvas id="mycanvas" width="500" height="500">
          Canvas element not supported.
        </canvas>
      </body>
    </html>

    Activate the touchmove example by touching the purple bumblebee, and draw something in the box below.

    HTML5 multi-touch example

    So, now we can handle single touches and swipes, what about mutliple simultaneous touch interactions, or, in the parlance of our times, multi-touch?

    We can determine the number of touch events by checking the length of the list of touches, using e.touches.length. In the previous examples we assumed just one touch, and so we referenced touches[0] to get at the data for this touch. So, to add multi-touch support to our demo, we can iterate over the touches array, and perform an appropriate action for each of the touches in the array. This amounts to wrapping our previous code in a loop, and instead of storing the last point for a single touch, we store an array of the last points for all the registered touches.

    Finally, to help the visualisation, we'll add a splash of colour with:

      var colours = ['red', 'green', 'blue', 'yellow', 'black'];

    Then we can set the colour of a line with:

       ctx.strokeStyle = colours[id];

    Maintaining the list of latest points is a little trickier when when want to know which touch path to terminate. For this we can make use of the identifier attribute of the touch object. We will maintain an associative array of the last points of all touches, keyed by the identifier attribute of the respective touch.

    We define our associative array as an Object:

    var lastPt = new Object();

    We can get the identifier of a touch with:

      var id = e.touches[i].identifier;

    And we can add new items into the array, using the touch identifier as the key, with:

    lastPt[id] = {x:e.touches[i].pageX, y:e.touches[i].pageY};

    Finally, we need to remove entries in the array when we detect the touchend event. To do this, we make use of thechangedTouches touchList. This array includes all the touches associated with the current event. So, when we detect the touchend event, we can iterate over this array, and remove the entries in the lastPt associative array that match the identifiers of the touches in the changeTouches array:

      function end(e) {
        e.preventDefault();
        for(var i=0;i<e.changedTouches.length;i++) {
          var id = e.changedTouches[i].identifier;
          delete lastPt[id];
        }
      }

    The full code listing is below:

    <!DOCTYPE html>
    <html>
      <head>
      <title>HTML5 multi-touch</title>
      <script>
        var canvas;
        var ctx;
        var lastPt = new Object();
        var colours = ['red', 'green', 'blue', 'yellow', 'black'];
     
        function init() {
          var touchzone = document.getElementById("mycanvas");
          touchzone.addEventListener("touchmove", draw, false);
          touchzone.addEventListener("touchend", end, false);   
          canvas = document.getElementById('mycanvas');
          ctx = canvas.getContext("2d");
        }
     
        function draw(e) {
          e.preventDefault();
     
          //Iterate over all touches
          for(var i=0;i<e.touches.length;i++) {
            var id = e.touches[i].identifier;   
            if(lastPt[id]) {
              ctx.beginPath();
              ctx.moveTo(lastPt[id].x, lastPt[id].y);
              ctx.lineTo(e.touches[i].pageX, e.touches[i].pageY);
              ctx.strokeStyle = colours[id];
              ctx.stroke();
     
            }
            // Store last point
            lastPt[id] = {x:e.touches[i].pageX, y:e.touches[i].pageY};
          }
      }
     
      function end(e) {
        e.preventDefault();
        for(var i=0;i<e.changedTouches.length;i++) {
          var id = e.changedTouches[i].identifier;
          // Terminate this touch
          delete lastPt[id];
        }
      }  
     
      </script>
      </head>
      <body onload="init()">
        <canvas id="mycanvas" width="500" height="500">
          Canvas element not supported.
        </canvas>
      </body>
    </html>

    Touch the squiggly lines below to activate the live multitouch demo; then move multiple fingers around the screen at the same time!

    Browser support and fallbacks

    Touch events are widely supported among mobile devices. However, unless specifically targeting touch devices, a fallback should be implemented when touchevents are not supported. In these cases, the traditional click etc. events can be bound to, but as discussed below, care is needed when deciding which events to support instead of the touch events.

     

      AndroidiOSIE MobileOpera MobileOpera ClassicOpera MiniFirefox MobileChrome for Android
    Touch support                
    (Sources: caniuse.comDeviceAtlasmobilehtml5.org)

    Touch and mouse events

    Since touch events may not be supported on a user's device - indeed, the user may not even be accessing your app on a touchscreen device - this contingency should be planned for. You may want to enable your app to support particular mouse events instead. Care should be taken here as there is not a one-to-one correspondance between mouse events and touch events, and the behaviour differences can be subtle. For a good overview of the issues involved take a look at the article Touch and Mouse by Chris Wilson and Paul Kinlan.

    Best practices

    Care should also be taken implementing touch events that the events don't interfere with typical browser behaviours such as scrolling and zooming - thus there is an argument for disabling these default browser behaviours if you are making use of touch events. Boris Smus outlines these and other potential pitfalls to look out for over on HTMLRocks.

    Conclusion

    In this article we've taken a look at the how the HTML5 Touch Events API enables touch interactions for your web apps. We saw how to access raw touch data, and how we can manage multi-touch interactions. While we worked through some examples to demonstrate how to access and display touches on the screen (with a little help from our friend, the canvas element), it's worth mentioning that there are open source libraries available which take care of the some of the lower level details for you, such as the very useful Hammer.js, a JavaScript library for multi-touch gestures. That's all for now, stay tuned for our follow up articles in our HTML5 series.

    Update Live examples updated to work with mouse events as well as touch events for illustration purposes

    Links and references

    Download

    The code examples in this article can be downloaded below.

    AttachmentSize
    touch-demos.zip 2.06 KB
  • 相关阅读:
    HDU-5818-Joint Stacks
    蓝桥杯-2016CC-卡片换位
    HDU-2255-奔小康赚大钱(KM算法)
    蓝桥杯-PREV31-小朋友排队
    crypto.js加密传输
    js之对象
    LigerUi之ligerMenu 右键菜单
    关于js中window.location.href,location.href,parent.location.href,top.location.href的用法
    设置js的ctx
    AngularJS简单例子
  • 原文地址:https://www.cnblogs.com/skying555/p/4980407.html
Copyright © 2020-2023  润新知