Events

Calvin (Deutschbein)

3 April 2023

Announcements

  • Welcome back from break!
    • .js day
    • New "reading" and response for next Monday.
  • Today we'll show events.
  • Homework for Monday.
    • Read (watch) “We Need To Fix Black Hair in Video Games”.
    • Write an HTML/CSS response paper. 500 words / ~3k chars / ~10-20 theses.
    • Include an event listener on your page, potentially with a canvas element. It can be unrelated.
  • Discussion section Monday

Script elements

<!DOCTYPE html>
<html>
  <body>
    <p id="showEle">1</p>
    <button onclick="update()">Click me</button>    
    <script>
      let val = 1 ;
      const showVar = document.getElementById("showEle") ;
      function update() 
      {
        val = 2 * val ;
        showVar.innerText = val.toString() ;
      }
    </script>
  </body>
</html>

Review Question 1

Consider the following HTML excerpt.

<p id="showEle">1</p>

What type of thing is id?

  1. CSS property
  2. HTML element
  3. HTML attribute
  4. JavaScript Object

Review Question 2

Consider the following HTML excerpt.

<button onclick="update()">Click me</button> 

What type of thing is update()?

  1. CSS function
  2. HTML attribute name
  3. HTML attribute value
  4. JavaScript function name

Review Question 3

Consider the following JavaScript excerpt from within the HTML document.

const showVar = document.getElementById("showEle") ;

This line:

  1. Defines a changing value visible to HTML, CSS, and JavaScript
  2. Defines an unchanging value visible to HTML, CSS, and JavaScript
  3. Defines an changing value visible to JavaScript only
  4. Defines an unchanging value visible to JavaScript only

Review Question 4

Consider the following JavaScript excerpt from within the HTML document.

let val = 1 ;

This line:

  1. Defines a changing value visible to HTML, CSS, and JavaScript
  2. Defines an unchanging value visible to HTML, CSS, and JavaScript
  3. Defines an changing value visible to JavaScript only
  4. Defines an unchanging value visible to JavaScript only

Review Question 5

Consider the following JavaScript function from within the HTML document.

function update() 
{
  val = 2 * val ;
  showVar.innerText = val.toString() ;
}

Consider the first line function update()

  1. This function accepts integer input and has an integer return value.
  2. This function accepts integer input and has an undefined return value.
  3. This function accepts void input and has an integer return value.
  4. This function accepts void input and has an undefined return value.

Review Question 6

Consider the following JavaScript function from within the HTML document.

function update() 
{
  val = 2 * val ;
  showVar.innerText = val.toString() ;
}

Consider the line val = 2 * val ;

  1. This is a built-in .js arithmetic operation over an integer.
  2. This is a built-in .js arithmetic operation over an float.
  3. This is an error because it defines a variable without let
  4. This creates a vector with two copies of val

Review Question 7

Consider the following JavaScript function from within the HTML document.

function update() 
{
  val = 2 * val ;
  showVar.innerText = val.toString() ;
}

Consider the excerpt showVar.innerText

  1. showVar is an HTML element, and innerText is an HTML attribute of that element
  2. showVar is an HTML element, and innerText is the content of that element
  3. showVar is a .js object, and innerText is a property of that object.
  4. showVar is a .js object corresponding to an HTML element, and innerText is an HTML attribute of that element.

Review Question 8

Consider the following JavaScript function from within the HTML document.

function update() 
{
  val = 2 * val ;
  showVar.innerText = val.toString() ;
}

Consider the excerpt val.toString()

  1. val is an HTML element, and toString() is a .js function of that element
  2. val is an HTML element, and toString() is a CSS function of that element
  3. val is a .js object, and toString() is a method of that object.
  4. val is a .js object corresponding to an HTML element, and toString() is a function of that element.

HTML and CSS

HTML elements and CSS rules are similarly vertically structured.

HTML is a

  • Element
    • Start Tag
      • Attributes
        • Attribute name
        • Attribute value
    • Content
    • End Tag
  • Element
    • Void Tag
      • Attributes
        • ...

CSS is a

  • Rule
    • Selector(s)
    • Declaration Block
      • Declaration
        • Property
        • Value
  • Attribute Value
    • Declaration Block
      • ...

Practice

Write a .js hello world.

  • Create an HTML file, hello.html
  • Create a .js file, hello.js
  • Create a text-holding element and button element in the HTML file.
  • Create a function that runs onclick in the .js file.
  • The onclick should trigger a change to the innerText of an HTML element to now read hello world.

 

More Scripting

Continue with the <script> element.

  • In the context of HTML/CSS, we may perform some limiting scripting.
  • <script>alert('Hello, world!');</script>
  • We will use scripting to "listen" for events, a way for users to interact with pages that are more sophisticated then pressing buttons.

Events

As far as I can tell, we are supposed to use events to do IO in .js

  • Events are actually HTML events.
  • However, the events themselves are defined in JavaScript.
  • JavaScript can attach event listeners to HTML elements.

  • button is clearly an HTML element.
  • onclick is clearly an HTML attribute, and is the event (for some value of is).
  • "this.innerText=Date()" is clearly JavaScript, the value of the event.

Listening

We don't always just want buttons.

  • We may want to bind arrow keys to something, to scroll.
  • We may want to support mouse movements.
  • We may want to support any manner of activities on mobile.

I don't know what we want to do, so I'm going to do my minimal IO example.

  • I'm going to make a canvas with a box in it.
  • I'm going to bind arrow keys to move the box around the canvas element.
  • This will be "fun" and "useful".

RECALL: Canvas

We once again use the canvas HTML element.

<body onload="draw();">
  <canvas id="canvas"  width="400" height="400"></canvas>
</body>

This is perfect for us, because lacking a better idea, I decided to draw rectangles.

function draw()
{
	const plot = document.getElementById("plot") ;
	const ctx = plot.getContext("2d");	
	ctx.fillRect(50, 50, 50, 50) ;
}

Many of us were tricked here - this code does not work well together. Why not?

RECALL: Canvas

Let's make a box by finding the center of our canvas and putting a rectangle there.


  • We add an outline, to make sure we have the element rendering.
  • We auto-margin right and left to center a block.
  • We name the element "display" which is different from plot and from canvas.

RECALL: Canvas

There we have it!

RECALL: Canvas

Now we will start with a centered rectangle.

  • Reflect: How does centering differ in HTML document vs. within a canvas?
function draw()
{
	const dspl = document.getElementById("display") ;
	ctx = dspl.getContext("2d") ;	
	w = dspl.width ;
	h = dspl.height ;
	s = w / 8 ;
	x = w / 2 - s / 2 ;
	y = h / 2 - s / 2 ;
	ctx.fillRect(x, y, s, s) ; // x y width height
}

This is a bit goofy because I declared variables globally for Reasons™

RECALL: Canvas

End-to-end, this is what we made:

Note at this time I've switched to externally rendered .png files, from internal live canvas elements.

Events

With our lovely lil box, we can now try for some more exciting events.

  • Globally, we will track the size of the canvas, the size of the box, and the box location.
var x ;
var y ;
var s ;
var ctx ;
var w ;
var h ;

I declared these as variables, and uninitialized, to make them global and have them set during the onload.

Events

We use built-in functions to attach an event listener to the entire HTML document.

document.addEventListener('keydown', keybind);
  • document refers to the special HTML element of type document.
  • addEventListener is a built-in .js function that takes two arguments.
  • 'keydown' is the name of the HTML event for which the listener listens.
  • keybind is the name of the .js function I will write to capture keystrokes.

Keybind is a variable, keydown is a keyword.

Scope

I set things up like this.

var x ;
var y ;
var s ;
var ctx ;
var w ;
var h ;

document.addEventListener('keydown', keybind);

function keybind()
{
	...

Events

When an event occurs, it generates an event object in .js.

function keybind()
{
	const key = event.key;

For keydown events, this will always be a key of some sort.

function keybind()
{
	alert(event.key)
}

Events

I decided to use the arrow keys. You can include wasd as well.

function keybind()
{
	const key = event.key; // "ArrowRight", "ArrowLeft", "ArrowUp", or "ArrowDown"

I introduce (?) the switch statement.

	switch (event.key) 
	{
		case "ArrowLeft":
		case "a":
			x = x - s ;
			break ;
		...
	}

This updates the global x value to be less when the left arrow key is pressed.

Switch

Switches are commonly used in IO programming, which is okay I guess.

  • Switches are control flow statements, like if/for/while.
  • Switches "fall through" - after a case is met, all code is executed until a break or return.
  • Breaks and returns are also control flow statements!

    switch (event.key) {
    	case "ArrowLeft":
    	case "a":
    		x = x - s  ; // this runs for a or left
    		break ;      // this exits the switch
    	case "ArrowRight":
    	case "d":
    		x = x + s  ; // this runs for d or right - but not a or left
    		break ;
    

Switch

Be careful!

switch (event.key) {
	case "ArrowLeft":
	case "a":
		x = x - s  ; // this runs for a or left
	case "ArrowRight":
	case "d":
		x = x + s  ; // this runs for d or right or a or left
		break ;

Switch

Be careful!

switch (event.key) {
	case "ArrowLeft":
	case "a":
		x = x - s  ; // this runs for a or left
		return ;
	case "ArrowRight":
	case "d":
		x = x + s  ; // this runs for d or right or a or left
		return ;
}
alert(event.key) ; // this doesn't fire for arrows

Switch

Be efficient! This would be bad.

switch (event.key) {
	case "ArrowLeft":
		x = x - s  ; // this runs for a or left
		return ;
	case "a":
		x = x - s  ; // this runs for a or left
		return ;
	}

Canvas

Well... we can compute new x (or y) values with switch... but what good is that.

function keybind()
{
	// old x value here
	switch (event.key) {
		// well written switch
	}
	// new x value here
}

This doesn't exactly doing IO - it does the I, but there's no changes to the canvas!

Canvas

We need to draw rectangles - just like in the onload function!

function keybind()
{
	switch (event.key) {
		// well written switch
	}
	ctx.fillRect(x, y, s, s) ; // x y width height
}

This adds a new rectangle to the canvas!

Canvas

We use another built in function to clear the old rectangle.

function keybind()
{
	ctx.clearRect(0, 0, w, h);
	switch (event.key) {
		// well written switch
	}
	ctx.fillRect(x, y, s, s) ; // x y width height
}

In effect, this moves the rectangle.

  • Question: What happenes when a key not enumerated in the switch statement is pressed?

Trenary Operator

But wait - we have a problem with bounds checking.

switch (event.key) {
	case "ArrowLeft":
		x = x - s  ; // this runs for a or left
		return ;
	case "a":
		x = x - s  ; // this runs for a or left
		return ;
	}

What happens when the box is moved off of the canvas space?

Trenary Operator

We could write extensive if statements.

switch (event.key) {
	case "ArrowLeft":
		if (x - s > 0)
		{
			x = x - s  ;
		}
		break ;
	case "ArrowRight":
		if (x + s < w)
		{
			x = x + s  ;
		}
		break ;
	}

Trenary Operator

Imagine how bad that looks without switch.

if (event.key == "ArrowLeft")
{
	if (x - s > 0)
	{
		x = x - s  ;
	}
} else if (event.key == "ArrowRight") {
	if (x + s < w)
	{
		x = x + s  ;
	}
}

Trenary Operator

Though of course there's some case combinations we can do

if ((event.key == "ArrowLeft") && (x - s > 0))
	x = x - s  ;
} else if ((event.key == "ArrowRight") && (x + s < w))
	x = x + s  ;
}

This could be an argument against switch, that said.

Trenary Operator

We can inline conditions with the "trenary operator".

switch (event.key) {
	case "ArrowLeft":
	case "a":
		x = x - s > 0 - s ? x - s : x ;
		break ;

Basically, it is

const bool = x - s > 0 ;
const someVal = x - s ;
const otherVal = x ;
x = bool ? someVal : otherVal ;

This is the same as an if statement in this simple assignment case.

Homework

Homework for Monday

  • Read (watch) “We Need To Fix Black Hair in Video Games”.
  • Write an HTML/CSS response paper. 500 words / ~3k chars / ~10-20 theses.
    • You don't have to write just 15 theses, but I would.
    • Bold a main thesis that summarizes your thoughts.
    • Aim for between 30% and 70% to be discussion-provoking questions.
    • These can be like my abstract responses, for example.
  • Webhost at *.github.io/kindafunny.html no latter than Friday at Midnight AOE
  • Read at least 3 of your peers' documents before class.
  • Have an event listener do something to your page, and document it (write a sentence somewhere saying what it does).
// reveal.js plugins