My recent explorations in canvas animation, starfields and randomness came together in an experiment recreating television static… and as it turns out, they’re all related to each other. Like the starfield article, this will be an exploration of code with an improving, ongoing example.
Static static
The first task is to create static, as shown in the example above. For an image, that’s fairly straightforward: take a <canvas>
element of known width
and height
and fill it with small drawn rectangles in various shades of grey.
Our canvas
element:
<canvas id="static" width="750" height="500"></canvas>
The initial variables in the script, added to the bottom of the page:
var canvas = document.getElementById("static"),
context = canvas.getContext("2d"),
tvHeight = canvas.offsetHeight,
tvWidth = canvas.offsetWidth,
smallestPixel = 4;
Using this information, we can create the function to draw the static:
function drawStatic() {
for (var v=0; v < tvHeight; v += smallestPixel){
for (var h=0; h < tvWidth; h += smallestPixel){
lum = Math.floor( Math.random() * 50 );
context.fillStyle = "hsl(0, 0%," + lum + "%)";
context.fillRect(h,v, smallestPixel, smallestPixel);
}
}
}
The function contains two nested for
loops. The first works vertically, increasing by the distance determined by smallestPixel
. Within the loop is another working horizontally, filling each row with a square filled with an HSL grey. When a row completes, the next horizontal row starts.
Making The Canvas Fill The Screen
To make the <canvas>
fill the page we turn to an old and trusted technique in CSS:
body, html {
margin: 0; height:100%;
}
#static {
position:absolute;
width:100%;
height:100%;
}
Optimising The Draw Time
If the <canvas>
is 800 pixels across and 400 high, and each “pixel” is 4 × 4, that makes for 200 “pixels” per row, for a total of 20,000 drawn squares. JavaScript can achieve this, but it may struggle to draw updates to the rectangles 30 times a second; if we want to animate the effect, we may need to consider reducing the number of elements.
To do that, we could reduce the height
and width
of the <canvas>
element and / or increase the “pixel” size. Alternatively, we could draw larger pixel shapes, and fewer of them. We could create the default “color” of the TV screen by flood-filling the background with CSS:
#static { background: #333; }
Then, randomly filling the space with rectangles. The rectangles will be a random height and width, between certain limits. That height and width will also determine the position of the rectangle: it will be positioned from 0 to the width or height of the canvas, less the dimension of the pixel. We’ll create 1200 rectangles using a new function. First, I’ll use a function from my random recipes collection:
function getRandomInRange(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
The rest of the code starts the same as the previous example:
var canvas = document.getElementById("static"),
context = canvas.getContext("2d"),
tvHeight = canvas.offsetHeight,
tvWidth = canvas.offsetWidth,
staticWidth = 0,
staticHeight = 0,
smallestWidth = 8,
largestWidth = 32,
smallestHeight = 4,
largestHeight = 8,
maxPixels = 1200,
horizontalPosition = 0,
verticalPosition = 0;
The drawStatic
function changes too:
function drawStatic() {
for (var i=0; i < maxPixels; i++){
lum = getRandomInRange(40,80);
context.fillStyle = "hsla(0, 0%," + lum + "%, 0.8)";
staticWidth = getRandomInRange(smallestWidth, largestWidth);
staticHeight = getRandomInRange(smallestHeight, largestHeight);
horizontalPosition = getRandomInRange(0, tvWidth - staticWidth);
verticalPosition = getRandomInRange(0, tvHeight - staticHeight);
context.fillRect(horizontalPosition,verticalPosition, staticWidth, staticHeight);
}
}
The result is “rougher”, and perhaps more suited for animation:
I’ll be looking at this animation in the next article.
Enjoy this piece? I invite you to follow me at twitter.com/dudleystorey to learn more.
Check out the CodePen demo for this article at https://codepen.io/dudleystorey/pen/xOgPQE