please dont rip this site

JavaScript Canvas / Animation Tutorial

The Canvas was added to allow JavaScript to have direct access to the bitmap of the screen in a web page. It shorts out all the text, images, etc... and just lets your code draw on the screen. 2D graphics are the obvious application, but with a little help from WebGL, 3D graphics are also very possible. Apple, Inc came up with it in 2004 for their Safari browser and it became a standard in 2005. It is supported right from the start in Chrome and Safari, and in current versions of all other browsers.

To use it, in the HTML page, just add a canvas tag. You can specify a size which is in pixels on the screen, and probably want to give it an id so your code can find it.

<canvas height="400" width="600" id="screen">This browser doesn't support canvas.</canvas>

The text between the tags won't display if the browser understands a canvas. By itself, the canvas just sets aside some space on the page. To talk to it, you need to get it's "context".

const canvas = document.getElementById("screen")
const ctx = canvas.getContext("2d")

A graphics context is a way of looking at a section of the screen. You can look at in different ways; with different points of view. Most of the time, we want the "2d" context, but we could get the "webgl" context for 3D work or "imageBitmap" (which is good for displaying camera images).

To better see the canvas, we can fill it, or part of it with some style, like a solid color.

ctx.fillStyle = "black"

let p1={x:10, y:200, w:20, h:75} //w is the width, h is height. ctx.fillRect(p1.x, p1.y, p1.w, p1.h)

Note that we are in the 4th quadrant: X is the distance from the left edge. Y is the distance down from the top.

And we can draw stuff on there as well.

let b={x:300, y:200, r:10}
ctx.beginPath()
ctx.arc(b.x, b.y, b.r, 0, Math.PI*2, false)
//draw arc from 0 to Math.PI*2 (0-360 degrees), clockwize
ctx.closePath()
ctx.fill()

p1.msg = "1:0"
ctx.font = "50px fantasy"
ctx.fillText(p1.msg, p1.x, 40)

If we have a bunch of points, we can draw pretty much anything at any size

function drawPath(pts, x, y, size, fill_style, stroke_style) {
	ctx.beginPath()
	ctx.moveTo(pts[0].x*size + x, pts[0].y*size + y)
	for (let i = 1; i<pts.length; ++i) {
	  ctx.lineTo(pts[i].x*size + x, pts[i].y*size + y)
	  }
	ctx.closePath()
	ctx.fillStyle = fill_style
	ctx.fill()
	ctx.strokeStyle = stroke_style
	ctx.stroke() //outlines the shape
	}

let points = [
  {x:10,y:10},
  {x:15,y:10},
  {x:15,y:15},
  {x:20,y:20},
  {x:15,y:20},
  {x:15,y:15},
  {x:10,y:15}
  ]

drawPath(points, 10, 50, 2, "rgb(255,0,0)", "rgb(0,0,255)")

Animation

Animation is nothing more than drawing them in once place, erasing them, and drawing them in a new place for people to look at for a little while. We know how to draw things, and we can change where we draw them, how do we erase things and how do we pause?

Erasing is pretty easy: Just draw a rectangle over the entire canvas.
ctx.fillStyle = "black"
ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height)

Pausing for a bit is also easy. JavaScript has a great command:
let interval = setInterval(function_def, milliseconds)
Note that "function_def" here is not a call to a function, but a reference to a functions code directly or via it's name. E.g. if we want a function called "render" to run every 100ms then we say setInterval(render, 100) instead of saying setInterval(render(), 100) because "()" calls the function, and we need setInterval to do the call, when the time has passed. We aren't calling the function, we are telling setInterval what function to call.

So, all we need to do is create a function that will...

  1. move the positions of all the stuff
  2. render the screen by first erasing it, and then re-drawing everything

and then we call that function every 100 ms or so. That is 10 FPS (Frames per Second).

const fps = 10 // Frames Per Second (10 is enough to start)
let ms = 1000/fps // Milliseconds between frames

let p2={x:ctx.canvas.width-30, y:200, w:20, h:75, dy:5}

function render() {
	//erase everything
	ctx.fillStyle = "black"
	ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height)
	//re-draw everything
	ctx.fillStyle = "white"
	ctx.fillRect(p2.x, p2.y, p2.w, p2.h)
	}

function move() {
	p2.y += p2.dy
	if (p2.y < 0 | p2.y + p2.h > ctx.canvas.height) {
		p2.dy *= -1
		}
	}

function frame(){
	move()
	render()
	}

let interval = setInterval(frame, ms)

Objection Oriented Animation

Of course, that isn't very object oriented. p2 should know how to move itself. And we should only have to call the move() method of each object in the move program. We can move the move code into the objects move method, and we can do that for each object. And we might as well move in the draw stuff as well:

let p2 = {
	x:ctx.canvas.width-30, 
	y:200, 
	w:20, 
	h:75, 
	dy:5,
	move: function() {
		this.y += this.dy
		if (this.y < 0 | this.y + this.h > ctx.canvas.height) {
			this.dy *= -1
			}
		},
	draw: function() {
		ctx.fillStyle = "white"
		ctx.fillRect(this.x, this.y, this.w, this.h)
		}
	}

And then in the move function:

function move() {
	p2.move()
	b.move()
	//etc...
	}

And in the render function:

function erase() {
	ctx.fillStyle = "black"
	ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height)
	}

function render() {
	erase()
	//re-draw everything
	p2.move()
	b.move()
	//etc...
	}

This is nice for more complex animations with a bunch of different things moving in different ways. Each sort of thing can have it's own way of moving, it's own way of being drawn, and the code for it is just right there in the object definition. As long as we call every objects move method every frame, we are good to go. In fact... we could just make an array of all the objects, and then iterate the array.

let stuff = [p1, p2, b]
function move() {
	for (let i = 0; i < stuff.length; ++i) {
		stuff[i].move()
		}
	}

And, of course, the same sort of thing can be used in render.

Faster / Smoother / Better

We can go faster to get a smoother animation, but depending on how many things we are drawing, and how big they are, we may run out of processor cycles between frames. We can reduce the frame rate to compensate, but a more common issue is that the computer will get busy doing something totally unrelated (checking for updates, etc...) and that will cause a momentary glitch during just one or 2 frames. We may ask the computer to call update every 100 ms, but it might actually call it 110 ms later, and then 90ms after that. This can make the movement we calculate be wrong and look jerky. One way to compensate for that is to record the time when we do a frame, then subtract that from the next time, and use this actual interval to decide how much to move stuff. But that's pretty complex and may not be needed. Modern browsers implement this with the requestAnimationFrame command^

This video series does a great job of explaining it all and showing how to make some really nice effects with it. Be sure to watch all 4 episodes.

See also:


file: /Techref/language/java/script/canvas.htm, 8KB, , updated: 2020/3/2 21:03, local time: 2024/3/28 11:24,
TOP NEW HELP FIND: 
3.227.239.160:LOG IN

 ©2024 These pages are served without commercial sponsorship. (No popup ads, etc...).Bandwidth abuse increases hosting cost forcing sponsorship or shutdown. This server aggressively defends against automated copying for any reason including offline viewing, duplication, etc... Please respect this requirement and DO NOT RIP THIS SITE. Questions?
Please DO link to this page! Digg it! / MAKE!

<A HREF="http://piclist.com/techref/language/java/script/canvas.htm"> JavaScript Canvas Tutorial</A>

After you find an appropriate page, you are invited to your to this massmind site! (posts will be visible only to you before review) Just type a nice message (short messages are blocked as spam) in the box and press the Post button. (HTML welcomed, but not the <A tag: Instead, use the link box to link to another page. A tutorial is available Members can login to post directly, become page editors, and be credited for their posts.


Link? Put it here: 
if you want a response, please enter your email address: 
Attn spammers: All posts are reviewed before being made visible to anyone other than the poster.
Did you find what you needed?

  PICList 2024 contributors:
o List host: MIT, Site host massmind.org, Top posters @none found
- Page Editors: James Newton, David Cary, and YOU!
* Roman Black of Black Robotics donates from sales of Linistep stepper controller kits.
* Ashley Roll of Digital Nemesis donates from sales of RCL-1 RS232 to TTL converters.
* Monthly Subscribers: Gregg Rew. on-going support is MOST appreciated!
* Contributors: Richard Seriani, Sr.
 

Welcome to piclist.com!

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  .