ループでパターンを埋め尽くす
前回は1つの四角形を描きました。今回は for ループを使って「キャンバスを埋め尽くす」技法を学びます。
ビジュアルコーディングにおけるループは、単なる繰り返し処理ではありません。ループのカウンター変数 i が位置・色・サイズを決める数学式の材料になります。これがコードからビジュアルが生まれる仕組みの核心です。
1次元ループ — 横方向に並べる
まず1次元のループから始めます。カウンター i を x 座標として使います。
for (var i = 0; i < 10; i++) {
var x = i * 60; // i番目のx位置
ctx.fillStyle = 'hsl(' + (i * 36) + ', 80%, 55%)'; // i番目の色
ctx.fillRect(x, 0, 58, H);
}
ここでの重要な考え方:
i * 60→ 等間隔にx座標を生成i * 36→ 0〜360(10等分)の色相を生成58は幅で、60 - 2にすることで隙間ができる
for (var i = 0; i < 10; i++) {
ctx.fillStyle = 'hsl(' + (i * 36) + ', 80%, 55%)';
ctx.fillRect(i * 60, 0, 58, H);
} 2次元ループ — グリッドを作る
ループを2重にネストすると、縦横のグリッドが作れます。
var size = 40; // セルのサイズ
for (var x = 0; x < W; x += size) { // 横方向
for (var y = 0; y < H; y += size) { // 縦方向
ctx.fillStyle = 'hsl(' + ((x + y) / (W + H) * 360) + ', 70%, 55%)';
ctx.fillRect(x, y, size - 2, size - 2);
}
}
(x + y) / (W + H) * 360 という式が肝です。
x + yは左上から右下に向かって大きくなる値- それを
W + Hで割って 0〜1 に正規化 - 360 を掛けて色相(0〜360)に変換
この「インデックス → 正規化 → 色相」の変換パターンは、ビジュアルコーディングで何度も登場します。
var size = 40;
for (var x = 0; x < W; x += size) {
for (var y = 0; y < H; y += size) {
var hue = (x + y) / (W + H) * 360;
ctx.fillStyle = 'hsl(' + hue + ', 70%, 55%)';
ctx.fillRect(x, y, size - 2, size - 2);
}
} 隙間ゼロにする
size - 2 を size に変えると隙間がなくなり、ピクセルアート風になります。
var size = 40;
for (var x = 0; x < W; x += size) {
for (var y = 0; y < H; y += size) {
var hue = (x + y) / (W + H) * 360;
ctx.fillStyle = 'hsl(' + hue + ', 70%, 55%)';
ctx.fillRect(x, y, size, size);
}
} 数学関数で模様を変える
色相の計算式に Math.sin() を加えると、直線的なグラデーションではなく波状のパターンが生まれます。
var brightness = (Math.sin(x * 0.05) * Math.sin(y * 0.05) + 1) / 2;
// Math.sin の値域は -1 〜 1 なので、+1 して /2 すると 0〜1 に正規化
ctx.fillStyle = 'hsl(200, 80%, ' + (brightness * 60 + 20) + '%)';
Math.sin(x * 0.05) * Math.sin(y * 0.05) は、縦横それぞれの波を掛け合わせた干渉パターンです。
var size = 20;
for (var x = 0; x < W; x += size) {
for (var y = 0; y < H; y += size) {
var v = (Math.sin(x * 0.06) * Math.sin(y * 0.06) + 1) / 2;
ctx.fillStyle = 'hsl(200, 80%, ' + (v * 60 + 15) + '%)';
ctx.fillRect(x, y, size, size);
}
} すべてのピクセルを制御する
サイズを 1 にすると、1ピクセルずつすべてを塗れます。
for (var x = 0; x < W; x++) {
for (var y = 0; y < H; y++) {
var hue = (x * x + y * y) % 360; // 距離の二乗から色相を計算
ctx.fillStyle = 'hsl(' + hue + ', 90%, 50%)';
ctx.fillRect(x, y, 1, 1);
}
}
x * x + y * y は原点からの距離の二乗(ピタゴラスの定理)。これを使うと中心から同心円状に色が広がります。
ctx.fillStyle = '#0d1117';
ctx.fillRect(0, 0, W, H);
for (var x = 0; x < W; x++) {
for (var y = 0; y < H; y++) {
var hue = ((x - W/2) * (x - W/2) + (y - H/2) * (y - H/2)) * 0.003 % 360;
ctx.fillStyle = 'hsl(' + hue + ', 90%, 50%)';
ctx.fillRect(x, y, 1, 1);
}
} ピクセル単位のループはキャンバスが大きいと少し描画に時間がかかります。サイズを
2や4にして間引くと高速化できます。
ランダム性を加える
Math.random() は 0〜1 のランダムな数値を返します。位置や色に掛け合わせると、散らばったパターンが生まれます。
for (var i = 0; i < 500; i++) {
var x = Math.random() * W;
var y = Math.random() * H;
ctx.fillStyle = 'hsl(' + (Math.random() * 360) + ', 80%, 60%)';
ctx.fillRect(x, y, 4, 4);
}
ctx.fillStyle = '#0d1117';
ctx.fillRect(0, 0, W, H);
for (var i = 0; i < 800; i++) {
var x = Math.random() * W;
var y = Math.random() * H;
ctx.fillStyle = 'hsl(' + (Math.random() * 360) + ', 80%, 60%)';
ctx.fillRect(x, y, 4, 4);
} ループのパターンまとめ
ビジュアルコーディングで使う典型的な計算パターンをまとめます。
| やりたいこと | 式の例 |
|---|---|
| 等間隔の位置 | i * spacing |
| 全体を0〜1に | i / count |
| 0〜360の色相 | (i / count) * 360 |
| -1〜1の波 | Math.sin(i * freq) |
| ランダム値 | Math.random() |
| 0〜360のランダム | Math.random() * 360 |
これらを組み合わせることで、コードの数行が数万のピクセルを支配するのがビジュアルコーディングの魔法です。
まとめ
この回でやったこと:
- 1次元ループで横に並べた
- 2重ループで 座標系? Canvas上の位置を(x, y)の数値ペアで表す仕組み。左上が原点(0,0)でxは右向き、yは下向きに増加する(数学の座標系とy軸が逆)。 グリッドを作った
- ループのインデックスを HSL? 色相(Hue 0〜360)・彩度(Saturation)・明度(Lightness)で色を指定する方式。ループ変数から色相を計算しやすく、ビジュアルコーディングで多用される。 の色相に変換した
Math.sin()で波状パターンを作ったMath.random()でランダムな散布図を作った
次回は 円 と 三角関数 に入ります。Math.sin() と Math.cos() を使って、ローズ曲線やスパイラルといった滑らかで有機的な曲線を描いていきます。