I'm braindead. So I decided no to go into philosophical discussion - rather checked the Canvas API the first time. Yeah, I know it's already too old. Anyways. Canvas is so simple anybody can learn the basics in 5 minutes. To make a little sense I decided to make a silly screensaver like animation - a curve that bouncing on the screen and leaves a frame.
The idea is very simple. A bezier curve has a start context point, 2 control points an an end point.
Fig.: Bezier curve
First you need a nice HTML5 template like this:
<!doctype html> <html> <head> <script type="text/javascript"> </script> </head> <body onload="onBodyLoad();"> </body> </html>
For the canvas you need the dom element in the body:
<canvas id="screen" width="640" height="480"></canvas>
The canvas has a drawing context, so let's create a variable for it:
var ctx;
This context can accept our commands later. We need to access our canvas' boundaries somehow:
var boundaries = { w: 640, h: 480 };
We set the timer interval to 0.01 second:
var interval = 10;
Set the average speed of a point:
var speed = 10;
Then we generate 4 random points with random vectors:
var number = 4; var items = []; for (var i = 0; i < number; i++) { items[i] = { point: { x: Math.random() * boundaries.w, y: Math.random() * boundaries.h }, speed: getRandomSpeedVectors(speed) } }
To make all speed the same but with a different angle we use some math to generate the X and Y speed values:
function getRandomSpeedVectors(speed) { var speed_x = Math.random() * speed; return { sx: speed_x, sy: Math.sqrt(Math.pow(speed, 2) - Math.pow(speed_x, 2)) }; }
To make point updates easy we add a new method to the JavaScript Object prototype:
Object.prototype.applyWorld = function(speed_vector, boundaries) { if (this.x + speed_vector.sx >= boundaries.w || this.x + speed_vector.sx <= 0) { speed_vector.sx *= -1; } if (this.y + speed_vector.sy >= boundaries.h || this.y + speed_vector.sy <= 0) { speed_vector.sy *= -1; } this.x += speed_vector.sx; this.y += speed_vector.sy; };
This function will be available on the object method level and can handle 1 state change on a point. That's enough to make the point moving.
Now we need something that actually handles 1 step for all the points and draw the curve on the canvas:
function loop() { ctx.clearRect(100, 100, boundaries.w - 200, boundaries.h - 200); ctx.beginPath(); ctx.moveTo(items[0].point.x, items[0].point.y); ctx.bezierCurveTo( items[1].point.x, items[1].point.y, items[2].point.x, items[2].point.y, items[3].point.x, items[3].point.y ); ctx.stroke(); for (var idx in items) { var item = items[idx]; if (!item.point) { continue; } item.point.applyWorld(item.speed, boundaries); } setTimeout(loop, interval); }
It also calls itself so that makes it an animation. And finally we have to initialize the canvas and start the animation, so let's hook into the body onload event:
function onBodyLoad() { var canvas = document.getElementById('screen'); if (!canvas.getContext) { return; } ctx = canvas.getContext('2d'); ctx.lineWidth = 6; ctx.strokeStyle = 'rgba(33, 66, 99, 0.5)'; loop(); }
That's it. You can find the demo here: https://dl.dropbox.com/u/2629592/canvas_screensaver.html. For the source code check the Github repo: https://github.com/itarato/CanvasScreensaver/blob/master/index.html.
---
If you have a more efficient way to do it (I bet you have) please let me know.
Peter
---
If you have a more efficient way to do it (I bet you have) please let me know.
Peter
No comments:
Post a Comment
Note: only a member of this blog may post a comment.