
Node Gerdenは、白丸を線で繋いだアニメーションです。白丸をTwitterのアイコンにしたり、Youtubeのお気に入り画像を表示すれば、関係性を視覚化できたりします。複雑なようで実は簡単なのでProcessingで作ってみましょう。
以下ソースコードがたくさん書かれているように感じますが、修正前と修正後のソースコードをすべて貼り付けているためです。実際はコメントを含めて100行ぐらいで、簡単なので挑戦してみてください。
大まかな作り方を把握
- ノード(白丸)をランダムに表示します。
- 白丸が移動できるようにします。
- すべての白丸を線でつなぎます。
- ある一定の距離だけ線でつなぐように修正します。
- (応用)線をばね(スプリング)と考え、白丸の速度に変化を加えます。
ノードをランダムに表示します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
|
class Node { // x座標 float x; // y座標 float y; // 半径 float radius; // コンストラクター // コンストラクターは日本語で組み立て、建造の意味で、 // プログラム上で、new Node();のように記述すると呼ばれます。 Node() { x = random(0, width); y = random(0, height); radius = 8; } // ノードを表示 void show() { // 白色 fill(255, 255,255, 255); // xy座標に、半径radiusの円を表示 ellipse(x, y, radius, radius); } } // 50個のノードを入れられる配列 Node[] nodes = new Node[50]; // setupはProcessing起動時に1回呼ばれます。 void setup() { // 画面サイズは640x640 size(640, 640); // 表示をなめらかにします。 smooth(4); // 50個ノードを作成して、nodes配列に入れておきます。 for (int i = 0; i < 50; i++) { nodes[i] = new Node(); } } // 1/60秒毎に呼ばれます。 void draw() { // 背景描画 fill(0, 0, 50, 80); rect(0, 0, width, height); // 50個のノードを配列から取り出し、showで表示します。 for (int i = 0; i < 50; i++) { Node node = nodes[i]; node.show(); } } |
白丸が移動移動できるようにします。
ノードクラスに速度を表すxv(X座標のVelocity)とyvを用意して、描画毎にxy座標に足すことで移動します。また画面外に移動した場合は、反対側から出てくるようにします。例えば白丸が右側に進んで画面外になったら、左側からでてくるようにします。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
|
class Node { // x座標 float x; // y座標 float y; // x座標の速度 float vx; // y座標の速度 float vy; // 半径 float radius; // コンストラクター // コンストラクターは日本語で組み立て、建造の意味で、 // プログラム上で、new Node();のように記述すると呼ばれます。 Node() { x = random(0, width); y = random(0, height); vx = random(-0.5, 0.5); vy = random(-0.5, 0.5); radius = 8; } void update() { x += vx; y += vy; if (x > width) { x = 0; } else if (x < 0) { x = width; } if (y > height) { y = 0; } else if (y < 0) { y = height; } } // ノードを表示 void show() { update(); // 白色 fill(255, 255,255, 255); // xy座標に、半径radiusの円を表示 ellipse(x, y, radius, radius); } } // 50個のノードを入れられる配列 Node[] nodes = new Node[50]; // setupはProcessing起動時に1回呼ばれます。 void setup() { // 画面サイズは640x640 size(640, 640); // 表示をなめらかにします。 smooth(4); // 50個ノードを作成して、nodes配列に入れておきます。 for (int i = 0; i < 50; i++) { nodes[i] = new Node(); } } // 1/60秒毎に呼ばれます。 void draw() { // 背景描画 fill(0, 0, 50, 80); rect(0, 0, width, height); // 50個のノードを配列から取り出し、showで表示します。 for (int i = 0; i < 50; i++) { Node node = nodes[i]; node.show(); } } |
すべての白丸を線でつなぎます。

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
|
class Node { // x座標 float x; // y座標 float y; // x座標の速度 float vx; // y座標の速度 float vy; // 半径 float radius; // コンストラクター // コンストラクターは日本語で組み立て、建造の意味で、 // プログラム上で、new Node();のように記述すると呼ばれます。 Node() { x = random(0, width); y = random(0, height); vx = random(-0.5, 0.5); vy = random(-0.5, 0.5); radius = 8; } void update() { x += vx; y += vy; if (x > width) { x = 0; } else if (x < 0) { x = width; } if (y > height) { y = 0; } else if (y < 0) { y = height; } } // ノードを表示 void show() { update(); // 白色 fill(255, 255,255, 255); // xy座標に、半径radiusの円を表示 ellipse(x, y, radius, radius); } } // 50個のノードを入れられる配列 Node[] nodes = new Node[50]; // setupはProcessing起動時に1回呼ばれます。 void setup() { // 画面サイズは640x640 size(640, 640); // 表示をなめらかにします。 smooth(4); // 50個ノードを作成して、nodes配列に入れておきます。 for (int i = 0; i < 50; i++) { nodes[i] = new Node(); } } // 1/60秒毎に呼ばれます。 void draw() { // 背景描画 fill(0, 0, 50, 80); rect(0, 0, width, height); // 50個の白丸ノードの表示 for (int i = 0; i < 50; i++) { Node node = nodes[i]; node.show(); } // 白丸のバネを表示 for (int i = 0; i < 50 -1; i++) { Node node1 = nodes[i]; for (int j = 0; j < 50; j++) { Node node2 = nodes[j]; showSpring(node1, node2); } } } // 引数で与えられたノードをつなげ表示します。 void showSpring(Node n1, Node n2) { stroke(255, 255, 255, 255); line(n1.x, n1.y, n2.x, n2.y); } |
ある一定の距離だけ線でつなぐように修正します。

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
|
class Node { // x座標 float x; // y座標 float y; // x座標の速度 float vx; // y座標の速度 float vy; // 半径 float radius; // コンストラクター // コンストラクターは日本語で組み立て、建造の意味で、 // プログラム上で、new Node();のように記述すると呼ばれます。 Node() { x = random(0, width); y = random(0, height); vx = random(-0.5, 0.5); vy = random(-0.5, 0.5); radius = 8; } void update() { x += vx; y += vy; if (x > width) { x = 0; } else if (x < 0) { x = width; } if (y > height) { y = 0; } else if (y < 0) { y = height; } } // ノードを表示 void show() { update(); // 白色 fill(255, 255,255, 255); // xy座標に、半径radiusの円を表示 ellipse(x, y, radius, radius); } } // 50個のノードを入れられる配列 Node[] nodes = new Node[50]; // setupはProcessing起動時に1回呼ばれます。 void setup() { // 画面サイズは640x640 size(640, 640); // 表示をなめらかにします。 smooth(4); // 50個ノードを作成して、nodes配列に入れておきます。 for (int i = 0; i < 50; i++) { nodes[i] = new Node(); } } // 1/60秒毎に呼ばれます。 void draw() { // 背景描画 fill(0, 0, 50, 80); rect(0, 0, width, height); // 50個の白丸ノードの表示 for (int i = 0; i < 50; i++) { Node node = nodes[i]; node.show(); } // 白丸のバネを表示 for (int i = 0; i < 50 -1; i++) { Node node1 = nodes[i]; for (int j = 0; j < 50; j++) { Node node2 = nodes[j]; showSpring(node1, node2); } } } // 引数で与えられたノードをつなげ表示します。 void showSpring(Node n1, Node n2) { // ノード2のx座標からノード1のx座標を引いて、x座標の差を求めます。 float dx = n2.x - n1.x; float dy = n2.y - n1.y; // ピタゴラスの定理により、ノード1とノード2の距離を求めます。 float distance = sqrt(dx * dx + dy * dy); // ノード間が100ピクセル以内ならバネを表示します。 if (distance < 100) { stroke(255, 255, 255, 255); line(n1.x, n1.y, n2.x, n2.y); } } |
ここまででほぼ完成しました。冷静に考えると2点の丸を好きな場所に表示して、それを移動するようにして、線でつなげるだけです。
(応用)線をばね(スプリング)と考え、白丸の速度に変化を加えます。

線を表示した場合は、少しだけ速度を変化させるようにしました。例えばx座標の距離dxが100ピクセルなら、係数0.0001を掛けて、0.001速度を加えます。値はかなり小さいのですが、1/60秒毎にこのメソッドが呼ばれているためかなりの効果があります。いろいろ係数を調整してみてください。
また、ノード間の距離が長くなると線が薄く表示されるようにアルファチャンネルを修正しました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
|
class Node { // x座標 float x; // y座標 float y; // x座標の速度 float vx; // y座標の速度 float vy; // 半径 float radius; // コンストラクター // コンストラクターは日本語で組み立て、建造の意味で、 // プログラム上で、new Node();のように記述すると呼ばれます。 Node() { x = random(0, width); y = random(0, height); vx = random(-0.5, 0.5); vy = random(-0.5, 0.5); radius = 8; } void update() { x += vx; y += vy; if (x > width) { x = 0; } else if (x < 0) { x = width; } if (y > height) { y = 0; } else if (y < 0) { y = height; } } // ノードを表示 void show() { update(); // 白色 fill(255, 255,255, 255); // xy座標に、半径radiusの円を表示 ellipse(x, y, radius, radius); } } // 50個のノードを入れられる配列 Node[] nodes = new Node[50]; // setupはProcessing起動時に1回呼ばれます。 void setup() { // 画面サイズは640x640 size(640, 640); // 表示をなめらかにします。 smooth(4); // 50個ノードを作成して、nodes配列に入れておきます。 for (int i = 0; i < 50; i++) { nodes[i] = new Node(); } } // 1/60秒毎に呼ばれます。 void draw() { // 背景描画 fill(0, 0, 50, 80); rect(0, 0, width, height); // 50個の白丸ノードの表示 for (int i = 0; i < 50; i++) { Node node = nodes[i]; node.show(); } // 白丸のバネを表示 for (int i = 0; i < 50 -1; i++) { Node node1 = nodes[i]; for (int j = 0; j < 50; j++) { Node node2 = nodes[j]; showSpring(node1, node2); } } } // 引数で与えられたノードをつなげ表示します。 void showSpring(Node n1, Node n2) { // ノード2のx座標からノード1のx座標を引いて、x座標の差を求めます。 float dx = n2.x - n1.x; float dy = n2.y - n1.y; // ピタゴラスの定理により、ノード1とノード2の距離を求めます。 float distance = sqrt(dx * dx + dy * dy); // ノード間が100ピクセル以内ならバネを表示します。 if (distance < 100) { // mapは、第一引数の値が、0~1なら、0~255に変化させます。 float alpha = map(1 - distance / 100, 0, 1, 0, 255); stroke(255, 255, 255, alpha); line(n1.x, n1.y, n2.x, n2.y); // ばね効果 // 上記で求めた、距離dx,dyに係数0.0001を掛けて、速度を追加します。 float ax = dx * 0.0001; float ay = dy * 0.0001; n1.vx += ax; n1.vy += ay; n2.vx += ax; n2.vy += ay; } } |
このコードでは、ばね効果でどんどんノードの速度が速くなってしまいます。vx,vyがある一定速度になったら、0.5に戻すなどの処置をすると綺麗になります。
応用
基礎のため白色の丸でしたが、別に画像ファイルでも問題ありません。そのため、TwitterアイコンやYoutubeのサムネイルでノードを作成して、関連が強いものは引き合うアルゴリズムなどを作ってみるとおもしろそうです。またノードの追加、削除、ノードをクリックしたときのエフェクトや、任意のノード間の最短経路など様々応用が可能です。
まとめ
インターネット上では日本語でもNode Gardenのサンプルはあるのですが解説が少ないので、ProcessingでNode Gardenを作ってその解説をしてみました。作る前はすごく大変そうと思っていたのですが、100行足らずで作成できたので拍子抜けでした。