Tags:
I spent a little bit of time last night playing around with the new HTML5 canvas and seeing if I could create a realistic glowing line that moved around on the screen. My efforts can be found at the end of this article, but here is a screenshot of it:
The code itself is fairly straight-forward. A few random parameters are first set up to determine the colour of the line, as well as it's start and end points, and the control points (it has two because it's a Bezier), then a window interval just calls a function which draws a series of lines in decreasing thicknesses in the highlight colour, followed by one thin white line on top.
<head>
<script type="text/javascript">
window.onload = function()
{
canv = document.getElementById("glow");
if (!canv || !canv.getContext)
return;
context = canv.getContext("2d");
// the glow colour
highlight = new Array(Math.round(Math.random()*255), Math.round(Math.random()*255), Math.round(Math.random()*255));
step = 7; // amount each movement of coord is in canvas pixels
// start and end coordinates for the line
x1 = new Array(random_coord('x'), -1, 'x');
y1 = new Array(random_coord('y'), 1, 'y');
x2 = new Array(random_coord('x'), -1.5, 'x');
y2 = new Array(random_coord('y'), -1.5, 'y');
// coordinates for the control points of the bezier curve
cx1 = new Array(random_coord('x'), 1, 'x');
cy1 = new Array(random_coord('y'), -1, 'y');
cx2 = new Array(random_coord('x'), -1, 'x');
cy2 = new Array(random_coord('y'), 1, 'y');
timer = window.setInterval(draw_line, 30);
};
function draw_line()
{
// paint over the existing canvas
context.fillStyle = "#000";
context.fillRect(0, 0, canv.width, canv.height);
// get the new coords based on each ones current trajectory
get_bounce_coord(x1);
get_bounce_coord(y1);
get_bounce_coord(x2);
get_bounce_coord(y2);
get_bounce_coord(cx1);
get_bounce_coord(cy1);
get_bounce_coord(cx2);
get_bounce_coord(cy2);
for(i=5; i>=0; i--)
{
context.beginPath();
// draw each line, the last line in each is always white
context.lineWidth = (i+1)*4-2;
if(i==0)
context.strokeStyle = '#fff';
else
{
context.strokeStyle = 'rgba('+highlight[0]+','+highlight[1]+','+highlight[2]+',0.2)';
}
context.moveTo(x1[0], y1[0]);
context.bezierCurveTo(cx1[0],cy1[0],cx2[0],cy2[0],x2[0],y2[0]);
context.stroke();
context.closePath();
}
}
/**
* update the position and direction of movement for an end point on the line or one of the control points
*/
function get_bounce_coord(coord_array)
{
coord_array[0] += step * coord_array[1];
if( (coord_array[0] > (canv.height - 2*step) && coord_array[2] == 'y')
|| (coord_array[0] > (canv.width - 2*step) && coord_array[2] == 'x')
|| coord_array[0] < 2*step)
{
coord_array[1] *= -1;
}
}
/**
* get a random x or y coordinate
*/
function random_coord(type)
{
dimension = (type == 'x')?canv.width:canv.height;
return Math.random() * (dimension - 2*step) + step;
}
</script>
</head>
<body>
<canvas id="glow" width="1200" height="700">
Your browser does not support HTML5 Canvas.
</canvas>
</body>
Lines 5-10 get the 2D context from the <canvas>
object (at the very bottom of the script in the HTML) in order to work with it. The reason for this is that there are plans eventually to allow a 3D context in canvas, but currently it's not supported in the offical canvas spec. Line 13 sets the glow colour using 3 random numbers from 0 to 255, and line 14 sets the number of canvas pixels each movement translates to.
Then follows a list of setting variables used for the coordinates. As this is a bezier curve, there are 2 control points as well, making 4 coordinate pairs in total. In each array element is the coordinate value, the step multiplier (a value multipled by the step to calculate the increment/decrement to a coordinate) and the type of coordinate out of x or y (this is useful to know when the canvas isn't square to make sure coordinates don't stray beyond the edges as they get moved. The coordinate value itself is gotten from the random_coord()
function, which just returns a value for either the x or y that is within the dimensions of the canvas. Lastly, line 28 sets up a window interval which is used to update the line 33.3̅ times a second.
The key to this whole script is the draw_line()
function, which cleans the canvas area by drawing a black rectangle over the whole canvas before drawing the lines that make up the glow. Lines 38 through 46 get the new coordinates from get_bounce_coord()
function which I'll explain in a moment. A loop is set up in line 48 that draws 5 lines in decreasing thicknesses, all the same colour with an opacity of 0.2. This gives the lines that glow effect as the cumulative semi-transparent lines drawn on-top of each other appear to make it look like its brighter towards the middle of the line. To top it off, the very innermost line is drawn as solid white.
The next function is the get_bounce_coord()
one, which updates each coordinate and the direction it needs to travel. Rather than thinking about them in pairs at this point, remember that each coordinate is actually made up of two numbers. This function only updates one of those at a time, so it requires 2 calls to update a whole coordinate. First, the coordinate array which was passed as an argument to it (set up as an array in lines 17-26) is updated by incrementing it by the step
multiplied by the second array argument, the step modifier. As you will see in the example code, the step modifier is always something like 1, -1 or -1.5. While this looks like it should always increase the coordinates' value, it doesn't, because -1×7 is -7, so it actually ends up as a decrement. Line 74-76 is a simple if statement that checks to see if the new coord value is less than 2×step
or more than one of the edges minus 2×step
, depending on what coordinate value is being checked. If this seems complicated just think about it as making sure that a coordinate value stays inside the dimensions of the canvas.
The last function random_coord()
just returns a random coordinate within the dimensions of the canvas. This is not necessary, I just wanted a nice easy way to get random coordinates each time I refreshed the page.
The final result of all of that code is here:
Comments