What do you want to learn?
Skip to main content
by Craig Shoemaker
Start CourseBookmarkAdd to Channel
Table of contents
Overview and Prerequisites
What Is HTML5?
History of HTML5
It's time for a very short history lesson on the legacy of HTML and HTML5. And along the way, I think we'll get a clear picture of the difference between HTML and HTML5. The purpose of this brief explanation is not to provide a detailed account of the drama and intrigue that surrounds what we now know as HTML5, but rather as a high-level overview of what will help you recognize the relevant and main players in the formation of HTML5 because a few of these names will come up from time to time. Now back in the early 90s, Tim Berners-Lee publishes the proposal for hypertext markup language or HTML, along with the first browser and first server software. Now speaking of the first server, This is a picture of the first-ever web server. There's so much to love about this image, particularly the warning sticker that someone obviously tried to scrape off. So that's the birth of the web. Next, things needed to formalize a little bit. After a number of years of evolution, the direction and development of HTML as formalized in the foundation of the World Wide Web consortium or W3C. This is the birth of the first HTML specification. Interestingly, this is mainly a formalization of what HTML is already rather than the description of new features, which is a bit different than what we have today. So as development continued, one of the first major changes to HTML emerged in the form of HTML4. HTML4 was a really big deal in the world of web development because this was the first time it was possible to build animation and true interactivity into a web application. Now things get a little interesting. After the rise of HTML4, the W3C began work on the next version of HTML, which is mean to alleviate many of the shortcomings encountered after years of working with HTML in the real world. The next iteration was known as XHTML. This turned out to be a bit of a mistake. The whole aim of XHTML was to make HTML more strict and, therefore, harder for people and machines to work with, which should have been the first sign that we were headed down the wrong path. Well, we all have good intentions, but in the end the loser here was the end user. So something big had to happen next. A line was drawn in the sand. One camp at the W3C wanted to continue to evolve HTML, and the other wanted to leave HTML behind for favor of the stricter XHTML flavor of the markup. So then the HTML working group, known as the HTML WG, was formed to champion moving beyond HTML. But this proved to be a short-lived endeavor. Upset by the direction the W3C and the HTML WG was headed, an independent group calling themselves the web hypertext application technology working group (yeah, I know, big old acronym there) was what we call the WHATWG (yeah) was formed with the express intent of continuing to push HTML forward. Now what's interesting is that the most significant differences between these groups is really found in their culture. While the specifications emerging from the W3C is determined by consensus, the working group spec is driven by a single editor. This allows the WHATWG to make advancements in HTML much faster than at the W3C. And that is a very good thing. This difference still persists today, and it helps push the web forward, while at the same time ensuring quality and standardization of the spec. So now we arrive at the advent of HTML5. The HTML working group is largely disbanded, and the W3C and what the WHATWG decide to do is work and collaborate on what we now think of as HTML5. They're still working independently but continue close collaboration as a specification evolves. And again at the WHATWG, you have a more nimble and fluid environment where advances come a little more fluidly, while the spec at the W3C is treated with a little more academic rigor. So in one sense, you get the best of both worlds. So once everyone is in large part playing nice together, the WHATWG announces that it will no longer work on named versions of HTML. So this means instead of planning for HTML6 or HTML7, the HTML spec is now a living standard. This move makes a lot of sense if you think about it. With HTML5, you have a set of functionality that exists in the specification but is implemented at different times and at different levels of completeness by the different browser vendors. So to say whether or not your application could "use HTML5" is a bit of a misnomer. You could often use parts but not all of the APIs. So to sidestep this issue entirely, HTML continues to evolve as a living standard. This means that as new features are developed, they're added to the spec. And then hopefully soon after are implemented by the browser vendors. So you may hear people say that HTML5 no longer exists. And so when they say this, what they mean is that the latest and greatest version of HTML is simply not numbered. It's found in the living standard. Now while all this is true, I still do often talk about the HTML5 elements and new APIs as HTML5 simply out of a force of habit. So it's a bit futile to try and figure out exactly what is and is not in HTML5. What I want you to be concerned about are the different resources that are available to you that give you the tools that you need to find out what's best for your application and your situation. And one of those resources is platform.html5.org.
So here we are platform.html5.org. And as you can see here, there're a number of different advancements and APIs that are considered under the umbrella of HTML5. And you'll also notice some familiar names here. So we have icons and links over to the W3C and also to the WHATWG. And there're other standards bodies as well that make up specifications that are considered a part of HTML5. So if you want to get a good idea of what's in HTML5 or the living standard, you can always come to platform.html5.org. But let's not stop there because what I've got prepared for you next is a roundup of many of the different advancements that are a part of HTML5, and that's coming up next.
What, Why, and When
As the web platform or HTML5 continues to evolve, you'll need to make decisions about what to use and when to use it because as you saw in the timeline earlier in the course, HTML is a continually growing and evolving ecosystem. So you need a framework to help you figure out how to answer some of these questions. The first thing that you need to ask yourself is What? What advancements to the web platform are applicable to you? And there're a lot. I mean, a lot available within the browser now. So you need to be able to figure out what are your application's needs and what APIs are available that you can take advantage of. Next, you need to be able to figure out how to match the functionality to the business needs or the needs of the application that you're building. So what sorts of needs are you trying to meet? And then at that point, you can ask yourself the question of When? Are the APIs ready? Is the browser support there for you? Is everything that you need available in order for you to take that next step to build your application using these advancements? So let's take a look at What. Let's take a look at what APIs are available inside the browser.
What: Structural Elements: Part 1
Structural Elements: Part 2
Elements with APIs
If you want to draw on the page, then you'll use the canvas element for that job. Now I'll go into depth on canvas during the Drawing Shapes, Charts, and More module. The audio and video elements are largely the same thing with the obvious exception that the video element plays video and the audio element plays sound. The code sample as shown here demonstrates how you can add a source and track elements to the video tag on a page in order to define the supported media and options. Together we'll dive in to more details in the module that focuses in on native media. But for now, just know that these elements have become much more practical since the rise of mobile devices and the decline of Flash. Now the final section of elements are often used in forms and for visualizing data.
New APIs - Graphics and Typography
Interaction, Events, and Messaging
This group can make a big difference in the functionality in user experience of your applications. The first is Battery Status. As many applications are tailor-made to run on mobile devices, the Battery Status API allows your application to be aware of the amount of juice left on the device. This gives you the opportunity to adjust how your application behaves at differing levels of power. The Clipboard API and Events gives you programmatic access to the clipboard. Now before this API, we had to use Flash fallback implementations in order to have access to the clipboard. Now this is native functionality in the browser. In some cases, you may find that you want to send a message from a page on site A to a page on site B. The Cross Document Messaging API will allow you to do just that. When dealing with mobile devices, sometimes you want your applications to be able to respond to changes in the orientation of the device or screen. These APIs give you the events to respond to to recognize movement. And whether you're building a game, a kiosk app, or you just want a clean user experience, the Fullscreen API gives you and the control to make your app fill the entire client screen. Being able to find your user's location is possible via the Geolocation API. This API uses a number of different approaches to attempt to find the user's device using Wi-Fi, cellular, and GPS positioning. When looking to allow your application to record audio and video and take pictures, the Media Capture API grants you programmatic access to native devices to capture media. The Notification API gives you the ability to create toast-like pop-up notifications on the desktop. And for mobile devices, you can get access to touch events so you can respond to different types of gestures in your application. The last API in this group is a way to control the vibration capabilities of the device. Now the next section groups together APIs that deal with storage and files.
Storage and Files
When it comes to storing data on the client, there're a number of different APIs available to you. Blob URLs, the File API, and the File Reader are all related HTML5 technologies. Let's start with the File Reader and work backwards. The File Reader class provides a way for you to read in-browser file data that can come in a few different forms. The File class and Blob URLs expose the same set of functions or more formally show the same interface. But instances of the File class represent actual files in the browser's file system. And blobs represent data in chunks of bites. So blobs are a very low-level way of representing data in the browser. On the other hand, the IndexedDB API is a sophisticated object where document database is implemented entirely in the browser. If you have large sets of data that you need to store and query on the client, then IndexedDB is a great candidate. If your needs are a little bit more basic, then Local Storage may be a better fit. With Local Storage, you have the option to store data for long periods of time or just for the session. And sessions are determined by the lifespan of a browser tab. And each flavor of the API uses the same interface, so working with local storage is very easy. Now there's a lot more to come on local storage in an upcoming module. So next, let's look at APIs that facilitate real-time communication.
Real Time Communications
When dealing with real-time communication, the first API is called Push. Now as the name suggest, this API gives you the opportunity to push data from the server to the client. And it gives you a lot of flexibility. Data can be pushed to the browser even when it's running in the background on the computer. And this greatly improves performance of applications that need real-time data from the server. The next two APIs, Server-Sent Events and Web Sockets, are similar in nature to Push but are distinct technologies. Both address the need for the client to receive messages directly from the server. But they achieve it in different ways. Server-Sent Events work with a one-way channel of communication from the server to the client. And messages are sent via HTTP, which means there's no specialized server technology required. On the other hand, Sockets facilitate two-way communications and work under custom communications protocol. Now if any of this sounds confusing, no worries. Make sure to check out my Advanced HTML5 course here in Pluralsight where I spend an entire module discussing Web Sockets. Next up, let's talk about how HTML might look if you could customize the names and meanings of the very HTML tags.
Whenever we're measuring performance, using a stopwatch is not going to cut it. The High Resolution Time API gives you the opportunity to measure time with sub-millisecond accuracy. This is great for measuring operations and calculations. But if you really want to measure things like page load time, then us the Navigation Timing API. With this API, you can find out how the user navigated to your page and are able to respond to custom events related to the page load lifecycle. Have you ever wanted your page to behave differently when it wasn't the active tab in the browser? Say pause music or video perhaps? Well, if so, the Page Visibility API will allow you to respond to changes in the page's visibility based on the tab state. Now the accuracy provided by High Resolution Time pays off when you use the User Timing API. Here, you have a simple interface available to create timing boundaries inside your code giving you an easy way to measure at a high resolution how your application performs. And, finally, we have Web Workers where you have a chance to get huge performance gains by using different threads in the browser. When you create a web worker, the execution context is in an entirely separate thread in the browser. These extra threads are completely independent of the UI thread so you can crunch some serious numbers in the background, and the user will never know what's happening behind the scenes. Well the next category deals with security and privacy.
Security and Privacy
One of the most basic attacks on a website is the cross-site scripting attack where foreign scripts are introduced into a page that compromises the security of a web application. To mitigate these attacks, the Content Security Policy allows you to create a whitelist for sources of a page including scripts and styles. The Referrer Policy gives you tighter control over the amount of data that's transmitted through the HTTP referrer. And, lastly, the Web Cryptography API provides a way to encrypt and decrypt data entirely on the client. Now for the final category, everybody's favorite, the miscellaneous items.
Once you know what's available, then you need to probe the needs of your users and your applications to see which technologies fit for your circumstances. Now, obviously, this is a decision that only you can make. But as an example, you may find that you need to improve the performance of your application, which may lead you towards some of the timing APIs to instrument your code to find bottlenecks. From there, perhaps you realize that some of the lookup data is taking too long to fetch from the server, so you realize that you can cache the data on the client in an IndexedDB datastore, and then from there create a wrapper around the native API using new features of the Promises API. And it can go on and on from there, and every situation is different. But at this point, you want to find the right tool for the job, and the web platform or HTML5 has much to offer. So once you've nailed down what problem you're trying to solve, and you have some HTML5 APIs that you're considering implementing in your applications, the next issue is to deal with browser support. And this is a big deal. So let's talk about how to know when an API is considered ready to use and what to do if you need it before browser support is widespread.
As with many things in life, timing is everything. To fully appreciate the browser support conundrum, it's best if you understand the nature of how enhancements are made to browsers. Advancements on the web is not a linear endeavor. New features are proposed, and the spec is written. From there, browser makers have to make a decision of how many resources to allocate towards implementing a new feature. And just as with any development team, and this is true even for open source projects, developer resources are limited, so new features can only come so fast. Now, each development team independently selects what projects to work on. So different aspects of HTML APIs are implemented at different rates among each browser. And this is why the classic browser support disparity exists. So let's take a look at an example. Earlier in this module, I introduced you to the Shadow DOM. And this is the support profile from caniuse.com from spring 2016. At the moment, Chrome, Opera, and Android browsers are the only ones with a comprehensive implementation. Now I'm sure Microsoft Edge will eventually support it, and Firefox and WebKit have people on it. But this just illustrates that the implementations are progressively rolled out through the browsers depending on the focus and attention of the respective development teams. So when is HTML5 considered done? When you can take for granted all the features that are just there? Well you really can't. Since new features are worked on at different rates with a continually evolving living standard, you're best to think of the web as based on a continually evolving platform. Now there're some ways that you can deal with all this uncertainty, which lie in feature detection and the use of fallbacks and polyfills, which we'll discuss in short order. But for now, let's crack open the code editor and take a look at some of the basic differences between HTML4 and HTML5.
HTML4 vs. HTML5
Getting Started with HTML5 Pages
Fallbacks and Polyfills
So the big question at this point is what do you do if you're developing an application and you really need a certain API, and it's not supported by all browsers, or maybe it's not supported by some at all. The second line of defense is to turn to fallbacks and polyfills. As the name suggests, a fallback is an implementation that you can fall back to that's usually done by a third party with a different API than what you might find natively implemented in the browser. An example here is a popular library called Q which provides an implementation for Promises, which is an API that's used to deal with asynchronous processing. And it was available far before any browser supported Promises natively. Now the API, the functions in your code calls, was different than what was spec-ed out for the native browser implementation, but you generally got the same functionality. And that's the hope of a fallback, to provide similar functionality as a native feature but maybe just with a different API. A polyfill, on the other hand, is meant to replicate the exact same interface, as well as functionality as how the native implementation would be built in to the browser. The benefit to using a polyfill is that once browser support is ubiquitous, the idea is that you can simply remove the polyfill from your application, and the functionality will remain unchanged, although I'd still recommend some rigorous testing during this time. Now there's a website that can help you out a lot when you're trying to find fallbacks and polyfills, and that's HTML5PLEASE. HTML5PLEASE is a good website that gives you a pretty good handle on what's available as far as APIs and which one needs to be used with a fallback or a polyfill. So here's the home page. And as it says, use the shiny and new responsibly. So let's take a look at a new API like video. So there's three different classifications. You have use, caution, and avoid. So in this case, it says use with polyfill, and it gives you a description of how you can use the API and what you might want to consider if you're going to use it in a production scenario. Oftentimes, it's perfectly acceptable to use it with modern browsers, but if you want to use it with older browsers, then you might have to use a polyfill. Now let's take a look at another one that's classified as caution, and that's IndexedDB. Here, this is marked as caution with fallback because not all the browsers have completely implemented the API. Here at the bottom, you'll see that there're some recommended polyfills. So armed with this information, you should have everything that you need in order to have the widest browser reach possible for the implementation of this feature. Let's take a look at one last one, and that is WebSQL. This is marked as avoid. The WebSQL API is officially deprecated and is not being worked on in any browser. So this is certainly an API that if you're going to use, you need to know exactly why you're using it and what the dangers are should you rely upon it. So HTML5PLEASE gives you a good look at the state and availability of a number of different HTML5 APIs, as well as a listing of what fallbacks and polyfills might be needed in order to work with them.
Well now that you've become acquainted with HTML5 as a whole, you're ready to move on and begin working with code by using the selection API. And this is where you'll learn to use a native API to find different parts of the page. But in this module, you've learned about the collection of APIs, markup and attributes, that make up what's new in HTML5. You've learned about the different standards bodies that have brought HTML5 to life and how and why different features are implemented in the browsers at different rates. You also learned that it's easy to get started. And if you need something that's not available yet, there's a chance that there's a fallback or a polyfill available for just about any missing functionality. I'll see you in the next module where we dig in to the Selection API.
Finding Parts of the Page
In this module, you'll learn all about the Selection API that's now available within HTML5. In the past, traditional DOM selection left something to be desired. The API is limited, and it lacks some of the basic functions needed to be truly useful. In fact, the meteoric success of libraries like jQuery initially came from the need to be able to select against the DOM in an easy, reliable, and speedy fashion. Well, in HTML5, there's a host of new selectors that make it not only easy to work with the DOM but also super-fast. So let's begin working with the Selection API. But, first, I want to show you how to set up the sample code for this course.
As you download and unzip the files for this course, you'll be presented with the files and folders that you see here. So this is all of the files that are required in order to run the sample application. Now what we need to do is use Node.js in order to install the dependencies. Now there's just one dependency for this sample application, and that's a personal web server. And the purpose for the personal web server is that some of the APIs like canvas and drag and drop want a server context to execute in order to operate correctly. Now if you're on Windows, you can do this very easily by double-clicking the Install command. And once that's done, double-click start, and that will launch the website in the browser for you. But if you like to do it manually or you're on Mac or Linux, we'll do it here in the command line. So the first thing that we want to do is type npm install. Once that's installed all of the dependencies, you'll notice that now there's a node_modules folder available in the directory. And now all we need to do is type npm start. And this launches the application for us in the browser. So now let's move on to working with finding parts of the page.
querySelector and querySelectorAll
Now sometimes the elements that you want to select against the page aren't simply available through a class name or a tag name, and your needs are a little more sophisticated. So let's return back to the markup for a second. And, again, you'll notice that each one of the images has a class of img-responsive applied to it. So before we used getElementsByClassName, but there's another member that we could use to get the same type of result. This is querySelector. Now what querySelector takes in is a CSS3 selector. So before when we called getElementsByClassName, and we simply passed in the name of the class, here we can achieve the same result by passing in a selector, and in this case, it'll simply be dot (.) and then img-responsive. So what's returned from this is a single item, and this returns the first match that it finds in the document. Now if we want to find all matches to that selector, we can use querySelectorAll. And notice that I'll pass in an identical selector, so .img-responsive. Now by calling querySelectorAll, I get back once again an array of all the matches to my selector. So to make the point, let's clear this off, and let's use a selector that's a little more complicated than what we've been using so far. In this case, what I'd like to do is look at my example-container. So if you notice here, there's a div that contains everything, and this is my example-container. I'd like to go down to the list items, and I'd like to pull out the very first list item here. So we'll do that with this selector. So what this selector is saying is that look at the element with an Id of example-container. And that's delineated by the pound sign. Then I'll say inside of that example-container, look for a list item, and I want to find the first child. So as I execute that, you'll notice that it returns a single item, and that matches the first item in the list. Now notice from these brackets here, you'll see that it returned an array even though there's a single result. And that's because querySelectorAll always returns an array of results. And if there's no match, it simply returns an empty array, whereas by contrast, querySelector simply returns the first matched item from your selector.
querySelectorAll Returns a NodeList
Now in a previous exercise, I showed you how querySelectorAll returns an array of elements. Now that's not exactly accurate, and I wanted to save that discussion until right now. So, for instance, if we take a look at querySelectorAll, and we'll look at the example-container list items, you'll see that what is returned from this command is what appears to be an array of elements. But, in fact, it's not. It's actually a node list. So let's try this one more time. So here we're taking the result of querySelectorAll and setting it to the item's variable. And now when we call toString against items, you can see that it returns a type of NodeList. This is important because as you try to iterate through the return value of querySelectorAll, it's technically not an array, and so it doesn't have the same capability and functionality that you might be used to with an array. So, for instance, you can't take a NodeList and simply iterate over it using the foreach function. So with that in mind, let me show you a few different ways that you can iterate through a NodeList.
Iterating NodeList: for loop
There's at least two different ways that you can iterate over a NodeList. The first way is using a standard for loop, and another way is using the foreach method off of the array prototype. And so I'll show you the two different methods here. So let's start off by setting a value of items equal to all of the list items found in our example-container. I've got this set aside from the last clip, so here we'll just execute querySelectorAll against example-container looking for all of the list items and set that equal to the items variable. Now what we can do is build up a for loop that will allow us to iterate through each one of the items in the NodeList. So here we have a standard for loop. And so as we iterate through each item, we'll log out the innerText to the console. So these are the items that we'll be working with. So if you come down here, you can see everything from the master suite down to the shower enclosures are all the items that we'll be iterating through on this loop. So this gives you an easy and familiar way to iterate through the NodeList. Now the next approach is to use the foreach method off of the array prototype.
Iterating NodeList: forEach loop
Another way that you can execute iteration over a NodeList is to use the foreach method off of the array prototype. So the first thing that we'll do here is set aside access to that method. Now with that defined, we can go ahead and get access to the items once again. And now you can use the foreach method in order to iterate over the NodeList. You simply need to call forEach.call, and then the first argument is the list of items that you want to iterate over, and the second argument is the anonymous function that you use to execute as you're iterating through each item. And from here, we can just log out the innerText of each item. So the result is the same, but what I've shown you here are two different ways to approach iteration over a NodeList. So next let's look at maintaining results either through a live result or a static result.
Live Result from getElementsByClassName
Now once you make a selection against an element on the page, depending on whether or now you have a live connection to it or a static connection to it will determine how it behaves as it changes throughout the lifecycle of the page. So, for instance, if we were to take a look at the example-container and get access to the unordered list element, and so that would be the parent element of each one of these list items, and then change the number of list items inside that unordered list, when you're working with a live result, you'll be able to recognize that change programmatically as it happens. So let's take a look at what this looks like. So the first thing that we'll do is set aside a selection of the unordered list itself. So here I'm using querySelector rather than querySelectorAll because I want to get the first result that matches the selector. Now there's only one unordered list inside the example-container, but I want to show you how to use both API members in different contexts. Next, let's select all the list items so that we can see how many we're working with as we make changes to the page. And so here, we'll change the approach a little bit and use getElementsByClassName. And if you recall, each one of the list items has the class name of feature applied to it. So now let's take a look at how many items are in that result. So it returned 6 list items. Now let's add an item to the collection. So here I've created a new item by calling document.createElement, and we'll add the feature className to this item, and give it an innerText of new live feature. Out of habit, I put a parenthesis there. We want that without the parenthesis. So, next, we'll append that item to the list. Now watch as I press Enter, look over at the list of features, and you'll see it appear in that list. There it is. And now when I do a console.log on the items.length, you'll notice that it returns 7 even through the selection that I made for it by calling getElementsByClassName was done in advance before I'd made any changes by adding a new item to the unordered list. So the distinction that you want to keep in mind here is that calling getElementsByClassName will return to you a live result, whereas if you try to access even the same elements by using querySelectorAll, then you'll end up with a static result. Let's take a look at that next.
Static Result from querySelectorAll
This demonstration is basically almost exactly the same as what we just did except instead of using getElementsByClassName, we'll be using querySelectorAll in order to access the items. So, first, let's get reference to the list. Next, let's get reference to the items. And, again, here instead of calling getElementsByClassName, we'll call querySelectorAll. And in this case, since we're not going against a class name, we'll pass in a selector. And so here instead of looking for the unordered list like we are above, we'll look for the list items, and that will give us access to all the items. So let's take a look at the number of items right now. So here we have 6 items in the list. Now let's add a new item to the list, and this is the same code as we had before. So as we come down, you can see that new static feature is added to the list. But when we log out the number of items, you see that it still returns 6. And, again, that's because querySelectorAll returns a static result, whereas getElementsByClassName returns a live result. So this is an important distinction to keep in mind as you're building your pages. If you need to have a hook or a place where you can access elements, and you need to maintain a live result for those elements, then you'll probably want to add a class name and access them through getElementsByClassName. Otherwise, you can access any other element any way you want using querySelector or querySelectorAll using CSS3 selectors.
Excellent! You've done a great job learning about the Selection API. And in the next module, we'll turn our attention towards reviewing some of the advancements in web forms. Here we'll cover validation, new elements, and more. Let's go ahead and summarize this module. In this module, you learned about the native DOM Selection API and how you can easily find any element on the page. The new API members are both fast and flexible by providing a number of different functions that allow you to locate elements using CSS3 selectors. Now it's on to user input. I'll see you in the next module.
Working with User Input
New Elements Overview
So let's begin by taking a look at the new HTML5 form elements. New elements are meant to help people as they enter specific types of data into web forms. Rendered in Chrome as a colored rectangle as you see in the top left here, when you click on the rectangle, a color picker appears that allows you to select from a set of predefined colors. Beyond that, it gives you the opportunity to define some custom colors. You can easily access the value of the color picker the via the element's value attribute. The datalist element is interesting. By itself, this element doesn't render anything on the page, but when it's associated with an input element, then the items in the datalist appear as predefined options for a textbox. This makes it easy for you to provide some default options for an input element but still have a freely editable textbox. The datetime type provides a date picker, which allows you to easily select a date value. Now each browser renders the picker a little bit differently, but all supporting browsers give you a chance to easily cycle through months and days. In similar fashion, the datetime-local input type gives your users the chance to easily select date and time in their local time zone. And then there's the email type. On the desktop, you don't really notice much of a difference. In fact, it renders like any other textbox. However, on a mobile device, if supported, the keyboard changes to an optimized version making it easier to enter in an email address.
New Elements Overview (continued)
The URL type behaves in the same way. It's a bit uninspiring on the desktop, but as you look at it on a mobile device, you're presented with a custom keyboard layout specifically tailored for entering in web addresses. And the same goes for the telephone type. The month input type does have a custom visualization on desktop, as well as on mobile devices. The number type renders some handy spinners at the side in order to go through values and has a custom keyboard layout for mobile. The range control renders out a slider, as well as giving you control over the start, stop, and step values. We'll work more with the range element later on in this module. Circling back to user input types that deal with points in time, the week input type allows you to select a single week of a given year. And getting a bit more granular, the time type allows you to select a specific time and comes with a custom mobile visualization if supported. And, finally, we have the search input type. This renders what is essentially a regular textbox but is accompanied by a small x on the right-hand side that allows you to easily clear the value in the box. So there it is. That's your tour of all the new input elements available in HTML5. And that brings us to a closely held preset about application input. Never trust input, or in this context, never trust user input, which takes us directly to a discussion about forms validation in HTML5. So, next, let's take a look at what sort of validation support is available native within the browser.
Validation Rules Overview
New Elements: Demo
New Elements: Markup
New Elements in Different Browsers
Now let's take a look at the same page in some different browsers. So here we have everyone's favorite browser, IE 11. So let me refresh the page here, and you'll notice that autofocus works. So we have the search bar getting autofocused. As we come down, you can see that the placeholder is working for a number of different elements. And if I go to submit this, I get the message kicking in saying that I have required fields. So it's respecting the required field attribute that's set on each one of those textboxes. So I'll add in some values here. And as I tab through each field, I get the native message popping up showing me that each field is required. As I come down to take a look at the number input element, you'll notice that there's no spin button. As I try to type in some text, you'll notice it just goes away as I exit the box. The slider here's kind of nice because it shows you the step increments visually and gives you a preview of the value as you change the value on the range element. Datalist is supported. But the color picker is not. And the date pickers are also not available within IE 11. Well let's take a look at Edge. Let's start off by refreshing the page, and you'll notice that autofocus does work with Edge. This has the same capability for required fields. So if I click Save, I'll get the confirmation saying that I need to add in data to the required elements. For number of bedrooms, if I type in text, what's interesting here is that the placeholder moves along to give you a hint that you're probably not entering in the right type of data. So I can clear this out and now add in, say, 4. But there's still no spin button. But the number type will still only accept number values. Now the same type of slider is available for the range input. And, again, in Edge, there's still no color picker for the time being. And for the date input type ranges, we still have some nice visualizations available for month, week, and datetime-local. Next, let's move along to Firefox. So as I refresh, you'll notice that autofocus works and that's great. I'll try to submit the form, and you'll notice that I have the native validation popping in. This is applying the class a little bit differently than it did in Edge or Explorer. Here if I try to type in text to the number type, it shows that it's invalid, but I do have spin buttons here so I can clear this off and start going through the values. Now, remember, the max value on this element was 6, so I'm not able to go up or down with the spin buttons any more than that. And I'm also using the keyboard here, and that spins through them as well. The range type is a little more of a traditional look than what we saw in Internet Explorer and Edge. And as we take a look here, we've got color picker supported but still no date picker's available here within Firefox. Let's look at one more browser. Let's take a look at Opera. As I refresh the page, you'll see that Opera does support autofocus. And here I have the native validation messages showing up for each of these items. If I try to type in some text to the numeric box in Opera, nothing shows up. It's not until you start entering in some numerical values that you get to see the values showing up within the box. The range type in Opera is actually quite nice. It's a simple slider here. And datalist shows up here within Opera. We've got the color picker and essentially the same rendering of the date pickers as what we saw in Chrome. So now let's take a look at implementing some forms using some of the native validation support.
Building Interactivity with CSS Pseudo Classes
Custom Validation Messages: Demo and Markup
So here's the overview for this code sample, and let's start at the bottom and work our way up. So what will happen is as you click on the Login button, it will run the validate function. So we'll take a look at validate in just a moment. But I'll turn your attention here to the inputElements and what's being selected on the page are all the inputElements that are not buttons. And then once we do that, we'll loop through each one of them and hook up validate for onblur and validationFail for oninvalid. So essentially what happens is that as you're tabbing through the form, it will validate as you go off of each one of the inputElements. And once the invalid event is raised, then it will call validationFail. Now let's head up to the top. So the first thing that I'm doing is creating an array called ruleNames and then setting aside the forEach method off of Array.prototype. Now the reason that I'm doing that is because what I want to do is look at each one of the ruleElements, so each span that has a data-rule applied to it, and I'll go through each one of those and grab the ruleName out of the data-rule attribute of those elements. So as I spin through each one of those, I'll add each one in to the ruleName's array by pushing it in here. So what this does is fills up the array here called ruleNames with each one of the ruleNames that are defined in the HTML. Now with that set up, let's take a look at the validate function. So, again, remember, validate runs when you click on the Login button, as well as when you blur off of each one of the inputElements. So the first order of business here is to find the validation-messages and the span is inside of those. Now the reason that we're looking for these is because as this loop indicates, we'll hide each one on the form. So essentially all the validation-messages are being hidden upfront. And then as we go and check validity for the form, we can turn on the validation message that's appropriate for each broken rule. So calling checkValidity validates the form. And then if anyone of the inputElements is invalid, then it will call the validationFail function. So as we look in here, this is associated to an input element by way of the oninvalid event handler. And so we'll look at the element in question. e.currentTarget is our way to access that. And then we'll also set aside the validity state by looking at element.validity. So if validity.valid evaluates to false, then we'll go through each one of the rule names and call the checkRule function passing in the validity, the ruleName, and this element. And then I'm calling e.preventDefault here just to make sure no other actions happen on the form as we're checking validity. So, finally, the implementation for the checkRule function is right here. So we'll take a look at the validity state passing in the ruleName. So if the ruleName that we're looping through exists in the validity state, then we can go through by calling element, nextElementSibling, querySelectorAll, and using the selector of data-rule and passing in the ruleName. Then we have all the rules that we need to show on the page, and then we can loop through each one of those and remove the hide class. And that will show all the custom validation messages based off the invalid elements.
Bootstrap Module: Demo and Markup
Music & Video (without Plugins)
Welcome to the Music and Video module of HTML5 Fundamentals. In this module, you'll learn how to add media support to your applications using the native media players. We'll take a look at what's included in the media APIs and how to work with them, plus I'll show an overview of browser support for the different media types. HTML5 media consists of at least three parts. First, the native media element. This is the audio or video tag used in your HTML markup to host a media file. Next are the different media types. There are scores of options available to you when it comes to encoding and packaging media. So I'll briefly cover how these are supported by the major browsers of the day. Lastly, there's the Speech API. Have you ever wanted your application to respond to speech? Well, this is the API to do it. Now the Speech API is out of the scope for this fundamentals course. But as we move on, let's go ahead and touch on browser support and media types.
This slide charts the different media types that are supported in different browsers by the audio element. The WAV format is supported across the board except for Internet Explorer. MP3 and MP4 work in all but Chromium, which is the open source baseline for Chrome, but Chrome itself obviously fully supports both formats. And, lastly, OGG is a little less supported, where Edge and Internet Explorer and Safari Desktop do not have support. In the end, most audio formats on the web are found in MP3 as support is widespread, and it features an acceptable balance between file size and quality. Alright, now let's look at video formats.
For video, here supports gets a little more patchy. Notice how the legend at the bottom left has indicators for partial and pending support. Now partial support means that it may be supported in one operating system but maybe not another. And pending means that it may be available in preview builds of the browser. So first up is Theora, which for now is not supported in Edge and is partially supported in Internet Explorer and Safari Desktop. Next is H.264 or one of the formats that we know as MP4 Video. The only unsupported one here is Chromium. But, remember, very few people actually use Chromium as their actual browser. Then HEVC, another MP4 format. This is newer and while it currently isn't supported across the board, it's likely to come. VP8 or Google's WebM format is partially supported by Edge and Safari Desktop while IE will likely never support it. And, finally, the successor to VP8, VP9 is pending on Edge and not supported in IE or Safari. When encoding and packaging video, many different factors come into play. But at the moment, the H.264 format enjoys the most widespread browser support. One last thing, as you host video from your web server, the content types are very important. If you do not serve the video files with the matching content type, then the browsers will not know how to process the video. The content type values will vary depending on your video format. So make sure to check the documentation for each format you intend to use. Well now that you have an idea of the formats that are supported by which browsers, let's take a look at the basics of working with the audio and video elements.
So let's start off by talking about some of the basics of the media element. So if we come up to Media and select the Basics demo, you'll be able to see the code that I'm working with here. Now as we look down at the video, it doesn't really look like much special. We just basically have a picture, and there's nothing really there for audio. Well the video and audio elements are here, but the controls are not turned on yet. So let's switch over to the code and make a few changes. So here you can see that I have a video and an audio element on the page. And they're loaded with a number of different sources. So here I have an MP4, an OGG Vorbis, and a WebM format each for the video. Down for audio, I have an MP3, OGG as well, and WAV. Now according to this comment up at the top, we want to serve the MP4 first so that the iPad can pick that up. And that's just done to ensure that your media is served in the most reliable fashion. Now let's go over here to the video element, and we'll add controls. And do the same thing with the audio element. Now when we refresh the page, you can see that each one of the video and audio elements now have controls associated with them. So for video, I can come and press Play, and the video's displayed. There's some volume control. And I can also mute the sound, as well as there being a time tracker here. And also I can go full-screen on that video. For audio (music playing), there's the scrubber, the Play and Pause button, mute, and volume control, And the time tracker. So by adding the controls attribute to the media element, it displays the controls on the page so that you can work with it. Now the reason it's optional is because you might want to have a situation to where you're controlling all of the different aspects of the media whether it's playing or pausing, volume, speed, any of those. I have a demo coming up that shows you exactly how to do that. But in the meantime, let's take a look at a few more attributes that you can use with these elements.
Basic Controls (continued)
Well make sure to stick with me for the next module on drawing shapes and more. But to summarize what we've learned here, we've talked all about music and video. Now this is all native support available without any plugins and accompanied by a very rich API. We've had the opportunity to take control of speed, volume, placement within the media, and even be able to automatically load media in any order that we want. Well thanks again for joining me. Let's move on to the next module on drawing with the browser's canvas.
Drawing Shapes, Charts, and More
Drawing Shapes, Charts, and more. In this module, you'll learn the basics of the Canvas API, and together we'll cover what you can and can't do and a little bit about what you should and shouldn't do when it comes to using the canvas. You'll learn how to draw paths and shapes, use transformations, learn to manipulate the canvas with state management, create dynamic charts, and even extract a thumbnail image from a running video. Now before we begin discussing the canvas, let's contrast two different types of images. The first is a vector image. When you think of vector images, you can think of the type of image often associated with Adobe Illustrator where the image is made up of a set of instructions of how to draw the image. And this is all rendered on the fly when the image is displayed. Vectors are often used to form relatively simple shapes or compositions of shapes that make a larger image. One of the benefits of a vector image is that you can scale the image to any size that you want without losing resolution. Here you can see how the smaller image is just as crisp as the larger one. Now another type of image that you encounter is a raster image. Raster images are like JPEGs or PNGs or GIFs. These are images with a set dimension where every pixel within the defined space of the image has a designated color. Raster images have many advantages. In fact, the web is built on these types of images. But one of the drawbacks is that as you increase the size of the raster as shown here on the right, you begin to see that the image loses fidelity as the dimensions are stretched beyond the original intent of the image. So rasters, though, are great for pictures where you need to have explicit control over the color of each pixel in the image. Now when you think of HTML5 canvas, we're talking about rasterized images supported within the dynamic drawing surface.
What Is Canvas?
So a canvas is just that, a drawing surface similar to what an artist might have along with a paintbrush or a pen. You can draw shapes, apply colors, and even manipulate images on the canvas. And the rasterized nature of the canvas gives you a pixel-by-pixel control of that drawing surface. So how does it work? Well the canvas is the marriage between the HTML element and the canvas API. So let's talk about some fundamentals. There's an underlying grid system used by the canvas, and it may be a little bit different than what you remember from your high school math class. Here you want to more along the lines of cascading stylesheets. Positive values are found in the southern and eastern axes of the grid, while negative values are found in the northern and western axes of the grid. So if you were to render out a canvas in the browser, position 0, 0 rests at the top left corner of the canvas. Here the canvas is shown as being rendered at the top left corner of the browser, but, of course, you can place the canvas anywhere on the page that you wish. This is just to give you a mental model of how the canvas operates. To give you an idea of how to use the canvas, let's draw a simple triangle together.
Drawing Basics Part One
Here's the final result of what we hope to achieve. The first step is to begin with a blank canvas and gain access to the drawing context. Now the code I'm showing you here in the slides is a bit abbreviated. But I want you to get a feel for how the API works before diving in to the details. From the context, the first command to call is beginPath. What this does is tells the canvas, Be aware of what's coming next as it needs to keep track of all the coordinates being fed into the drawing context. The next step is to locate the starting position of the context to begin drawing. By calling moveTo, the drawing position on the context is set to an X position of 75 and a Y position of 50. Now that the starting position is established, the next command is lineTo. The call to lineTo creates a line from the starting position to a given destination. In this case, it's a straight line down as the X value remains the same, but the Y value is changed to 100. Now at the moment, the drawing context is only beginning to give instructions of where to draw lines. The actual line is not being drawn yet. And, in fact, in this case, a line won't be drawn at all, but the shape will be filled with a solid color. That command will come in a moment. The next operation is to give instructions to create a horizontal line at the bottom of the triangle. By calling lineTo again between 25 and 100, the left-most point of the triangle is established. The last step is to fill the shape with color. The call to fill does two important steps. First, it takes the last point in the path and connects it to the first point. This is really useful because it makes it easy to automatically close a path. And then as the function indicates, it also fills the now-closed shape with a color. In this instance, the default color of black is used. So that's the basics of working with the canvas. You begin drawing with the context. You give it one instruction at a time, and once you know how to appropriately apply the tools, you can do some amazing things.
Drawing Basics Part Two
This next demo shows you how to work with the fillRect function in order to create a number of different types of shapes and effects. So notice that I've created two squares here, and so I'm kind of doing that on purpose to show you that you will use fillRect to create squares. You can just pass it the same dimensions in order to create a square. So I've got a red square here. That's a full transparency. Then I have this blue square that's set at half transparency. And then I have this section here in the middle where there's a green outline, and the middle of that square has been cleared out. And that's accomplished by using the clearRect function. Let's take a look at the code. So I'm grabbing reference to my canvas and then taking a look at Modernizr.canvas to make sure it's supported. Getting reference to the context. And the first thing that I want to do is set my fillStyle. Now I'm doing this because as I call fillRect in the next statement, it needs to know what to color it. So here I'm passing in an RGB value. Before you saw me using hexadecimal values. You have the option of doing one or the other. So this is rgb(500,0,0). That gives me a nice red color. And then I can create that rectangle by giving it the X and Y coordinates that I want it to start off with, as well as the height and width of the rectangle. So in this case, it's a square because it's 100, 100. Now by calling fillRect, it creates a red square because just previous to that command, I called fillStyle passing in the correct color. So now what I want to do is create another box. This time I want a blue box with transparency. So now I'm setting the fillStyle to RGBA with an alpha channel and setting it to 0.5, so 0, 0, 500 gives me a blue color, 0.5 says that I want it to be halfway transparent. And then I can call fillRect giving me a different position here for the X and Y coordinates but the same width and height so I have the same dimensions for that square. So by calling fillRect, it will take the style that was applied right before it and create a rectangle for me. Now in the middle, I have this box that has a green outline, and it cleared out the contents of that box. And so to accomplish that, I want to call clearRect. So, again, it's the same set of arguments. I've got my X and Y coordinates of where I want that rectangle to appear. I've got my dimensions. So in this case, I have my height and width of 20. And I'm clearing out the rectangle in that spot. But to finish up of what I showed you in the beginning, I want to create a green outline around the area that I cleared out. So I set strokeStyle equal to RGB and a color that maps to the green shade. I set my lineWidth to 6, and then do strokeRect, which strokes the outside of a rectangle. And you'll notice that I have the very same arguments that I passed in for clearRect--115, 115 for the X and Y coordinates, and then a height and width of 20 each. So when we take a look at the end result, we've got the red box. We've got the blue box with the alpha channel. We've got a cleared out box. And then we have a rectangle with a green stroke around it.
Order of Operations
Now one of the things I want you to be aware of is in the order of operations does affect how the commands are applied. As this diagram depicts, if you apply a fill first and the stroke the path, the stroke is distributed along the boundary line where half the width of the stroke is inside the shape, and the remaining half is outside the shape. Alternatively, if you stroke the shape first and then apply the fill, the entirety of the shape is filled with the given color effectively making the stroke half the thickness of what it might be otherwise. So if you're creating shapes that need to have identical strokes, make sure the stroke and fill order of operations is the same among your different shapes.
Arcs, Text, and Gradients
Effects: Scale and Rotation
One of the features of the canvas API that can really save you a lot of time is state management. Now here I've brought you back to the same demo that I create earlier when I created the rectangles except with some slight variation. You'll notice I've got the red box, I've got the blue box, and the clear rectangle with a green outline. But in between the steps of creating that blue box, what I did was save the state of the canvas. So once I saved that state, then I can make changes like calling translate and scale and a few other things, create that box, and then restore back to the previous state of the canvas, and then create the green box. So the whole point of state management on canvas is that what you can do is take a snapshot of the canvas, make some changes, and then revert back to a previous state. And it's stackable too, so if you save state on the canvas multiple times, each time you call restore on the canvas, it'll back you up to the last snapshot on that stack. So, again, this code is exactly the same as what you saw before with just a few minor changes. So you'll see here I've got a place to build up that red box, but then I'm calling context.save. At this point, I've created a snapshot on the canvas, and then all the code that's between these comment blocks, they call the translate, rotate, scale, and then even adding that blue box, that's all done in isolation on the canvas. So I can call all of those commands and then come down here to context.restore, and now the canvas is reset to this state before any of those commands are done. So now when I call clearRect, even though I called translate and scale previously, those are essentially undone because I've gone back to a previous state of the canvas. And, again, they're stackable. So if you call context.save many times, each time you call context.restore, it'll go back to the last one in the stack. Now let's talk about animation on the canvas.
Clipping during image manipulation involves taking a certain area of an image and restricting rendering to that specific area. Here you can see a circular mask or a clip area and how it's applied over the image. By creating this clip area, changes made to the image inside the circle are rendered while changes that fall outside are disregarded. This is the same concept when you use clipping in canvas except the same rules apply to the entire canvas rather than just a single image. The following demo uses images, as well as shapes on the canvas to demonstrate how the clip feature works in detail.
Just as I showed you in the slides, the first demo that I have available for you here shows how to apply a circular clip area to the canvas. So the thing I want you to pay attention to right now is the order in which everything is done, and I'll move things around a little bit so you can kind of see how the order affects the way the canvas interprets the commands. So starting from the top here, I have beginPath. I create an arc. And then I call context.clip in order to create a clip area in the canvas. Now the way the clipping works is that you need to create your clip area first and then apply commands to it in order to have the clipping work correctly. So here I've created the clip, and then I create a new image, and then draw that image onto the canvas. Now you notice I've stroked my image with an outline, and I have a lineWidth of 15. But, in fact, the lineWidth that you're seeing here is much smaller. It's about half a size smaller than that 15 lineWidth because, remember, when you stroke path, half of it falls on the inside of the path, half of it falls on the outside of the path. But some of that outline is falling outside the clip area so you're not seeing it. So let' me update this code a little bit, and I'll rearrange things a bit, you can kind of see how things change. So I've moved things around a little bit, and you'll notice here I'm starting off by creating the image first, and then coming down after this, calling beginPath, and creating the circle clip area. So let's execute this. And you'll notice that nothing's different. Now the reason nothing changed is because although I have my instructions for beginPath and creating a clip here at the bottom, because of this callback, all of this code is running after the clip has been established. So essentially the order of operations is the same as what you saw before. Let's update this one more time, and then I'll call the clip after the image has been loaded. We'll see how that changes things. Now things start to look a little bit different. So notice again the code here in the onload function. So the image is loaded and then drawn on to the canvas. I begin to create a lineWidth and strokeStyle and try to stroke something, but that's all called before beginPath has been called. And then I call beginPath and build an arc and try to clip it. And so nothing happens at this point. So if more code executed after context.clip, then it would only show inside the clip are. But this is meant just to illustrate the fact that you need to create your clip area first and then the commands that come after that are applied to the canvas. Let me go ahead and reset this back to the way it should be. So just as I've pointed out in a number of different ways, the way and the order in which you add commands to the canvas make a big difference. So here we are back to calling beginPath, creating my arc, and clipping that circle so that once the image is loaded, it loads into that clip area. So, of course, you're not limited to using circles. So let's take a look at how you might clip with a rectangle.
This next demonstration shows you how you can use a clip area with a rectangle, as well as with the circle. So no surprise when I call beginPath and create a rectangle and clip that area. Once the image has loaded and it's drawn on to the canvas, the clip area is in this case a square but using the rectangle API. Now just to drive home the point that once you apply extra commands to the canvas after you've called a clip, what it'll do is discard any information that's outside of that clip area. So let me update this code one more time, and you can see what happens if I draw another rectangle after I've drawn the image and after the clip area has been established. So what's changed here is really not much. I've added two lines of code down here at the bottom. So you can see I've added fillStyle. I gave it an alpha transparency so you can see that as I create that rectangle, you can see it on top of the image. And then I called fillRect. Now the arguments that I've given here are what's significant. So I said start at position 0, 0, so it's starting up here at the top. And then I've given it the dimensions of 100 px by 100 px tall so it's essentially a square. So once that's rendered onto the canvas, you'll only see a part of it because it falls within the clip area. So let's take a look at this without the call to clip. So here I've commented out context.clip. And now you can see that I have my full image. I've got my full stroke. And I have my full box that's all rendered onto the canvas. But since there's no clip area, it's not restricted to a certain part of the canvas. So, next, let's investigate how you can reset clip areas once you've applied them since they have so much power over the canvas.
Clear Clipping Areas
Now sometimes you'll apply a clip to the canvas that you want to have available only for a certain amount of time because it's pretty powerful in the way it restricts the way that you render out to the canvas. So I'll show you the code here in a second, but in this demo I've created sort of this weird shape on the canvas. And then after I created my clip area of this strange triangular shape, then I created a rectangle or square and applied it. And you'll notice that only a certain part of it is showing up, and that's the part within the weird triangle shape. But then what I do is remove the clip area and render out another box within the canvas. And this shows up unrestricted by the clip area. So there's a special way that you need to use in order to reset clip areas. So let's take a look at the code here. I start off by giving a fillStyle, and I set up the strokeStyle and lineWidth and everything for my shape. And then I'm calling context.save. At that point, I can call beginPath, and then I draw out my strange triangle shape, call closePath. I stroke it and then call context.clip. After I call context.clip, then I can call fillRect. And this is kind of a big box. So it's starting at the 0, 0 position. It's 215 by 215. But all that renders out on the canvas is what shows up in my clip area. Now you would think that in order to reset your clip area, you could do something like this. You could call context.rect, and you start at the 0, 0 position giving it the full width and height of the canvas, so basically opening it up to the entire dimension of the canvas, and then calling clip. Unfortunately, that does not work. The way that you reset a clip area is by using a technique that you learned previously, and that's through state management. So, remember, I called context.save at the top before I created my clip area. Now what I can do is come down and say context.restore, and that essentially removes the clip area. So when this call to fillRect is done at position 200, 200 giving it a height and width of 50 px, when that command is run, it renders outside the clip area because context.restore has removed the clipping that's been applied to the canvas. So you can see how state management quickly becomes something that's really valuable as you work with the canvas because once you apply a clip to the canvas, any of that information that falls outside of the boundary will be discarded. Well, so far, the clipping's been pretty simple and basic. Now let's talk about creating a clip area that's with some noncontiguous areas.
Clipping Non-contiguous Areas
Now so far every clip area that I've shown you has been a circle or a rectangle or even some weird triangle shape. But it's all been one shape. So what I'd like to show you now is how you can create a clip area that's noncontiguous. And the point is you can clip on the canvas using any sort of shape or geometry that you want. So I've executed the code here, and you can see how this runs without any calls to clip. So I have a large box that I have rendered out onto the canvas here. I've stroked a couple of areas on the canvas, and then, lastly, I've created another box here at the end that's roughly the same size as my stroke areas. So now I'll uncomment out the call to context.clip, and we'll see how things change. So notice with the clip area defined, now I have what seemingly looks like three different boxes on the canvas, and two of them are outlined. The key here is I'm creating two different types of rectangles before I call the clip function. And so essentially what happens even though I have that large box in the background, I'm slicing through two little windows on the canvas. So once those commands are applied, the only thing that shows up is the stroke and the background color. And I'm getting that last box on the canvas because once I call context.restore, that removes the clip area, and then I can do a fillRect or anything that I want afterwards. So the main takeaway to this demonstration is the fact that your clip areas can be anything. If you need it to be a simple shape, you can do that. Or you can punch holes in the canvas and clip any way that you want. So let's put everything that you've learned all together right now and create a magnifier on an image.
Demo: Magnifying Glass
Now by bringing together everything that we've learned so far, we can create something that's a big more interactive. So here on my image, if I click on the image, I have a magnifier, and it zooms in on a certain part of the image. And if I click, it goes away. So to create this, we'll strokes paths, we'll use clipping areas, we'll use state management, a number of the different things that you've seen so far in order to create this sample. Now the code's a little bit longer than usual, so I'll drop down to my text editor, and we can take a look at it there. The basic structure for the way this is set up is pretty simple actually. So the first thing to do is initialize the canvas with some of the basics. This draws the image out on the canvas and sets aside the image data so that we have it later when we want to add it into the magnified area. But when the canvas is clipped, it looks to see if it's been magnified. If it's already magnified, then it reinitializes the entire canvas. Otherwise, it calls the function to magnify that area of the canvas. Well, let's take a look at the init function first. The first thing the init function is concerned about is loading the image onto the page. So here it has the img.src, home.jpg, and then I'm setting up a flag to say that isMagnified is equal to false. Once that image loads, then it can draw onto the context. But then I can go to canvas and call toDataURL. Now this is important because what this will do is give me basically a string representation of all the data of my image so that when I go to magnify it, I don't have to load the image in from a server or the file system or anywhere else. It all exists within memory here. So the init function will be called when the canvas first loads, as well as when we click on it to remove the magnifier in order to reset up everything to its initial state. Now let's look at magnify. Now to start things off, the first thing I'm doing is calling context.save. And so that ensures that anything that I'm doing within this command to magnify is all done basically within its own logical container. Then I want to set up some defaults. I'll set up the lineWidth, the shadowColor, and some basic settings for the shadow itself. So as I'm creating the circle around the magnifying class and also the handle, I want both of those areas to have the same shadow settings, so I set that up ahead of time. Then I'll call context.save again because what I want to do is create the glass area of the magnifying glass next. So by calling beginPath and moving to a certain area within the canvas, then I can draw that circle. I'll give it a lineCap of round, lineWidth of 30. Then I'll call context.save again, and I can begin creating the handle for the magnifying glass. So by calling beginPath and moveTo(230, 230), that puts me in the correct position to draw the handle on the canvas. I want lineCap set to round so that the handle looks like it's rounded. And then give it a pretty big width, so here I have 30. And then I can lineTo(285, 285), which gives me a diagonal line, which will represent the handle. Calling stroke on that will render out the handle onto the canvas. Next, I want to create another path. So I create a circle for the glass of the magnifying glass. And then once that's set, then I can create a clip area. Now since I've clipped the canvas, I can go ahead and render in the image. So here I create the magnified version of this image and set the source equal to dataUrl. So this is the text-based data that's been set aside for that image. So I don't have to load it again from anywhere else. I can add that into the source for my image. I can scale that up to 150% and draw the image on the canvas. Now since I'm using the clip area, I don't need to worry about any extra settings. All I need to do is draw the image on the canvas. Then to clean things up, I call context.restore. That removes the clipping area. And then I can stroke the arc around the glass part of the magnifying glass by creating an arc and calling stroke. And then I call context.restore to restore the canvas back to its original state before I started applying any settings to it. I flip the bit on magnified to say that isMagnified equals to true. And so now when we go and click on the canvas, if it's magnified, it reinitializes it. Otherwise, it'll apply the logic to magnify the canvas. So that wraps up clipping. Now we can continue doing interesting things by building some charts using the canvas.
Demo: Static Chart
Demo: Dynamic Chart
This next example builds upon the last one where well still use a background image for the canvas for the chart. But what this does is it simulates a service or some data coming in at different intervals that you're drawing on the canvas. So instead of clearing out all of the information that's on the canvas during each one of the frames like we did with the animation sample, here what's happening is a segment by segment piece of the data plots is being added to the canvas at a time. There's a little bit more code for this demo, so I'll drop into the code editor so we can look at that piece by piece. Now since I want this to be a stand-alone sample, what I've done here, I've set up the demo with an array of data objects. So here I have month and performance. So this could be, say, charting a stock for a stock ticker. So I have the chart data here. And then I'll set aside variables for the canvas, the context, and the index. So the index will keep track of the item that we'll looking at based off the data array. Now most of the work will be done here in the drawSegment function. So I'm keeping track of the data points by having x1 and y1 and x2 and y2. So this is basically the start and stop points of each one of the segments on the chart. So as this function executes, I'll go into the chart data, take out the month and performance points based off of the index. That'll be the start position. And then the end position is accessed by taking the index + 1, and then I'll have month and performance for the end point. So for each one of these segments, I'll call beginPath, move to the starting point, and then create a line to the ending point, and then call stroke. Then I'll update the index so that next time drawSegment is called, I'll be looking at the next data pinot in the array. So now let's look down at how this is called. So here's the standard ceremony of ensuring canvas, of making sure we have the context, and everything that we need. And so I'll load in the background image. Here I'm setting the source. And once the image is loaded, I'll draw it into the context by calling drawImage. Then I'll call drawSegment the first time. Now the formatting of the line is set up here by setting the strokeStyle, the lineWidth, and the lineCap. Now like I said, the first segment will be drawn as the background image is loaded. But then I'll set up some animation. And this is just here to simulate a call being made out to an Ajax service or use of web sockets or some other method of getting data into the page. But here I'll just setInterval for every 750 msec and drawSegment. Now I'll go ahead and clear out the interval once we reach outside the bounds of the chartData. So this cancels the animation once it's done. But the main point for you is that you can continually update the canvas, just like I'm doing here, by going to beginPath, moveTo, lineTo, and then stroke as many times as I need in order to plot the data points on the canvas.
Demo: Video Thumbnails
In this last demo that I have prepared for you, I'd like to show you the amount of flexibility that you have available in the canvas. So the way this works is I have a video element on the page. And as I press Play on the element, I can click this button and extract out a thumbnail from the video. So what's going on behind the scenes is that as the video is playing, I'm passing the video element into a function that extracts out the frame's image data and passes that into the canvas. And so once I have that data, I can render in the canvas. And so even though you can do all kinds of drawing within the canvas, here you could see how you're not left to do all the work on your own. You can load in images directly or even from a video. Let's take a look at the code that makes this all happen. So starting off, I'm just setting aside some variables for different elements on the page. So here I have the video itself, and then also the canvas. Of course we'll need access to the drawing context of the canvas so I've created this variable here. And then also I have the buttons and a container for the thumbnails. Now most of the work is done down in this function called getThumb. But before we get there, let's take a look at the width and the height. So I want all of the dimensions to be uniform. So the video.width, the canvas.width, and the video.offsetWidth setting equal to 320. And the unit of measure here is pixels. Doing the same thing for height, so the video.height, canvas.height, and the video.offsetHeight is set to 180. So now as we run the function for getThumb, I access the drawing context of the canvas and call the drawImage function. Now by passing in the video as the first argument here, the current frame of the video is the source of the data for drawImage. Now I want to draw it on the canvas at the 0, 0 position, and I'll pass in the width and height that I've already set aside. Now I can create a new image, and then I can set the source of that image as what comes out of toDataURL. Now here I'm passing in the content type of image/PNG. And so that is set as the source of the image. I'll scale down the image just a little bit by setting the width to 60 and then append each one of those thumbnail images into my container by calling thumbs.appendChild. So all that's left to do is to wire up the button in order to call getThumb. So here I'm calling addEventListener, looking for the click on the button, and so when you click on the button, it'll run the getThumb function. So once again, as the video plays, we call Get Thumbnail, and it writes the image data from the video into the canvas.
Now that you've had a chance to learn all about canvas, make sure you join me for the next module that discusses HTML5 drag and drop. Well here we've been talking about drawing shapes, charts, and more, and that's all done through the canvas found in HTML5. You saw how it's a raster drawing context where you have control on a pixel by pixel basis of what you can draw within that context. And you can apply different effects from translation to scale. You have the full ability to manipulate what's drawn on the canvas. Well, alright, let's move on to the next module where we talk about drag and drop.
Drag and Drop
Welcome back to HTML5 Fundamentals. This is Craig Shoemaker, and thanks for joining me for this module on drag and drop. In this module, you'll learn the basics of drag and drop, learn about the event pipeline and restrictions of drag and drop operations, and learn how the browsers deal with the drag and drop data internally. Now the drag and drop functionality is driven passed off of events, so let's dive in to each one of these events now.
So how does drag and drop work? Well first you need to define a drag source and a drop target. Once the elements on the page are marked as draggable, then you may drag them around onto elements. But the number one rule that you need to keep in mind about this API is that you must cancel the default behavior on drop targets in order to allow the drop action to execute. Now this might seem a little counterintuitive at first, but the reasoning behind this implementation is to keep pages secure. So while you can drag elements all around the page whenever you like, in order to handle a drop action, you must explicitly tell the drop target to accept the draggable action by preventing the default behavior and appropriately handling the drop events. Now there're a number of different events associated with the drag and drop API. At first glance, the events may seem a bit unruly. There're no less than seven different events, and a number of them are required for you to handle in order to implement drag and drop behavior. Events are either associated with the drag source or the drop target. The drag source is the element you click on and drag on in order to initiate a drag operation. The drop target is the element you drag the source over and eventually drop onto. This slide depicts how the events are associated with either the source or the target. Now let's take a look at them individually.
Events in Detail
As you click on an element and begin to drag it, the dragstart event fires. Then as an element is being dragged, the drag event fires. Once an element is dropped on the target, then all drop target events are fired. And then, finally, the dragend event fires on the drag source. Now an important thing to note here is that the drag event continuously fires as the drag is happening on the element. And you'll see this in more detail once we arrive at the events demo. Alternatively, on the same operation, there are events that fire on the drop target. As the source element enters the boundary of the target, the dragenter event fires. Then as the source is over the target, the dragover event fires. Now much like the drag event on the source, the dragover event continually fires as the source is being dragged over the target. Now if you drag the source off the target, then the dragleave event fires. But if you drag the source over to the target and then drop it, the dragenter, dragover, and drop events all fire. Let's see it in action now by checking out the demoes.
Basics: Demo and Markup
Let's start off looking at this demo from the bird's eye view. I want you to get an overview of how this code works before I dig in to the details. So you'll notice first that I have a drag source just like we talked about on the slides. So here's the drag source, and then also a drop target. For the source, I can add an event listener for the dragstart event, which we'll call the dragStart function. And in there, it'll set everything up that's required in order to handle the drag and drop operation. Then from the target, you'll notice there're three events that are handled. There's drop, dragenter, and dragover. The only event that has any sort of functionality applied to it is the dropped function. Everything else is canceled because, remember, as I told you in the slides that some of these events need to have the default functionality canceled in order to allow a drop action to occur. And that's for security. You don't want everything opened up by default. You want to be able to explicitly say, These are the areas of the page where you can allow dropping to happen.
Well let's take a look at dragStart. Now as the comment explains, IE doesn't support the data type of text/plain. So when the dragStart happens, we're going to take a look at a e.dataTransfer, and then we're going to try and set some data into the dataTransfer object. So for any other browser except for Internet Explorer, we'll be able to do that through the text/plain content type. And here we're just pulling out the value of the Id of the drag source. So e.target.id is pointing to the source. It's a little confusing here. Make sure you don't get this target confused with the drop target. That's totally different. Here, this is the event target's Id. So we grab the Id of the element that we're dragging and pass that into the dataTransfer object. And there's just some plain text that we're sending in to setData. So if it's Internet Explorer, then we use the content type of just Text. That capital T is very important. But now either way, we're able to support all the browsers. So now this dataTransfer object will take the Id of the element that we're dragging and send it over to the drop target. Well before we get there, let's take a look at the cancel function. Cancel really does live up to its name. It looks to make sure that e.preventDefault and stopPropagation exist and calls them in turn if they do, and then returns false. So this stops everything that's happening on the element that it's pointing to, which is exactly what we want in order to allow a drop operation to happen. So dragenter and dragover are automatically cancelled. But then we'll also do that when an element is dropped on to the drop target as well. So let's take a look at the dropped function. So here within dropped, the first thing that we'll do is cancel all operations allowing the drop to happen. And then we'll go back into that dataTransfer object, and this time instead of calling setData, we'll call getData making sure to pass in the same content type that we used to set the data. So here we're using text/plain or Text with a capital T for Internet Explorer. Either way, we get the Id that we're working with, and then we can call e.target. Again, this does apply to the drop target. It's the target of the event. e.target.appendChild, and then I can do document.querySelector and then pass in the Id. So this gets referenced to the element itself and appends it as a child to the drop target. So essentially what's happening is I'm able to take the element and move it from the source into the target all with this one line of code. So that's the very basics of working with drag and drop. So now let's take it a little bit further, and I'll show you how to use role selectors in order to generalize things a little bit so you can expand the functionality of your drag and drop operations.
Role Selectors: Demo and Code
This next demo adds a little bit more flexibility to the drag and drop operations by generalizing things just a bit. So you notice here what I can do is drag the image over to this drop target. But then I can also take it, and I can't drag it up here, and I can't drag it down here, but I can put it back to where it came from, so I can swap back and forth between these two divs. So by using role selectors and many other different techniques, but here I'll show you how to use a data-attribute in order to set up the drop targets, and you can take the source back and forth between the two. Let's go back to the code editor and take a look at the code. Once again, starting with the bird's eye view of this demo, you can see that I'm setting up targets, meaning more than one target, and then also the drag sources. Now the key here is I'm setting up the drop target through the data- attribute of data-role. So if you remember from the markup, the div had data-role="drag-drop-target" applied to that development. So by calling querySelectorAll, I get each one of those elements and have it set to the targets. Now I showed you earlier on in the course how you can use array.prototype.forEach and set that aside into a variable in order to do an iteration over the element list that comes back from querySelectorAll. Well here's a shortcut. So by using the brackets representing the array class, this is basically shorthand for that exact same syntax. So here off of array calling forEach and calling it on the targets, I can iterate through each one of the targets, setting an event listener for drop, dragenter, and dragover. Now this is the same thing as the last time I showed you. We're automatically cancelling dragenter and dragover and handling drop. For sources, I'm doing querySelectorAll for everything that is draggable set to true, iterating over each one, and adding an event listener for dragStart. Now let's take a look at the functions that provide implementation for each one of the events. Now sourceContainerId comes into play because what I want to be able to do is to only allow dropping on an element that's different from the source container. So here for dragStart, I'm doing the same thing you saw previously, setting the data using the content type of text/plain or Text equal to the target's Id. And then I'll also look at the parent element's Id and just set that aside. That'll come into play in a dropped function. Before we get there, let's take a quick look at cancel. This is the same as what you saw before. It's basically just stopping everything, calling preventDefault, stopPropagation, and returning false. So now once dropped executes, then we can take a look at the Id that's coming in. Well take a look at this Id, and if it doesn't equal the sourceContainerId, then we know that we're dropping into a different container and can continue on with the drop operation. So here I'm calling getData using the content type that we needed before, and then can call e.target.appendChild passing in the Id of the element that was dragged and getting reference to it through document.querySelector. Basically, the implementation of what you saw from this demo and the previous demo was nearly identical except for the fact that by adding the data- attributes and using querySelectorAll in order to set up the events for each one of the elements, I greatly increased the flexibility of my drag and drop application because now I can set anything to a drop target and anything as draggable. So, next, let's take a visual tour of the seven different events that are involved with drag and drop.
Events: Demo and Markup
This next demo is a bit of a visual tour of the different events that are involved in a drag and drop operation. So I'll start off just by dragging this around a little bit. I won't drop it into the drop target. But I'll just drag it around a bit, and you can see the events that begin to fire as we're moving the image around. So I'll take this and drag it around and just set it down there for a moment. So starting at the very top, you'll notice that from the source element, the dragstart event first fired. And then the drag event on the source fired. And that continued to fire as I was dragging the element around on the page. Now in turn for the target, you'll notice that dragenter fired, and then dragover continued to fire as I was dragging it around on the page. So both the source and the target have events that continue to fire allowing you to keep track of what's going on during the drag and drop operation. As we look down the list, you'll notice here that the dragleave event fired, and that's because I took the image, brought it over on top of the target, didn't drop it, and then brought it out again. So that's how dragleave fires. And then dragenter and dragover just continue to fire a lot. And then, finally, at the very end, you'll notice that the drop event fired on the target, and then dragend fired on the source. So the source will get the beginning and the last event that fires in the chain during a drag and drop operation. Now I'll show you the code for this demo, but I'm going to go through it fairly quickly because it's basically built on the last demo that we did, and I'm just logging out labels to the console for each one of the events as they fire.
So for this demo once again looking at the bird's eye view of everything that's happening, I have targets and sources, and I'm setting up event listeners for each one of the events that are possible when doing drag and drop. So drop, dragenter, dragover, dragleave all for the targets, and then dragstart, drag, and dragend for the sources. So for dragStart, I'm doing the exact same thing I did in the last demo, basically the biggest thing here is getting the Id, setting it into the dataTransfer object, and setting aside the sourceContainerId. Cancel is exactly the same as you've seen in each one of the other demoes. And for dragend, I'm simply logging out to the console that it is fired. That's the same thing for drag. Dropped again has the same implementation that you've seen in the past. I'm getting the data out of the dataTransfer object using the getData function, taking that Id, and appending the element to the target, that's the drop target, by using document.querySelector and passing in the Id. dragEnter cancels and then logs out to the console. That dragEnter is fired. dragOver also cancels and then logs out to the console. And dragLeave just simply logs out to the console. But the source element has left the drop target. So the main purpose of this demo is to give you an opportunity to see the different events as they fire and really get a feel for the fact that there are those events that continually do fire on the source and the target so that you can keep track of what's going on during the drag and drop process.
Effects: Demo and Markup
Now just as I've done with my other drag and drop demoes, I'm starting off here with an overview so you can see everything kind of all at once. Now I have a source and I have a target. And so let's start by taking a look at the events that are associated with the source. So the first one is dragStart. Here, what I want to start off by doing is getting access to the element that's clicked. So the radio button that's chosen. So I can do that by going into document.querySelector, looking for the input with the name allowed, and finding the element that's checked. So by running this selector, I have the checked element or the selected radio button. And from there, I can go into the value and pull out what's selected there and set that equal to effectAllowed. Now some older browsers, particularly older versions of Firefox, have a requirement that you have to set something into the dataTransfer object. So here you'll notice that I'm calling setData, and I'm passing in an empty string. So this is just to help with compatibility with some of those older browsers. So that's dragStart. So now let's take a look at dragEnd. Now once the drag and drop operation is complete, dragEnd will fire. And so I can take a look at the dataTransfer object, the dropEffect that's been set there, and set that equal to the innerText of the span that I have to report up what effect has been chosen. So now let's take a look at the events associated with the source. Now, of course, dragEnter is just immediately cancelled, and the implementation for that is exactly the same as what you've seen in all of the other demoes, so that's cancelled. And we'll use that in the different event handlers for the source as well. So, for instance, for dragOver, I'm immediately cancelling the default behavior allowing the drag and drop operation to execute. And here I'm looking for the radio button that's been selected associated with the source. So here you can see I'm looking for the input with a name of effect. I'm looking for the checked item there. Once I have that element, I can take its value and set that equal to dropEffect. So really this is the key here--e.dataTransfer.dropEffect, and if you look up here to dragStart, you'll see that I have e.dataTransfer.effectAllowed. Now normally you'll set these explicitly by setting the string of whatever effect you want to have set. This demo is built to show you how you can mix and match different effects and what the outcomes are from there. But normally when you're building a drag and drop interaction, you'll set the value for effectAllowed and dropEffect explicitly. So going back down, we're setting the dropEffect and then updating the UI here because what we want to be able to do is take the classList and add the over class. So as you drag something over this target, we want to add a class that updates the background color to show that you can drop something here on this element. So next let's take a look at dragLeave. Here if you drag something over the target and then take it off, really all we need to do here is just take off that over class. So it removes the background color from the element showing that you're not going to drop anything on the target. And so, finally, for dropped, we'll cancel the default behavior and then increment the count. So we'll do that by looking for the element that has the Id of count. I can grab the innerText, and now I have the value of that count. I can increment it and then set it back equal to the innerText. And, of course, if you've dropped something on the target, then we can remove that over class because we want to take the background color off the element showing that the drag and drop operation is complete. You've had a chance to see the different effects associated with drag and drop operations. Now let's take a look at different dataTransfer types that you have available to you.
Types: Demo and Markup
The real meat of this demo is found in the dropped handler, but I'll take you through the other functions just real quick, although they'll be really familiar to you. So, of course, cancel is exactly the same as you've seen in the other demoes. dragLeave will remove the over class that is added to the element when something is dragged over it. So here you see that with dragOver cancelling the default behavior and then adding the over class as we're over the target. The dropped handler is where we'll be able to look at the dataTransfer types and really find out a lot of information. So we can get to the types by looking at the arguments that're passed in to the handler here, so e.dataTransfer.types. And I'm setting that aside into the types variable. So if the length is greater than 0, then I'll take a look at the item in the 0 index position and see if that's set equal to Text. Now, remember, this is the IE implementation. And so if I have that, then I can call getData, and that just returns Text. There's no different types of data types when you're working in Internet Explorer. We'll just grab what's there set into the dataTransfer object. However, if we're working with a more modern browser, then we can take a look at each one of the types and iterate over each one. So for each one of the types, we can go to the dataTransfer object and call getData based off the type that we're passing in. So, remember, that's plain text, HTML, and uri-list. So once I have that type, I can call getData and get the content of the type. And here I'm just adding it into the innerHTML of a paragraph. But in your applications, you can find use for the HTML, the plain text content, and the uri-list as needed. And the last little bit that's a part of this demo is just to clear my drop target, so here I'm calling preventDefault, and then setting the target's innerHTML to blank.
File System: Demo and Markup
This demo shows you how you can drag files from the file system into the browser and what kind of information you have available during that operation. So let me take these three selected files and drop them in over here into the drop target. And you'll notice for each one I have information on the type of file, its name, its size, a modified date even all the way down to the time zone. Now once again, this is very much like the last demo that you saw, it's just a different source coming in to the drop target. Well, let's take a look at the code.
What's interesting about this implementation is that since we're dragging files in from the file system, there's no drag source to find here. So all I have is my target, and I have a little bit of code that clears out the target. But here there's just no source. So I'm starting out by handling dragenter, dragover, dragleave, and drop on the target. So dragEnter cancels the default implementation. dragOver sets the dataTransfer effect to copy so that when you're dragging the files over the drop target, you get a copy icon, and then updates the CSS class so it has the over class changing the background of the drop target. dragLeave simply removes the CSS class. So in case we decide not do that drop, the background color is updated. And, of course, dropped is where all of the implementation actually happens. So I'm cancelling and then getting reference to the dataTransfer types. So for each one of them here in this case, it's the type of Files. I'm looking for files that are coming in from the file system. Now if the dataTransfer type of Files exists, then there'll be a collection of files available off of the dataTransfer object. I can iterate through each one of those. And for each one of the files, I can report out the type, the name, the size, and the last modified date. And then to finally clean things up, I can remove the over class from the target. But for your implementation, you'd probably take this information and maybe upload some files, fill out a list, or whatever your application calls for. Well this wraps up the drag and drop module. Let's finish up with just a quick summary.
In this module, you've learned all about the drag and drop capabilities found native in the browser through HTML5. You've learned about the events and the event pipeline required in order to handle drag and drop operations, how to build sources and targets so that you can control which parts of your page are draggable and droppable. You saw how you can handle different dataTransfer types and set effects on different elements of the page and how to work with the file system by dragging files directly from your computer onto the browser. Well thanks again for spending time with me on this course. Again, this is Craig Shoemaker. I hope that you've learned much. Now, please don't stop here. There's so much more available on Pluralsight for you to learn about HTML5. A really good next step is my HTML5 Advanced Topics course, as well as my HTML5 Line of Business Apps course, along with all the other great course content here on Pluralsight. Well thanks again, and I hope to talk to you again soon.
Craig Shoemaker is a developer, instructor, writer, podcaster, and technical evangelist of all things awesome.
Released3 Mar 2017