0t1 steckt noch in den Kinderschuhen.

Kaleidoskop Zeichenanwendung p5.js

In dieser Übung lernst du, wie man eine Zeichenanwendung für Kaleidoskop ähnliche Muster in p5.js programmiert.

Editor öffnen

Um das Tutorial durchzuführen, öffnen wir den p5.js Editor über den folgenden Link: p5.js Web Editor (p5js.org).

function setup() {
  createCanvas(400, 400);
}

function draw() {
  background(220);
}

In der Funktion setup() wird deine Zeichenfläche, ein sogenannter Canvas erzeugt. Diese Funktion wird nur einmal am Anfang ausgeführt.

Die Funktion draw() wird wiederholt ausgeführt. Hier generiert p5.js automatisch einen grauen Hintergrund.

Für unsere Anwendung möchten wir eine größere Zeichenfläche und einen dunkelgrauen Hintergrund. Dafür werden die Werte folgendermaßen geändert.

function setup() {
  createCanvas(450, 450);
}

function draw() {
  background(30);
}

Erstellen einer Zeichenanwendung

Damit Linien zukünftig auf die Anwendung gezeichnet werden können, wird der Hintergrund nicht mehr in der draw(), sondern in der setup() Funktion initialisiert. Da wir im weiteren Verlauf mit den HSB Farbwerten arbeiten wollen, konfigurieren wir den Farbmodus mit colorMode(HSB, 360, 150, 100, 1).

Die Werte stehen für folgendes: HSB (Farbton, Sättigung, Helligkeit, Transparenz).

Um mit der Maus Linien zeichnen zu können, erstellen wir eine Linie line(mouseX, mouseY, pmouseX, pmouseY);. Es zeichnet eine Linie von der vorherigen Mausposition (pmouseX, pmouseY) zur aktuellen Mausposition (mouseX, mouseY).

Um die Linie sichtbar zu machen, weisen wir ihr eine Strichstärke und eine Farbe zu. Die Farbe ist hierbei im HSB Modus. Durch die Angabe der horizontalen Mausposition mouseX beim Farbton, wird sich der Farbton je nach X-Position verändern.

function setup() {
  createCanvas(450, 450);
  background(30);
  colorMode(HSB, 360, 150, 100, 1);
}

function draw() {
  strokeWeight(15);
  stroke(mouseX, 150, 100, 0.5);
  line(mouseX, mouseY, pmouseX, pmouseY);
}

Folgendes sollte nun möglich sein:

Bild von bunter Linie

Anpassungen zu einem Kaleidoskop

Um den Startpunkt des Koordinatensystems in die Mitte zu versetzen, verwenden wir translate(width/2, height/2) in der draw() Funktion.

Für den Kaleidoskop Effekt benötigen wir einen Winkel, an dem die Linien gespiegelt werden. Dafür wird zu aller erst eine Variable angle erstellt. Diese befindet sich außerhalb der Funktionen, damit sie global gültig ist.

Durch den Wert 12 werden die Linien in einem 12 Grad Winkel gespiegelt. Im späteren Verlauf wird diese Variable veränderbar sein, sodass die Linien unterschiedlich oft gespiegelt werden können.

let angle = 12;

Um die Spiegelungen umsetzten zu können, erstellen wir eine for-Schleife in der draw() Funktion. Innerhalb der for-Schleife wird das Koordinatensystem um den Winkel angle rotiert, dann wird eine Linie gezeichnet, deren Farbe und Dicke festgelegt sind. Danach wird das Koordinatensystem gespiegelt und eine weitere Linie wird gezeichnet. Dieser Prozess wird angle-mal wiederholt, wodurch eine Reihe von Linien entsteht, die sich um den Mittelpunkt der Leinwand drehen und dem Mauszeiger folgen.

for (let i = 0; i < angle; i++) {
    rotate(angle);
    strokeWeight(15);
    stroke(mouseX, 150, 100, 0.5);
    line(mouseX, mouseY, pmouseX, pmouseY);
 
    push();
    scale(1, -1);
    line(mouseX, mouseY, pmouseX, pmouseY);
    pop();
  }

for (let i = 0; i < angle; i++) { Diese Zeile beginnt eine for-Schleife, die von i = 0 bis i < angle läuft. i wird bei jedem Durchlauf um eins erhöht.

Mit rotate(angle); wird das Koordinatensystem um den durch i bestimmten Winkel rotiert.

push(); speichert den aktuellen Zustand des Transformationsstapels. Durch scale(1, -1); wird die Zeichenrichtung gespiegelt, sodass die Linien nach unten gezogen werden. Zum Schluss stellt pop(); den vorherigen Zustand des Transformationsstapels wieder her.

Der Zwischenstand

let angle = 12;

function setup() {
  createCanvas(450, 450);
  background(30);
  colorMode(HSB, 360, 150, 100, 1);
}

function draw() {
  translate(width / 2, height / 2);

  for (let i = 0; i < angle; i++) {
    rotate(angle);
    strokeWeight(15);
    stroke(mouseX, 150, 100, 0.5);
    line(mouseX, mouseY, pmouseX, pmouseY);
 
    push();
    scale(1, -1);
    line(mouseX, mouseY, pmouseX, pmouseY);
    pop();
  }
}

Mit dem bestehenden Code lässt sich z.B. folgendes Muster erstellen:


Extra Einstellungen zur individuellen Anpassung des Kaleidoskops

Im nächsten Schritt werden nun 3 Slider hinzugefügt, um Sättigung, Strichstärke und den Winkel selbstständig anpassen zu können, sowie ein Button, welcher es ermöglicht eine zufällige Hintergrundfarbe zu generieren.

Dafür definieren wir zuerst ganz oben in unserem Code unsere Slider und Buttons, wo wir vorher schon den Winkel definiert haben.

let angle = 12;
let slider, slider2, slider3;
let colorButton;

let slider, slider2, slider3 sind Variablen für drei verschiedene Slider-Elemente, die in der Benutzeroberfläche erscheinen und jeweils die Parameter Sättigung, Strichstärke und Winkel steuern.

let colorButton ist die Variable für den Button, der die Hintergrundfarbe ändert, wenn er geklickt wird.

Die Slider und ihre Beschriftungen (Sättigung, Strichstärke, Winkel) werden in eigenen Containern erstellt. Jeder Container verwendet das Flexbox-Layout display: flex und orientiert sich vertikal mitflex-direction: column.

Nun können wir damit beginnen, die Container für die einzelnen Slider und Buttons zu erstellen.

Erstellen des Containers für die Einstellungen

// Erstelle einen Container für die Einstellungen
  let settingsContainer = createDiv('');
  settingsContainer.style('display', 'grid');
  settingsContainer.style('grid-template-rows', 'auto auto'); 

// Zwei Reihen: eine für Überschrift, eine für Slider
  settingsContainer.style('grid-template-columns', '215px 215px'); 
  settingsContainer.style('grid-gap', '10px'); 
  settingsContainer.style('padding', '10px'); 
  settingsContainer.style('margin-bottom', '10px');
  settingsContainer.style("font-family", "Arial"); 
  settingsContainer.style("font-size", "10pt");

Mit let settingsContainer = createDiv('') wird ein neues <div> HTML-Element erstellt, das als Container für die anderen Elemente dienen soll. Der leere String '' bedeutet, dass das <div> ohne Inhalt erstellt wird.

Mit der Zeile settingsContainer.style('display', 'grid') wird die display CSS-Eigenschaft des Containers auf grid gesetzt. Das Grid-Layout ermöglicht es, Elemente in einem zweidimensionalen Raster anzuordnen.

Die Zeile settingsContainer.style('grid-template-rows', 'auto auto')definiert die Reihenstruktur des Grids. auto auto bedeutet, dass zwei Reihen erstellt werden und jede Reihe automatisch die Höhe des Inhalts ihrer Zellen annimmt.

settingsContainer.style('grid-template-columns', '215px 215px') Hier werden die Spalten des Grids definiert. Durch die Angaben 215px 215px werden zwei gleichgroße Spalten erstellt, die zusammen ungefähr die Breite des Canvas ergeben.

settingsContainer.style('grid-gap', '10px')setzt den Abstand zwischen den Reihen und Spalten auf 10 Pixel. und settingsContainer.style('padding', '10px') fügt einen Innenabstand von 10 Pixeln auf allen Seiten innerhalb des Containers hinzu.

Durch settingsContainer.style('margin-bottom', '10px') wird ein Abstand von 10 Pixeln unterhalb des Containers hinzugefügt.

Mit den letzten zwei Styles wird die Schriftart und Schriftgröße festgelegt.

Sättigung (satContainer)

let satContainer = createDiv('').parent(settingsContainer).style('display', 'flex').style('flex-direction', 'column');
createP('Sättigung').parent(satContainer).style('color', 'black');
slider = createSlider(100, 255, 170).parent(satContainer);

createDiv('')erstellt ein <div> Element ohne Inhalt.

Durch .parent(settingsContainer) wirddas neu erstellte <div> als Kind des settingsContainer hinzugefügt.

.style('display', 'flex')setzt das Display-Property des <div> auf Flexbox und .style('flex-direction', 'column')richtet die Kind-Elemente vertikal an.

createP('Sättigung')erstellt ein <p> Element mit dem Text "Sättigung" als Beschriftung für den Slider und durch

.parent(satContainer) wird das <p> Element als Kind des satContainer hinzugefügt.

.style('color', 'black')setzt die Textfarbe der Beschriftung auf Schwarz. Den Slider erstellt man mit createSlider(min, max, default).In diesem kann man einen bestimmten Wertebereich mit einem Standardwert definieren. createSlider(100, 255, 170)erstellt einen Slider mit einem Minimalwert von 100, einem Maximalwert von 255 und einem Startwert von 170.

Durch .parent(satContainer)wird der Slider wird als Kind des satContainer hinzugefügt.

Strichstärke (weightContainer)

let weightContainer = createDiv('').parent(settingsContainer).style('display', 'flex').style('flex-direction', 'column');
createP('Strichstärke').parent(weightContainer).style('color', 'black');
slider2 = createSlider(4, 20, 12).parent(weightContainer);

Dieser Abschnitt tut im Wesentlichen das Gleiche wie bei der Sättigung, erstellt aber Elemente für die Anpassung der Strichstärke. Der Slider slider2 hat hier einen Bereich von 4 bis 20 mit einem Startwert von 12.

Winkel (angleContainer)

let angleContainer = createDiv('').parent(settingsContainer).style('display', 'flex').style('flex-direction', 'column');
createP('Winkel').parent(angleContainer).style('color', 'black');
slider3 = createSlider(5, 23, 12).parent(angleContainer);

Dieser Abschnitt wiederholt den Prozess ein drittes Mal, diesmal aber für den Winkel. Der Slider slider3 erlaubt Werte zwischen 5 und 23 und beginnt mit dem Wert 12.

In jedem der drei Fälle wird eine vertikale Gruppierung flex-direction: column von zwei Elementen erstellt. Ein Paragraph-Element <p>, das als Label dient, und ein Slider-Element, das die Steuerung bietet. Diese Gruppen sind wiederum im settingsContainer angeordnet, der als Grid konfiguriert ist.

Diese Struktur erlaubt es, die drei verschiedenen Aspekte des Kaleidoskops interaktiv zu steuern: die Sättigung der Farben, die Strichstärke von Linien und den Winkel, in dem das Kaleidoskop gezeichnet wird.

Erstellen des Buttons

let buttonContainer = createDiv('').parent(settingsContainer).style('display', 'flex').style('flex-direction', 'column');

Die Funktion createDiv('') erstellt ein neues <div>-Element. Das Element.parent(settingsContainer)wird zum Kind des settingsContainer. Durch.style('display', 'flex') wird das <div>-Element auf "flex" gesetzt, um das Flexbox-Modell anzuwenden..style('flex-direction', 'column') bestimmt die Hauptachse der Flexbox, "column" legt fest, dass die Kind-Elemente des Containers vertikal angeordnet werden.

colorButton = createButton('Hintergrundfarbe generieren');

createButton('Hintergrundfarbe generieren')erstellt ein Button-Element mit dem Text "Hintergrundfarbe generieren". Dies wird der sichtbare Text auf dem Button sein.

colorButton.style('background-color', 'gray');
colorButton.style('color', 'white');
colorButton.style('font-family', 'Arial');
colorButton.style('padding', '10px 20px');
colorButton.style("margin-top", "20px");
colorButton.style('border', 'none');
colorButton.style('border-radius', '5px');
colorButton.style('cursor', 'pointer');

.style('background-color', 'gray')setzt die Hintergrundfarbe des Buttons auf Grau. Durch .style('color', 'white')wird der Text auf dem Button weiß gefärbt.

.style('font-family', 'Arial')legt die Schriftart Arial für den Text auf dem Button fest.

.style('padding', '10px 20px') fügt einen Innenabstand zum Button hinzu und colorButton.style('margin-top', '20px') fügt einen Rand oben von 20px hinzu.

.style('border', 'none') entfernt jeglichen Rahmen um den Button herum und mit

.style('border-radius', '5px') werden die Ecken des Buttons um 5px abgerundet.

.style('cursor', 'pointer') ändert den Mauszeiger zu einem Zeiger, wenn er über dem Button ist, was verdeutlicht, dass der Button klickbar ist.

colorButton.mousePressed(changeBackgroundColor).parent(buttonContainer);

colorButton.mousePressed(changeBackgroundColor) weist dem Button colorButton eine Funktion zu, die ausgeführt wird, wenn der Button geklickt wird. In diesem Fall ist die Funktion changeBackgroundColor() ausgeführt, wenn der Button geklickt wird. Diese Funktion ändert die Hintergrundfarbe der Zeichenfläche.

.parent(buttonContainer) setzt das neu erstellte Button-Element als ein Kind-Element von buttonContainer.

Zufällige Farbe generieren

function changeBackgroundColor() {
  let randomHue = random(360);
  background(randomHue, 150, 100);
}

Die Funktion function changeBackgroundColor() generiert eine zufällige Farbtonkomponente (Hue) und ändert die Hintergrundfarbe entsprechend, wenn der Button gedrückt wird. Hier wird eine Variable randomHue deklariert und ihr ein zufälliger Wert zwischen 0 und 360 zugewiesen. Die Funktion random() generiert eine zufällige Zahl zwischen 0 und 360.

background(randomHue, 150, 100); setzt die Hintergrundfarbe des Canvas auf eine neue Farbe. Der erste Parameter randomHue ist der zufällige Wert für den Farbton (Hue) im HSB-Farbraum, der zwischen 0 und 360 liegt. Die nächsten beiden Parameter sind festgelegt auf 150 für die Sättigung und 100 für die Helligkeit. Diese Werte bleiben konstant, was bedeutet, dass die Hintergrundfarbe immer eine bestimmte Sättigung und Helligkeit haben wird, während der Farbton zufällig variiert.

Vollständiger Code des Buttons

let buttonContainer = createDiv('').parent(settingsContainer).style('display', 'flex').style('flex-direction', 'column');
  colorButton = createButton('Hintergrundfarbe generieren');
  colorButton.style('background-color', 'gray');
  colorButton.style('color', 'white');
  colorButton.style('font-family', 'Arial');
  colorButton.style('padding', '10px 20px');
  colorButton.style('border', 'none');
  colorButton.style('border-radius', '5px');
  colorButton.style('cursor', 'pointer');
  colorButton.mousePressed(changeBackgroundColor).parent(buttonContainer);
}


// Funktion zum Ändern der Hintergrundfarbe
function changeBackgroundColor() {
  let randomHue = random(360);
  background(randomHue, 150, 100);
}

Sliderwerte in die for-Schleife einfügen

function draw() {
  translate(width / 2, height / 2);
  let sat = slider.value();
  let weight = slider2.value();
  angle = slider3.value();

  for (let i = 0; i < angle; i++) {
    rotate(angle);
    strokeWeight(weight);
    stroke(mouseX, sat, sat, 0.5);
    line(mouseX, mouseY, pmouseX, pmouseY);

    push();
    scale(1, -1);
    line(mouseX, mouseY, pmouseX, pmouseY);
    pop();
  }
}

Jetzt ersetzen wir die Standartwerte, die im ersten Teil des Tutorials festgelegt wurden durch die Werte der Slider die zuvor erstellt wurden.

Über slider.value() wird der Wert für die Sättigung ausgelesen welcher dann in der Stroke-Funktion eingesetzt wird. Das selbe macht man mit slider2.value() und slider3.value() um die Strichstärke und den Winkel in die entsprechenden Funktionen einzusetzen.


Vollständiger Code des Kaleidoskops

let angle;
let slider, slider2, slider3;
let colorButton;

function setup() {
  createCanvas(450, 450);
  background(30);
  colorMode(HSB, 360, 150, 100, 1);

  // Erstelle einen Container für die Einstellungen
  let settingsContainer = createDiv("");
  settingsContainer.style("display", "grid");
  settingsContainer.style("grid-template-rows", "auto auto"); // Zwei Reihen: eine für Überschrift, eine für Slider
  settingsContainer.style("grid-template-columns", "215px 215px"); // Spaltenaufteilung
  settingsContainer.style("grid-gap", "10px"); // Abstand zwischen den Spalten
  settingsContainer.style("padding", "10px"); // Padding für das gesamte Container
  settingsContainer.style("margin-bottom", "10px");
  settingsContainer.style("font-family", "Arial");
  settingsContainer.style("font-size", "10pt");


  // Erstelle Container für jeden Slider und Überschrift
  let satContainer = createDiv("")
    .parent(settingsContainer)
    .style("display", "flex")
    .style("flex-direction", "column");
  
  createP("Sättigung").parent(satContainer).style("color", "black");
  slider = createSlider(100, 255, 170).parent(satContainer);

  let weightContainer = createDiv("")
    .parent(settingsContainer)
    .style("display", "flex")
    .style("flex-direction", "column");
  createP("Strichstärke").parent(weightContainer).style("color", "black");
  slider2 = createSlider(4, 20, 12).parent(weightContainer);

  let angleContainer = createDiv("")
    .parent(settingsContainer)
    .style("display", "flex")
    .style("flex-direction", "column");
  
  createP("Winkel").parent(angleContainer).style("color", "black");
  slider3 = createSlider(5, 23, 12).parent(angleContainer);

  let buttonContainer = createDiv("")
    .parent(settingsContainer)
    .style("display", "flex")
    .style("flex-direction", "column");
  
  colorButton = createButton("Hintergrundfarbe generieren");
  colorButton.style("background-color", "gray");
  colorButton.style("color", "white");
  colorButton.style("font-family", "Arial");
  colorButton.style("padding", "10px 20px");
  colorButton.style("margin-top", "20px");
  colorButton.style("border", "none");
  colorButton.style("border-radius", "5px");
  colorButton.style("cursor", "pointer");
  colorButton.mousePressed(changeBackgroundColor).parent(buttonContainer);
}

function draw() {
  translate(width / 2, height / 2);
  let sat = slider.value();
  let weight = slider2.value();
  angle = slider3.value();

  for (let i = 0; i < angle; i++) {
    rotate(angle);
    strokeWeight(weight);
    stroke(mouseX, sat, sat, 0.5);
    line(mouseX, mouseY, pmouseX, pmouseY);

    push();
    scale(1, -1);
    line(mouseX, mouseY, pmouseX, pmouseY);
    pop();
  }
}

// Funktion zum Ändern der Hintergrundfarbe
function changeBackgroundColor() {
  let randomHue = random(360);
  background(randomHue, 150, 100);
}

Viel Spaß beim Nachmachen!

Hier kannst du den Code direkt im Editor öffnen.

Als Inspiration für dieses Tutorial diente das Video Kaleidoscope - p5.js Tutorial (youtube.com) .


© 0t1

Cookies

0t1 mag keine Kekse (und kein Tracking). Wir verwenden lediglich notwendige Cookies für essentielle Funktionen.

Wir verwenden Schriftarten von Adobe Fonts. Dafür stellt dein Browser eine Verbindung zu den Servern von Adobe in den USA her. Wenn du unsere Seite nutzen möchtest, musst du dich damit einverstanden erklären.

Weitere Informationen in unserer Datenschutzerklärung.