Regelmäßigkeit im Chaos - ein Canvas-Effekt mit Faszinations-Garantie
Kategorien: Design, Inspiration, JavaScript, Programmieren and Tutorials
In meinem letzten Artikel habe ich beschrieben, wie man mit ein wenig Physik, JavaScript und dem Canvas einen interaktiven Effekt erstellen kann. In diesem Artikel möchte ich einen neuen Effekt vorstellen, der diesmal zwar nicht interaktiv, aber nicht weniger interessant ist.
Zuerst das Resultat
Ein bisschen Theorie über Zykloide
Auch in diesem Effekt brauchen wir ein bisschen Theorie, jedoch nicht sehr viel. Obwohl die Bewegungen beinahe chaotisch wirken, steckt hinter ihnen ein mathematisches Muster. Punkt für Punkt wird das Muster aus der Rotation von Kreisen gegeneinander generiert. Klingt kompliziert, ist aber eigentlich ganz einfach. Gehen wir es Schritt für Schritt durch.
Als erstes denken wir uns einen Kreis in der Mitte. Dieser Kreis rotiert pro Iteration um einen bestimmten Winkel, zum Beispiel 2°.
Nun denken wir uns einen zweiten Kreis, der an dem Punkt auf dem ersten Kreis befestigt ist. Dieser Kreis ist halb so groß und rotiert doppelt so schnell, jedoch in die entgegengesetzte Richtung.
Wir können nun beliebig viele Kreise hinzufügen, so wird die entstehende Bewegung immer komplexer. So sieht die Bewegung zum Beispiel mit drei Kreisen aus.
Umsetzung I: HTML
Bevor wir den Effekt mit JavaScript umsetzen müssen, brauchen wir zunächst ein HTML-Dokument mit einem Canvas. Hier binden wir auch die JavaScript-Datei ein.
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8" />
<title>Cycloids</title>
</head>
<body>
<canvas></canvas>
<script type="text/javascript" src="js/main.js"></script>
</body>
</html>
Umsetzung II: Javascript
Nun können wir mit dem Erstellen des Effekts beginnen. Als erstes definieren wir ein paar Konstanten.
var width = 600, height = 600;
var numCircles = 5;
var ratio = 1.41;
var maxRadius = 290;
var step = Math.PI / 180;
width
und height
stellen die Größe des Canvas dar. numCircles
definiert die Anzahl der Kreise, ratio
ist das Verhältnis zwischen den Größen der einzelnen Kreise. In diesem Fall ist jeder Kreis 1,41 mal so klein wie der vorherige. maxRadius
ist der maximale gesamte Radius aller Kreise. So passt das Muster immer in den Canvas. step
ist der Winkel, um den sich der erste Kreis jede Iteration dreht.
document.body.setAttribute('style', 'margin: 0px; padding: 0px; background: #111111; text-align: center;');
var canvas = document.getElementsByTagName('canvas')[0];
canvas.setAttribute('style', 'margin: 0px auto;');
canvas.setAttribute('width', width);
canvas.setAttribute('height', height);
var context = canvas.getContext('2d');
Nun bereiten wir den Canvas vor. Zunächst weisen wir dem Body ein paar Stile vor, danach wählen wir den Canvas aus und geben ihm auch Stile, Breite und Höhe. Zuletzt fragen wir noch den Context ab.
var smallestRadius = maxRadius;
while(smallestRadius > .01 && accumulatedRadius(smallestRadius) > maxRadius) {
smallestRadius -= .01;
}
Als nächstes ermitteln wir den Radius des kleinsten Kreises. Insgesamt dürfen alle Radien zusammen nicht größer sein als maxRadius
. Also starten wir mit maxRadius
und verkleinern den Radius so lange, bis alle Radien zusammen kleiner als maxRadius
sind. Mit der Funktion accumulatedRadius
berechnen wir den summierten Radius aller Kreise.
function accumulatedRadius(smallestRadius) {
var result = 0;
for(var i = 0; i < numCircles; i++) {
result += smallestRadius;
smallestRadius *= ratio;
}
return result;
}
In der Funktion accumulatedRadius
gehen wir einfach alle Kreise durch und addieren den Radius zur Summe.
Nachdem wir nun den kleinsten Radius kennen, können wir die Kreise generieren und in einem Array speichern.
var circles = [];
for(var i = 0; i < numCircles; i++) {
circles.push({
angle: 0,
radius: smallestRadius * Math.pow(ratio, numCircles - i - 1)
});
}
Für jeden Kreis speichern wir im Array circles
ein Objekt, dass den Winkel und Radius dieses Kreises enthält. Der Winkel ist zu Anfang bei allen Kreisen 0. Den Radius können wir aus dem kleinsten Radius generieren, indem wir pro Kreis den Radius mit ratio
multiplizieren.
context.fillStyle = '#ffffff';
window.setInterval(function() {
var position = {
x: width / 2,
y: height / 2
};
var deltaAngle = step;
for(var i = 0; i < numCircles; i++) {
position.x += circles[i].radius * Math.sin(circles[i].angle);
position.y += circles[i].radius * Math.cos(circles[i].angle);
circles[i].angle += deltaAngle;
deltaAngle *= -1 * ratio;
}
context.fillRect(position.x, position.y, 1, 1);
}, 1);
Schließlich können wir die Iteration starten. Den fillStyle
setzen wir auf #ffffff
.
In jeder Iteration beginnen wir im Mittelpunkt des Canvas. Diesen speichern wir im Objekt position
. In der Variable deltaAngle
speichern wir den Winkel, um den der erste Kreis rotieren wird. Nun gehen wir alle Kreise durch.
Mit Sinus und Cosinus verschieben wir für jeden Kreis position
. So berechnen wir in jeder Iteration den Endpunkt der aktuellen Kreiswinkel. Diesen Endpunkt zeichnen wir schließlich auf unserem Canvas ein. Nach jeder Iteration werden die für die Kreise gespeicherten Winkel um deltaAngle
geändert, wobei deltaAngle
selbst mit jedem Kreis wieder umgekehrt und mit ratio
multipliziert wird, genau wie vorhin bei unseren drei Kreisen.
So entsteht Punkt für Punkt ein komplexes Muster. Obwohl dieses Muster zufällig wirkt, zeichnen sich mit der Zeit Regelmäßigkeiten ab. So oder so ist der Effekt jedenfalls interessant.
Variationen und Spielerei
Den Effekt selbst kann man über die Anzahl der Kreise und die Größenverhältnisse variieren. Dafür habe ich hier eine interaktive Demo hochgeladen.
Mit diesem Effekt zeige ich nur stellvertretend die vielen Möglichkeiten, die uns dank Canvas, JavaScript und ein bisschen Fantasie offen stehen. Hiermit fordere ich Dich auf, ein wenig mit dem Canvas herum zu experimentieren. Im Web gibt es schon extrem viele Canvas-Experimente, aber der Kreativität sind keine Grenzen gesetzt.