Created
July 21, 2011 07:09
-
-
Save lamberta/1096696 to your computer and use it in GitHub Desktop.
Buffalo JavaScript Club Presentation: Let's Set Up an Animation Loop, Using HTML5 and a Canvas Element
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!doctype html> | |
<html> | |
<head> | |
<meta charset="utf-8"> | |
<title></title> | |
<style> | |
body { | |
background-color: #bbb; | |
} | |
#canvas { | |
background-color: #fff; | |
} | |
</style> | |
</head> | |
<body> | |
<canvas id="canvas" width="400" height="400"></canvas> | |
<script> | |
if (!window.requestAnimationFrame) { | |
window.requestAnimationFrame = (window.webkitRequestAnimationFrame || | |
window.mozRequestAnimationFrame || | |
window.oRequestAnimationFrame || | |
window.msRequestAnimationFrame || | |
function (callback) { | |
return window.setTimeout(callback, 17 /*~ 1000/60*/); | |
}); | |
} | |
function Ball (radius, color) { | |
this.radius = (radius === undefined) ? 40 : radius; | |
this.color = (color === undefined) ? "#ff0000" : color; | |
this.x = 0; | |
this.y = 0; | |
} | |
Ball.prototype.draw = function (context) { | |
context.save(); | |
context.translate(this.x, this.y); | |
context.fillStyle = this.color; | |
context.beginPath(); | |
//x, y, radius, start_angle, end_angle, anti-clockwise | |
context.arc(0, 0, this.radius, 0, (Math.PI * 2), true); | |
context.closePath(); | |
context.fill(); | |
context.restore(); | |
}; | |
window.onload = function () { | |
var canvas = document.getElementById('canvas'), | |
context = canvas.getContext('2d'), | |
ball = new Ball(), | |
vx = Math.random() * 10 - 5, | |
vy = Math.random() * 10 - 5; | |
ball.x = canvas.width / 2; | |
ball.y = canvas.height / 2; | |
function checkBoundaries () { | |
var left = 0, | |
right = canvas.width, | |
top = 0, | |
bottom = canvas.height; | |
if (ball.x + ball.radius > right) { | |
ball.x = right - ball.radius; | |
vx *= -1; | |
} else if (ball.x - ball.radius < left) { | |
ball.x = left + ball.radius; | |
vx *= -1; | |
} | |
if (ball.y + ball.radius > bottom) { | |
ball.y = bottom - ball.radius; | |
vy *= -1; | |
} else if (ball.y - ball.radius < top) { | |
ball.y = top + ball.radius; | |
vy *= -1; | |
} | |
} | |
(function drawFrame () { | |
window.requestAnimationFrame(drawFrame, canvas); | |
context.clearRect(0, 0, canvas.width, canvas.height); | |
ball.x += vx; | |
ball.y += vy; | |
checkBoundaries(); | |
ball.draw(context); | |
}()); | |
}; | |
</script> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
\documentclass{beamer} | |
\usepackage{listings} | |
\usepackage{textcomp} | |
\usetheme{Szeged} | |
\usecolortheme{beaver} | |
\title[HTML5 Animation Loop]{Let's Set Up an Animation Loop!} | |
\subtitle{Using HTML5 and a Canvas Element} | |
\author[Lamberta]{Billy Lamberta \\ \href{http://lamberta.org}{lamberta.org} \\ \href{http://twitter.com/billyist}{@billyist}} | |
\date{Buffalo JavaScript Club, 21 Jul 2011} | |
%%For source code, use straight quotes and a monospace font | |
\lstset{upquote=true,basicstyle=\footnotesize\ttfamily} | |
\begin{document} | |
\begin{frame} | |
\titlepage | |
\end{frame} | |
\begin{frame} | |
\tableofcontents | |
\end{frame} | |
\section{A Minimal HTML5 Document} | |
\begin{frame}[fragile] | |
\begin{lstlisting} | |
<!doctype html> | |
<html> | |
</html> | |
\end{lstlisting} | |
\end{frame} | |
\begin{frame}[fragile] | |
\begin{lstlisting} | |
<!doctype html> | |
<html> | |
<head> | |
<meta charset="utf-8"> | |
</head> | |
</html> | |
\end{lstlisting} | |
\end{frame} | |
\begin{frame}[fragile] | |
\begin{lstlisting} | |
<!doctype html> | |
<html> | |
<head> | |
<meta charset="utf-8"> | |
<title></title> | |
<link rel="stylesheet" href="style.css"> | |
</head> | |
</html> | |
\end{lstlisting} | |
\end{frame} | |
\begin{frame}[fragile] | |
\begin{lstlisting} | |
<!doctype html> | |
<html> | |
<head> | |
<meta charset="utf-8"> | |
<title></title> | |
<link rel="stylesheet" href="style.css"> | |
</head> | |
<body> | |
<canvas id="canvas" width="400" height="400"></canvas> | |
</body> | |
</html> | |
\end{lstlisting} | |
\end{frame} | |
\begin{frame}[fragile] | |
\begin{lstlisting} | |
<!doctype html> | |
<html> | |
<head> | |
<meta charset="utf-8"> | |
<title></title> | |
<link rel="stylesheet" href="style.css"> | |
</head> | |
<body> | |
<canvas id="canvas" width="400" height="400"></canvas> | |
<script> | |
window.onload = function () { | |
//our javascript code will go here... | |
}; | |
</script> | |
</body> | |
</html> | |
\end{lstlisting} | |
\end{frame} | |
\section{Access the Canvas API} | |
\begin{frame} | |
\tableofcontents[currentsection] | |
\end{frame} | |
\begin{frame}[fragile] | |
\begin{definition} | |
The \emph{canvas} is a bitmap image we draw \emph{to}, | |
and \\ | |
the \emph{context} is what we use to draw \emph{with}. | |
\end{definition} | |
\begin{lstlisting} | |
window.onload = function () { | |
var canvas = document.getElementById('canvas'), | |
context = canvas.getContext('2d'); | |
}; | |
\end{lstlisting} | |
\end{frame} | |
\begin{frame}{Example Context Commands} | |
\begin{itemize} | |
\item \texttt{moveTo} | |
\item \texttt{lineTo} | |
\item \texttt{stroke} | |
\item \texttt{fillRect} | |
\item \texttt{fillText} | |
\item \texttt{drawImage} | |
\item \textit{and many more!} | |
\end{itemize} | |
\end{frame} | |
\begin{frame}[fragile] | |
\begin{lstlisting} | |
window.onload = function () { | |
var canvas = document.getElementById('canvas'), | |
context = canvas.getContext('2d'); | |
context.fillStyle = "#ff0000"; | |
context.fillRect(50, 50, 100, 100); | |
}; | |
\end{lstlisting} | |
\begin{center} | |
\includegraphics[width=0.5\textwidth]{./include/canvas01.jpg} | |
\end{center} | |
\end{frame} | |
\section{The Animation Loop} | |
\begin{frame} | |
\tableofcontents[currentsection] | |
\end{frame} | |
\begin{frame}[fragile]{The Old Days (6 months ago)} | |
Timer-based loops. | |
\begin{lstlisting} | |
var callback = function () { | |
console.log("tick!"); | |
}; | |
window.setInterval(callback, 1000/60); //fps | |
\end{lstlisting} | |
\begin{block}{Output} | |
\texttt{tick!}\\ | |
\texttt{tick!}\\ | |
\texttt{tick!}\\ | |
\texttt{...} | |
\end{block} | |
\end{frame} | |
\begin{frame}{Precision Problems} | |
\begin{itemize} | |
\item The specified delay is added to the queue. If other jobs, then we wait. | |
\item Timers aren't accurate to the millisecond. Different browsers, different resolutions. | |
\end{itemize} | |
\end{frame} | |
\begin{frame}{The New Hotness} | |
\texttt{window.requestAnimationFrame(callback [, element]);} | |
\begin{itemize} | |
\item Browsers can consolidate CSS and JS animations into a | |
single reflow and repaint cycle. | |
\item If the animation is in a tab that's not visible, the | |
browser won't keep it running. | |
\item Vendors can continue to optimize this function. | |
\end{itemize} | |
\end{frame} | |
\begin{frame}[fragile]{The Shim} | |
\begin{lstlisting} | |
if (!window.requestAnimationFrame) { | |
window.requestAnimationFrame = | |
(window.webkitRequestAnimationFrame || | |
window.mozRequestAnimationFrame || | |
window.oRequestAnimationFrame || | |
window.msRequestAnimationFrame || | |
function (callback) { | |
return window.setTimeout(callback, 1000/60); | |
}); | |
} | |
\end{lstlisting} | |
\end{frame} | |
\begin{frame}[fragile]{The Loop} | |
\begin{lstlisting} | |
window.onload = function () { | |
var canvas = document.getElementById('canvas'), | |
context = canvas.getContext('2d'); | |
(function drawFrame () { | |
window.requestAnimationFrame(drawFrame, canvas); | |
context.clearRect(0, 0, canvas.width, canvas.height); | |
//animation code... | |
}()); | |
}; | |
\end{lstlisting} | |
\end{frame} | |
\section{Draw Stuff} | |
\begin{frame} | |
\tableofcontents[currentsection] | |
\end{frame} | |
\begin{frame}[fragile,shrink]{ball.js} | |
\begin{lstlisting} | |
function Ball (radius, color) { | |
this.radius = (radius === undefined) ? 40 : radius; | |
this.color = (color === undefined) ? "#ff0000" : color; | |
this.x = 0; | |
this.y = 0; | |
} | |
Ball.prototype.draw = function (context) { | |
context.save(); | |
context.translate(this.x, this.y); | |
context.fillStyle = this.color; | |
context.beginPath(); | |
//x, y, radius, start_angle, end_angle, anti-clockwise | |
context.arc(0, 0, this.radius, 0, (Math.PI * 2), true); | |
context.closePath(); | |
context.fill(); | |
context.restore(); | |
}; | |
\end{lstlisting} | |
\end{frame} | |
\begin{frame}[fragile,shrink]{Detect Edges} | |
\begin{lstlisting} | |
function checkBoundaries () { | |
var left = 0, | |
right = canvas.width, | |
top = 0, | |
bottom = canvas.height; | |
if (ball.x + ball.radius > right) { | |
ball.x = right - ball.radius; | |
vx *= -1; //bounce | |
} else if (ball.x - ball.radius < left) { | |
ball.x = left + ball.radius; | |
vx *= -1; | |
} | |
if (ball.y + ball.radius > bottom) { | |
ball.y = bottom - ball.radius; | |
vy *= -1; | |
} else if (ball.y - ball.radius < top) { | |
ball.y = top + ball.radius; | |
vy *= -1; | |
} | |
} | |
\end{lstlisting} | |
\end{frame} | |
\begin{frame}[fragile,shrink] | |
\begin{lstlisting} | |
<script src="utils.js"></script> | |
<script src="ball.js"></script> | |
<script> | |
window.onload = function () { | |
var canvas = document.getElementById('canvas'), | |
context = canvas.getContext('2d'), | |
ball = new Ball(), | |
vx = Math.random() * 10 - 5, | |
vy = Math.random() * 10 - 5; | |
ball.x = canvas.width / 2; | |
ball.y = canvas.height / 2; | |
(function drawFrame () { | |
window.requestAnimationFrame(drawFrame, canvas); | |
context.clearRect(0, 0, canvas.width, canvas.height); | |
ball.x += vx; | |
ball.y += vy; | |
checkBoundaries(); | |
ball.draw(context); | |
}()); | |
}; | |
</script> | |
\end{lstlisting} | |
\end{frame} | |
\begin{frame}{References} | |
\begin{thebibliography}{10} | |
\bibitem{Irish} | |
Paul Irish | |
\newblock \href{http://paulirish.com/2011/requestanimationframe-for-smart-animating/}{\emph{requestAnimationFrame for smart animating}} | |
\bibitem{Lamberta} | |
Billy Lamberta | |
\newblock \href{http://www.amazon.com/dp/1430236655?tag=de05f-20}{\emph{Foundation HTML5 Animation with JavaScript}} | |
\bibitem{Mozilla} | |
Mozilla Developer Network | |
\newblock \href{https://developer.mozilla.org/en/DOM/window.mozRequestAnimationFrame}{\emph{requestAnimationFrame}} | |
\bibitem{Zakas} | |
Nicholas C. Zakas | |
\newblock \href{http://nczonline.net/blog/2011/05/03/better-javascript-animations-with-requestanimationframe/}{\emph{Better JavaScript animations with requestAnimationFrame}} | |
\end{thebibliography} | |
\end{frame} | |
\end{document} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment