Chapter 3. Interactive Media with Mobile Events

In this chapter, we will cover:

  • Moving an element with touch events

  • Detecting and handling orientation event

  • Rotating an HTML element with gesture events

  • Making a carousel with swipe events

  • Manipulating image zoom with gesture events

Introduction

One of the biggest differences between mobile and desktop is the way in which we interact with the screen. On a desktop screen, we use a mouse to move and click events to control the interaction. On a mobile screen, the interaction comes from touch and gesture events. In this chapter, we will see some of the events that are unique to touch screens (for example, two finger events) and how you can leverage these features to build something unique for mobile.

Moving an element with touch events

Target device: cross-browser

On a mobile screen, we interact with elements using touch events. Because of that, we can move an HTML element on the screen with our fingers.

Getting ready

For this example, we will be using jQuery. First, let's create a new HTML file, and name it ch03r01.html.

How to do it...

In your HTML document, use the following code:

<!doctype html>
<html>
<head>
<title>Mobile Cookbook</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
#square {
width: 100px;
height: 100px;
background:#ccc;
position:absolute;
}
</style>
</head>
<body>
<div id="main">
<div id="square">
</div>
</div>
<script src="http://code.jquery.com/jquery-1.5.2.min.js"></script>
<script src="http://code.jquery.com/mobile/1.0a4.1/jquery. mobile-1.0a4.1.min.js"></script>
<script>
$('#square').bind('touchmove',function(e){
e.preventDefault();
var touch = e.originalEvent.touches[0] || e.originalEvent.changedTouches[0];
var elm = $(this).offset();
var x = touch.pageX - elm.left/2;
var y = touch.pageY - elm.top/2;
$(this).css('left', x+'px'),
$(this).css('top', y+'px'),
});
</script>
</body>
</html>
  • Now let's see how it renders in Opera:

    How to do it...

How it works...

First, we register the square div with a touchmove event.

You can detect the touch position relative to the page which is touch.pageX and touch.pageY in our example. We use the finger position minus half the width and height of the square div element, so it feels like we are moving with the div center as the registration point.

var x = touch.pageX - elm.left/2;
var y = touch.pageY - elm.top/2;

We apply the x and y values to the square element using CSS position. This is the 'moving' action.

$(this).css('left', x+'px'),
$(this).css('top', y+'px'),

There's more...

You may have realized that, at the top of this example, there is one line as follows:

var touch = e.originalEvent.touches[0] || e.originalEvent.changedTouches[0];

Now you might be wondering what it does. Mobile Safari does not allow the e.touches and e.changedTouches properties on event objects to be copied to another object. You can get around this issue by using e.originalEvent. You could read more about it here:

http://www.the-xavi.com/articles/trouble-with-touch-events-jquery.

jQuery mobile events

jQuery mobile is a set of components. If you want to dig into all the mobile-related events, you can find them at:

https://github.com/shichuan/jquery-mobile/blob/master/js/jquery.mobile.event.js.

Zepto

Zepto is a more lightweight alternative to jQuery that you could consider using if your main target is WebKit-based browsers. You can find out more about it at:

https://github.com/madrobby/zepto.

Safari's guide on mobile event handling

For the official reference, you could visit Safari's online guide at:

http://developer.apple.com/library/safari/#documentation/appleapplications/reference/safariwebcontent/HandlingEvents/HandlingEvents.html.

See also

  • Redrawing a canvas with orientation events

  • Rotating an HTML element with gesture events

  • Making a carousel with swipe events

  • Manipulating image zoom with gesture events

Detecting and handling orientation event

Target device: cross-browser

On mobile browsers, if your site is built based on a fluid layout, it shouldn't be affected by orientation change. But for a highly interactive site, sometimes you may want to handle orientation change in a special way.

Getting ready

Create a new HTML file, and name it ch03r02.html.

How to do it...

Now let's start creating the HTML and Script to detect and handle orientation event.

  1. Enter the following code:

    <!doctype html>
    <html>
    <head>
    <title>Mobile Cookbook</title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <style>
    html, body {
    padding: none;
    margin: none;
    }
    </style>
    <link rel="stylesheet" href="http://code.jquery.com/mobile/1.0/jquery.mobile-1.0.min.css" />
    <script src="http://code.jquery.com/jquery-1.6.4.min.js"></script>
    <script src="http://code.jquery.com/mobile/1.0/jquery.mobile-1.0.min.js"></script>
    </head>
    <body>
    <div id="a">
    </div>
    <script>
    var metas = document.getElementsByTagName('meta'),
    var i;
    if (navigator.userAgent.match(/iPhone/i)) {
    for (i=0; i<metas.length; i++) {
    if (metas[i].name == "viewport") {
    metas[i].content = "width=device-width, minimum-scale=1.0, maximum-scale=1.0";
    }
    }
    document.addEventListener("gesturestart", gestureStart, false);
    }
    function gestureStart() {
    for (i=0; i<metas.length; i++) {
    if (metas[i].name == "viewport") {
    metas[i].content = "width=device-width, minimum-scale=0.25, maximum-scale=1.6";
    }
    }
    }
    </script>
    <script>
    $(window).bind('orientationchange',function(event){
    updateOrientation(event.orientation);
    })
    function updateOrientation(orientation) {
    $("#a").html("<p>"+orientation.toUpperCase()+"</p>");
    }
    </script>
    </body>
    </html>
    
  2. Now, render this code in your mobile browser and rotate the screen to view in both portrait and landscape mode. In portrait mode, the text output will be 'PORTAIT'.

    How to do it...
  3. When we rotate the screen to landscape mode, the text will be 'LANDSCAPE'.

    How to do it...

How it works...

By listening to window.onorientationchange event, we could get the orientationchange event, when it occurs; we get the event.orientation parsed to the function to output the result.

There's more...

At times, you may want to lock the orientation of the screen if let's say when building a game. For a native application, this can be easy, but for a web app, this can be a bit difficult to achieve.

Let's create a one-page screen that locks to only landscape mode. Note that this is a proof-of-concept, and to create really sophisticated apps or game requires more calculation and handling.

Create a document and name it ch03r02_b.html, and enter the following code

<!doctype html>
<html>
<head>
<title>Mobile Cookbook</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="css/style.css">
<style>
body {
font-family: 'Kranky', serif;
font-size: 36px;
font-style: normal;
font-weight: 400;
word-spacing: 0em;
line-height: 1.2;
}
html {
background:#F1F2CE;
}
html, body, #screen {
padding:0;
margin:0;
}
#screen {
text-align:center;
-moz-transform:rotate(90deg);
-webkit-transform:rotate(90deg);
-o-transform:rotate(90deg);
-ms-transform:rotate(90deg);
}
#screen div {
padding-top:130px;
}
@media screen and (min-width: 321px){
#screen {
text-align:center;
-moz-transform:rotate(0deg);
-webkit-transform:rotate(0deg);
-o-transform:rotate(0deg);
-ms-transform:rotate(0deg);
}
#screen div {
padding-top:70px;
}
}
</style>
</head>
<body>
<div id="screen">
<div id="loader">enter the game</div>
</div>
<script>
var metas = document.getElementsByTagName('meta'),
var i;
if (navigator.userAgent.match(/iPhone/i)) {
for (i=0; i<metas.length; i++) {
if (metas[i].name == "viewport") {
metas[i].content = "width=device-width, minimum-scale=1.0, maximum-scale=1.0";
}
}
document.addEventListener("gesturestart", gestureStart, false);
}
function gestureStart() {
for (i=0; i<metas.length; i++) {
if (metas[i].name == "viewport") {
metas[i].content = "width=device-width, minimum-scale=0.25, maximum-scale=1.6";
}
}
}
window.onorientationchange = function() {
update();
}
function update() {
switch(window.orientation) {
case 0: // Portrait
case 180: // Upside-down Portrait
var cWidth = window.innerWidth;
var cHeight = window.innerHeight;
document.getElementById("screen").style.width = cHeight-36+'px';
document.getElementById("screen").style.height = cWidth+'px';
break;
case -90: // Landscape: turned 90 degrees counter-clockwise
case 90: // Landscape: turned 90 degrees clockwise
var cWidth = window.innerWidth;
var cHeight = window.innerHeight;
document.getElementById("screen").style.width = "100%";
document.getElementById("screen").style.height = "auto";
break;
}
}
update();
</script>
</body>
</html>

Now if you render the page in your browser, you will see the following screen. In portrait mode, it suggests to the user the game/application is designed to be viewed in landscape mode:

There's more...

When you rotate the screen from portrait to landscape mode, it looks normal:

There's more...

In this example, we used transform:rotate from CSS3 to rotate the screen to 90 degrees when viewed in portrait mode:

#screen {
text-align:center;
-moz-transform:rotate(90deg);
-webkit-transform:rotate(90deg);
-o-transform:rotate(90deg);
-ms-transform:rotate(90deg);
}

The mode the user is in can be determined by window.orientation. There are four values: -90, 0, 90, 180. The device is in landscape mode when the degree is -90 and 90. And it's in portrait mode when the degree is 0 and 180.

switch(window.orientation) {
case 0: // Portrait
case 180: // Upside-down Portrait
//...
break;
case -90: // Landscape: turned 90 degrees counter-clockwise
case 90: // Landscape: turned 90 degrees clockwise
//...
break;
}

With this, you can determine the orientation of the screen.

Safari's native support

For the official reference, you could visit Safari's online guide at:

http://developer.apple.com/library/safari/#documentation/appleapplications/reference/safariwebcontent/HandlingEvents/HandlingEvents.html.

Web versus native

Although mobile web is catching up, if you are developing a highly interactive application, always keep in mind that even the slowest native app still performs faster than an HTML app. If you are deciding to use HTML5 to build an app, you also have to keep all the hacks and browser inconsistencies in mind.

See also

  • Moving an element with touch events

  • Rotating an HTML element with gesture events

  • Making a carousel with swipe events

  • Zooming an image with gesture events

Rotating an HTML element with gesture events

Target device: iOS, Android, Symbian

On Mobile Safari, you can detect the degrees of rotation when people use two fingers to do a rotation on the screen. Because of that, we can use our fingers to rotate an element on the screen!

Getting ready

Let's create an HTML document and name it ch03r03.html.

How to do it...

  1. Add the following code to ch03r03.html and render it in your mobile browser:

    <!doctype html>
    <html>
    <head>
    <title>Mobile Cookbook</title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0">
    <style>
    #main {
    text-align:center;
    }
    #someElm {
    margin-top:50px;
    margin-left:50px;
    width: 200px;
    height: 200px;
    background:#ccc;
    position:absolute;
    }
    </style>
    </head>
    <body>
    <div id="main">
    <div id="someElm">
    </div>
    </div>
    <script>
    var rotation =0 ;
    var node = document.getElementById('someElm'),
    node.ongesturechange = function(e){
    var node = e.target;
    //alert(e.rotation);
    // scale and rotation are relative values,
    // so we wait to change our variables until the gesture ends
    node.style.webkitTransform = "rotate(" + ((rotation + e.rotation) % 360) + "deg)";
    //alert("rotate(" + ((rotation + e.rotation) % 360) + "deg)");
    }
    node.ongestureend = function(e){
    // Update the values for the next time a gesture happens
    rotation = (rotation + e.rotation) % 360;
    }
    </script>
    </body>
    </html>
    
  2. Now use two fingers to rotate the box and you will see something like this:

    How to do it...

How it works...

In this example, we rotate the element when there is an ongesturechange event triggered. We get the rotation degree by using the following value:

e.target.rotation

There's more...

You may have noticed that we also listen to ongestureend event, because if the user has previously rotated, this script will remember the last rotated angle and continue to rotate from there.

Safari event handling

For the official reference, you could visit Safari's online guide at:

http://developer.apple.com/library/safari/#documentation/appleapplications/reference/safariwebcontent/HandlingEvents/HandlingEvents.html.

CSS3 transforms

In this example, we used CSS3's transforms feature. You can find more information about WebKit and CSS transform at WebKit's blog at:

http://www.webkit.org/blog/130/css-transforms/.

Drawbacks of the scale bug fix

In this example, we used maximum-scale=1.0 to prevent zooming when using a gesture event. This will cause some accessibility drawbacks, so use a rotate event only if you are building a highly interactive web application. Try to avoid it when building a mobile website.

See also

  • Moving an element with touch events

  • Redrawing a canvas with orientation events

  • Rotating an HTML element with gesture events

  • Zooming an image with gesture events

Making a carousel with swipe events

One of the common features of mobile devices is swiping. When you browse photos in your photo gallery, you swipe left and right to navigate from one picture to another. On Android devices, you swipe down to unlock the phone. On a mobile browser, you can use swipe as well.

Getting ready

First, let's create an HTML document and name it ch03r04.html.

How to do it...

  1. Enter the following code:

    <!doctype html>
    <html>
    <head>
    <title>Mobile Cookbook</title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <style>
    html, body {
    padding:0;
    margin:10px auto;
    }
    #checkbox {
    border:5px solid #ccc;
    width:30px;
    height:30px;
    }
    #wrapper {
    width:210px;
    height:100px;
    position:relative;
    overflow:hidden;
    margin:0 auto;
    }
    #inner {
    position:absolute;
    width:630px;
    }
    #inner div {
    width:200px;
    height:100px;
    margin:0 5px;
    background:#ccc;
    float:left;
    }
    .full-circle {
    background-color: #ccc;
    height: 10px;
    -moz-border-radius:5px;
    -webkit-border-radius: 5px;
    width: 10px;
    float:left;
    margin:5px;
    }
    .cur {
    background-color: #555;
    }
    #btns {
    width:60px;
    margin:0 auto;
    }
    </style>
    </head>
    <body>
    <div id="main">
    <div id="wrapper">
    <div id="inner">
    <div></div>
    <div></div>
    <div></div>
    </div>
    </div>
    <div id="btns">
    <div class="full-circle cur"></div>
    <div class="full-circle"></div>
    <div class="full-circle"></div>
    </div>
    </div>
    <script src="http://code.jquery.com/jquery-1.5.2.min.js"></script>
    <script src="http://code.jquery.com/mobile/1.0a4.1/jquery.mobile-1.0a4.1.min.js"></script>
    <script>
    var curNum = 0;
    $('#wrapper').swipeleft(function () {
    $('#inner').animate({
    left: '-=210'
    }, 500, function() {
    // Animation complete.
    curNum +=1;
    $('.full-circle').removeClass('cur'),
    $('.full-circle').eq(curNum).addClass('cur'),
    });
    });
    $('#wrapper').swiperight(function () {
    $('#inner').animate({
    left: '+=210'
    }, 500, function() {
    // Animation complete.
    curNum -=1;
    $('.full-circle').removeClass('cur'),
    $('.full-circle').eq(curNum).addClass('cur'),
    });
    });
    </script>
    </body>
    </html>
    
  2. Once you've entered the code in the page, swipe left and right of the viewing area, and you can see the boxes being scrolled horizontally:

    How to do it...

How it works...

We have used a couple of HTML5 techniques in this example. First, we used jQuery Mobile to detect the swipe event. When we use our finger to swipe the page to the left or right, an event listener is assigned:

$('#wrapper').swipeleft(function () {
});
$('#wrapper').swiperight(function () {
});

When the swipe events are detected, jQuery animation .animate() is used to create the moving effect:

$('#inner').animate({
left: '+=210'
}, 500, function() {
// Animation complete.
curNum -=1;
$('.full-circle').removeClass('cur'),
$('.full-circle').eq(curNum).addClass('cur'),
});

There's more...

In this example, we used a CSS3 technique for the circle buttons. You can draw an entire circle using just pure CSS3:

.full-circle {
background-color: #ccc;
height: 10px;
-moz-border-radius:5px;
-webkit-border-radius: 5px;
border-radius: 5px;
width: 10px;
}

In this example, we define the width and height of the document to be 10 px, and the border radius to be 5 px. Now you can have a perfect circle in just a couple of lines of CSS!

Zepto framework and swipe events

You can use the Zepto framework to do something similar. It has events such as swipe, swipeLeft, swipeRight, swipeUp, swipeDown.

YUI and gesture events

YUI has gesture events which you can use to create swipe events. You can read more about this here: Supporting A Swipe Left Gesture:

http://yuiblog.com/sandbox/yui/3.3.0pr3/examples/event/ swipe-gesture.html

Dive into the source

Events in jQuery mobile are built in a modular way. Those who want to learn how jQuery made the swipe event can visit:

https://github.com/jquery/jquery-mobile/blob/master/js/jquery.mobile.event.js. The part related to swipe events is under:

$.event.special.swipe = {...}

Vertical, horizontal, and distance threshold are calculated for the event calculation.

See also

  • Moving an element with touch events

  • Redrawing a canvas with orientation events

  • Rotating an HTML element with gesture events

  • Zooming an image with gesture events

Zooming an image with gesture events

On the iPhone, you can resize an element based on zoom detection. On gesture change, you could get the value of the scale factor, and zoom HTML elements based on it.

Getting ready

Create an HTML document and name it ch03r05.html.

How to do it...

Enter the following code:

<!doctype html>
<html>
<head>
<title>Mobile Cookbook</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<style>
#frame {
width:100px;
height:100px;
background:#ccc;
}
</style>
</head>
<body>
<div id="main">
<div id="frame"></div>
</div>
<script src="http://code.jquery.com/jquery-1.5.2.min.js"></script>
<script src="http://code.jquery.com/mobile/1.0a4.1/jquery.mobile-1.0a4.1.min.js"></script>
<script>
var width = 100, height = 100;
var node = document.getElementById('frame'),
node.ongesturechange = function(e){
var node = e.target;
// scale and rotation are relative values,
// so we wait to change our variables until the gesture ends
node.style.width = (width * e.scale) + "px";
node.style.height = (height * e.scale) + "px";
}
node.ongestureend = function(e){
// Update the values for the next time a gesture happens
width *= e.scale;
height *= e.scale;
}
</script>
</body>
</html>

How it works...

In this example, we assign the element we want to scale with the ongesturechange event. The scale factor is determined by the e.target.scale:

width *= e.scale;
height *= e.scale;

There's more...

Gesture events can be tricky, so using them properly is very important. For a two finger multi-touch gesture, the events occur in the following sequence:

  1. touchstart for finger 1. Sent when the first finger touches the surface.

  2. gesturestart. Sent when the second finger touches the surface.

  3. touchstart for finger 2. Sent immediately after gesturestart when the second finger touches the surface.

  4. gesturechange for current gesture. Sent when both fingers move while still touching the surface.

  5. gestureend. Sent when the second finger lifts from the surface.

  6. touchend for finger 2. Sent immediately after gestureend when the second finger lifts from the surface.

  7. touchend for finger 1. Sent when the first finger lifts from the surface.

Official iOS Safari guide on GestureEvent

There is an official iPhone Safari guide that explains the details of GestureEvent class on Safari:

http://developer.apple.com/library/safari/#documentation/UserExperience/Reference/GestureEventClassReference/GestureEvent/GestureEvent.html.

YUI gesture events

YUI from Yahoo! has a cross-browser solution for gesture events, but only supports one-finger events. You can find out more about it at:

http://developer.yahoo.com/yui/3/event/#gestures.

Google Maps and gesture events

One example of a site that relies heavily on the two fingers gesture event is Google Maps on Mobile Safari:

Google Maps and gesture events

See also

  • Moving an element with touch events

  • Redrawing a canvas with orientation events

  • Rotating an HTML element with gesture events

  • Making a carousel

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset