Arranging Items in a Grid

Arranging items in a line

function setup() {
	createCanvas(windowWidth, windowHeight);
	background(100);
}

function draw() {
	for (let x = 10; x <= width; x += 50) {
		circle(x, 100, 40);
	}
}
image

Counting by shape

Use i to count the number of shapes. Draw 20.

This code has the same behavior as the sketch above, but it counts shapes instead of repeating them until they reach the window width.

function draw() {
	let x = 10;
	for (let i = 0; i < 20; i++) {
		circle(x, 100, 40);
		x += 50;
	}
}
image

We can also increase x as a ratio (a geometric progression), instead of by a constant (an arithmetic progression).

function draw() {
	let x = 10;
	for (let i = 0; i < 20; i++) {
		circle(x, 100, 40);
		x *= 1.2;
	}
}
image

Back to the arithmetic progression. This version starts x at 10, and increases it for each new shape.

function draw() {
	let x = 10;
	for (let i = 0; i < 20; i++) {
		circle(x, 100, 40);
		x += 50;
	}
}
image

An alternative is to compute x as a function of i. The shape position is derived from the shape number.

function draw() {
	for (let i = 0; i < 20; i++) {
		let x = 10 + 50 * i;
		circle(x, 100, 40);
	}
}

Bending the line

Derive y from i as well.

function draw() {
	for (let i = 0; i < 20; i++) {
		let x = 10 + 50 * i;
		let y = 100 + 10 * i;
		circle(x, y, 40);
	}
}
image

Replace 10 * i by 20 * i or 5 * i to increase or decrease the angle of the line (make it more or less steep).

image

image

Waves

function setup() {
function draw() {
	for (let i = 0; i < 20; i++) {
		let x = 10 + 50 * i;
		let y = 100 + 20 * sin(i);
		circle(x, y, 40);
	}
}
image
function draw() {
	for (let i = 0; i < 20; i++) {
		let x = 10 + 50 * i;
		let y = map(sin(i), -1, 1, 80, 120);
		circle(x, y, 40);
	}
}
image
function draw() {
	for (let i = 0; i < 20; i++) {
		let x = 10 + 50 * i;
		let y = map(sin(i), -1, 1, 80, 120);
		let size = 20 + 20 * cos(i);
		circle(x, y, size);
	}
}
image
function draw() {
	background(100);

	for (let i = 0; i < 20; i++) {
		let x = 10 + 50 * i;
		let y = map(sin(i) + sin(frameCount), -1, 1, 80, 120);
		let size = 20 + 20 * cos(i / 2);
		circle(x, y, 20);
	}
}
image

function draw() {
	background(100);

	for (let i = 0; i < 20; i++) {
		let x = 10 + 50 * i;
		let y = map(2 * sin(i) + sin(i / 2) + sin(i / 4), -1, 1, 80, 120);
		let size = 20 + 20 * cos(i / 2);
		circle(x, y, 20);
	}
}
image

Deriving the row

function draw() {
	background(100);

	for (let i = 0; i < 20; i++) {
		let x = 10 + 50 * i;
		let y = 50 * i;
		circle(x, y, 20);
	}
	
}
image
function setup() {
	createCanvas(windowWidth, windowHeight);
}

function draw() {
	background(100);

	for (let i = 0; i < 20; i++) {
		let x = 10 + 50 * i;
		let y = 50 * (i % 5);
		circle(x, y, 20);
	}
}
image

Deriving the column

function setup() {
	createCanvas(windowWidth, windowHeight);
}

function draw() {
	background(100);

	for (let i = 0; i < 20; i++) {
		let x = 30 + 50 * floor(i / 5);
		let y = 40 + 50 * (i % 5);
		circle(x, y, 20);
	}
}
image
function draw() {
	background(100);

	for (let i = 0; i < 30; i++) {
		let row = i % 5;
		let column = floor(i / 5);
		
		let x = 30 + 50 * column;
		let y = 40 + 50 * row;
		circle(x, y, 20);
	}
}
image
function draw() {
	background(100);

	for (let i = 0; i < 30; i++) {
		let row = i % 5;
		let column = floor(i / 5);
		
		let x = 30 + 50 * column;
		let y = 40 + 50 * row;
		
		
		let size = map(row - column, 0, 10, 10, 50);
		circle(x, y, size);
	}
}
image

Using a function to draw each cell

function draw() {
	background(100);

	for (let i = 0; i < 30; i++) {
		let row = i % 5;
		let column = floor(i / 5);
		
		let x = 30 + 50 * column;
		let y = 40 + 50 * row;
		
		myShape(x, y, row, column, i);
	}
}

function myShape(x, y, row, column, i) {
	let size = map(row - column, 0, 10, 10, 50);
	circle(x, y, size);
}
image
function draw() {
	background(100);

	for (let i = 0; i < 30; i++) {
		let row = i % 5;
		let column = floor(i / 5);
		
		let x = 30 + 50 * column;
		let y = 40 + 50 * row;
		
		myShape(x, y, row, column, i);
	}
}

function myShape(x, y, row, column, i) {
	let size = map(row - column, 0, 10, 30, 40);
	circle(x, y, size / 2);
	square(x, y, size);
	circle(x + size, y, size / 2);
	circle(x, y + size, size / 2);
	circle(x + size, y + size, size / 2);
}
image

Why push and pop

function draw() {
	background(100);

	for (let i = 0; i < 30; i++) {
		let row = i % 5;
		let column = floor(i / 5);
		
		let x = 30 + 50 * column;
		let y = 40 + 50 * row;
		
		myShape(x, y, row, column, i);
	}
}

function myShape(x, y, row, column, i) {
	translate(x, y);
	
	let size = map(row - column, 0, 10, 30, 40);
	circle(0, 0, size / 2);
	square(0, 0, size);
	circle(size, y, size / 2);
	circle(0, size, size / 2);
	circle(size, size, size / 2);
}
image

Draw just the first shape

function draw() {
	background(100);

	for (let i = 0; i < 30; i++) {
		let row = i % 5;
		let column = floor(i / 5);
		
		let x = 30 + 50 * column;
		let y = 40 + 50 * row;
		
		myShape(x, y, row, column, i);
		break;
	}
}

function myShape(x, y, row, column, i) {
	translate(x, y);
	
	let size = map(row - column, 0, 10, 30, 40);
	circle(0, 0, size / 2);
	square(0, 0, size);
	circle(size, 0, size / 2);
	circle(0, size, size / 2);
	circle(size, size, size / 2);
}
image

Draw just the fourth shape

function setup() {
	createCanvas(windowWidth, windowHeight);
}

function draw() {
	background(100);

	for (let i = 0; i < 30; i++) {
		let row = i % 5;
		let column = floor(i / 5);
		
		let x = 30 + 50 * column;
		let y = 40 + 50 * row;

		if (i === 3) {
			myShape(x, y, row, column, i);
		}
	}
}

function myShape(x, y, row, column, i) {
	translate(x, y);
	
	let size = map(row - column, 0, 10, 30, 40);
	circle(0, 0, size / 2);
	square(0, 0, size);
	circle(size, 0, size / 2);
	circle(0, size, size / 2);
	circle(size, size, size / 2);
}
image

Fixed: add push() and pop()

function draw() {
	background(100);

	for (let i = 0; i < 30; i++) {
		let row = i % 5;
		let column = floor(i / 5);
		
		let x = 30 + 50 * column;
		let y = 40 + 50 * row;

		myShape(x, y, row, column, i);
	}
}

function myShape(x, y, row, column, i) {
	push();
	translate(x, y);
	
	let size = map(row - column, 0, 10, 30, 40);
	circle(0, 0, size / 2);
	square(0, 0, size);
	circle(size, 0, size / 2);
	circle(0, size, size / 2);
	circle(size, size, size / 2);
	pop();
}
image

Nested loops

An alternative to deriving the row and column from the linear index i, is to use nested loops to step through the row and column numbers directly.

function draw() {
	background(100);
	
	for (let row = 0; row < 5; row++) {
		for (let column = 0; column < 6; column++) {
				let x = 30 + 50 * column;
				let y = 40 + 50 * row;

				myShape(x, y, row, column);
		}
	}
}

function myShape(x, y, row, column) {
	push();
	translate(x, y);
	
	let size = map(row - column, 0, 10, 30, 40);
	circle(0, 0, size / 2);
	square(0, 0, size);
	circle(size, 0, size / 2);
	circle(0, size, size / 2);
	circle(size, size, size / 2);
	pop();
}

If we need i (the shape number), we can derive it from the row and column numbers.

function draw() {
	background(100);
	
	for (let row = 0; row < 5; row++) {
		for (let column = 0; column < 6; column++) {
				let x = 30 + 50 * column;
				let y = 40 + 50 * row;
				let i = row * 6 + column;

				myShape(x, y, row, column, i);
		}
	}
}

function myShape(x, y, row, column, i) {
	push();
	translate(x, y);
	
	let size = map(row - column, 0, 10, 30, 40);
	circle(0, 0, size / 2);
	square(0, 0, size);
	circle(size, 0, size / 2);
	circle(0, size, size / 2);
	circle(size, size, size / 2);
	pop();
}

Or we can keep count of how many shapes we've drawn.

function draw() {
	background(100);
	
	let i = 0;
	for (let row = 0; row < 5; row++) {
		for (let column = 0; column < 6; column++) {
			let x = 30 + 50 * column;
			let y = 40 + 50 * row;

			myShape(x, y, row, column, i);
			i++
		}
	}
}
image

Adding a second cell type

Rename myShape to decoratedSquare

function setup() {
	createCanvas(windowWidth, windowHeight);
}

function draw() {
	background(100);
	
	for (let row = 0; row < 5; row++) {
		for (let column = 0; column < 6; column++) {
			let x = 30 + 50 * column;
			let y = 40 + 50 * row;

			decoratedSquare(x, y, row, column);
		}
	}
}

function decoratedSquare(x, y, row, column, i) {
	push();
	translate(x, y);
	
	let size = map(row - column, 0, 10, 30, 40);
	circle(0, 0, size / 2);
	square(0, 0, size);
	circle(size, 0, size / 2);
	circle(0, size, size / 2);
	circle(size, size, size / 2);
	pop();
}

Add a second drawing function circles() and use it instead.

function draw() {
	background(200);
	
	for (let row = 0; row < 5; row++) {
		for (let column = 0; column < 6; column++) {
			let x = 30 + 50 * column;
			let y = 40 + 50 * row;

			circles(x, y, row, column);
		}
	}
}

function circles(x, y) {
	push();
	translate(x, y);
	
	fill('white');
	circle(0, 10, 20);
	fill('yellow');
	circle(10, 10, 20);
	fill('green');
	circle(10, 0, 20);

	pop();
}

function decoratedSquare(x, y, row, column, i) {
	push();
	translate(x, y);
	
	let size = map(row - column, 0, 10, 30, 40);
	circle(0, 0, size / 2);
	square(0, 0, size);
	circle(size, 0, size / 2);
	circle(0, size, size / 2);
	circle(size, size, size / 2);
	pop();
}
image

Animate the circles, by incorporating data from frameCount

function draw() {
	background(200);
	
	for (let row = 0; row < 5; row++) {
		for (let column = 0; column < 6; column++) {
			let x = 30 + 50 * column;
			let y = 40 + 50 * row;

			circles(x, y, row, column);
		}
	}
}

function circles(x, y) {
	push();
	translate(x, y);
	
	let dx = map(cos(frameCount / 30), -1, 1, 0, 10);
	let size = 30;
	fill('white');
	circle(0, dx, 30);
	fill('yellow');
	circle(dx, dx, 30);
	fill('green');
	circle(dx, 0, 30);

	pop();
}

Extract grid() into a function

image
function draw() {
	background(200);
	for (let row = 0; row < 5; row++) {
		for (let column = 0; column < 6; column++) {
			let x = 30 + 50 * column;
			let y = 40 + 50 * row;

			circles(x, y, row, column);
		}
	}
}

function draw() {
	background(200);
	grid();
}

function grid() {
	for (let row = 0; row < 5; row++) {
		for (let column = 0; column < 6; column++) {
			let x = 30 + 50 * column;
			let y = 40 + 50 * row;

			circles(x, y, row, column);
		}
	}
}

Add parameters

function draw() {
	background(200);
	grid(5, 6);
}

function grid(rows, columns) {
	for (let row = 0; row < rows; row++) {
		for (let column = 0; column < columns; column++) {
			let x = 30 + 50 * column;
			let y = 40 + 50 * row;

			circles(x, y, row, column);
		}
	}
}

Use (call) grid() twice, to draw two grids.

function setup() {
	createCanvas(windowWidth, windowHeight);
}

function draw() {
	background(200);
	grid(5, 6);
	
	translate(width / 2, height / 2);
	grid(3, 4);
}

function grid(rows, columns) {
	for (let row = 0; row < rows; row++) {
		for (let column = 0; column < columns; column++) {
			let x = 30 + 50 * column;
			let y = 40 + 50 * row;

			circles(x, y, row, column);
		}
	}
}
image

(Optional) Higher-Order Programming

(Using a function as a parameter.)

Make the cell drawing function a parameter.

function setup() {
	createCanvas(windowWidth, windowHeight);
}

function draw() {
	background(200);
	grid(5, 6, circles);
	
	translate(width / 2, height / 2);
	grid(3, 4, circles);
}
image

Now different calls to grid() can draw different cells.

function setup() {
	createCanvas(windowWidth, windowHeight);
}

function draw() {
	background(200);
	grid(5, 6, circles);
	
	translate(width / 2, height / 2);
	grid(3, 4, decoratedSquare);
}

function grid(rows, columns, drawer) {
	for (let row = 0; row < rows; row++) {
		for (let column = 0; column < columns; column++) {
			let x = 30 + 50 * column;
			let y = 40 + 50 * row;

			drawer(x, y, row, column);
		}
	}
}
image