Creating an Animated Hero Image with Canvas

animated-canvas-header

By Dave DeHaan

When we were looking at laying out spark.lamplighter.io, we decided we wanted to add the feel of our graphs to the top of the page. The suggestion came up that it would be cool if our graph actually “cut off” our hero image, so that any part of our hero image under the lines would be the page background color. You can see the result on our company 404 page. Let’s look at how it was created.

Setting the Context

By changing the hero image’s div to a canvas, while keeping the background image, we were able to draw on top of the image without changing the formatting of the page. From there, we started by randomly generating the numbers for each of the graph lines, so we’d be able to draw both the lines, and the area below them.

First, we got our canvas, made sure the dimensions would be what we expected, and created a context.

var pageWidth = document.width ? document.width : document.documentElement.clientWidth;
var canvas = document.getElementById('header');
canvas.width 	= pageWidth;
canvas.height 	= 500;
var context = canvas.getContext('2d');

From there, we created a colors object, so we could loop through it for how many lines we wanted to create on the graph, and then created an array of points between 400 and 500 for each of the colors.

var points = [];
var colors = {
	'green': '#81bf06',
	'yellow': '#ffc50c',
	'red': '#ff0808',
}
var pointCount = 20;
for (var i = 0; i < pointCount; i++) {
	point[i] = [];
	// Get a number between 400 & 500
	for (var color in colors) {
		point[i][color] = Math.floor(Math.random() * 100) + 400;
	}
}

Filling the Gaps

At this point, we wanted to be able to fill in the area below each graph, so we drew each of the lines across the canvas, then created a bounded area by drawing lines from the last line point to the bottom right, from the bottom right to the bottom left, and from the bottom left to the first line point. After that, we filled in the area with the page background color.

var fillColor = '#F9F9F9';
// Draw the area under the graph
for (var color in colors) {
	for (var i = 1; i < pointCount; i++) {
		context.lineTo(pageWidth * i/pointCount, point[i][color]);
	}
	context.lineTo(pageWidth, 450);
	context.lineTo(pageWidth, 500);
	context.lineTo(0, 500);
	context.lineTo(0, 450);
}
// Set fill color
context.fillStyle = fillColor;
context.fill();

Since we have the space under each of the lines filled now, we just need to draw the actual graph lines. We decided it would look best if each line started and ended at 450.

var lineWidth = 4;
// Set our line width
context.lineWidth = lineWidth;
// Draw our lines
for (var color in colors) {
	context.beginPath();
	// Move to the first point
	context.moveTo(0,450);
	// Loop through all the points
	for (var i = 1; i < pointCount; i++) {
		context.lineTo(pageWidth * i/pointCount, point[i][color]);
	}
	// Line to the last point
	context.lineTo(pageWidth, 450);
	// Set our color
	context.strokeStyle = colors[color];
	// Draw the line.
	context.stroke();
}

Creating Multiple Graphs

When this was finished and working, we moved all the configuration variables at the top, and wrapped the entire thing in a function, so it could be called multiple times to create different graphs.

Our finished code:

/**
 *	Graph Canvas --
 *  Adds a graph to the bottom of a hero image
 *  By Masuga Design
 *  http://masugadesign.com
 *  Copyright (c) 2013 Masuga Design
 **/

/** START CONFIG VARIABLES **/

	// Set our line colors
	var colors = {
		'green': '#81bf06',
		'yellow': '#ffc50c',
		'red': '#ff0808',
	};

	// Set the fill color for under the graph
	var fillColor = '#F9F9F9';

	// Set our line width
	var lineWidth = 4;

	// How many points in the array?
	var pointCount 	= 20;

/** END CONFIG VARIABLES **/

// Point Array
var point 		= [];

function generateGraph() {
	var pageWidth = document.width ? document.width : document.documentElement.clientWidth;

	// Set up our canvas & context
	canvas 			= document.getElementById('header');
	canvas.width 	= pageWidth;
	canvas.height 	= 500;
	context 		= canvas.getContext('2d');

	// Create our points array with our colors.
	for (var i = 0; i < pointCount; i++) {
		point[i] = [];
		// Get a number between 400 & 500
		for (var color in colors) {
			point[i][color] = Math.floor(Math.random() * 100) + 400;
		}
	}

	// Draw the area under the graph
	for (var color in colors) {
		for (var i = 1; i < pointCount; i++) {
			context.lineTo(pageWidth * i/pointCount, point[i][color]);
		}
		context.lineTo(pageWidth, 450);
		context.lineTo(pageWidth, 500);
		context.lineTo(0, 500);
		context.lineTo(0, 450);
	}

	// Set fill color
	context.fillStyle = fillColor;
	context.fill();

	// Set our line width
	context.lineWidth = lineWidth;

	// Draw our lines
	for (var color in colors) {
		context.beginPath();
		// Move to the first point
		context.moveTo(0,450);
		// Loop through all the points
		for (var i = 1; i < pointCount; i++) {
			context.lineTo(pageWidth * i/pointCount, point[i][color]);
		}
		// Line to the last point
		context.lineTo(pageWidth, 450);
		// Set our color
		context.strokeStyle = colors[color];
		// Draw the line.
		context.stroke();
	}
}

Since this was all in a function, we were able to call the function on an interval using setInterval, creating the effect found on our 404 page, where our graph is being regenerated every second.

setInterval(function() {
		generateGraph();
	}, 1000);

This article was originally published at http://spark.lamplighter.io/post/2013/10/10/creating-a-dynamic-hero-image-using-canvas

Modern Web Newsletter

Subscribe to receive the Modern Web tutorials, sent out every second Wednesday.

  • SB

    110Mb and 15% CPU, good starting for 404 page.

Top