Configure player

Close

WWDC Index does not host video files

If you have access to video files, you can configure a URL pattern to be used in a video player.

URL pattern

preview

Use any of these variables in your URL pattern, the pattern is stored in your browsers' local storage.

$id
ID of session: wwdc2008-391
$eventId
ID of event: wwdc2008
$eventContentId
ID of session without event part: 391
$eventShortId
Shortened ID of event: wwdc08
$year
Year of session: 2008
$extension
Extension of original filename: m4v
$filenameAlmostEvery
Filename from "(Almost) Every..." gist: ...

WWDC08 • Session 391

Building an Advanced iPhone Web Application, Hands On

Essentials • 1:07:44

Safari on iPhone provides a rich feature set, and Mac OS X includes a comprehensive set of first-class tools for web developers. Learn how to bring the two together as you walk through code step by step with Apple experts. Create a compelling iPhone web application that uses cutting-edge features such as DOM touch events and CSS animations and transforms. This session includes a prerequisite download.

Speakers: Antoine Quint, Chris Marrin

Unlisted on Apple Developer site

Downloads from Apple

SD Video

Transcript

This transcript was generated using Whisper, it has known transcription errors. We are working on an improved version.

Hi, everyone, and good morning. I appreciate all of you coming here because it is pretty early. I mean, I'm usually sleeping around that time. So my name is Antoine. I'll be joined during this session by my colleague, Chris. We both work on a great team at Apple, and working on implementing these great new features that have been talked about during the week.

And today, we're really going to go inside the code. It's all going to be about code, very little about theory. It's really just going to be about seeing how you make all of these new features we have in Safari and iPhone working together. So it's really about how can you practically integrate all these new great technologies that we have for you on iPhone.

So we have CSS transforms, which gives you hardware-accelerated 2D and now also 3D transforms right into your browser with no plug-in or any extra, just strictly in your browser. And we also have CSS transitions, which allow you to leverage your browser to your iPhone. So we have a very average hardware acceleration for animations done implicitly by simply describing two states and the browser taking care of everything on its own.

And we also have touch events, which really, you know, the iPhone is all about multi-touch. And you have all these functionality now directly in the browser. So using JavaScript events, just like any other events you use on a web page, you'll be able to react to touches and have a really responsive and very flexible UI for your web application on iPhone.

And finally, we also introduced JavaScript media APIs so that you can control the playback of your movies on iPhone using your own UI that you will implement using HTML and CSS and use JavaScript to hook up to the media layer and play content and control it. And all of these things are brand new for Safari on iPhone 2.0.

So we actually start with a demo. Today we're going to build a demo that you might have already seen this week. But I'm going to go through it quickly again. So can we switch to the phone, please? Okay, so we load up our demos called Fingertips, and Apple created a lot of videos, small tutorial videos we call Fingertips, so that you can learn about features of your iPhone in a minute. And so obviously all these videos play on the iPhone as well, which is really great.

And we created, using all our technology, a 3D ring where we lay out all this content, and you can just navigate through it. And of course, given it's iPhone, you really want to flick through the content, and we can flick at various speeds depending on how fast the finger's moving. We can select an item.

get a nice little animated transitions, find out more information about this content. We can go into landscape mode. The content will automatically change a ratio. We can change the layout so that it's more adapted to our content here. We have touch event support so we can do ratings straight onto the device, really responsive, really fast.

And we can go back to the ring. And as you see, with the power of CSS, just based on the orientation of the phone, we can actually change the direction of the ring and also adapt the content we see on there. We always have the poster frames. We also have a bigger title. But we don't have as much room for a short description. So that's all we got here. Select an item again. And we have movie playback on iPhone, of course. So we can just play a movie.

Oops. And there it is playing straight away. And as you'll notice, we actually provided our own custom UI for this. is a great way to-- ALAIN VONGSOUVANH: This is our own little play button. It doesn't look like the play button you get usually by embedding a movie in your page. So that is what we're going to be building today. So back to the slides, please.

And so just give you a quick overview of how our web application is going to be built. It's actually very traditional. So we have an HTML page, call it index. And this page is going to have all the markup to have the core components of our page. So the items in the info pane, the ring markup, and et cetera. And this HTML page loads up CSS, style.css file, which is a CSS resource where all the CSS declarations are going to be put in that file.

We have a main script where all the interactivity is going to be implemented. And finally, we have a data source that we chose to implement using a JavaScript structure. But really, in this app, you could load the data with XML HTTP requests or any AJAX methodology that you would like. It is all browser-based technology. And any workflow that you've been using so far will work right out of the box with all these new technologies that we implemented.

And so we're going to build this demo step by step so that we really highlight in each step a very crucial part of our technology. So the first step will be setting the stage. It's actually pretty intense because we're going to get into 3D here, and it will be all about how you can take a flat HTML list and actually style it so that it's mapped on what looks like a 3D ring. So we're going to be using CSS transforms here.

And the second stage will be adding interactivity with touch events. So using our fingers, we'll be able to flick through the content, just tap and drag and release, and that will be how we navigate. So we'll be using touch events in this case to add that interactivity. The third step will be adding the functionality to slide inside the InfoView. So it will really be all about updating transforms on the fly, all through script, and having the changes transition with a nice animation.

and the fourth step, we're going to add a new behavior to the selection so that the ring rotates before it slides. So we'll be looking at how you can chain different transitions together using events in our CSS transitions technology. And the final step is actually just going to be hooking up movie playback.

And once all this is done, the demo will be complete. And I'd like to invite my colleague, Chris, who is really our main 3D guy on our team and wizard, really. And he's going to come on stage and demonstrate how we get started and build the first stage. Thanks.

Thanks, Antoine. So Antoine showed you this really nice web application that we're going to be building today. And the central component of that is this really nice 3D ring that contains all these elements that are going to be the contents of the fingertips demo. And so what I want to show you now is how do we build that 3D ring.

3D rings, building 3D things in our CSS properties is really easy. It's something that allows us to position things in three-dimensional space, to rotate them, translate them, scale them. And what I want to show you first is a little demo I put together to show how this ring gets built up.

Could we have this monitor please? Okay, so I wrote this to run on the phone, so let me show it to you in the simulator here. If we go to the first step, we can see what we've got is just the normal XY coordinate space. This is just normal CSS coordinate space. X goes to the right, Y goes down. But when we're doing 3D transforms, we add a Z transform, which goes out of the screen toward the viewer for positive Z values and into the screen for negative Z values.

The first thing we add is we have a parent element. This is going to be the parent of all of these items that are going to be populating the ring. It's going to be the thing that we're going to be animating as we spin the ring around. So let me go ahead and get that spinning. I'm spinning it about X, which is going to spin about the central axis of that item. That's the default.

Rotations go about the center of the item that you're rotating. But you'll notice that this doesn't really look very good. It doesn't really look 3D. It it really just kind of looks like a trapezoid that's getting smashed down and stretched out. And that's because we don't have perspective on it.

If you went to the really great talk on CSS animations and transforms yesterday that Simon Fraser and Dean Jackson gave, you'll see that we have a lot of different properties to support the transform capabilities in CSS, perspective being one of them. Let me go ahead and add the perspective to this.

And you can see now that this plane looks a lot nicer. It is foreshortened, and so it looks further away when it's more distant and larger when it's closer to you. So this gives you a lot better 3D look. So let's go ahead then and add an item to that.

This is going to be one of the items that is going to be in our ring. In the demo, it's going to be populated with text and graphics. In this case, I just have something simple on it for illustration purposes. So the first thing... The first thing we want to do is we want to push this into the middle of the parent.

That allows it to rotate also about its central x-axis. And that's what we want. But what we really want is for that to be at the edge of a ring. So the next thing we're going to do is we're going to push that element out in z. So now we can see, if we kind of spin it around, that that item is now pushed out in z by the distance of what we're going to use as the radius. But it's still rotating about that. It's still at that central point. And so it's rotating essentially at the edge of a cylinder.

Next step, of course, is just to add another item. And you can see this item, it's been rotated a little bit. It's actually been rotated by 30 degrees relative to its neighbor because we're going to have 12 items around this ring. So it's 1/12 of the distance around that circle. So if we push this one out now, you see it ends up next to its neighbor, which is exactly what we want. Now, the only thing left, really, is to add another item.

So we have the ring fully populated. And now we have essentially what we want, except for one little problem. So we're going to have to add another item. And we're going to have to add another item. I'm a big fat liar, and it's not actually this easy, because I showed you a very nice 3D ring, but this is not the default behavior. If you saw the talk yesterday, you saw that the default behavior in CSS is for it to look like this.

And that doesn't look very good. It actually is still a 3D ring. As you can see, the items that are more distant are smaller and the items that are closer are larger. But it's flattened against its parent, and that's the default behavior in these new CSS properties is for items to flatten into their parent.

Well, that's obviously not what we want, and so we've added a new property, which is called WebKit Transform Style. And if we set that Transform Style to preserve 3D, then it takes away that restriction of all of the elements being on their parent plane, and it allows them to sit above and below it. So that's exactly what we want. We've got that. Now, one last thing is you'll notice that you can see the more distant objects, and you'll be able to see this more clearly when we go to the actual application.

But that can be really distracting to see those distant objects, especially when there's some nice text up there. So what we want to do is we want to get rid of that using another property that is called WebKit Transform Style. So we're going to make it so that when the items aren't facing you, when they're facing away from you, they're going to disappear. They're not going to be shown. And so that's exactly what we want. We have a nice ring. And so why don't we go ahead and build that ring right now.

Okay, so here we have in Dashcode all of our files. The three files that are interesting to us are this index.html, which is really very simple. It's got some nice setup. It's going to set up the viewport so that we have a fixed window. We're not going to be doing any scaling because we want the application to look exactly, layout exactly the way we want it to. We have some other pretty standard setup stuff here. And then we have this ring. This is going to be the parent of our app. our content.

If we look at the style, it's all pretty standard stuff. We're setting up the page. We're setting up some pretty simple style. Then we have a bunch of style here for laying out each of the items. Script also is pretty simple. There's some initialization. And then this main function here, populate ring, which is going to create each element, populate it, add its style so that it looks the way you want it to, and then it's going to add it to the ring.

And so let's look at this without any changes and see what we've got. And you can see all the items are shown there, but they're all sitting on top of each other because we haven't moved them into their proper place yet. So let's go ahead and do that.

If we go here and grab some code and drop it right here, you can see what this is, is it's setting the angle of each element to go around the ring. And then we are positioning each element at that angle, and we're pushing it out by the value of its radius.

So just by adding that, we go from a ring where everything's sitting on top of each other to something that looks, starts to look like what we want it to look like. First thing you might notice here is that we haven't added perspective, and so all of the items look like they're very flat. And so let's go ahead and add that.

First thing we're going to do is we want to add perspective to the parent of the ring so that we keep the perspective separate from the animations that we're going to be doing on the ring. So let's go ahead and replace this hierarchy with one that's just slightly bigger. So here all we've done is we've added a ring container. This is the thing that we're going to apply the new property to. Let's actually go to the CSS.

So let's go ahead and add the style for that. So you can see this style is going to set the perspective to 1,000. 1,000 is a pretty moderate amount of perspective. It's not going to have a whole lot of foreshortening. It's going to give us about the look we want. We're turning on Preserve 3D. Like I said, through the entire hierarchy, you're going to want to have Preserve 3D so that the items can live on top and below their parent.

We're also here setting WebKit perspective origin. What that's going to do is normally the perspective is centered at the center of the item that it's placed on. But since our item here doesn't have a width or a height, we're going to have to set it ourselves. We're going to set it right in the middle of the screen. The reason we don't have a width and a height is because we don't want this element to interfere with the interaction that we're going to be doing later when Antoine shows you how to interact with this.

And so now we've added those two things. Let's see what we've done. We've got -- now you can see we've got something that looks pretty 3D. Things in front are bigger than things behind. But then, of course, we can see those things behind, and that's not what we want. Turn on the back face visibility to hidden. So let's go ahead and do that.

So we've just turned on backface visibility hidden here. If we look now, looks the same, except that you're not seeing those back faces. We're starting to look pretty close here. And so a couple more things that you're going to notice is that the text, especially this text right in front, looks pretty fuzzy. It doesn't really look very good. And that front item is too big.

It stretches out. And that, of course, is because we've pushed it out by the radius, and so it's closer to the viewer. And so it's going to look larger because of the perspective we've added. And so what we want to do is we want to push that back, because that item is going to look best if it's at the z equals 0 plane. We've kind of laid it out to look best there.

And so we're going to push the entire ring back by the distance of the radius so that the ring is still going to rotate about the center of the ring parent, but it's going to be pushed back so the frontmost item is at the z equals 0 plane.

To do that, we're going to have to, again, Add another layer of hierarchy here so we have something to add. and I will be talking about the pushback tool. So here, in addition to the ring container and the ring, we've added this thing called ring aligner. That's just going to be a static transform in Z. So let's go ahead and add that.

Sorry. Let's try that. So here we have a style for the ring aligner. It's going to also be preserved 3D so that we can make sure that we maintain that 3D hierarchy. And all we're going to do is we're just going to translate it in Z by this amount, which happens to be our radius.

So now when we look at it one more time, now you can see that frontmost item. It looks sharp, it looks crisp, and it's filling the screen just fine. So this looks pretty close to what we want. There's one last thing that I need to check out. If you look at the ring, you can see that in the ring aligner and the ring container, I added Preserve 3D, but the ring style, which was pre-existing, that doesn't have Preserve 3D. It looks fine because we haven't started animating, but once we start animating, it looks fine.

You'll see that all those elements are going to be flat unless we add a Preserve 3D to the ring, too. So let me do that so that when Antoine starts animating, everything looks good. You can see we've added it. We go here now. It looks the same, but when we animate it, it's going to start looking a lot better. So let's go back to the slides real quick, and let's summarize what we've done.

That's what we just did. Okay, so the properties that we've looked at is 3D transforms. 3D transforms are the basic property that you're going to use to position things in three dimensions. You can position things like we did, rotate them like we did. You can also scale. We didn't really have to use that today, but that's available too. You can also combine all these as you've seen.

And in support of that, we have WebKit Perspective. We've used a WebKit Perspective that was fairly small. You can use some perspectives that make things look very, very warped or whatever kind of look you're looking for. We used one that's pretty moderate. So it looks 3D, but it doesn't kind of get in your face too much.

And then we've used this Preserve 3D flag, which basically allows you to make sure that things that are positioned in Z actually live in Z. And it's hierarchical, and so you can have things that are positioned by one element in Z and then positioned differently so that you can animate around different armatures and have some pretty complex 3D hierarchies.

And finally, we hid the back faces. In a demo like this is what you want. Sometimes you don't. Sometimes you want to see the back faces, but a lot of times this really helps out. And so let's, we stepped into the code. Let's go to the second step, and I'll give you back to Antoine.

Thanks, Chris. So I hope you got all that, because it's not the easiest part. From now on, it's going to be a lot easier, and we're going to do a lot more stuff with a lot less code, actually, because it's really the power of what we implemented. It's really easy for you to get things done. So the second step is, like I said earlier, we're going to add the first bit of interactivity. We want to be able to drag around the ring.

And so Chris has already done the main setup. The ring is laid out in 3D. Preserve 3D is preserved on the ring. So if we change the rotation of the whole ring, the thing will move in 3D, and everything will look exactly like we intend to. So what we really need to do now-- is we need to listen to touch events. Like I said, in Safari on iPhone now, we have multi-touch events straight into your JavaScript using DOM events. And reacting to these events, we're going to figure out what the delta is between each interaction and update the rotation of the whole ring as we drag along.

So let me tell you a little bit about how touch events work with the DOM and JavaScript in your web content. So the first thing you're going to want to do is on each of our elements, we want to add an event listener and start listening to the TouchStart event. TouchStart is one of the new events that we introduced for touch event support in Safari and iPhone.

And this will tell us the user has put his finger on the screen. And at this point, we'll want to start listening to all the other events to have the dragging interaction working. You'll notice the second argument to this function, which is a standard DOM function at event listener, is an object.

And this object will conform to a protocol from DOM events, which is event listener protocol. And that means that if we implement and handle event method on this object, all the events that we use will be routed to that function. So we use a single scoped method to handle all our event handling. So we'll look into that in more detail. And we'll get back to the code.

So we're going to start by having a TouchStart. User touches the screen. At this point, register new events for touch move and touch end. So touch move is when the user is going to move around the screen while keeping pressure on the screen. And finally, on touch end, we'll do some cleanup after our interaction when the user lifts the finger off the screen.

And all this interaction is going to go to a single function, which is handle event on a controller object. Because we implement the right event listener protocol, we're going to have a protocol from DOM events specification. So this is basically how we're going to work all of this. So if we get into the code-- and I'd like to switch to a demo machine, please-- we can get started doing this right away.

All right. So let me get rid of the previous version of the code that we have, load up the new project in Dash Code, Okay, so we're really starting from the same amount of code as we had before with Chris. So we have our JavaScript here. We still have our HTML, which is populated by script like it used to be.

And the first thing we got to do, like I said, we need to start listening to touch events. So while we're populating events and setting up the transforms for the individual items in the ring to have the right rotation, et cetera, we're actually going to start We're actually going to start by adding an event listener on each of our items.

So this is pretty much the code that we saw on the slide. We register an event for touch start. We pass the ring controller object as the object is going to take care of the events. And if we take a look further down in the file, we do have our ring controller already set up.

Ring controller is going to really control the whole interactivity in our ring. So we have a field, a single field to track what the current rotation is. And that field will be updated as we call set rotation, which we'll call continuously as we implement the interaction, which will track the rotation and also apply it to the ring using WebKit transform.

That's what the setRetention method does. And of course, we implement the handleEvent method, which is the method where all the events are going to go to as we register them. So what we'll do is we'll just branch those events into separate methods so that when we get a touch start, we'll call it an interaction start. Touch moves, we'll call it an interaction move, and so on.

So there's another thing we're going to want to do here is, because we're going to implement selection later on, I really want to track the index of the item that will be receiving the interaction. So we have an index as we go through the ring, and this is mapped to the data source that we have. We'll look at that a little bit more later.

And we'll just track that on a custom JavaScript field directly on the node in the DOM. So when we will be done with selection behavior, we'll be able to go back and look at that index and figure out what was touched and know that this is the item that was selected. So we're done with the initial work here, and we're all set up to react to touch start events. So now we really have to go into interaction start and start writing the code that we need to get this dragging interaction working.

So there's a few things we're going to do here. First of all, we need to track some start stage for the interaction. So we need to start tracking where the user touched on the screen to get the interaction started. So usually with mouse events, you just go event.pageY or clientY, depending on what information you're interested in. In our case, we're dealing with touch events. And on iPhone, we have multi-touch.

And so if the user uses three fingers, you'll need to get various coordinates to find the coordinates of all those fingers. So you now have a new array on the event object, which will give you access to all of these touches individually. So we just care about the first touch here. We're going to do one finger dragging.

And we're going to get pageY, and that'll be our start position for rotation. We also need to track what the current rotation was before we started the interaction, so that as we go along, we can just build on top of that. And we also need to track what the angle difference was for our object compared to the center, so that we have a really accurate rotation.

So now we're done tracking this base information. We want to track now the touch move and touch end event listeners so that we can really have callbacks every time the user moves the finger. However, you notice that we do not register the events on our item in the ring. We're actually going to register the events on the whole window.

And we do that because if you want to have a good drag and drop interaction, you want to be able to drag the finger anywhere on the screen and have the interaction follow along. So even if we take the finger out of the object that started the interaction, we still want the ring to keep going and rotating. So in this case, we add event listener on window so that we always get events wherever they happen on screen. We pass this as the handler object. So once again, everything will go through ring controller and the handle event method.

And finally, we set capture mode in our event handling. That means that the event is going to go straight into the window. And we'll be able to handle the event as soon as it happens. And you'll notice we'll be using that in a little while just to make sure things work very smoothly.

So now we are ready to start listening to touch events. But we also need to implement, of course, what happens when a touch move comes in. So this all happens in our interaction move method, which was routed from handle event. So let's drop the code in here. And what we're going to do here is reminiscent of what we did in touch start. We need to figure out what the current y is, because we're going to have to do a lot of things.

Because based on that current y, we'll be able to subtract that to the previous y and figure out how much delta there was in our interaction. So what we do here is we take our start y angle, and we subtract to that the new y angle for this position so that we're going to get the exact angle delta between the first interaction and the current interaction. And once we figure out what this angle delta is, we just call set rotation, subtract the new angle delta, to the star rotation, and that will give us our current rotation for the whole ring.

So before we-- we're almost done here. Technically, we'll be rotating along as we touch along. But the problem is we also need to clean up when the interaction ends. So-- oops, sorry. At interaction end, we really need to just remove the event listeners that we placed dynamically. So we don't want to listen to touch move anymore, and we do not want to listen to touch end anymore.

We still want to listen to touch start, because we'll need that to start again when we drag in another point later on. So we're going to keep that intact. So at this point, it seems like we've done all that we need to do for our rotations. We're ready for touch move and touch ends, and we're updating the rotation as we go along. So I'm going to touch on this and start dragging. Oh, so something-- that's not exactly what I want, because we do get a certain amount of rotation, but we also see the whole page panning.

[Transcript missing]

and David . It really looks like it this time. So that is all we need to do for step two. Can we switch back to the slides, please? So let's take another look-- whoops, sorry. We're done with step two. So now we're done with the dragging interaction. We want to be able to tap on items in the ring and slide into the info view.

So you probably noticed that current web applications actually do that kind of effect on iPhone. But they do that with really what can be considered as a big fat hack. They just scroll the whole view around. And they get decent performance with it. And in our case, we already have WebKit Transform, which are great hardware-accelerated transforms, and we also have CSS transitions. And we really want to start leveraging this so that we can have smooth interaction going in and out. And we'll be able to do that just as many times as we please. And it's actually going to be pretty simple to implement.

So our goal here is we want to detect selection. And we're not going to use clicks, because we want to be a really responsive application. So we want to use touch events to figure out as soon as a tap happened on our page. And we want to be able to slide the ring out and the info pane in, and the opposite when we want to get back to the ring.

And so to do that, we're going to track touch moves to figure out when a selection happens. A tap is really going to be touch start and touch end events happening one after the other, no touch move in between. So we're going to be tracking touch moves to make sure to identify if we have a selection or not.

We're also going to want to set up CSS transitions so that when we update the transform of either the ring container or the info pane container, that we have a nicely hardware-animated transition going on automatically. And finally-- So we're going to be able to update the transform of each of those containers so they actually get transition in and out of screen. So let's get back into the code and switch to the demo machine, please.

All right, so we're going to quit this version of the project and load up a third step right here. So there's a bit more code that's already in here. It's not that interesting, so I thought I would spare you, but let's go and take a quick look. So we're going to introduce the info pane here, the info view, and we have all the basic HTML for it already laid out.

So we have a back button, we'll have an info image, which is like the snapshot of the movie that we'll be playing, some metadata, a wrapper for the title, duration, date, and the description. All of this is going to be populated by JavaScript in a single new function that we introduced, which is called update info pane.

And based on a current index that we'll be updating, global variable, we'll get into the data source, which is a simple little JavaScript file which has little objects in an array with title, fields, desk, and et cetera. Based on that, we'll be updating all the elements in the DOM to content from the data source.

So this is not really interesting. I mean, that's really pretty standard functionality. And we have a little bit of script, of course, to take care of all of that. So just info title, info description, all these are going to be laid out, font size set, and et cetera. So we're not going to worry about this right now.

We have to focus on the interaction here, because the first thing we've got to do is we've got to figure out if we have a selection or not. So like I said, we want to detect that by figuring out if we have a touch start and a touch end happening right one after the other. We do not want any touch move happening in the middle.

So to do that, we're actually going to do a simple thing, is that when the interaction starts, we're going to want to... track a new object that's going to figure out if touchMoved has been set to true or false. So each time an interaction starts, we're going to say no touchMoved so far, we just started interaction, so touchMoved is false.

And we also want-- because we're going to do selection, we want to figure out what item we touched, so that we can track it at the end of a written interaction and say, that was the item that was touched, get to the index on it, and figure out what item needs to be populated in the info pane.

So we're just going to track the current item as well in the scope of our object, in a controller object, and that will be just the current target of the event. That means the element that was tapped into our code. So that's it for Interaction Start. But of course, in Interaction Move, you probably guessed what we're going to do here. We're just going to update Touch Moved.

[Transcript missing]

So we can still drag around the screen, and if we release, nothing happens because we figured out this is not a selection. However, if we just tap, we got a selection. And we went straight into the info view. Well, OK, it looks fine. We have content based on what we just touched.

Everything was updated, and it looks pretty good. But what happened to our transitions? And we did update the transform, but we need to say, well, we need to tell the browser, I need this transform when it changes from a state to another state to be transitioned with a nice, smooth animation.

So it's probably going to be a lot of work, right? I mean, if you did this in JavaScript, you'd take a lot of code, have to manage your own timer. It'd be pretty tedious. But, fortunately, we did a lot of work for you here. And all we've got to do is declaratively in our CSS just say, when this element changes WebKit transform, animate this change of state during a certain time. So let's start with our info pane. Info pane, we're changing the transform.

It has a base transform of 320 pixels, which makes it out of the screen so we don't see it. And what we're going to do here is we're just going to add two lines of CSS. And the two lines of CSS just say, I want the property WebKit transform to be animated, and I want this to happen across 0.5 seconds. You can put in any old time you want here. So that means now every time we're going to change the transform, our info view is going to slide as opposed to just snapping.

And we didn't really do anything here. I mean, we're just changing the-- it's really about thinking what you do on the high level. You're just changing the value and let the browser work the magic to make it all happen, animated and very smooth, because all of this is done in the GPU. And so we also have to do it on the container because both elements need to slide together. So we'll do the exact same thing, dragging a little bit of code, set up WebKit transition probability with WebKit transform, and set up the duration to be 0.5 seconds.

So that's probably all we really need here. So let's run it again and see what happens. I'm going to drag around. Nothing happens. Hit Select, and things slide in. So we really didn't do that much extra work to get the animation, just a couple lines of CSS. There's still a little bit of work left to do. I mean, we want to go back.

And we have an item here on screen, but we didn't hook up any behavior to it yet. So going back to the script, we have the button in our HTML, and it's called info back button. We had an even listener for touch end. That means the touch was released on it. And we want to call go back at this point.

So Go Back is all set up for us. We just need to do a little bit of magic here to do the inverse of what we just did in Item Selected. So Item Selected is here, which is Update WebKit Transform and to a new Translate X. And so here, we're just going to do the exact opposite.

So now the ring container is going to go back to zero. And the info pane is going to go back to screen width, which means that its left will be aligned to the right of the screen, and essentially we won't be seeing it anymore. So that should be pretty simple. Do it again. Select an item, and we can go in and out very easily.

And so that concludes step three. We did a lot of work in not that much code, actually. Just a little bit of script to figure out the tech selection. Just updating transform and a little CSS to say we want the animation happening on transform. Can we jump back to the slides, please? So to recap, the core things we need to do is set up CSS transitions so that the animations happen automatically as transform properties change. So you want to set a base state for this.

A transition happens from a value to a new value. So we had translate exit to zero on the ring container when we started. And we also set the WebKit transition property to WebKit transform. And the WebKit transition duration is 0.5 seconds. If you got that, any change of WebKit transform from that point on in the element will just animate.

And the second thing was a beta transform from script. So it's really cool how we define anything in CSS declaratively, but we still can do everything based on JavaScript. So any old context-related interaction based on things you need to evaluate in script, you can do all that with no problem, because you can change the style from the JavaScript. So in our case, that's what we do. We just change the translate to slide things in and out screen. And that concludes step three. It was really pretty straightforward.

Now we're going to want to take it a step further. When we transition things to the Info View, we kind of lost context of what was activated in the first place. So we tap on an item at the top of the screen, we go into the Info View, and we go back, and we're not really sure where we hit anymore, and we lose context. And it'd be really cool if we could just rotate the selected item to the center before we transition into the Info View. And that is exactly what we're going to do. We're going to tap on something, and it's going to center the ring to center the item.

And so the key thing here is that we want to be able to do two transitions one after another. First transition, rotate center. Second transition, do what we just did before, slide the info view in and the ring container out.

[Transcript missing]

So what we did here to make sure that you always have synchronized behaviors based on your transition is that we added a new DOM event, which is called WebKit Transition End.

And based on that event, you can tell that a transition has finished, and you're ready to go to do something else. So based on that, we're going to listen to that event, and we're going to chain transition. We're going to start the first rotation through the center, and once it's done, slide the info view in. And so we're going to get back into the code here, so I'd like to go back to the demo machine, please.

and hopefully we can do that without too much trouble. All right, so, load up first step. As you notice, we're almost done here. I mean, just two steps to go. You almost have the hook. And we already have a little bit of code already set up for us here. We have a new init function on the ring controller because we're going to need to do a new thing here. And that thing is that we need to set up transition and event on our ring container.

So this function is going to be called just once. The same time we register touch event handlers at the very beginning of our code, we now need to make sure that we listen to WebKit transition and events. We only need to do that once. We don't need to do that dynamically each time we transition in and out.

To do that, we just slide in a code, and we just add a new event listener on our ring, WebKitTransitionIn, and it's always going to go back again to our ring controller, which is this object in this context. And this means that to be able to take care of it, we're going to need a new case in our switch statement. So that's pretty easy. It looks like any other switch statement, case WebKitTransitionIn. And we're going to want to call a new function called settingSelectionTransitionDone.

So a few other changes we made to this code. Because the selection behavior is going to be a bit more complex than what we did before, we're now going to call a new function called perform selection, which is empty so far. And instead of having a single callback on selection, which would automatically drag the info view straight in, we actually want to do two things. We want to have a callback for when the ring starts animating to the center, and another callback when it's done with this and ready to actually end the transition and go into the info view.

So we now have two functions. We have item being selected, which is going to be called as soon as we get the touch-in event and the ring starts to rotate. And we're going to have item selected as well, which is called when the rotation is done and we're good to go for the rest of the animation. So item selected looks exactly like it looked before. We have -- that's where we change the transform of the different containers to slide things in and out. We already know how to do that.

But the code to populate the info pane has been moved to the item being selected. We already know what's going to be selected, so we want to update our content straight away so there's no delay. All right, OK. So you also notice that we get an extra parameter called is immediate, because if we hit an item that's already in the center of the ring, we're not going to have any rotation. So we just want to go straight to item selected and update the info pane. All right, so far we haven't really done anything. We really need to get started on perform selection here. So in perform selection, we're just going to start another transition from script.

Sorry, what have I done here? OK. So in performSelection, we want to update the rotation of the whole ring. So we already know how to update the rotation of the whole ring. We have setRotation built up for that. We used that when we did dragging around the ring, which is called setRotation all the time. Because setRotation just changes the WebKit transform of the ring.

So what we have to do here is we're going to figure out what the new rotation is going to be for the object that we selected. So we look at the index of the current item, multiply it by a fraction of the full rotation, which is going to be based on the number of ports that we got. So it's really going to be-- we've got 12 ported, so it's going to be 30 degrees. And that tells us that's the rotation that we need to center that item.

[Transcript missing]

And so what we're going to do here is just say, rotation selection is done. We want to go to the next step of the transition, which is sliding items in and out. And that's done by our item selected callback, just like we used to in the previous piece of code. Update ring container and info container. So it looks like we're done here.

So now, when we select, hopefully it's going to rotate to the center and slide to the rest of the content. And that works perfectly. That's great. So now we can drag again. Oh dear. Things are going south here. I mean, the ring, it looks like there's a delay as we drag along the ring, huh? Isn't there? So the problem here is that we did set the transition on the whole ring here.

We did say WebCon transition duration 0.5 second. But when we drag along, we do pretty much the same thing. We update the rotation. That means from now on, every time we drag along the ring, we're actually going to have rotations going on on each change of the value.

And because the transitions have a nice little easing animation behavior, it's actually going to look like there's a delay. Because it's really changing a bunch of animations, like a lot of them. Every time we change position of the finger, it's going to call the new transition. And that's not what we want to do. We want to kill transitions when we're done with the rotation transition here.

So it's actually going to be pretty easy. Because the way we turned on transition by setting transition to 0.5 second, we're just going to do the opposite and set it back to 0 second. So in selection transition done, when the rotation is done, we want to reset the behavior and not have transitions happening anymore.

So we just set the WebKit transition duration back to zero second. And hopefully now we can have a nice transition, go into the info view, go back, and get back to dragging our ring with no side effect. And that's all we need to do for step four. We really unleashed the power of CSS transitions here by not just having declarative behavior, but also have nice little hookups into our script. So I'd like to go back to the slides, please. And just quickly recap what we just did here. Thank you.

So we're changing transitions. And to do that, we just set up an even listener to begin with, WebKit transition end, transition is over. That's what we got here. And just call code based on that callback to do whatever it needs to do when transition is over. It'd be really convenient, for example, if you want to fade something out on your page and remove it completely from the page to set display none or remove it from the tree when the transition is over. Stuff like that really gives you control to exactly what you want to do here.

And toggling transitions, well, there are different ways you can do it. You can set transition duration like we did to a positive value and set it back to zero to stop transitions from happening. You can also change WebKit transition property to be a name of a property like we had before, WebKit transform, or just be none where you don't really need anything else going on.

And that really wraps up what we needed for step four. And so the last step is going to be hooking up movie playback. And it's actually going to be the easiest step. Even though it looks like it's doing a lot of stuff, the new JavaScript APIs we added in Safari on iPhone makes this really easy for you to build your custom UI and hook up into the media layer on iPhone.

And so all we got to do here is when we detect a touch end on the Play button that's overlaid on the image, just tell our movie to play. And a movie is just going to be an embed element. That's what we always do on the web to play movies so far on iPhone.

And we're going to use the JavaScript Media APIs to just say, well, here's the URL for this movie. We'll load that from the data source, and please play it now. And so that's what we're going to do now by getting into the code. So I'd like to switch back to the demo machine, please. close our previous projects and go back to the last step.

So we do have a little bit more code set up here, namely in the HTML. We have our play button, which is just the image, a nice little icon, custom icon that we made that's going to be overlaid on top of the image. So the cool thing here is that even though it's a static button here, if you really want to get fancy, you could have like a big throbbing animation on your button using CSS animation so that it's really look alive. And that's the kind of thing you couldn't do with built-in controls of movie playback in iPhone in previous versions of Safari on iPhone. But we're adding new features here so we can have our own icon to do movie playback.

And we need to have an embed element to actually-- that will hook up the media layer right here. And so our embed just-- we just give the mind type of the video and give it a little handle movie so that we can get to it and call JavaScript APIs on that element later on.

So we're actually looks like we already have a bunch of stuff ready for us to go. So let's look at what it does now. The ring looks the same. If we go into the ring, we'll have a nice little play button. But we do have a little problem here is that we see an icon here, and that is because embed on Safari on iPhone has a bunch of default behaviors already hooked up. So that when you just say, here's the movie I want to embed in my web page, you don't need to do extra work to provide UI controls or anything if you don't want to. If you just want to use a built-in behavior, that's fine.

But what happens here is that instead of showing the poster frame for it or the play button for it that the embed element would show by default, because there's no SRC set up on our embed, it actually shows an icon saying, I can play that movie. And we don't want to set up an SRC attribute yet, because that's going to be done dynamically as we select elements in the page. So the first thing we're going to want to do is make sure this doesn't show up.

We can do that really easily. It's a bit of a trick. Actually, in the CSS, sorry. It's a bit of a trick, but I feel pretty comfortable at this time doing these kind of things, because what we've done so far was all so clean. So select on the movie, and all we're going to do is push it to the left of the screen.

That means it's always going to be on the page, but it's just never going to be visible. 320 pixels out of the screen, it's just going to be out there, and we don't have to worry about it. So let's read our project. And we don't have anything getting in our way. So that's really cool.

So we did a little bit more work already in the script. Just like we hooked up touch events on the back button in the previous step, we do the exact same thing on the play button. Get a handle to it with document.galvinbyid, add event listener and touch end, and call the play movie function.

So we already have Play Movie set up for us right here. And what we need to do here is really just set the source of the elements to be the new URL for the movie that we selected and call play because we're ready to go and we need to just get into movie playback mode. And so to do that, I'm just going to drag a little piece of code here. And it's really three easy steps. First step, get a pointer to the movie. That's our embed element in our HTML.

And this is where all the new JavaScript media APIs are going to be exposed on. So on this element, we'll be able to call new API straight away. So we get back into our data source with the current index, get the movie URL, and set that URL using set URL. That's a new function in Safari on iPhone 2.0. We can now dynamically change the URL of movies right using JavaScript. And now the URL is set, all we want to do is actually play the movie. So hopefully we're done here.

At this point, we get really nervous. I mean, what if everything goes wrong, and as the last step, I'll look really bad? So hopefully, we're going to click on there. And you'll notice that we actually have a little touch state here for our button. So this was actually done simply in CSS by having on our info play button an active state.

And every time you're going to touch on an element, if you implement the active pseudo class, you'll be able to change properties of the element. So in that case, we changed the background image to have the little button ring. So that's actually pretty cool. So let's try and click it again. We have our nice touch state. And if we release it, we get into movie view, and we just play a movie straight out from the internet.

And that's all we needed to do. We can actually play it, which would be even better. And once we're done, we can just reuse the current UI that's already exposed for us and just get back in our presentation. And we're done. The code is finished now, and we have all the features we wanted to implement. So can we go back to the slides, please, so we can wrap it up? Thanks. Thank you.

So just to recap what we did here, get a pointer to the movie elements, which is an embed, and just call setURL and play. That's all you got to do. There's a lot more stuff you can do with this. You can get events when you get in and out of full screen view. You can detect when a movie is done playing so that you can play another one. You can do playlists like that. I mean, there's a lot of stuff you can do. I mean, you have to go and dig into that because it's just fantastic.

And so to wrap things up, what we did here is that we put together all this cool stuff we got for you in Safari on iPhone 2.0. We used CSS Transform to leave the ring out in 3D. Obviously, this is a first in any kind of web content strictly based on web standards.

And that's coming first on Safari on iPhone 2.0. And we used Touch Event as well. Obviously, an innovation, again, of iPhone because we're the only device which has this great multi-touch display, and that's what gives you the opportunity to create those really advanced interactions in a web app.

And the third stage, we're adding CSS transitions to automatically have a state-based, hardware-accelerated animation going from one state to the other to slide things in and out. And the fourth step, we took that thing further and add the advanced support for CSS transitions to actually change transitions based on events. And that was really just fantastic. And finally, we just played movies using JavaScript media APIs. And once again, all of this stuff is new in Safari on iPhone 2.0.

So looking forward, we have actually a bit more features implemented in the main demo that we saw at the very beginning. And all that code is actually going to be available to you. I'll give you the URL in a minute. So you'll be able to actually get the code we've just done here and actually add all these great features if you're really feeling adventurous and feel you have a knack for it all. So we had a selection highlight. When you tap on something, it had a little blue background. That's really pretty easy. You just change the background color of the items in the ring. There's really nothing fancy here.

Landscape mode, again, is pretty easy. You just listen to orientation change events in your script. You can just change the CSS properties for the ring to change from a vertical ring to a horizontal ring. Just relay out your items. And we actually did this all in CSS by just applying different selectors.

We also had really great flicking. So that was actually a bit too much for this session because we didn't have time to put it all in. But using CSS animations, which are different from transition because you have key frames and you can really specify what the animation does, you can just flick, lift your finger, and just let the ring animate based on the interaction data that you just recorded.

And we also had great things with selecting a rating with touch events. So it's pretty obvious, and it's really the same kind of interaction that we did in the ring where you want to track touch moves and et cetera. And we also have really advanced hit testing in our demo because we had really drop shadows on top of the ring at the bottom and the top so that we can really have more depth to our presentation. And because we have stuff on top of the ring, we don't get even straight into the ring.

We get it on other elements. So to figure out what we hit, we actually have our own custom hit testing based on the 2D point APIs that we get from the touch events and map them out to the 3D content in the ring because we have special point conversion APIs.

And so the code for this is all available for you right now for free on the developer.apple.com website, the attendee site for WWDC. So I'll let you take a minute to actually write this down. And if you navigate to the session 391, which is our session, you'll get the code link straight from here as well as a lot of documents. So if you want to get the code, you can get it from here. And we have documentation for all the technology that's relevant to our presentation here. So developer.apple.com/wwdc/attendee.

And so I really hope you can take this home, look at it, review all the code we've done. You can download the podcast later on and just get a good feel of how everything was done. For more information, we have great evangelists. We have Vicky, who really helped us come up with this session. Mark Malone as well. Contact these people if you need any help with this or want to find out more.

And we have a coming session. We have debugging websites using Safari's integrated developer tools, where you can find out how you can do these kind of things and go into bugs and actually solve them, because it's not always that easy. And also, it's a great session about improving responsiveness of websites and web applications, where we'll be focusing on performance.

And there were other sessions this week that already passed, but you really want to check those out when the podcasts come out on iTunes and download them. And if you missed any of this, you can go back to the fundamentals of what we talked about today. And there's a great live this afternoon directly related to this session, so I hope you can come and stump us with great questions.

All the team will be here-- Simon, Chris, Dean, myself, Barry, and our manager, Gilles. So come around and just ask us anything you want to know to make this happen in your own application. And we're a bit short of time, but I think we can open the floor for Q&A. Thanks. Just didn't have time to go.

Gilles, do you still want to do it? What if you were here? So actually we have a last demo. Because we had some technical difficulties at the beginning of the week, there's a demo that we couldn't do at a Grifix in Media State of the Union, which is actually pretty amazing. I mean, it's just a lot of work put into it, and it's fantastic. So if you can go back to the phone here, please. And Chris will show it to you right now.

There we go. Okay, so we love 3D. 3D is such a fun thing to put into Safari on iPhone. And so we wanted to see how far we could push it. You know, rings, that's fine. Practical UIs, that's great. But we wanted to see how far we could take it, so we went and did a little demo here. This is a map of the world. You might notice that it's, you can kind of see them.

It's actually made up of a bunch of little tiles. These are just background images. And they just make a nice flat map of the earth. But of course, if we work at it, since we have CSS, transitions, transforms, we can reshape those tiles into a very nice looking globe.

And in fact, we can style -- We can add some nice shadowing so it looks a lot better. And then we can add, these are just little pop-ups that have some straight HTML, CSS formatted information. And it's just, you know, where people went, where people have been, what they've been doing. We can have that or we can also touch down and we can have direct interaction with this globe. We can flick the globe and have it spin around. We can look all over the place, you know, see where different people were.

And then we can let go and we can let it go back into its automatic mode and see where other people were. We can also go to one particular little information pop-up here. And what it is, is this is Peter. He actually was in New York. He actually was in New York and he sent us a little video that we can show.

You might have seen this already, so I won't go through the whole thing, but it's a very fun little short video. And also, we can look at some pictures. This is another thing that we put together. You've probably seen this in other sessions this week because it's very cool and a lot of people really enjoy it. Basically, what it is is it looks like just a regular picture, but what it actually is is a panorama.

It's actually six images put together in a box, in a cube, just using CSS transforms and transitions to do the spinning. And it allows you to look in all directions. You can actually go and grab a lot of different panoramas that are cube-mapped, six different images, and apply these and use any one you want. And so this is something that we put together just to kind of show how far we could go with the 3D, and that's what I wanted to show you.