[MUSIC PLAYING] BRIAN YU: OK. Welcome back to CS50 Beyond. Hope you're all staying warm. So we'll pick up where we left off, diving a little bit more into JavaScript. Goal of this afternoon is look at a couple other JavaScript features just to give some more exposure, show you what kinds of things do exist, and how you can use JavaScript to build user interfaces. And then we'll dive a little more into user interfaces. In particular, today, looking at animation, animation which we can create using both CSS and JavaScript just to liven up pages, make them a little bit more interactive, make them a little more aesthetically pleasing. And we'll get an opportunity to play around with the types of web applications we can create once we have the ability to draw shapes and create animations all across the screen. So we'll start by looking at one JavaScript feature, which a couple of people were asking me about earlier this morning, which is the idea of doing something repeatedly and recurringly in over a fixed interval. And so if we take a look at inside the interval.HTML, what we'll see is inside the body we have an H1 that has ID of counter that initially is just set to zero. And then we have, very similar to what we had before, a counter variable that equals zero and a function called count that increments the counter and then just updates the counters HTML to be whatever the new value of the counter is. But here's the interesting part, when the DOM content is loaded we run this function called set interval, count, and 1,000. So what this is basically saying is every 1,000 milliseconds, or every second, run the count function again. And the result of that is-- I can open up interval.HTML. And then without doing anything, every one second we're just going to increment that counter again and again and again. So you could do this type of thing to implement like a timer feature, for instance. So if you wanted to go back into the quiz application you made this morning and had a timer to see, OK, how quickly can you get through all of the questions? You could do something like this to keep track of a running timer as you go through the game in order to keep track of how long something is taking you, for instance. Or if you want for some action to take place every so often on your web application, you can use intervals to do that as well. Now, one thing you may have noticed is as you're working on your web pages using JavaScript, anytime you close the page and reopen it it's as if everything is starting afresh. If I were to close this page and reopen interval.HTML, for instance, I go back to zero. Or if you were doing your quiz application and you started on question zero and maybe you were halfway through your questions and you closed the page and reopened it, you'd be back at the very first question again. And so JavaScript, at least in later versions and in more modern browsers, also supports this idea of local storage. The idea that sometimes I want to take information and just store it in the browser such that next time I reload the page I can just draw any information from that local storage. And so I'll show you an example of that. It's in storage.HTML. And all of the examples for this afternoon are already on the course website, if you want to take a look at those. And here's what we're doing, the body is exactly the same as before, we just have some counter variable and a button that says click here. And here's the interesting logic, the first thing that I'm going to do is say, all right, if local storage.getitem counter-- so local storage you can think of as just like a key value store where I can store something at a particular key and then I can access the value for a particular key. So if I try and get the counter, but it doesn't exist-- the exclamation point just means not as in not there, then I'll go ahead and set the counter to zero. Local storage.setitem, set the counter to zero. And so this is distinct from a variable, whereas a variable will only exist for this page while it is open, while this function is running, something in local storage is going to persist. You can close the page, you can quit the browser, restart the browser, and something in local storage will continue to stay there. And so now what's happening when the DOM content is loaded, I take the counter and I set it's inner HTML to be whatever you get when you take local storage and get whatever is inside the counter. Which means that rather than just set it to zero by default, I'm saying check local storage, get the counter out of local storage, and make that the default value of the counter. Anytime the button is clicked, this part at least should look very similar. I take the counter, give it a variable that's set to whatever the counter currently is-- call it counter. Increase the value of the counter. And then I'm going to do two things. Thing number one, I update whatever is inside the HTML page, setting its value to be whatever the counter variable is. And then I update local storage as well. I'm saving whatever the current value of the counter is to local storage, such that next time I open up the page I can draw on that local storage and those values will still be there. And so the result of this is, if I open up storage.HTML, I see-- OK. I see the number zero there. And I click one, two, three, four, five, six, seven, eight. And once it's there, normally if I were to close the page, reopen it, I'd be back to zero. But now if I close the page and reopen it, I'm still with the number eight. It was able to save that state inside of local storage, such that the next time I open it up I can actually access those values. And so that could be a helpful tool as you go about building applications that maybe, for example, in your quiz application you want it such that it remembers what question you're on or it remembers your score, such that even if you close your page and reopen it later, you're still at that same place. And so you can consider that as something you may want to implement as well later on this afternoon when we get to project time. Questions. Yeah. AUDIENCE: What is the scope [INAUDIBLE] BRIAN YU: Sure. What is the scope of local storage? How wide does it go? When you deploy applications to the internet it's by the domain name. So something .COM, for instance, would have its own local storage. In the case of files, your file systems basically are all going to share the same local storage. And you can actually see the contents of what's inside of local storage if you want to. If I Control Click on Chrome, at least, go into the inspector. And if you go in to application, on the left hand side here you should see local storage. And if I look at what's there, I see, OK, the key counter has a value of eight, so that's what's currently stored inside my local storage. So you could see that. You could update it if I wanted. I want to make the counter a little bit higher, like 28, for example. I can close the page, open the page again, and, OK, my counter is updated. I've changed what's inside of local storage and the result is that I've changed what shows up on the page. Other things? OK. So thus far, all of our JavaScript programs have only existed on the client side and they've only involved code running inside of the browser. Yesterday, of course, we were dealing with server side code, like flask applications whereby you could talk to and interact with a server. And so what we're going to do now is just show a brief example of trying to combine these two ideas together, of having a client side application that can talk to some web server or some web API. We'll talk a little bit more about APIs, or application programming interfaces, tomorrow. But let's do one brief example, that maybe I want to write a website in JavaScript that allows me to get exchange rates. I want to figure out, OK, one US dollar, how many euros is that? Or how many Japanese yen is that? For example. And I wanted to do that conversion. Now, I could look up currently what the conversion rate is and plug that into my JavaScript code, but, of course, that's not totally accurate because tomorrow the exchange rates are going to change or even in a couple hours the exchange rates might change. I would like some way of knowing for sure what the current exchange rate is. And there happens to be an API that actually allows you to do this pretty easily. It's called Exchange Rates API. And you'd only know this by sort of Googling and looking around. And there are different APIs that do different things. And if I type in API.exchangeratesapi.io/latest. And I got this just by reading the website's documentation. What that does for me is it gives me a big JavaScript object that looks rather complicated, but basically it's giving me a whole bunch of exchange rates. And it's telling me, OK, here is how many Canadian dollars 1.5117 is equal to what base currency, one euro. So it's giving me all these exchange rates that are potentially useful for me. But, of course, I would rather not compare against the euro. I probably, in this case, want to be able to say, OK, how many of a certain currency is one US dollar? For example. And so in this case, I'm going to say, OK, I'm going to provide a parameter to this API route and say, base equals USD. I want US dollars only. Oh, sorry. Not ampersand. Question mark. Base equals USD. And what I get there is I get a whole bunch of exchange rates, but now the base-- the base currency is US dollars. So I get all these exchange rates in terms of US dollars. And, again, this I would only know by actually going to exchangeratesapi.io and you can read the documentation here for how you would go about getting the exchange rates for any particular thing. And instead of getting all the currencies, if I just wanted one currency, I would say, and symbols equals euros. And so there we get, OK, one US dollar is equal to 0.8801 euros, at least as of today and as of right now. So this is an API that's returning to me some JavaScript object. And I could use this information to be able to implement something like a currency conversion application. And so I'll show you an example of that now. I'll open up currency.HTML. So this is a very simple application that all it does is it has an input field where I can type in a currency, a button that says Get Exchange Rate. And so if I type in something like Euro, for example, and click Get Exchange Rate, it says, one US dollar is equal to that number of euros, for example. Or if I type in Japanese yen. And so Get Exchange Rate. One US dollar is equal to 109.66 Japanese yen. If I type in something that doesn't exist, like beyond is not a currency, OK, there was an error. So how does this work? What is the code that actually implements this? We'll open up currency.HTML to take a look. Inside the body of the page, the body is actually quite simple. I have a form that has an input field called currency where I can type in the currency that I want. And I have a button, a Submit button for the form that just says Get The Exchange Rate. And I'm going to click on that button. And then I have a line break. That's what BR is. And then a div that's currently empty, where eventually I'm going to put the result of this calculation, whatever the result of looking up the exchange rate is. Now, what is the JavaScript that's making that work? Well, when the form is submitted, so on Submit for the form I'm going to get the value of the input field for the currency and save that in a variable called currency. And then I'm going to use this function called fetch. And what fetch is going to do it it's just going to request-- make an HTTP request, request some URL and get me back the results. And here I'm getting the results of going to API.exchangeratesapi.io/latest specifying the base being US dollars, and what symbol do I want? I want whatever currency I'm trying to convert into as the currency. So this is me making what's called an AJAX request, an asynchronous request where I'm requesting from some other URL, some other website not my own for some data. And in particular, I'd like data about the exchange rate, and then I'm going to get that back and do something with it. Before I go on, questions about this? I saw some yellow and red faces. So I'll pause for questions if there are any. Yeah. AUDIENCE: [INAUDIBLE]. BRIAN YU: So the currency variable is going to be equal to whatever it is that I typed it, so like EUR for euros is what I typed into the text field. And then I'm taking that currency variable and plugging it into the URL, because if you look at the URL that I was using on the exchange rates API, up at the top I said, OK, base is going to be US dollars and the symbol is whatever I want to convert into. So I'm just plugging something into that spot in the URL, such that I can get a different exchange rate based on whatever I type in. Yeah. SPEAKER 3: Do you need to worry about escaping that string that you're plugging in to the URL? BRIAN YU: Do you need to worry about escaping that string? Sure. Certainly there are security considerations you might add here to check it to make sure. This is something we'll talk a little bit more about later in the week when we start talking about security in particular with regards to web requests. But, yeah, good thinking. Other things. Yeah. AUDIENCE: [INAUDIBLE]. BRIAN YU: If you're using JQuery and you do $.get, that'll behave in a very similar way. There are many ways of achieving the same general effect. Fetch just happens to be one of the more modern ways of doing so. But yeah, there are many ways in JavaScript to make an outgoing HTTP request. This syntax of .then don't worry about too much. This has to do with JavaScript promises. But the basic idea, or at least the idea that you should be getting across is, OK, I'm going to request this information from the server, then take the response and convert it to JSON, JavaScript Object Notation, until I get back a JavaScript object. And then with the resulting data, where is the actual exchange rate stored? Well, it's in a key called rates, and then this is the value. So I have to go into the key called rates and then go into a key called whatever the name of the currency is, and the value there is going to be the exchange rate, at least for this particular API. And so I'm going to set my-- the contents I'm going to fill in to my page to be one US dollar is equal to-- here is where I'm going to actually plug-in the currency exchange rate. So I go into the data, the object that came back, go into the rates key and then index into it and say, OK, get me the currency key. And that's going to get me the number of the exchange rate. And then just fill in the currency there, so it says this is equal to this number of euros or this number of yen, for example. And then just fill that into the result section of the page. The catch here is very similar to Python's Try Except syntax of like, try something, and if something goes wrong, do something. Catch just means, if anywhere along this path there was some sort of error, then go ahead and just include in the results section there was an error. That'll happen if I can't find the right key or if the request doesn't work for some reason. That's what will end up happening. Yeah. AUDIENCE: So it's not based on [INAUDIBLE]. Based on [INAUDIBLE]. From the line above and fetch just goes by the chain of [INAUDIBLE]. BRIAN YU: Yeah. JavaScript is not indentation based, unlike Python. So the indentation in JavaScript is just aesthetic. It helps to make things clearer, but it's not necessary. The way that these are linked together is via these dots. So in reality these are all just being chained together. And this is a common syntax in JavaScript that you'll often see, that things get chained together one function being called after another function after another. We'll see another example of this when we get to animation as well, of this chaining of functions after each other. Yeah. AUDIENCE: [INAUDIBLE]. To have a constant content [INAUDIBLE]. BRIAN YU: You could certainly eliminate the variable. I did it this way just so it would fit on one screen so you all could see it more easily. Yeah. AUDIENCE: [INAUDIBLE] data [INAUDIBLE]? BRIAN YU: Yes. This word response and this word data, these are just arguments to the function. And so they could be called anything you want to call them. Yeah. AUDIENCE: Yeah. I'm just a little confused about what is response and what is data and what exactly do they pull? BRIAN YU: Yeah. So response, in this case, is a special JavaScript object that represents an HTTP response just to some web request. And so an HTTP response happens to have a function called .Json, which takes that HTTP response, converts it to a JavaScript object, just keys and values like we were doing with the questions this morning, and returns that object. Of course, not all HTTP responses can be turned into objects, so there's a chance that something will go wrong there, which is what the catch here is for in case something happens to go wrong. So we take the HTTP response, convert it into an object, and then data is just going to be that JavaScript object. It's just going to be literally this, the curly brace rates and then what the base is, for example. AUDIENCE: And how does data know that what it's taking in as input is response.Json? BRIAN YU: How does data know that what it's taking in is a result of response.Json? That's what this chaining .then is. So when you chain the .thens together, it's one thing after another. I wouldn't worry too much about the specifics of the syntax here. You can take a look at the example later as well for more examples of that. Yeah. AUDIENCE: Just to make sure. Does that have to be [? response and ?] [? data? ?] Or we can just [? take it in whatever? ?] BRIAN YU: No. Response and data are arbitrary names. They could be anything. OK. So those are just some other JavaScript features, the idea of intervals, the idea of local storage, the idea of AJAX requests to get additional data. So now let's turn our attention a little bit, change gears a little bit to talking about user interfaces. We'll talk about user interfaces, how to make them more engaging, the types of features you'll often see in modern user interfaces. And we'll start by a little bit of discussion about a window. And so here is what a browser window might look like. You've got the menu bar along the top and then you've got the entire contents of the page. And there are certain attributes you can access about the window in JavaScript. If you say window.innerwidth what you'll get is a number of pixels equal to how wide the current page is. So you shrink the page, you grow the page, that will change window.innerwidth. And likewise, window.innerheight is how many pixels tall the page is. And so we saw this a little bit when we were dealing with media queries in CSS when we wanted to say, OK, if the page is smaller than a certain number of pixels, then do something slightly differently. But that's inner width and inner height. Then there are also some other variables that we can access about the current state of the user's experience on the page. The entire page is probably bigger than what's visible on the window, because there might be stuff above it, stuff below. You would scroll up and scroll down in order to see. Window.scrollY is a value that represents how far in the Y direction, the vertical direction, have you scrolled so far. So if you're at the very top of the page, window.scrollY is zero. If you scroll down 50 pixels, window.scrollY is 50. And finally, one other value that might be interesting to know, document.body.offsetheight just refers to the entire height of the document, not just the visible area, but from top of the document to the bottom of the web document, how many pixels is it? How many pixels would you have to scroll to get all the way from the top to the bottom? So a couple of interesting values there. And so now, interesting question, what would you write in code if you wanted to check to see if you were at the bottom of a page? What would the expression look like if you wanted to see if you were at the bottom of a page? Take a few moments to think about it. And then we'll see if anyone has a guess. AUDIENCE: [INAUDIBLE]. BRIAN YU: Document.body.offsetheight refers to the entire height of the web page, not just the visible part on the window, it's from the very top of the page all the way to the bottom of the page, which you might theoretically need to scroll through, but it's the entire height of the document. OK. How would you find out if you're at the bottom of the page? Yeah. AUDIENCE: Window.scrollY plus window.innerheight [INAUDIBLE] document.body.offsetheight. BRIAN YU: Yeah. So long is window.scrollY and window.innerheight are as tall as document.body.offsetheight. That's how you would know if you're at the bottom of the page, because the amount that you scrolled by plus the height of the window would take you all the way to the bottom of the page. And so we could actually use this in a brief example. Let's open up scroll.HTML. And whereby in the body of scroll.HTML I just have a lot of paragraphs, paragraph one, two, three, four, all the way down to paragraph 100. So I just have 100 paragraphs that just have numbers in them. Nothing all that exciting. But here inside my JavaScript I've got some code. Window.onscroll, so this is another event handler. Whenever the window is scrolled, run some code. And if window.innerheight plus window.scrollY is at least as tall as the document.body.offsetheight, then go ahead and change the style of the body of the page to green, and otherwise, change it to white. In other words, if I hit the bottom of the page, turn the page green. So I'll show you that code. As soon as I hit the bottom of the page, scrollY plus innerheight is equal to the total height of the document. I'm going to change the background of the page to be green. And so open up scroll.HTML. I see I have all these paragraphs. And if I scroll down all the way to the bottom, paragraph number 100, the page is white right now. And as soon as I hit the bottom, OK, the page turns green. I scroll up, it's white. Hit the bottom, the page turns green. So I'm able to detect when I'm at the bottom of the page. And now, why might that be useful? In what context, in an application would it be good to know if you're at the bottom of a web page? Why do we care? Yeah. AUDIENCE: Well, a lot of news sites nowadays when you get to the bottom it shows the next story. BRIAN YU: Yeah. A lot of news sites nowadays when you scroll to the bottom you get the next story or we'll get sort of this dynamic loading where when you get to the end of the page, it'll load the next set of posts or the next set of articles, for instance, so that you can keep scrolling infinitely, this infinite scroll idea. And so we can use this notion to actually implement infinite scroll. I won't show you all of the code, but I'll show you the relevant portions of it. If we go in to the post zero example. What I have here is a flask application where in application.pi I basically just have a route that's going to-- called slash post where you can specify the start post that you want and the end post that you want and it will return to you a JSON object that's containing all of those posts. And in index.HTML, here's the interesting code. We're going to start with a body that just has an empty set of posts. And we're going to-- whenever we scroll the page-- so first, when DOM content loaded, when we first load the page, call the load function to load the first 20 posts, for example. And then when the window is scrolled, if the inner height plus scrollY is at least document.body.offsetheight, same equation as we were using before. In other words, if we've hit the bottom of the page, then go ahead and load the next set of posts. And all load is doing-- and you can take a look at this later-- is it's calculating what the start and end post number should be. And then it's making a fetch request, just fetching from the server just like we saw a moment ago trying to get the next set of posts. But the relevant part, at least for now, is just to understand these couple of lines here, that when the window is scrolled, if it is the case that we've hit the bottom of the page, then go ahead and load the next set of posts. And so I'll go ahead and go flask run here. We'll load up this page. We get a whole bunch of posts. I notice I'm almost about to hit the bottom. And when I hit the bottom, post number 20, there's a moment's pause, but, OK, then the next set of post loads. I scroll to the bottom again, and, OK, the next set of post loads. And I can do this infinitely. I can continue to scroll and continue to get a new set of posts because every time I hit the bottom of the page, the next set loads. And so this ability to know where I am on the page can allow for things like infinite scroll and the implementation of features like it. Questions. Yeah. AUDIENCE: [INAUDIBLE]. If it was on the top of the page as well [INAUDIBLE]. BRIAN YU: If I'm at the top of the page, then the document.body.offsetheight, the body of the document is going to be the entire document, but the window.innerheight, the height of the window is only going to be a small portion of that. And scrollY will be zero, because I won't have scrolled at all. And so the total height is going to be much less than the total height of the document. So if you go back to this image, if I'm at the top of the page, if you add scrollY, which is zero with the inner height, it's going to be substantially less than the offset height if it's a tall document. Other things. Yeah. AUDIENCE: Why [? is it ?] [? greater ?] [? than ?] [? or equal to? ?] BRIAN YU: Greater than or equal to just to be able to handle browser case where sometimes you can do a little bit of scrolling past the bottom of the page, for example. Other things. OK. And with end, if you're curious about what the load function is doing, it's basically making a request, and for each post that comes back, running this add post function. All add post is doing is it's creating a new div, giving it a class name, and then adding it to the DOM, just appending it to the section of the page that is dedicated to all the posts. And the result of that is we get this infinite scroll-like feature. With a little bit of additional work, we can actually use it to allow users to hide posts as well. So I'll show you-- we'll go into post one. And the only difference in post one is in index.HTML, if you look down at the add post function, in addition to creating a div, I'm also just creating a button called Hide that's going to hide the post. And when you click the Hide button it's going to remove the post altogether. And so I'll let you look at that code in more detail if it's something you're curious about. It's online. But now what we have is we have infinite scrolling posts. But if I want to, I can click the Hide button next to post 16 and it goes away, just goes straight from 15 to 17, for example. Those are just more examples of what it is that you can do by taking advantage of the features that JavaScript offers. Questions about anything we've talked about so far? Yeah. AUDIENCE: As far as-- would you mind going back to the code? BRIAN YU: Which code? AUDIENCE: The [INAUDIBLE]. BRIAN YU: Yeah. AUDIENCE: As far as the constant variables throughout, is there any advantages [INAUDIBLE] accidental changes? Like, what if you just didn't [INAUDIBLE]? BRIAN YU: They could all be let variables instead of constant variables and it would work just fine in this case. Constant is just there as a security measure basically, to make sure that nothing gets changed. OK. Let's do a bit of a change gears. Still on the topic of user interfaces and user experience. And let's try creating a new HTML page. I'll call it index.HTML. It's going to have a header, title, hello. And in the body of the pager we're just going to say, welcome, again. Now what I'm going to do is I'm going to add some style code. But first let's look at the page, make sure it looks OK. Open up index.HTML. All right. Welcome looks fine. But now what I'm going to do is I'm going to add some style code. And in particular, I'm going to add some CSS animation, some CSS code that is going to allow me to animate what it is that's on the screen. And to do this I'm going to call-- use a special syntax called At Key Frames. So I'm going to define the name of an animation. And the name of this animation I'm going to call Grow, because we're going to grow the size of our heading, is what we're going to do. And to do this we define two keys, from and to. From is what the style is like at the beginning, and two is what the style is like at the end. And what I'd like to say is, when something grows it should go from having a font size of 20 pixels to having a font size of 100 pixels. So here I've defined an animation. At Key Frames Grow we're going to grow from something with a font size of 20 to something with a font size of 100. And now for any H1, any heading, I'm going to say animation name is Grow. In other words, you should apply the Grow animation. And I'll add a couple other CSS properties. Animation film mode forwards is just going to say, once you get to where you're going, once you get to 100 pixels at the end of the Grow animation, stop there, and just retain that style state. And then finally, you say, OK, how long should this animation take? We'll say animation-duration, two seconds. So I've defined an animation called Grow. Could've been called anything. What does the Grow animation do? It goes from a font size of 20 to a font size of 100. And then I said for any heading, go ahead and use the Grow animation go forwards and it should take two seconds to do so. So now I refresh index.HTML and you get that animation. You refresh the page, it goes from 20 pixels to 100 pixels. I've been able to create something a little bit more dynamic. Questions about that and what I just did? Yeah. AUDIENCE: Can you explain what key frames is again? BRIAN YU: Yeah. Key frames is just defining what the-- we'll call, what the key frames of the animation are. In other words, what are the points in the animation at which the element should have a particular style? And here I'm saying at the beginning of the animation it should have a font size of 20 and at the end of the animation it should have a font size of 100. The beginning of the animation and the end of the animation are what we'll call the key frames. And the browser is going to do the heavy lifting of figuring out how to actually change the element from the from state to the to state. Yeah. AUDIENCE: [INAUDIBLE]. BRIAN YU: You could have multiple properties inside of to. So you could have multiple things that are happening inside of this animation. And font size is not the only thing you could do. I could say, for example, left 0%, meaning start 0% away from the left hand side and go to 50% away from the left hand side, like 50% of the window away from the left side. And if I reload that, the effect of that is, OK, we get-- well, that didn't work. From left 0%-- oh, what I need to do is-- based on the way that CSS lines things up, I need to say that the heading has a relative positioning, meaning it can change relative to the rest of the page. And I think this should work. OK. Great. So it started at the left hand side, ended 50% of the way across the window. Show you that again. Starts on the left, moves 50% across the way. Questions. Yeah. AUDIENCE: Do you have like a middle step though? BRIAN YU: Yeah. I can give a middle step. Absolutely. Instead of from and to, I might say, when you're 0% of the way done with the animation be 0% from the left, when I'm 50% of the way through the animation be 50% from the left, and when you're 100% of the way through done with the animation, let's go back to 0%. So what's this going to look like? Yeah. OK. Someone's-- people are making the motion. We'll show it. Starts to the left, goes to the right, goes back to the left. Can refresh that. Goes to the right, goes back to the left. If I want it to happen multiple times there's animation iteration count. I can say, animation iteration count two, for example. And now I refresh the page, it goes there, it goes back, and then it happens again. Happens twice. You can even say animation iteration-- you guys are having fun with this. So we'll change it to infinite. And now you know you can just let it go and it will just go back and forth forever. So we've got these CSS animations running. Yeah. AUDIENCE: Why is not jumping? Because you're not telling it like the why. You're just specifying the beginning and the end, so why would it just not start here and end there. [INAUDIBLE] colors. [INAUDIBLE]. BRIAN YU: Yeah. Good question. So why is it not jumping? Why is it smoothly sliding from one side to another when all I'm saying is, at 0% do this, at 50% do that, at 100% do that? This is what CSS animation is all about. You define the key frames, the key points in the animation where you want it to be doing something, and then the browser fills in the rest of it, figuring out what the intermediate positions need to be in order to get from the first key frame to the next key frame. You can certainly do this with color if you wanted to change this to-- we'll change this to 100% left, 50% will go back to from and to, though you don't necessarily need to. I could say, OK, start with a color of red and go to-- I should add semicolons here. And go to a color of blue. And let me get rid of the iteration count. We'll just do it once. Now, if I refresh the page it goes from red to blue. From red to blue. Yeah. AUDIENCE: [INAUDIBLE] function. You can change linear versus exponential. BRIAN YU: Yes. You can change-- You can start to get fancier about how you go about doing that. AUDIENCE: One more question. Which is faster, CSS or jQuery animations? BRIAN YU: Good question. Which is faster, CSS or jQuery animations? jQuery is probably going to be slower, though I'm not actually 100% sure about that. Yeah. AUDIENCE: How would you-- if you were to do-- say you wanted to [INAUDIBLE] and then do the color. Would the formatting be different than if you wanted to [INAUDIBLE] and to do [INAUDIBLE]? BRIAN YU: Yes. So what I could do if I wanted to do like, first move and then change the color, is I'd say, OK, at 0% I want it to be on the left hand side and I want the color to be red, at 50% I want it to be left 50% and I want the color to still be red, and at 100% I want the color to be blue, for example. Where now it will move and then it'll change color. So you can define the intermediate key frames however you like. Questions about any of that. AUDIENCE: Can you show the code again? BRIAN YU: What? The code? Yeah. So those are the key frames. AUDIENCE: What happens if you do 99% and then [INAUDIBLE]? BRIAN YU: 99%? Why do you want it 99%? AUDIENCE: No. I mean, [INAUDIBLE]. BRIAN YU: Oh, no. That shouldn't. You can experiment with this all you'd like if you'd like to. You just need to create an HTML page and you can do whatever key frames you'd like to play around with. Yeah. AUDIENCE: [INAUDIBLE] left 50%. BRIAN YU: No. Some of this might be redundant that you can take out, for instance. Yeah. AUDIENCE: What is the meaning of the key frames? BRIAN YU: The key frames are just getting at the idea that rather than specifying what the state of the style should be at every single point at every single frame of the animation, I'm just specifying it at a couple of key frames and then the browser is going to fill in the rest to figure out how it should transition from one thing to the next. Yeah. AUDIENCE: So if you wanted it to basically make it appear and disappear and appear [INAUDIBLE] in the middle, basically no transition in between. Would you basically show it, hide it, show it on the middle, and then hide it? BRIAN YU: If you didn't want the transition, you probably don't need CSS animation. You could probably just use JavaScript to say, wait five seconds and then change the color. And then it would just change color, for example. Yeah. AUDIENCE: Is the CSS [INAUDIBLE]. BRIAN YU: Yeah. AUDIENCE: Is that referencing-- how does it know that we have an animation? [INAUDIBLE]. BRIAN YU: When you say animation name Grow, it's referencing this grow, just some animation that I've defined that is called Grow, for example. AUDIENCE: It just knows that Grow is an animation. BRIAN YU: Yes. The at key frames basically tells it what it is. Yeah. Good question. So we can actually use this. This is not just all for just like fun and games. We can see what we can do with the heading and get it to slide back and forth and change color. We can go in to-- let's look at post to now. And the only difference I've made in post two as opposed to post one, remember this was our auto-infinite scroll for posts-- if I go into index.HTML, I've added this Hide key frame that we can use to basically hide a post if we don't want it to be there. So remember before when we were hitting hide on each post, it would just sort of go away immediately and the next one would immediately be in its place. We can define a key frame called hide that goes from an opacity of one, meaning totally visible, to an opacity of zero, which means totally invisible, and we can give any post an animation name of Hide, and we can use JavaScript to trigger when we want that animation to begin. And so if I say flask run here. Open up flask. All right. Great. Here is our auto completing post. And now if I wanted to hide post three I click Hide. And then over the course of some time it fades out and then the next post jumps in to fill its place. We hide. It fades out. And the next post jumps in. And this user interface still isn't amazing. What would we like to change? Yeah. It would be nice if it would slide up as opposed to just jumping up. And so if we take a look at post three. And if we look at index.HTML. These key frames are a little fancier, but the idea here is at 0% we'll start at full opacity. When we're 75% of the way done with the animation the opacity will be zero, will fade out completely. And then will go from a height of 100% to-- when we're totally done with the animation the height will be zero. And when we go from a large height to a small height, when we fill in that transition, the result will be the height will shrink. And so if we say flask run now, open up this. We've got all of our posts. And if I want to hide post number three, I click Hide. It fades out. And then the next one slides in as the first size shrinks. Show you that again. Fades out and then it shrinks. So using CSS animation we're able to create these interactive, nicer and more aesthetically pleasing user interfaces just by taking advantage of these key frames and deciding when things are going to start and stop and how things transition from one thing to the other. Questions. What questions do you have? Yeah. AUDIENCE: Are those positions relative? Or are they using [INAUDIBLE]? BRIAN YU: This is relative positioning. Yeah. OK. So that's CSS animation. Yeah. Question. AUDIENCE: What if you wanted to give a post multiple animations? BRIAN YU: If you wanted to give a post multiple animations, you can do that. It'll be easier with some more JavaScript. And we're about to go to JavaScript based animations in just a second. Yeah. AUDIENCE: So we just set the size of where the document [INAUDIBLE] zero [INAUDIBLE] run the animation [INAUDIBLE] will that be [INAUDIBLE] zero? Or [INAUDIBLE] actually [INAUDIBLE]? BRIAN YU: I believe this code will actually remove the element after the animation is over, so you wouldn't have to worry about that. OK. Let's try something a little bit different. Yeah. AUDIENCE: So this is just all the visual stuff, right? The existence of the animation [INAUDIBLE] great accessibility? BRIAN YU: So good question about accessibility. There are certain things that-- element-- attributes that you should be adding to HTML elements for accessibility reasons. In particular on images and such, but in general, so long as you're following those guidelines, you can still have animations on the page and accessibility should still be OK. We can chat about specific use cases if you have them in mind too. All right. Let's go ahead and open up index.HTML. And let me get rid of the style code for now. All right. What I'm going to do now is inside the body of the page introduce SVGs, or scalable vector graphics. And vector graphics you can think of as just graphics that you can, at least in the context of web pages, are shapes that you can add to your page in order to create for some more interactive user interfaces, allow for some user experiences that we weren't able to have before. So here I'm going to say-- SVG is going to be an element-- its style is going to have a width of 100% and a height of 800 pixels. In other words, what I'm doing here is creating an SVG canvas, just an 800 pixel tall canvas on which I can draw shapes, at least for now. So inside of this canvas I'm going to say, all right, let's create a circle. And a circle has some attributes. It has a center x-coordinate. So where is it centered? We'll say center x-coordinate is going to be 200. It has a center y-coordinate. We'll say also 200. It has a radius. We'll say 50 pixels, at least for now. And we can add styling to it. Right? I can say, all right, the fill color of this circle should be blue. So what I've done here is I've created an SVG canvas, a place where I can draw shapes, it's 800 pixels tall, it fills up the full width of the page. And I'm going to draw a circle at location 200, 200 with a radius of 50 and it should be blue. So I open up index.HTML. And OK, I have a page and just a blue circle, as you might expect. So this is a vector graphic. Questions about that before we dive into more. You could certainly do all these vector graphics entirely by hand just by specifying where you want things, but there are libraries that are able to help with this. A library we're going to use at least for today is called D3, something you may be familiar with. It's actually quite good, especially for analyzing data and for data visualization, so it's quite powerful. We're not even going to use most of those capabilities today. We're just going to use it for interacting with vector graphics in order to draw things on the screen, but know that it's far more powerful than what we're actually going to get a chance to look at today. And so we'll go ahead and go in to circleone.HTML, if you're following along with the source code examples. And in circleone.HTML I first included a script, not a script that I've written, but I'm including D3's JavaScript. This is just a JavaScript library that's going to make it easier for us to draw these shapes. And inside the body of our application here's an SVG canvas. It has an ID called SVG and it's going to take up the full width of the page. It's going to be 800 pixels tall. And then here is the JavaScript code that makes this work. This is the JavaScript equivalent of what it is that we just did. And we're first using a function called D3.select, which is just going to use D3 to select the SVG container, storing it in a variable called SVG, and then we're going to programmatically add a circle to it. Instead of just writing it hard-coded into the HTML, we're going to say SVG.appendcircle. And here we see that chaining idea again. This chaining of function after function after function. These dots are all just chained functions being applied to each other. So we're saying take that circle and give it this attribute, give it the center x attribute of 200. Put it at x location 200. Take the y attribute, put it at 200. Give it a radius of 90 pixels. Fill it with the color green, for example. And so you can add CSS. Instead of using attribute, using .style to add CSS properties, like the fill color, for example. And the result of this is if I open up circleone.HTML, I get a big green circle. Basically the same as before, but now I'm using this D3 library that's going to make things a little bit easier. Questions about anything so far before I go on? Yeah? AUDIENCE: [INAUDIBLE] circle is supposed to be 100% [INAUDIBLE] BRIAN YU: The SVG itself has a width of 100. So the canvas on which I'm drawing takes up the entire width, but the canvas is white, so it's just in the background of the page. The circle itself only has a radius of 90. And so it's going to have a radius of 90 pixels, is what I specified there. Yeah. AUDIENCE: [INAUDIBLE]. BRIAN YU: Yes. You can do combinations of any of the things that we're talking about. OK. Just to show you one other shape. I'll show you rect.HTML for a rectangle. It's very similar. Instead of specifying CX and CY for the center x-coordinate and the center y-coordinate and an R for radius, I specify an x-coordinate, a y-coordinate, a width, and a height, and that lets you draw a rectangle wherever you want. So open up rect.HTML. And OK, we get a big blue rectangle. Questions. All right. So so far these shapes don't move, so let's go ahead and add some animation to them. Much as we did before with CSS, but now using D3 to be able to create transitions as things move from one state to another state. So we'll open up circletwo.HTML. And then circletwo.HTML, it starts basically the same way. I create a circle located at 200, 200 with a radius of 50. And we're going to fill it in with the color blue, but then I'm going to apply a transition to it. I'm going to say c.transition. C is the name of the circle. I just saved it inside of a variable. And this transition is going to have a duration of 1,000 milliseconds, or one second. And what's going to happen? I'm changing the x and the y attributes of the circle, moving it from 200, 200 to 500, 500. And I'm also changing its style. I'm changing its style from blue to red. And much in the same way that CSS allowed me to define key frames and then CSS took care of the rest of figuring out how to transition things from one state to the other. D3 is going to do the same thing with the idea being that we're going to apply a transition and it's going to smoothly move from one position to another position, from one color to another color. Where by now I can open up circletwo.HTML. And OK, the blue circle moves and it also changes color. Refresh it again, so you can see it. It moves and it changes color. Questions about that. Show you the code again. This is in circletwo.HTML, if you're following along with the examples. Do one more simple example. We'll open up circlethree.HTML. And now we're going to add a transition. And this transition is going to change the x position. So the duration is going to be 1,000 milliseconds. We're also going to add a delay, which is like how long it's going to take before the transition actually starts. But you can also add event listeners to this, much in the same way that you can add event listeners to other elements. So I can say, take this circle, and on click, in other words, when this circle is clicked on, then go ahead and run this function. D3.selectthis is just a fancy way of saying, get this object, this circle in particular, and apply another transition to it that lasts three seconds that changes its style to red. So a lot of this, when you see this chaining, just think of it as do this thing, and then do this thing, and then do this thing, or think of it as chaining these all things together into one big transition. We're doing a transition on the circle that is going to set the x attribute to 500. And then when the circle is clicked on we're going to apply another transition that's going to change the fill color of the circle to be red. So we open up circlethree.HTML. We have a blue circle. After one second it moves. I didn't do anything. But now if I go over it and I click, then over the course of a couple of seconds the circle changes color. Able to do animations in response to particular events. What questions do you have? Yeah. AUDIENCE: On the code [INAUDIBLE] D3.selectthis, why did you have to do that? Couldn't you just do c.transition? BRIAN YU: Good question. Why did I need D3.selectthis instead of just c. I probably could have done just c in this case-- actually, let's try just to make sure. Here and then click. And then, yeah, that'll work just fine. So in this case, you can get away with that. In some more complex examples when they're not necessarily referring to the same variable name, maybe when applying animations to a list of potential things, then D3.selectthis is helpful for getting the thing that triggered the event. And so I'm showing it to you for that sake, so that you know how to use it in future cases. But yeah, in this case, c.transition would've worked just fine. Yeah. AUDIENCE: So you [? divide ?] [INAUDIBLE] demo and then [INAUDIBLE] so are you [INAUDIBLE]? BRIAN YU: Yes. We are constrained to whatever width and height the SVG canvas is. And if we try and draw something beyond it, we're not going to see it because it's outside the bounds of that container. So using all these tools we can actually begin to build some interesting user interfaces. I'll show you one that I built that I thought was kind of fun. It's called stoplight.HTML. And it just looks something like this. All this is so far is a black rectangle and three gray circles, something you could create just by figuring out where the pixels go. And when you click on the circles the colors change. Right? You click on the different circles and the colors change much as a stoplight would, for example. Yeah. Question. AUDIENCE: [INAUDIBLE]. You have a transition where it moves out of the area and then back in. Does it look like the circle [? was ?] hiding and then it comes back? BRIAN YU: Yes. If it's outside and it moves back in, it still exists, it's just not in the visible area of the content of the page. That's correct. So there are interesting things you can do with that if you would like to. Yeah. AUDIENCE: If you were to shrink the size of your browser window, what would happen to your stoplight? BRIAN YU: Good question. What happens if I shrink the size of the browser window? Well, this browser window doesn't happen to go-- let's see if I can simulate this on a mobile device. Oh, well, this is just shrinking the viewport, as we talked about two days ago. Long story short, it's not going to work great on this example, but you might get a situation where the animation does get cut off. And so that might be a situation where if you really want to think about mobile responsiveness, you want to think about dynamically computing where pixels should be based upon the size of the screen, for example, or at least assuming that something will at least always be of at least a fixed width and then being able to add positioning in that sense. Other things. So I'll show you the code for this. We won't go into detail in it, but just so you can get a chance to see it and feel free to look at it in more detail if you'd like. All that's happening is we get the canvas, we add a rectangle to it, that's the big black rectangle, we go ahead and add a red circle to it, that at first is going to be styled as just gray, we add a yellow circle to it that's also gray, a green circle that's also gray. And basically-- and there are certainly better ways to design this. When each of the buttons are clicked we take the corresponding color, go ahead and fill it in with whatever color it should be, and take the other circles and fill them in as gray instead of whatever color they were before. And so this is all just using the tools that we've seen already in order to build some more interesting user interfaces. So OK. Let's try and do something a little more interesting now. We'll go to the desktop. I'm going to-- and this is the part where if you'd like to, feel free to try and follow along by writing in the HTML yourself. This is going to help lead into what's eventually going to be this afternoon's project, if you would like to. So go ahead and create a file called draw.HTML. And inside of draw.HTML we're going to start with just the basic HTML page. The title is just going to be draw. We're going to need to include D3. So if you go into any of the other source code examples you can just copy the script length for D3. And go ahead and copy that into the header of the page. Doesn't matter where in the header it is, so long as it's there. Inside the body of the page we'll go ahead and create an SVG that has an ID of SVG, so that we can refer to it later. Its style is going to be width 100%. It's going to take up the full width of the window. And it's going to have a height of 800 pixels, just sort of arbitrarily chosen to most likely be tall enough, but could be whatever you want. And now let's go ahead and write some JavaScript. Const SVG equals D3.select SVG. This is the same thing that we've been doing in all of the SVG examples thus far, whereby we're basically selecting the canvas and storing it inside of a variable called SVG. But now I'm going to define a function. And this function is going to be called draw point. And what draw point is going to do is it's just going to draw a point on the screen. And OK. So first of all, I need to figure out-- I want to draw a point wherever the mouse is-- wherever the mouse is, for example. So I need to know where the mouse currently is. And so in D3, the way to get that is to say D3.mouse and then in parentheses, this. So take the event and figure out where the mouse is for this particular event. And we're going to save that in a variable called cords, or coordinates, for example. And so that variable is going to store wherever the mouse currently is at this moment. And now I'm going to say SVG.appendcircle. So add a circle to the canvas. And the attribute cx, what is the center x-coordinate of this circle? Well, it's just going to be cords zero. Coordinates [INAUDIBLE] like an array of an xy pair. So cords zero is just going to say, what is the x-position of the mouse right now? And that should be the center x-coordinate of this circle. And likewise, cy, the center y-coordinate should be what? AUDIENCE: Cords one. BRIAN YU: Cords one. Great. So I'm creating a new circle and setting it's x and y coordinates to be the x and y coordinates of the mouse. We'll go and give this a radius. We'll give it a radius of 5, for instance. And we'll go ahead and give it some style properties. Fill, we'll just say, black for now. All right. So I've created a circle. AUDIENCE: Close the SVG-- BRIAN YU: Close the SVG-- the slash here is self-closing. I mean, you could do this and this, which I guess helps the color scheming, but technically we don't need to. Circle. We set the x and y coordinates at the radius of the fill color. And that's it for this draw point function. All we're going to do is figure out where the mouse currently is and then we're going to add a circle to the screen at that particular location. Questions about what we did just then? Yeah. AUDIENCE: Can you just quickly say again the .attribute [INAUDIBLE]. Just go through-- BRIAN YU: Yep. The .attribute section? AUDIENCE: Yeah. BRIAN YU: So SVG.appendcircle says take the SVG canvas and add a circle to it. And then I'm going to take that circle and modify its attributes. And so the circle needs to know where on the canvas it should go. And so we're saying, set the x-coordinate of the circle to be whatever cords zero, the x-coordinate of wherever the mouse is. Same thing goes for the y-coordinate of the circle, wherever the y-coordinate of the mouse is. Set the radius of the circle to be five and then fill the circle in all black. And then, now here comes the interesting part, we're going to add an event listener. SVG.on. And the event that we're going to listen for is the mouse move event. Whenever the mouse moves, we're going to run a function. And the function we're going to run is the draw point function. So we have our SVG canvas. Anytime the mouse moves, we're going to call the draw point function. And the draw point function is going to figure out where the mouse currently is, save it in a variable called coordinates, and then add a circle to the screen that has those coordinates. And so assuming we did everything right, if we now open up draw.HTML, we see a dot right underneath where my mouse is. And if I move the mouse we'll see that little dots keep getting drawn. Now, if I move the mouse quickly you'll see that it's not a perfect line. Reason for that is that the browser only is able to fire events every so many milliseconds. And so if I move my mouse too quickly, it's just not able to fire all the intermediary events in between. But the idea now is I can move my mouse around, and as I do so, the dots sort of follow. So I'm able to trace out whatever it is that I'm drawing. So this is all the code that did that. It's 24 lines of code and we're able to create that effect of drawing on the screen. Yeah. AUDIENCE: In the last statement you had where you were moving the mouse around, is there an overflow limit? Like, if you create too many dots, is that going to crash the system or something? BRIAN YU: If you create too many dots, is it going to crash the system? Certainly, the browser does have a memory limit, but these are pretty small circles that don't have a whole lot of data associated with them, and modern browsers can handle pretty big web pages, so probably not something that we have to worry too much about at least now. Yeah. AUDIENCE: Yeah. I'm confused about why you used const instead of let, because, aren't you changing that value every time you [INAUDIBLE]? BRIAN YU: Yeah. Why const instead of let here? Because the mouse is moving, so the coordinates are changing, because any one time I call the draw point function, the coordinates don't change. And so I'm never resetting coordinates later in the function. And so it's fine to use const here instead of let. Other things. Yeah. AUDIENCE: [INAUDIBLE]. BRIAN YU: Is there a way to make the dots actually complete each other? Yes. We'll talk about that in a couple of minutes. But yes, you can. So all right. Mouse move is an event that we can use to say, all right, when the mouse is moving, anytime the mouse moves, let's do something. There are other events too. There is mouse down and mouse up to mean when I'm clicking and when I'm not clicking. And maybe that's something I'd like to do, because right now I'm drawing, and I'm literally drawing anytime the mouse is moving, and so there's no way to stop drawing, for example. What I'd like to do is when the mouse is down, then I should be drawing, but when I lift up the mouse, then don't worry about it. So how would I do that? What variable do I now need? What type of variable should I add here? Any thoughts as to how to go about designing this? Yeah. AUDIENCE: [INAUDIBLE]. BRIAN YU: Yeah. Some Boolean variable-- yes, no, true, false, that's keeping track of, should I actually be drawing right now? And so we'll just call it let drawing equal-- and we'll start off by false, because by default, until you click down for the first time, we don't want to actually be drawing on the screen using let instead of const because this is a variable that I'm going to be changing pretty frequently as I click down and click up. And now the idea here is going to be-- all right, SVG on mouse down. In other words, when I click, then let's go ahead and run this function, whereby I'll say drawing equals true. I actually do want to start drawing now when I click down. And SVG on mouse up, let's go ahead and say drawing equals false. So I defined a variable called drawing that's keeping track of, should I be drawing right now? When the mouse goes down, when I click the mouse down, drawing is set to true. As soon as I lift my mouse up, drawing is set to false. Questions about that. What's the last step? What am I missing? Yeah. AUDIENCE: [INAUDIBLE]. BRIAN YU: Great. An if statement inside of the function that's actually doing the drawing that basically says, if not drawing, or in other words, if drawing is false, if I shouldn't be drawing right now, well, then just go ahead and return, ignore the rest of the function, just exit the function now, because if I'm not supposed to be drawing right now, then I don't want to actually calculate the coordinates or add the circle or do any of that. So now, again, assuming we did everything right, refresh the page. I move the mouse around and, OK, nothing's happening, nothing's being drawn. But if I hold down the mouse and try and draw something, OK, now I'm able to actually draw on the screen. Questions about that. Yeah. AUDIENCE: [INAUDIBLE] what is again that you're doing on line 18 with D3 mouse? BRIAN YU: D3.mousethis, you can just think of-- this refers to like the current event, the event of clicking. And D3.mousethis is just the special D3 function that's going to say, for this click event, where was the mouse? In other words, what were the coordinates of that position? And so we can use that to give us information about where to actually draw the circle, because we want to draw the circle wherever the mouse currently is. Other things. All right. So you have a couple options for the afternoon project. I'll introduce it before we all set you free. One option is, if you would like to, feel free to keep working on the quiz application. If you didn't quite finish it, feel free to keep working on it if you want to. Feel free to think about adding other features. We talked about like saving where you are in the game, for instance. We talked about the ability of adding a timer to it, for instance, using some of the things that we talked about today. Or if you would like to, expand upon this draw example. You can either use what you've just been working on. If you look at draw-- I think it's drawone.HTML in the source code examples, you can find basically exactly this. But here's some things that you could try to add that you should potentially try if you're interested. Let's go ahead and go into draw-- draw.HTML. Here's what a finished product might look like. And this is not all that much more complicated than what we already have, whereby you can specify a color. Like, OK, let's draw on red. And stroke width, OK, let's draw on eight-- in stroke width of eight. And you can draw-- you can draw whatever shapes you want. Change the color. Change the stroke width. Draw more. If you want to you can erase the screen. Draw again. And so think about the types of features you might want to add in order to support this. Now, this does, in fact, support the idea of, OK, even if I move the mouse quickly, we're still able to get the idea of things that are connected instead of independent circles. And the way that I'm doing this currently that you can try to do, it's the recommended way to do this, is that when you draw two points next to each other in the same one, just draw a line in between them. Usually they'll be pretty close together. And if you draw a line in between them, the result of it is that you're going to ultimately get something that looks smooth instead of something that just looks like a whole bunch of independent dots. So you can think about adding that if you'd like to. You can think about adding a dropdown that allows you to choose a color, a dropdown that allows you to choose a stroke width. And ultimately you can think about the components that are actually making this up. This is just a select menu that you know how to create. And you know how to, in JavaScript, try and query for a particular element, like a form input, get it its value, and then use its value inside of other code. And the SVG code we've been working with D3 is just JavaScript. So any JavaScript code you were able to write before you can use inside of D3 as well. And so we'll go ahead and let you work on your projects. Feel free to work on either the quiz or the drawing application where you can support different colors, different line weights, clearing the board, connecting the lines, and smooth lines, or other features if you would like to. And we'll go ahead and say, why don't-- I forget what we've been doing. Why don't you all go to room 136, and you all go to room 212, and you can stay in the middle? All right. And we'll reconvene tomorrow at 10:00 AM in order to talk more about SQL and databases. And we'll pick up from there.