Skip to content

Instantly share code, notes, and snippets.

@greenido
Created May 13, 2012 18:27
Show Gist options
  • Select an option

  • Save greenido/2689628 to your computer and use it in GitHub Desktop.

Select an option

Save greenido/2689628 to your computer and use it in GitHub Desktop.
Canvas fun
<html>
<head>
<style>
body {
margin: 0;
padding: 0;
}
canvas {
width: 100%;
height: 100%;
image-rendering: -moz-crisp-edges;
image-rendering: -webkit-optimize-contrast;
}
.newCan {
width: 100%;
height: 100%;
image-rendering: -moz-crisp-edges;
image-rendering: -webkit-optimize-contrast;
}
</style>
<script>
Object.size = function(obj) {
var size = 0, key;
for (key in obj) {
if (obj.hasOwnProperty(key)) size++;
}
return size;
};
var requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame;
window.onload = function () {
var canvas = document.getElementById('main');
var canvasWidth = canvas.width;
var canvasHeight = canvas.height;
var ctx = canvas.getContext('2d');
var imageData = ctx.getImageData(0, 0, canvasWidth, canvasHeight);
var data = imageData.data;
var buf = new ArrayBuffer(imageData.data.length);
var buf8 = new Uint8ClampedArray(buf);
var data32 = new Uint32Array(buf);
var pixelSet = new Uint8ClampedArray(new ArrayBuffer(imageData.data.length));
var pixelAreaCheck = new Uint8ClampedArray(new ArrayBuffer(imageData.data.length));
var PIXELS_PER_ITERATION = 50;
var NUM_COLORS = 16;
var totalPixelsSet = 0;
var palette = {};
var currentIndex = 0;
var MAX_BALAGAN = 60*60*24*10000;
function choosePalette() {
for (var i = 0; i < NUM_COLORS; i++) {
palette[i] = randomColor();
}
}
/**
* Place random pixels on the canvas
*/
function step1() {
for (var i = currentIndex; i < currentIndex + PIXELS_PER_ITERATION; i++) {
var pixel = randomPixel();
var color = palette[parseInt(Math.random() * 16)];
setPixelIndex(pixel, color);
}
currentIndex += PIXELS_PER_ITERATION;
if (totalPixelsSet < (canvas.width * canvas.height)) {
requestAnimationFrame(step1);
} else {
pixelSet = new Uint8ClampedArray(new ArrayBuffer(imageData.data.length));
totalPixelsSet = 0;
requestAnimationFrame(step2);
}
}
// file://localhost/Users/ron/Dropbox/Ron/src/shirley/becoming.html
function step2() {
var pixel;
for (var i = currentIndex; i < currentIndex + PIXELS_PER_ITERATION; i++) {
pixel = randomPixel();
if (pixelIsFree(pixel)) {
setPixelIndex(pixel, randomNeighborColor(pixel));
}
// check if it's not free
if (!pixelIsFree(pixel) && (pixelSet[pixel] == 0)) {
pixelSet[pixel] = 1;
totalPixelsSet++;
}
}
if (totalPixelsSet < (canvas.width * canvas.height)) {
requestAnimationFrame(step2);
} else {
pixelSet = new Uint8ClampedArray(new ArrayBuffer(imageData.data.length));
totalPixelsSet = 0;
requestAnimationFrame(step3);
}
}
function step3() {
if (getNumColors() <= 2) {
alert("done");
return;
}
var pixel = randomPixel();
var oldColor = getColor(pixel);
// var newColor = palette[parseInt(Math.random() * 16)];
pixelAreaCheck = new Uint8ClampedArray(new ArrayBuffer(imageData.data.length));
var adjacentColors = getAdjacentBlockColors(pixel, oldColor);
var newColor = pickRandomProperty(adjacentColors);
if (newColor == null) {
alert("Error, no adjacent color");
}
newColor = newColor.split(",");
for (i = 0; i < newColor.length; i++) {
newColor[i] = parseInt(newColor[i]);
}
paintPixels(pixel, oldColor, newColor);
requestAnimationFrame(step3);
}
function pickRandomProperty(obj) {
var result = null;
var count = 0;
for (var prop in obj)
if (Math.random() < 1/++count)
result = prop;
return result;
}
function getAdjacentBlockColors(pixel, oldColor) {
var result = {};
if (pixelAreaCheck[pixel] == 1) {
return result;
}
if (pixel >= canvas.width * canvas.height || pixel < 0) {
return result;
}
pixelAreaCheck[pixel] = 1;
var pixelColor = getColor(pixel)
// Check if its a new color
if (!sameColorArray(pixelColor, oldColor)) {
result[pixelColor] = 1;
return result;
}
var resultUp = getAdjacentBlockColors(pixel - canvas.width, oldColor);
var resultDown = getAdjacentBlockColors(pixel + canvas.width, oldColor);
var resultLeft = getAdjacentBlockColors(pixel - 1, oldColor);
var resultRight = getAdjacentBlockColors(pixel + 1, oldColor);
merge_options(result, resultUp);
merge_options(result, resultDown);
merge_options(result, resultLeft);
merge_options(result, resultRight);
return result;
}
function merge_options(obj1,obj2){
for (var attrname in obj2) { obj1[attrname] = obj2[attrname]; }
return obj1;
}
function paintPixels(pixel, oldColor, newColor) {
var pixelsToPaint = [];
if (sameColorArray(oldColor, newColor)) {
return;
}
pixelsToPaint.push(pixel);
while (pixelsToPaint.length > 0) {
var currentPixel = pixelsToPaint.pop();
if (!(sameColorArray(getColor(currentPixel), oldColor))) continue;
if (currentPixel < 0 || currentPixel > canvas.width * canvas.height) {
continue;
}
console.log(currentPixel);
setPixelIndex(currentPixel, newColor);
if (sameColorArray(getColor(currentPixel-1), oldColor)) pixelsToPaint.push(currentPixel-1);
if (sameColorArray(getColor(currentPixel+1), oldColor)) pixelsToPaint.push(currentPixel+1);
if (sameColorArray(getColor(currentPixel-canvas.width), oldColor)) pixelsToPaint.push(currentPixel-canvas.width);
if (sameColorArray(getColor(currentPixel+canvas.width), oldColor)) pixelsToPaint.push(currentPixel+canvas.width);
}
}
function sameColorArray(color1, color2) {
var c20 = ~~ (color2[0]+0.5);
var c21 = ~~ (color2[1]+0.5);
var c22 = ~~ (color2[2]+0.5);
return ( color1[0] == c20 && //Math.round(color2[0])) &&
color1[1] == c21 && // Math.round(color2[1])) &&
color1[2] == c22 );
}
function paintPixelsRecursive(pixel, oldColor, newColor) {
setPixelIndex(pixel, newColor);
if (sameColor(getColor(pixel-1), oldColor)) paintPixels(pixel-1, oldColor, newColor);
if (sameColor(getColor(pixel+1), oldColor)) paintPixels(pixel+1, oldColor, newColor);
if (sameColor(getColor(pixel-canvas.width), oldColor)) paintPixels(pixel-canvas.width, oldColor, newColor);
if (sameColor(getColor(pixel+canvas.width), oldColor)) paintPixels(pixel+canvas.width, oldColor, newColor);
}
function getNumColors() {
var colors = {};
for (var i = 0; i < canvas.width * canvas.height; i++) {
var color = getColor(i);
colors[color[0] + color[1] << 8 + color[2] << 16] = true;
}
var size = 0;
for (var key in colors) {
if (colors.hasOwnProperty(key)) size++;
}
return size;
}
function pixelIsFree(pixel) {
var colorAtPixel = getColor(pixel);
var pixelsSameCount = 0;
if (sameColor(colorAtPixel, pixel-1)) pixelsSameCount++;
if (sameColor(colorAtPixel, pixel+1)) pixelsSameCount++;
if (sameColor(colorAtPixel, pixel-canvas.width)) pixelsSameCount++;
if (sameColor(colorAtPixel, pixel+canvas.width)) pixelsSameCount++;
pixelFree = (pixelsSameCount < 1);
return pixelFree;
}
function getPixelArrayToMatch() {
var pixelArray = [];
for (var i = currentIndex; i < currentIndex + PIXELS_PER_ITERATION; i++) {
pixel = randomPixel();
pixelArray.push(pixel);
}
return pixelArray;
}
function randomNeighborColor(pixel) {
var options = [];
if (pixel > 0) {
options.push(getColor(pixel-1));
}
if (pixel < canvas.width * canvas.height) {
options.push(getColor(pixel+1));
}
if (pixel > canvas.width) {
options.push(getColor(pixel-canvas.width));
}
if (pixel < canvas.width * (canvas.height - 1)) {
options.push(getColor(pixel+canvas.width));
}
return options[parseInt(Math.random() * options.length)];
}
function getColor(pixel) {
var index = pixel * 4;
if (pixel < 0 || pixel > canvas.width * canvas.height) {
return [0,0,0];
}
return [data[index], data[index+1], data[index+2]];
}
function sameColor(color, pixel) {
var index = pixel * 4;
return (data[index] == color[0]) && (data[index+1] == color[1]) && (data[index+2] == color[2]);
}
function setPixelIndex(pixel, color) {
pixelSet[pixel] = 1;
totalPixelsSet++;
var index = pixel * 4;
var c0 = ~~ (color[0]+0.5);
var c1 = ~~ (color[1]+0.5);
var c2 = ~~ (color[2]+0.5);
data[index] = c0; //(0.5 + (color[0])) | 0; // red
data[++index] = c1; //(0.5 + (color[1])) | 0; // green
data[++index] = c2; //(0.5 + (color[2])) | 0; // blue
data[++index] = 255; // alpha
ctx.putImageData(imageData, 0, 0);
ctx.translate(1.5, 1.5);
}
function setPixel(x, y, color) {
var index = (y * canvasWidth + x) * 4;
var c0 = ~~ (color[0]+0.5);
var c1 = ~~ (color[1]+0.5);
var c2 = ~~ (color[2]+0.5);
data[index] = c0; // red
data[++index] = c1; // green
data[++index] = c2; // blue
data[++index] = 255; // alpha
ctx.putImageData(imageData, 0, 0);
ctx.translate(1.5, 1.5);
}
function resetAlpha() {
for (var i = 0; i < canvas.width * canvas.height; imageData) {
data[i * 4 + 3] = 0;
}
}
function randomPixel(allowOverride) {
var index;
var attempts = 10;
if (allowOverride == true) {
return parseInt(Math.random() * canvas.width * canvas.height);
}
do {
if (attempts > 0) {
index = parseInt(Math.random() * canvas.width * canvas.height);
attempts--;
} else {
index++;
}
if (index >= canvas.width * canvas.height) {
index = 0;
}
} while (pixelSet[index] != 0);
return index;
}
function randomColor() {
var h = Math.random(); // all colors
var s = Math.random() * 0.5; // add 0 to 50% gray
var l = Math.random() * 0.4 + 0.4; // add 50% to 100% light
return hslToRgb(h, s, l);
}
function hslToRgb(h, s, l){
var r, g, b;
if(s == 0){
r = g = b = l; // achromatic
}else{
function hue2rgb(p, q, t){
if(t < 0) t += 1;
if(t > 1) t -= 1;
if(t < 1/6) return p + (q - p) * 6 * t;
if(t < 1/2) return q;
if(t < 2/3) return p + (q - p) * (2/3 - t) * 6;
return p;
}
var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
var p = 2 * l - q;
r = hue2rgb(p, q, h + 1/3);
g = hue2rgb(p, q, h);
b = hue2rgb(p, q, h - 1/3);
}
return [r * 255, g * 255, b * 255];
}
choosePalette();
step1();
// 32 bit works only on chrome 20
/*
for (var y = 0; y < canvasHeight; ++y) {
for (var x = 0; x < canvasWidth; ++x) {
var value = x * y & 0xff;
value = 128;
data32[y * canvasWidth + x] =
(255 << 24) | // alpha
(value << 16) | // blue
(value << 8) | // green
value; // red
}
}
imageData.data.set(buf8);
*/
ctx.putImageData(imageData, 0, 0);
}
</script>
</head>
<body>
<canvas id="main" class="newCan" width="300px" height="400px"></canvas>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment