Komplexe Zeichenfläche in p5.js
Dieses Tutorial zeigt, wie man eine Zeichenfläche in p5.js aufbaut und verschiedene Einstellmöglichkeiten bezüglich der ‘Werkzeuge’ vornimmt. Dabei wird erläutert, wie man diese implementiert und individualisiert.
1. Voreinstellungen
Software
Eine Möglichkeit eine p5.js Datei zu erstellen ist mithilfe des Webeditors unter https://editor.p5js.org/. Dort kann man direkt im Webbrowser arbeiten und den geschriebenen Code gleichzeitig auf der gleichen Seite ausgeben lassen. Durch Erstellen eines Accounts ist es auch möglich, die einzelnen Projekte abzuspeichern.
Der Webeditor hat den Vorteil, dass einem Hinweise auf mögliche Fehler angezeigt werden.
Eine weitere Möglichkeit ist es, mit dem Programm Visual Studio Code zu arbeiten, welche auch für das Tutorial angewandt wird.
Erste Schritte
HTML-Datei
P5 ist für das Web ausgelegt und dadruch benötigen wir eine HTML-Datei, welche eine Webseite erstellt und auf die p5 Datei zugreift.
Man öffnet einen neuen Ordner in VS-Code und erzeugt eine neue Datei unter dem Namen "index.html", welche wie folgt aufgebaut ist:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Drawing App</title>
<script src="https://cdn.jsdelivr.net/npm/p5@1.6.0/lib/p5.js"></script>
<script src="script.js"></script>
</head>
<body>
</body>
</html>
.js-Datei
Anschließend wird eine Java-Script Datei mit dem Namen "script.js" erstellt, welche schon in der vorherigen HTML-Datei verknüpft wurde. In dieser Datei werden die gesamten p5.js Anweisungen geschrieben.
Zunächst wird die Grundstruktur von p5.js aufgebaut, welche aus den beiden Funktionen funktion setup() und der Funktion function draw() besteht.
Die Setup-Funktion wird nur einmal aufgerufen und wie der Name schon verrät, werden hier verschiedene Einstellungen wie die Größe der Zeichenfläche, die Hintergrundfarbe usw. definiert.
Die Draw-Funktion wird direkt nach der Setup-Funktion aufgerufen und führt den darin enthaltenen Code, solange aus, bis das Programm gestoppt wird.
function setup() {
createCanvas(400, 400);
}
function draw() {
background(220);
}
2. Grundstruktur des Zeichnenprogramms
Line Objekt erstellen
In den zweiten Schritt erstellen wir unsere Grundstruktur für das Zeichnenprogramm.
Zuerst wird eine neue .js Datei erstellt. In diesem wird ein "MyLine" Objekt für die gezeichneten Linien aufgebaut. Diese Datei muss auch im Head der HTML-Datei verknüpft werden.
Das Objekt hat 4 Parameter. Die aktuellen Mauspositionen - x und y - und damit die Linien richtig gezeichnet werden, brauchen wir auch die vorherigen Mauspositionen - px und py - diese Parameter sind schon im p5.js definiert so wir können sie gleich benutzen.
class MyLine{
constructor(){
this.px = pwinMouseX
this.py = pwinMouseY
this.x = winMouseX
this.y = winMouseY
}
Dann erstellen wir eine Methode, die die gezeichneten Linien auf dem Canvas zeigt.
show{
stroke(255)
line(this.px, this.py, this.x, this.y)
}
Array für die Linien erstellen
Als nächstens erstellen wir ein leeres Array in dem die Linien gespeichert werden, wenn man zeichnet. Zudem machen wir in der Funktion Draw eine MouseIsPressed Event, damit die Linien im Array eingefügt und gespeichert werden.
Das ist notwendig, weil wie schon vorher gesagt die "draw" Funktion wird solange ausgeführt bis das Programm gestoppt ist. Deshalb müssen wir die gezeichnete Linien speichern, damit die nicht immer wieder gelöscht werden bei der aufrufen der "draw" Funktion.
var lines = []
if(mouseIsPressed){
var line = new MyLine()
lines.push(line)
}
for (var line of lines) {
line.show()
}
Dann rufen wir die erstellte "show" Methode auf den Linien, damit diese im Canvas angezeigt werden.
for (var line of lines) {
line.show()
}
3. Werkzeuge erstellen
Auswählbare Stiftfarbe mit zusätzlicher "Rainbow"-Option
function setup(){
createP('Pen Color').parent(optionsTitles)
}
Eine am Anfang des Codes initiierte Variable: var penColor
, wird hierfür benötigt.
function setup(){
penColor = createColorPicker('ffffff').parent(optionsValues)
penRandom = createCheckbox("", false).parent(optionsValues).style('display:inline')
}
In einem weiteren Schritt, wird in diesem Screenshot gezeigt, wie die Option "Stiftfarbe" zu den Werkzeugen der Zeichenfläche hinzugefügt wird.
Auch wird eine Option generiert, um mithilfe einer Checkbox die "Rainbowstift"-Option zu aktivieren.
function draw(){
if(penRandom.checked()){
var r = hex(floor(map(noise(frameCount / 100 + 1000),0,1,0,255)),2) // noise function creates random values
var g = hex(floor(map(noise(frameCount / 100 + 3000),0,1,0,255)),2)
var b = hex(floor(map(noise(frameCount / 100 + 4000),0,1,0,255)),2)
//creates rgb values
penColor.value('#' + r + g + b)
}
if(mouseIsPressed){
var line = new MyLine(penColor.value(), penWidth.value(), penShape.value())
lines.push(line)
}
}
Als Nächstes wird mithilfe eines if-Satzes innerhalb der Draw-Funktion definiert, was ausgeführt, wenn die Rainbow-Funktion in der Auswahl bestätigt ist: die r,g,b-Werte für die Stiftfarbe werden mithilfe einer Noise-function zufällig generiert.
Zusätzlich muss die Variable innerhalb der class: "MyLine" aufgerufen werden, um dem Objekt diese Funktion hinzuzufügen.
class MyLine{
constructor(penColor, penWidth, penShape){
this.px = pwinMouseX
this.py = pwinMouseY
this.x = winMouseX
this.y = winMouseY
this.penShape = penShape
this.penColor = penColor
this.penWidth = penWidth
}
show(){ //method that shows the lines
if(this.penShape === 'Line' ){
stroke(this.penColor)
strokeWeight(this.penWidth)
line(this.px, this.py, this.x, this.y)
}
if(this.penShape === 'Circle' ){
fill(this.penColor)
noStroke()
ellipse(this.x, this.y, this.penWidth)
}
if(this.penShape === 'Rectangle'){
fill(this.penColor)
noStroke()
rect(this.x, this.y, this.penWidth)
}
}
}
Zu sehen ist in diesem Screenshot das fertige Fenster für die Farbauswahl, welches einem angezeigt wird.
Sowie der Rainbow-Effekt in Aktion.
Auswählbare Stiftgröße
Mithilfe einer am Anfang des Codes initiierten Variable: var penWidth
, wird in der Werkzeugleiste die Option eines Sliders zur Stiftgrößenauswahl eingefügt.
"createSlider" kreiert bereits den gewünschten Effekt mit individuell festgelegten Auswahlwerten.
function setup(){
penWidth = createSlider(1, 50, 2).parent(optionsValues).style('margin-top: 15px; width: 90px')
}
Innerhalb der "Draw-Funktion" wird die Stiftgrößen variable an dieser Stelle benötigt, um der gezeichneten Linie ihren gewünschten Größenwert zu diktieren.
function draw(){
if(mouseIsPressed){
var line = new MyLine(penColor.value(), penWidth.value(), penShape.value())
lines.push(line)
}
}
Zusätzlich muss die Variable innerhalb der class: "MyLine" aufgerufen werden, um dem Objekt diese Funktion hinzuzufügen.
class MyLine{ //object for the line
constructor(penColor, penWidth, penShape){
this.px = pwinMouseX
this.py = pwinMouseY
this.x = winMouseX
this.y = winMouseY
this.penShape = penShape
this.penColor = penColor
this.penWidth = penWidth
}
show(){ //method that shows the lines
if(this.penShape === 'Line' ){
stroke(this.penColor)
strokeWeight(this.penWidth)
line(this.px, this.py, this.x, this.y)
}
if(this.penShape === 'Circle' ){
fill(this.penColor)
noStroke()
ellipse(this.x, this.y, this.penWidth)
}
if(this.penShape === 'Rectangle'){
fill(this.penColor)
noStroke()
rect(this.x, this.y, this.penWidth)
}
}
}
Auswählbare Hintergrundfarbe
Mithilfe einer am Anfang des Codes initiierten Variable: var bgColor
, wird in der Werkzeugleiste die Option für eine Auswahl der Hintergrundfarbe für die Zeichenfläche definiert.
var bgColor
function setup(){
bgColor = createColorPicker('#1e1e1e').parent(optionsValues).style('margin-top: 10px')
}
Anschließend wird diese an der richtigen Stelle innerhalb der "Draw-Funktion" aufgerufen, um ihren Wert zu übergeben.
function draw(){
background(bgColor.value())
}
Auswählbare Stiftform
Für die Umsetzung dieses Werkzeuges wird zunächst die Variable: var penShape
, benötigt und in der setup-Funktion, wird eine Auswahlmöglichkeit erzeugt. Wir verwenden im Beispiel die Formen: Linie, Kreis, Quadrat.
var penShape
function setup(){
penShape = createSelect(false).parent(optionsValues).style('margin-top:20px')
penShape.option('Line')
penShape.option('Circle')
penShape.option('Rectangle')
}
Anschließend wird diese in der "Draw-Funktion" aufgerufen, um ihren Wert zu übergeben.
function draw(){
if(mouseIsPressed){
var line = new MyLine(penColor.value(), penWidth.value(), penShape.value())
lines.push(line)
}
}
Zusätzlich muss die Variable innerhalb der class: "MyLine" aufgerufen werden, um dem Objekt diese Funktion hinzuzufügen.
class MyLine{ //object for the line
constructor(penColor, penWidth, penShape){
this.px = pwinMouseX // to not skip lines dual buffer rendering
this.py = pwinMouseY
this.x = winMouseX
this.y = winMouseY
this.penShape = penShape
this.penColor = penColor
this.penWidth = penWidth
}
show(){ //method that shows the lines
if(this.penShape === 'Line' ){
stroke(this.penColor)
strokeWeight(this.penWidth)
line(this.px, this.py, this.x, this.y)
}
if(this.penShape === 'Circle' ){
fill(this.penColor)
noStroke()
ellipse(this.x, this.y, this.penWidth)
}
if(this.penShape === 'Rectangle'){
fill(this.penColor)
noStroke()
rect(this.x, this.y, this.penWidth)
}
}
}
4. Buttons hinzufügen
Variabeln deklarieren
Um ein Button zu erstellen, muss man zunächst eine Variable dafür oberhalb der setup-funktion deklarieren. In diesem Fall benötigt man ein Button, um die Zeichenfläche zu leeren, also um einmal alles zu löschen und um das gezeichnete Bild speichern zu können. Darum wird einmal der Button „var clearBut“ zum Löschen und „var saveBut“ zum Speichern deklariert.
var clearBut;
var saveBut;
Button erstellen
Um dem Button ein Aussehen zu verleihen, wird in der Setupfunktion folgender Code geschrieben:
clearBut = createButton('Clear').parent(options).style('width:100px')
Dadurch wurde ein Button der Variable 'clearBut' zugewiesen, mit Clear bezeichnet und besitzt eine Breite von 100px. Außerdem enthält der Button dieselben Anweisungen wie die Variable 'options'.
Das Gleiche wird für den Speichern-Button gemacht. Dafür wird der Code:
clearBut = createButton('Save').parent(options).style('width:100px')
function setup(){
clearBut = createButton('Clear').parent(options).style('width: 100px')
saveBut = createButton('Save').parent(options).style('width: 100px')
}
Dem Button eine Funktion geben
Damit ein Button auch eine Funktion hat, muss diese in der Draw-Funktion beschrieben werden.
Für den Clear Button wird dafür folgendes geschrieben:
function draw(){
clearBut.mousePressed(function(){
lines = []}
)
}
Dadurch wird, wenn man auf den Button mit der Maus klickt, der Variable 'lines' ein leeres Array zugewiesen und somit alle vorher gespeicherten Linien gelöscht.
Damit der Save-Button beim Daraufklicken die Zeichenfläche unter einem Namen und als JPG-Datei speichert, muss dies auch als Funktion der Variable 'saveBut' in der draw-Funktion erfolgen. Dafür schreibt man wie folgt:
saveBut.mousePressed(function(){
saveCanvas('myCanvas', 'jpg');
}
)
Asset-Download
Die Assets, die in diesem Tutorial entstanden sind, kannst du hier herunterladen:
Asset-Download