This is a continuation of my experiments into visualising the tube network. My previous experiment used Google Maps and its shape drawing tools to visualise proximity. This version tries a different approach using the Canvas object and simple image filters.
There are three parts to this experiment: the map, which is just a static image; the gradient image, which I’ll call the heat map; and a threshold filter written in javascript. The threshold filter is applied to the heat map and turns all pixels above a certain colour blue, and all below transparent, which creates the effect you see above.
This is a crop of the heat map, created in Photoshop using simple gradient fills and layer blends. It’s the same dimensions as the underlying map and each spot is centered on a tube station. The colours in the gradient map neatly to the RGB components of pixel colour, meaning the gradient moves smoothly from #FFFFFF to #000000. The values of each RGB channel are added (not multiplied) together from left-to-right to give a total of 765 levels. When applying the threshold filter it converts a value from 0-765 into a colour hex value and uses that as the threshold for applying the effect.
In order to composite the effect on top of the map I’ve used a Canvas object, which supports transparency. Canvas has a few methods to directly affect its pixel data, the two I’ve used it getImageData and putImageData, which return and set the image as an array of pixel data. This allows you to create something like a rudimentary pixel shader. For a threshold filter you simply need to clamp pixels either side of a given value to a specific colour. Here’s a stripped down version of how it works:
// Load an image and extract the pixel data
var imageData;
var img = new Image();
img.src = "gradient.png";
img.onload = function() {
// Get image data from the canvas context
imageData = context.getImageData(0, 0, canvas.width, canvas.height);
runFilter();
};
function runFilter() {
// Each pixel takes up 4 entries in the array using the RGBA format
var originPixels = imageData.data;
var filterPixels = imageData.data;
for (var i = 0; i < originPixels.length; i += 4) {
r = originPixels[i];
g = originPixels[i+1];
b = originPixels[i+2];
filterPixels[i] = filterPixels[i+1] = 0; // Red/Green channels
filterPixels[i+2] = 255; // Blue
filterPixels[i+3] = ((r + g + b) >= amount) ? 96 : 0; // Alpha
}
// Dump filtered pixel data to the canvas
canvasContext.putImageData(filterData, 0, 0);
}
See the source of the actual experiment page for the rest of the code. With further work I hope to be able to generate the heat map from the geographic data I used in the previous experiment, and if possible integrate the canvas threshold filter into Google Map overlays.
