Final Project Progress Day

In-Progress Presentations

Share your plan for the final project, and the current version of your code. Make sure to address:

  • Your pseudocode or outline of the overall project plan
  • Challenges and obstacles you’ve encountered so far
  • Pieces of your project plan you’re still figuring out
  • Any new APIs or libraries you are using for this project

In Class

  • Strategies for Debugging and Planning Complex Applications
  • Review of Final Project Guidelines
  • Open Lab Time

Remember: Final Projects are due by midnight, May 14th. Email me when your project is ready for review. If you have missing assignments, you have until the same deadline to complete them and email me the link!

Future of HTML5 + Keeping On Top of Development Skills

Mini-Project Five

Remember, Mini-Project Five is due before the start of class today. Anyone who has not presented yet this semester needs to:

  • Share your solution for Mini-Project Five
  • Walk through and explain your script
  • Describe any challenges or debugging tasks and how you resolved them

Platforms for HTML5 and JavaScript: Windows 8, Mobile and Beyond

Windows 8

Mobile

Extending JavaScript

Other Programming Languages (and how knowing JavaScript will help)

Keeping Up with the News

Planning your Final Project

Web Workers, Fractals, and Modernizr

Mini-Project Four

Remember, Mini-Project Four is due before the start of class today. We need two volunteers to:

  • Share your solution for Mini-Project Four
  • Walk through and explain your script
  • Describe any challenges or debugging tasks and how you resolved them

Everyone will have to present once this semester for participation credit.

Mastermind Tutorial Review: Working with the Canvas; building interactive applications;

Working with Best Practices
Mini-Exercise: Handling Clicks and the Canvas
<!doctype html>
<html lang="en">
<head>
<style>canvas {
 border: 2px solid black;
}
</style>
<title>Demo: Events, Clicks and Composite Types</title>
<meta charset="utf-8">
<script>
window.onload = init;
var canvas;
var context;
function init() {
 canvas = document.getElementById("myCanvas");
 context = canvas.getContext("2d");
 canvas.onclick = function(event) {
     handleClick(event.clientX, event.clientY);
 };
}
function handleClick(x, y) {
 var colors = ["red", "green", "blue", "orange", "purple", "yellow"];
 var color = colors[Math.floor(Math.random()*colors.length)];
 var compositeTypes = ['source-over','source-atop','destination-over','destination-out','destination-atop','lighter','darker','xor'];
 //others to try: 'copy', 'destination-in','source-out','source-in'
 var type = compositeTypes[Math.floor(Math.random()*compositeTypes.length)];
 alert("Type: " + type);
 context.globalCompositeOperation = type;
 context.beginPath();
 context.arc(x, y, 30, 0, degreesToRadians(360), true);
 context.fillStyle = color;
 context.fill();
}
function degreesToRadians(degrees) {
 //converts from degrees to radians and returns
 return (degrees * Math.PI)/180;
}</script></head><body><canvas id="myCanvas" width="300" height="300"></canvas></body></html>
When do we use web workers? How do we handle increasingly complex coding? Working from the Mandelbrot set example, we’ll consider the relationship between web workers, the canvas, and complex procedural generation and animation.

Reminder: Mini-Project Five is due next Monday, before the start of class. You should already be working on your final project: consider which previous projects (including mini-project five) you might want to revisit or expand as part of your concept.

Working Mastermind – Canvas Version

View in action at: http://selfloud.net/mmind.html
<!doctype html>
<html lang="en">
<head>
 <title>Mastermind</title>
 <meta charset="utf-8">
 <style>
body {
 font-family: Verdana, Helvetica, sans-serif;
}
canvas {
 border: 1px solid black;;
}
</style>
 <script>
 var secret = "BPGRY";
 var canvas;
 var context;
 var rowY;
 var rowX;
 var guesses;
 var particles;
 var timer;
 function makeParticles() {
 //create an array of particles for our opening animation
 particles = [];
 for(var i = 0; i < 30; i++)
 {
 particles.push(new createParticle());
 }
 }
 function createParticle()
 {
 //the constructor for a single particle, with random starting x+y, velocity, color, and radius
 this.x = Math.random()*canvas.width;
 this.y = Math.random()*canvas.height;
 this.vx = Math.random()*10-5;
 this.vy = Math.random()*10-5;
 var colors = ["red", "green", "blue", "orange", "purple", "yellow", "white"];
 this.color = colors[Math.floor(Math.random()*colors.length)];
 this.radius = 15;
 }
 function moveParticles() {
 //partially clear the screen to fade previous circles, and draw a new particle at each new coordinate
 context.globalCompositeOperation = "source-over";
 context.fillStyle = "rgba(0, 0, 0, 0.3)";
 context.fillRect(0, 0, canvas.width, canvas.height);
 context.globalCompositeOperation = "lighter";
 context.fillStyle = "white";
 context.font = "3em Lucida Grande";
 context.textAlign = "center";
 context.fillText("Mastermind", canvas.width/2, canvas.height/2);
 for(var i = 0; i < particles.length; i++)
 {
 var p = particles[i];
 context.beginPath();
 context.arc(p.x, p.y, p.radius, 0, degreesToRadians(360), true);
 context.fillStyle = p.color;
 context.fill();
 p.x += p.vx;
 p.y += p.vy;
 if(p.x < -50) p.x = canvas.width+50;
 if(p.y < -50) p.y = canvas.height+50;
 if(p.x > canvas.width+50) p.x = -50;
 if(p.y > canvas.height+50) p.y = -50;
 }
 }
 function clearScreen(color) {
 //clears the screen and fills with the color of choice
 context.clearRect(0, 0, canvas.width, canvas.height);
 context.fillStyle = color;
 context.fillRect(0, 0, canvas.width, canvas.height);
 }
 function startGame() {
 //clears the timer to end the animation, and sets up the board for the next game
 alert("Starting!");
 clearInterval(timer);
 context.globalCompositeOperation = "source-over";
 clearScreen("white");

 context.fillStyle = "black";
 context.font = "2em Lucida Grande";
 context.textAlign = "center";
 context.fillText("Mastermind", canvas.width/2, 30);
 rowY = 60;
 rowX = 40;
 guesses = 0;
 }
 function lostGame() {
 //Clears the screen and reveals the secret code
 clearScreen("black");
 context.fillStyle = "white";
 context.font = "2em Lucida Grande";
 context.textAlign = "center";
 context.fillText("The Code Revealed", canvas.width/2, canvas.height/2);
 rowY = (canvas.height/2)+30;
 rowX = (canvas.width/2)-75;
 printGuess(secret);
 }
 function getHighScores() {
 //grabs the high scores array from local storage. if not there, create it
 var highScoresArray = localStorage.getItem("highScoresArray");
 if (!highScoresArray) {
 highScoresArray = [];
 localStorage.setItem("highScoresArray", JSON.stringify(highScoresArray));
 } else {
 highScoresArray = JSON.parse(highScoresArray);
 }
 return (highScoresArray);
 }
 function wonGame() {
 //asks the player for their name, adds score and name to high scores array, and prints all high scores to screen
 clearScreen("black");
 context.fillStyle = "white";
 context.font = "2em Lucida Grande";
 context.textAlign = "center";
 context.fillText("High Scores", canvas.width/2, 30);
 var name = prompt("Congratulations! Please enter your name: ", "");
 //alert(name);
 var scoreObj = {
 "name": name,
 "guesses": guesses
 };
 var highScoresArray = getHighScores();
 var currentDate = new Date();
 var key = "score_" + currentDate.getTime();
 localStorage.setItem(key, JSON.stringify(scoreObj));
 highScoresArray.push(key);
 localStorage.setItem("highScoresArray", JSON.stringify(highScoresArray));
 rowX = canvas.width/4;
 rowY = 70;
 for (var k=0; k < highScoresArray.length; k++) {
 key = highScoresArray[k];
 var score = localStorage.getItem(key);
 var score = JSON.parse(score);
 printScore(score);
 }
 }
 function printScore(scoreObj) {
 //prints a high score to the list on the canvas
 var printScore = scoreObj.name + ": " + scoreObj.guesses;
 context.fillStyle = "white";
 context.font = "1.5em Arial";
 context.textAlign = "left";
 context.fillText(printScore, rowX, rowY);
 rowY += 30;
 }
 function init() {
 //initializes the canvas and buttons, and starts the animation
 canvas = document.getElementById("gameCanvas");
 context = canvas.getContext("2d");
 var button = document.getElementById("submitButton");
 button.onclick = submitGuess;
 var startButton = document.getElementById("startButton");
 startButton.onclick = startGame;
 var clearButton = document.getElementById("clearHighScores");
 clearButton.onclick = clearHighScores;
 makeParticles();
 timer = setInterval(moveParticles, 100);
 }
 function submitGuess() {
 alert("Nice guess.");
 //takes the user's guess, prints it, and evaluates it against secret
 var userInput = document.getElementById("userGuess");
 var userTry = userInput.value;
 //alert("Button was clicked! " + userTry);
 printGuess(userTry);
 rowX = canvas.width-200;
 var w = 30;
 for (var i=0; i < secret.length; i++) {
 var found = false;
 if ((userTry.charAt(i))==(secret.charAt(i))) {
 context.fillStyle = "green";
 context.fillRect(rowX, rowY-15, w, w);
 found = true;
 }
 else {
 for (var j=0; j<secret.length; j++) {
 if ((userTry.charAt(i))==(secret.charAt(j))) {
 context.fillStyle = "red";
 context.fillRect(rowX, rowY-15, w, w);
 found = true;
 }
 }
 }
 if (found == false) {
 context.fillStyle = "black";
 context.fillRect(rowX, rowY-15, w, w);
 found = true;
 }
 rowX += 30;
 }
 rowX = 40;
 rowY += 60;
 guesses++;
 if (guesses == 6) {
 //alert("You Lose!");
 lostGame();
 }
 else if (userTry == secret) {
 //alert("You Win!");
 wonGame();
 }
 }
 function printGuess(guess) {
 //takes the guess, checks each for color, and prints the right circle
 //alert("guess");
 for (var i=0; i < guess.length; i++) {
 guessColor = guess.charAt(i);
 switch (guessColor) {
 case "R":
 drawCircle("red");
 break;
 case "Y":
 drawCircle("yellow");
 break;
 case "G":
 drawCircle("green");
 break;
 case "B":
 drawCircle("blue");
 break;
 case "O":
 drawCircle("orange");
 break;
 case "P":
 drawCircle("purple");
 break;
 default:
 alert("That's not a color!");
 }
 }
 }
 function drawCircle(color) {
 //draws a circle of the given color at the right spot
 context.beginPath();
 context.arc(rowX, rowY, 15, 0, degreesToRadians(360), true);
 context.fillStyle = color;
 context.fill();
 rowX += 40;
 }
 function degreesToRadians(degrees) {
 //converts from degrees to radians and returns
 return (degrees * Math.PI)/180;
 }
 function clearHighScores() {
 //clears all high scores out of local storage
 localStorage.clear();
 alert("High Scores Cleared");
 }
 window.onload = init;
</script>
</head>
<body>
<canvas id="gameCanvas" width="500" height="400"></canvas>
<p>Guess the code (R,Y,B,G,O,P - 5 letters, no repeats)</p>
 <form>
 <input type="text" id="userGuess" size="15" placeholder="Your Guess">
 <input type="button" id="submitButton" value="Guess the Code">
 <br><br>
 <input type="button" id="startButton" value="Start the Game">
 <input type="button" id="clearHighScores" value ="Clear High Scores">
 </ul>
 </form>
</body>
</html>

Mastermind Tutorial

The Mastermind Tutorial is in two parts:

Part One: Build a working graphical interface for our Mastermind game that dynamically generates objects on the Canvas as needed. We’ll work from our foundation logic to create the two columns of color-coded results and practice our skills with circles, squares and text. Download Part One here.

Part Two: Now that we have the basic game, let’s jazz it up. We’ll add end screens for both winning and losing and a simple particle animation to open our game screen. We’ll also move from simple game to application by adding a working high scores table in local storage. Download Part Two here.

The full code of the final working game will be posted at the end of our scheduled class time Monday night. I encourage you to use the time we are not meeting in person to work through it on your own, and then compare or debug using the posted source code.

My tutorial files are in MS Word. I’ve tried to catch typos and pasted the code directly from my working file, but let me know if you have any problems with it. You can email me directly or reply to the group email for help debugging. Your final version of the game should be posted to your site by the start of class April 23rd.

Video and the Canvas

Video and the Canvas

  • HTML5 and the Video Element
  • Working with video formats
  • Event Listeners
  • Processing Video on the Canvas
  • Animation and objects in motion

In-Class Exercise: Bouncing Videos

We’ll be using a video from one of the book examples–you can download the video files in the range of necessary formats here. We will dynamically generate the video element using the canvas to draw the images, and manipulate the elements to create dynamic animation from our video objects. Variants on this and other example projects to give you inspiration for the possibilities of the canvas can be found in the book’s code reference library.

Local Storage and Mastermind: Tutorial for April16th

There will be a step-by-step tutorial posted instead of an in-person class on the 16th. The tutorial will include pseudocode and code snippets for combining local storage and the canvas to create an advanced version of our Mastermind game. Working either alone or with a group, your challenge is to complete the project either during the scheduled class time or by Wednesday at midnight. I will be sending out an email when the tutorial is posted, and replies to the email sent to all class members can ask questions of general concern.

Mini Project Five: Building on Canvas

Take an existing application or concept you’ve worked with this semester and change its existing interface to use the Canvas for primary display. Using the starting tutorial on taking MasterMind from a text-based to graphical interface as an example, choose an appropriate application and make use of the built-in drawing tools, imported images, and text output on the canvas. The resulting project must be dynamic: you should not be outputting a static picture, but instead updating or transforming it based on input from the user.

Your Canvas implementation should include:

  • Proper use of properties and built-in functions from the 2D context
  • Positioning of elements using the coordinate system
  • Use of the built-in drawing tools to add color, shapes or lines to the canvas
  • Use of the drawText function for adding formatted text to the canvas
  • Imported graphical or video elements from outside files manipulated appropriately
  • Handling of data and interpretation into graphical elements (ie, pegs for hits in Mastermind)
  • Some method for handling user input and updating the display accordingly

Optional extensions include integration with web services (as in the TweetShirt example from the text), outputting the canvas to an image file for download, building a complex user interface on the canvas itself or integrating appropriate uses of video or animation.

  • A-Level Work: Build a working interface for a user-responsive graphical application or game. A combination of generated graphics and imported elements should provide the user with a dynamic display of content. For A-level work, the application should go beyond the minimum requirements and include some dynamic elements, such as animation or direct user manipulation of the canvas.
  • B-Level Work: Build a working interface for a user-responsive graphical application or game. A combination of generated graphics and imported elements should provide the user with a dynamic display of content. For B-Level work, the application should meet the minimum requirements above, but does not need to attempt any optional elements.
  • C-Level Work: Create a basic Canvas application that may be derived heavily from the Mastermind example or otherwise be missing several required elements.
  • D-Level Work: The application is attempted but fails to work with the canvas element or suffers from significant bugs.
  • Failing Work: Project is not submitted or demonstrates no attempt to complete the task.

Remember, Mini-Project Four is due April 16th. If you are not posting to a designated site linked on our projects page, please email me the link before our regular start of class time. There is no in-person meeting on the 16th.

Abstract Art Generator

Aside

<!doctype html>
<html lang="en">
<head>
<title>Abstract Painting Generator</title>
<meta charset="utf-8">
<style>
body {
 font-family: Verdana, Helvetica, sans-serif;
}
canvas {
 border: 1px solid black;;
}
</style>
<script>
function makeTitle() {
//generate the title for your masterpiece
 var line1 = ["Meditative", "Objective", "Reflective", ];
 var line2 = ["Ellipses", "Tranformation", "State", "Emotion", "Composition"];
 var line3 = ["I", "II", "III", "IV", "V"];
var rand1 = Math.floor(Math.random() * line1.length);
 var rand2 = Math.floor(Math.random() * line2.length);
 var rand3 = Math.floor(Math.random() * line3.length);
var title = line1[rand1] + " " + line2[rand2] + " " + line3[rand3];
 return(title);
}
function artHandler() {
 var title = makeTitle();
 alert(title);

 var canvas = document.getElementById("artCanvas");
 var context = canvas.getContext("2d");

 fillBackgroundColor(canvas, context);

 var colors = ["white", "yellow", "blue", "red"];
 var shapes = ["square", "circle"];
 for (var i = 0; i < 20; i++) {
 var color = colors[Math.floor(Math.random() * colors.length)];
 drawSquare(canvas, context, color);
 drawCircle(canvas, context, color);
 }
 drawText(canvas, context, title);
}
function fillBackgroundColor(canvas, context) {
 var colors = ["white", "yellow", "blue", "red"];
 var bgColor = colors[Math.floor(Math.random() * colors.length)];
 context.fillStyle = bgColor;
 context.fillRect(0, 0, canvas.width, canvas.height);
}
function degreesToRadians(degrees) {
 return (degrees * Math.PI)/180;
}
//Draws a square at a random location
function drawSquare(canvas, context, color) {
 var w = Math.floor(Math.random() * 40);
 var x = Math.floor(Math.random() * canvas.width);
 var y = Math.floor(Math.random() * canvas.height);
context.fillStyle = color;
 context.fillRect(x, y, w, w);
}
// Draws a circle at a random location
function drawCircle(canvas, context, color) {
 var radius = Math.floor(Math.random() * 40);
 var x = Math.floor(Math.random() * canvas.width);
 var y = Math.floor(Math.random() * canvas.height);
context.beginPath();
 context.arc(x, y, radius, 0, degreesToRadians(360), true);
context.fillStyle = color;
 context.fill();
}
function drawText(canvas, context, title) {
 context.fillStyle = "black";
 context.font = "bold 1em sans-serif";
 context.textAlign = "right";
 context.fillText(title, canvas.width-20, canvas.height-40);
}
window.onload = function() {
 var button = document.getElementById("artButton");
 button.onclick = artHandler;
}
</script>
</head>
<body>
<h1>Abstract Art:</h1>
<canvas width="600" height="200" id="artCanvas"></canvas>
<form>
<input type="button" id="artButton" value="New Masterpiece">
</form>
</body>
</html>

The Canvas and Mini-Project Four

 Understanding the Canvas

  • Final Project Guidelines
  • Web Services and Mini-Project Four
  • Introducing the Canvas Element
  • Building Dynamic Web Graphics
  • Looking ahead: animation, video + more
  • Recommended additional reading: HTML5 Canvas

In-Class Exercise: Using the Canvas

Today we’ll build a simple abstract art generator that uses random colors, coordinates and sizes to build a “modern art” piece out of squares and circles. The code will be posted at the end of class. This project builds on the previous poetry generator, and can be combined with your first mini-project to build procedural content.

Mini-Project Four: Working with Web Services

Working from the example code below, create a simple application to take and display information from a web services API. Your application should demonstrate an understanding of the JSON object being accessed and an ability to dynamically update the information (not seen in the example below, but built in our example last week.) Any web service can be used for this project.

Your project should…

  • Successfully implement a callback function
  • Pull in data as JavaScript objects
  • Make use of appropriate properties of data
  • Display a portion of imported content
  • Update dynamically at regular intervals
Grading Rubric
  • A-Level Work: Build a working application to import and display data from a web service API.  The callback function should be clearly written and called dynamically at an appropriate time interval. Displayed output should be clearly appended to the DOM. For A-level work, the application should use multiple properties of imported data in a meaningful way–either to sort / search based on user input, narrow the range of returned results, or otherwise manipulate the data returned.
  • B-Level Work: Build a working application to import and display data from a web service API. The callback function should be clearly written and called dynamically at an appropriate time interval. Displayed output should be clearly appended to the DOM. For B-level work, the application might simply return all data or only use one or two properties of the objects.
  • C-Level Work: Create a basic application that imports data, but does not update dynamically at intervals. The objects are imported but not meaningfully displayed.
  • D-Level Work: The application is attempted but fails to connect to a web service or import data.
  • Failing Work: Project is not submitted or demonstrates no attempt to complete the task.
<!doctype html>
<html lang="en">
<head>
 <title>Tweets</title>
 <meta charset="utf-8" />
 <script>
 function updateTweets(tweets) {
 for (var i = 0; i < tweets.length; i++) {
 var tweet = tweets[i];
 var newDiv = document.createElement("div");
 var div = document.getElementById("tweetsHere");
 newDiv.innerHTML = tweet.text;
 div.appendChild(newDiv);
 }
 }
 </script>
</head>
<body>
 <div id="tweetsHere"></div>
 <script src="http://twitter.com/statuses/user_timeline/timoreilly.json?callback=updateTweets">
</script>
</body>
</html>

 

Gumballs

Aside

<!doctype html>
<html lang="en">
<head>
 <script>
 var lastReportTime = 0;
 
 window.onload = function() {
 //check regularly for new data 
 setInterval(handleRefresh, 3000);
 }
 function handleRefresh() {
 //grabs data from wickedlysmart, calls the updateSales function, cuts the array to only include data since the last report time, and adds a timestamp to avoid cached data
 var url = "http://gumball.wickedlysmart.com/?callback=updateSales" + "&lastreporttime=" + lastReportTime + "&random=" + (new Date()).getTime();
 //create a new script element to hold the call
 var newScriptElement = document.createElement("script");
 //set it to our new url
 newScriptElement.setAttribute("src", url);
 //give it an id so we can find and replace
 newScriptElement.setAttribute("id", "jsonp");
 //grab the head (from an array, so using index 0)
 var head = document.getElementsByTagName("head")[0];
 //look to see if there is already a script element (named jsonp)
 var oldScriptElement = document.getElementById("jsonp");
 //if we don't find it, we just append the new one to the head
 if (oldScriptElement == null) {
 //only append if first time (no "jsonp" exists) -- otherwise replaceChild
 head.appendChild(newScriptElement);
 }
 //otherwise we replace the old with the new (so we're not creating endless script elements)
 else {
 head.replaceChild(newScriptElement, oldScriptElement);
 }
 }
 function updateSales(sales) {
 //called by the newly added script element, and only includes data since the last report time
 //print the sales to our sales div
 //grab the sales div from the document
 var salesDiv = document.getElementById("sales");
 //cycle through every object in the sales array
 for (var i=0; i < sales.length; i++) {
 //grab the object at the current spot (going 0...length-1)
 var sale = sales[i];
 //create a new div to hold that sale info
 var div = document.createElement("div");
 //give it a class so we can format it with css later
 div.setAttribute("class", "saleItem");
 //add the data from this sale to the innerhtml
 div.innerHTML = sale.name + " sold " + sale.sales + " gumballs";
 //add our new div to the collection of sale information
 salesDiv.appendChild(div);
 }
 //save the last reported time to the global variable
 if (sales.length > 0) {
 //using sales.length-1 to get the object at the end of the sales array
 lastReportTime = sales[sales.length-1].time;
 }
 }
 </script>
</head>
<body>
 <h1>Gumballs</h1>
 <div id="sales">
 </div>
 
</body>
</html>

Web Services and JSON

Mini-Project Three

Remember, Mini-Project Three is due before the start of class today. We need two volunteers to:

  • Share your solution for Mini-Project Three
  • Walk through and explain your script
  • Describe any challenges or debugging tasks and how you resolved them

Everyone will have to present once this semester for participation credit.

Looking Ahead

  • Schedule Review
  • Pseudocode Project Reminder
  • Mini Project Four (APIs) and Mini Project Five (Canvas)
  • Thinking about the final project

JSON and APIs

In Class Exercise

Working with JSONP and Mighty Gumball: from the example project in Chapter 6, we will build the web application to display continuously updated sales from imported structured data. These same techniques can be applied to working with web service APIs, which will be the challenge for the next mini-project.