Unterstützung Uhrzeitdarstellung: p5.js / 2020-05-29 / Matthias Edler-Golla, CC BY-SA 4.0


|



 



Hallo!


SVGs importieren

SVG

SVGs lassen sich super in p5.js importieren – und animieren! Achtet beim Importieren auf die relativen Pfadangaben!

Demo

Schaut Euch die Demo an – oder ladet das komplette Paket runter!

p5.js

let arrow;
let compass;
let kreis;
let winkel = 0;

// Vorladen der Bilder
function preload() {
  kreis = loadImage("p/kreis.svg");
  arrow = loadImage("p/arrow.svg");
  stern = loadImage("p/stern.svg");
}

function setup() {
  const meinCanvas = createCanvas(960, 405);
  meinCanvas.parent("canvasContainer");
  frameRate(30);
}

function draw() {
  background(255);

  imageMode(CORNER);
  image(arrow, 10, height / 2 - 30);

  imageMode(CENTER);
  image(kreis, width / 2, height / 2);

  push();
  translate(width / 2, height / 2);
  rotate(radians(winkel));
  image(stern, 150, 0);
  pop();

  push();
  translate(width / 2, height / 2);
  rotate(radians(winkel / 4));
  image(stern, 82, 0);
  pop();

  push();
  translate(width / 2, height / 2);
  rotate(radians(winkel / 2));
  image(stern, 10, 0);
  pop();

  winkel = winkel + 3;
}

Sound abspielen

Alle 15sek wird ein kurzer Sound abgespielt.

Sound Library importieren!

Es muss zusätzlich die Library "p5.sound.min.js" geladen werden – diese befindet sich im Demo-Ordner bei assets>js>p5.sound.min.js

Demo

Schaut Euch die Demo an – oder ladet das komplette Paket runter!

HTML

<!DOCTYPE html>
<html lang="de">
  <head>
    …
  </head>
  <body>
    …
    <!-- p5 liegt auf einem externen Server, gut, solange man mit dem Internet verbunden ist -->
    <script src="https://cdn.jsdelivr.net/npm/p5@1.0.0/lib/p5.min.js"></script>

    <!-- zusätzlich Library zum Abspielen von Sounds! -->
    <script src="./assets/js/p5.sound.min.js"></script>

    <script src="./assets/js/sketch.js"></script>
  </body>
</html>

p5.js

let sekundenSound, winkel, stern;

// ACHTUNG: Es muss zusätzlich die Library "p5.sound.min.js" geladen werden
// siehe Source-Code von index.html
function preload() {
  winkel = radians(270);
  // Vorladen des Sounds
  sekundenSound = loadSound("sound/buttonchime02up.mp3");
  // SVG Vorladen
  stern = loadImage("p/stern.svg");
}

function setup() {
  const meinCanvas = createCanvas(960, 400);
  meinCanvas.parent("canvasContainer");
  frameRate(1);
}

function draw() {
  background(255);

  let sek = second();

  sekundenZeiger(sek);
  soundAbspielen(sek);
  skalaZeichen();
}

function skalaZeichen() {
  noStroke();
  fill("#000");
  ellipse(width / 2, 20, 20);
  fill("#fff");
  ellipse(width / 2, height / 2, 20);
}

function sekundenZeiger(sek) {
  strokeWeight(40);
  stroke("red");

  // rotierender Anzeiger
  push();
  translate(width / 2, height / 2);
  rotate(winkel + radians(sek * 6));
  line(0, 0, height / 2 - 20, 0);
  pop();
}

function soundAbspielen(sek) {
  // Der Sound wird alle 15sek abgespielt
  if (sek == 0 || sek == 15 || sek == 30 || sek == 45) {
    sekundenSound.play();
    // Stern wird nur kurz sichtbar
    sternZeigen();
  }
}

function sternZeigen() {
  image(stern, 0, 0);
}

HSL Farbraum

Der HSL-Farbraum ist intuitiver als der RGB-Farbraum und orientiert sich an den Farbkreis von Itten.

HSL

Hue | Saturation | Lightness
Farbton | Sättigung | Helligkeit

Demo

Schaut Euch die Demo an – oder ladet das komplette Paket runter!

p5.js

// 360° Farbkreis, andere Werte von 0% bis 100%
// letzter Wert für Transparenz, kann auch weggelassen werden
colorMode(HSL, 360, 100, 100, 100);

function hsl_rechteck() {
  // Rechteck mit Farbfüllung im HSL-Modus
  // 360: 360° Farbton im Farbkeis
  // 100: Sättigung
  // 100: Helligkeit
  // 100: Transparenz
  fill(180, 100, 50, 30);

  rect(10, 10, 150, 60);
}

function farbkreis() {
  fill("#000");
  noStroke();
  text("Farbkreis mit Winkelangabe für 'Hue'", 10, 30);

  const xMitte = 300;
  const yMitte = 340;

  // 36 * 10° = 360° (komplette Drehung)
  for (var i = 0; i < 36; i++) {
    push();

    translate(xMitte, yMitte);
    rotate(winkel - radians(90)); // -90 damit rot oben steht

    strokeWeight(22);

    // die sich ändernde Farbe, hier nur "Hue"
    stroke(i * 10, 100, 50, 100);
    line(145, 0, 220, 0);

    fill("rgba(0,0,0,.5)");
    textSize(14);
    noStroke();
    text(`${i * 10}°`, 240, 5);

    pop();

    winkel = winkel + radians(10);
  }
}

HSL Farbraum | interaktiv

Der Sketch fragt die Cursor-Positon ab:

  • vertikal: Hue (Farbwert im Farbkreis)
  • horizontal: Saturation (Farbsättigung)

Die rechte Hälfte zeigt jeweils die komplementäre Farbe zur linken Hälfte

Demo

Schaut Euch die Demo an – oder ladet das komplette Paket runter!

p5.js

function setup() {
  const meinCanvas = createCanvas(960, 500);
  meinCanvas.parent("canvasContainer");

  textSize(260);
  textAlign(CENTER);
  textStyle(BOLD);
  noStroke();
  fill(0);

  // 360° Farbkreis, andere Werte von 0% bis 100%
  // letzter Wert für Transparenz, kann auch weggelassen werden
  colorMode(HSL, 360, 100, 100);

  frameRate(30);
}

function draw() {
  background(255);

  // map "mapped" die mouseY-Pos auf Werte zwischen 0 und 360 (Farbkreis!)
  let farbe = Math.round(map(mouseY, 0, height, 0, 360));
  let saturation = Math.round(map(mouseX, 0, width, 0, 100));

  // komplementaerFarbe ist jeweils um 180° gegenüber im Farbkreis
  let komplementaer;
  if (farbe <= 180) {
    komplementaer = farbe + 180;
  } else {
    komplementaer = farbe - 180;
  }
  // console.log(farbe, komplementaer);

  // linkes Rechteck
  fill(farbe, saturation, 50);
  rect(0, 0, width / 2, height);

  // rechtes Rechteck
  fill(komplementaer, saturation, 50);
  rect(width / 2, 0, width / 2, height);

  // linkter Text
  fill(komplementaer, saturation, 50);
  text(farbe, width / 4, height / 2 + 90);

  // rechter Text
  fill(farbe, saturation, 50);
  text(komplementaer, width / 2 + width / 4, height / 2 + 90);
}

Wachsendes Tortenstück (Arc)

Bei der arc-Funktion kann man verschiedene Modi auswählen:
PIE macht das bekannte Tortendiagramm (links), CHORD füllt die Fläche wie auf der rechten Seite dargestellt…

Demo

Schaut Euch die Demo an – oder ladet das komplette Paket runter!

p5.js

const startPunkt = 270; // 12 Uhr oben, Gradangabe!

function setup() {
  const meinCanvas = createCanvas(960, 480);
  meinCanvas.parent("canvasContainer");

  frameRate(1);
}

function draw() {
  background(255);

  let sek = second();

  // externe Funktion mit vielen übergebenen Werten…
  arcZeichnen(240, height / 2, 450, "red", sek, PIE);

  arcZeichnen(width - 240, height / 2, 450, "hsl(220,70%,70%)", sek, CHORD); //
}

function arcZeichnen(x, y, r, farbe, sek, typ) {
  // console.log(x, y, r, farbe, sek, typ);

  // HG-Kreis zur Orientierung
  stroke("#ddd");
  noFill();
  ellipse(x, y, r + 8); // etwas größer als die eigentliche Fläche

  noStroke();
  fill(farbe);

  // https://p5js.org/reference/#/p5/arc
  arc(
    x,
    y,
    r,
    r,
    radians(startPunkt), //damit kann man hier Grad-Angaben eingeben!
    radians(startPunkt + sek * 6), // 60sek * 6 = 360°
    typ
  );
}

Wachsendes Bogenstück (Arc)

Durch die unterschiedlichen strokeCap-Angaben kann man das Aussehen des Bogenstückes beeinflussen: ROUND rundet den Strich ab, SQUARE lässt ihn präzise enden.

Demo

Schaut Euch die Demo an – oder ladet das komplette Paket runter!

p5.js

const startPunkt = 270; // 12 Uhr oben, Gradangabe!

function setup() {
  const meinCanvas = createCanvas(960, 480);
  meinCanvas.parent("canvasContainer");

  frameRate(1);
}

function draw() {
  background(0);

  let sek = second();

  // externe Funktion mit vielen übergebenen Werten…
  arcZeichnen(240, height / 2, 400, "red", sek, SQUARE);
  arcZeichnen(240, height / 2, 330, "orange", sek, SQUARE);
  arcZeichnen(240, height / 2, 260, "red", sek, SQUARE);
  arcZeichnen(240, height / 2, 190, "orange", sek, SQUARE);
  arcZeichnen(240, height / 2, 120, "red", sek, SQUARE);

  arcZeichnen(width - 240, height / 2, 400, "blue", sek, ROUND);
  arcZeichnen(width - 240, height / 2, 260, "orange", sek, ROUND);
  arcZeichnen(width - 240, height / 2, 120, "blue", sek, ROUND);
}

function arcZeichnen(x, y, r, farbe, sek, typ) {
  // console.log(x, y, r, farbe, sek);

  // HG-Kreis zur Orientierung
  strokeWeight(1);
  stroke("#ddd");
  noFill();
  ellipse(x, y, r + 35); // etwas größer als die eigentliche Fläche
  ellipse(x, y, r - 35); // etwas größer als die eigentliche Fläche

  strokeWeight(28);
  stroke(farbe);
  strokeCap(typ);

  // https://p5js.org/reference/#/p5/arc
  arc(
    x,
    y,
    r,
    r,
    radians(startPunkt), //damit kann man hier Grad-Angaben eingeben!
    radians(startPunkt + sek * 6) // 60sek * 6 = 360°
  );
}

Textausgabe der Zeit

Demo

Schaut Euch die Demo an – oder ladet das komplette Paket runter!

p5.js

let min, stunde;

function setup() {
  const meinCanvas = createCanvas(1050, 565);
  meinCanvas.parent("canvasContainer");

  frameRate(1);
}

function draw() {
  background(0);

  min = minute();
  stunde = hour();

  // zum Testen auskommentieren und verschiedene Minuten- und Stundenwerte eingeben
  // min = 57;
  // stunde = 12;

  // wenn Uhrzeit > 12 ist, 12 abziehen, sonst Stundenstriche doppelt
  if (stunde > 12) {
    stunde = stunde - 12;
  }

  fill("rgba(255,255,255,0.2)");
  textSize(167);
  textLeading(145);
  textStyle(BOLD);
  text(ausgabeTextErzeugen(), -10, -8, width);

  // damit man sieht, dass die Uhr läuft
  sekundenBlink();
}

function ausgabeTextErzeugen() {
  // let anfang = "es ist \n";

  let ausgabe = stundenText() + " UHR " + minutenText();
  return ausgabe;
}

function minutenText() {
  // umwandeln der min in einen String
  // um die Länge abzufragen
  let minString = min.toString();

  let minErsteStelle, minZweiteStelle;

  if (minString.length < 2) {
    // einstellige Minuten
    minErsteStelle = "0"; // besonderer Eintrag, weil hier die 1. Stelle nicht vorhanden ist!
    minZweiteStelle = minString.charAt(0);
  } else {
    minErsteStelle = minString.charAt(0);
    minZweiteStelle = minString.charAt(1);
  }

  // console.log(minErsteStelle, minZweiteStelle);

  // ============== Ausgabe der zweiten Stelle als Text ==============

  let minErsteStelleText;

  switch (minErsteStelle) {
    case "0":
      minErsteStelleText = "NULL";
      break;
    case "1":
      minErsteStelleText = "ZEHN";
      break;
    case "2":
      minErsteStelleText = "ZWANZIG";
      break;
    case "3":
      minErsteStelleText = "DREIZIG";
      break;
    case "4":
      minErsteStelleText = "VIERZIG";
      break;
    case "5":
      minErsteStelleText = "FÜNFZIG";
      break;
    default:
      console.log("Sorry, Fehler!");
  }

  // ============== Ausgabe der zweiten Stelle als Text ==============

  let minZweiteStelleText;

  switch (minZweiteStelle) {
    case "0":
      minZweiteStelleText = "NULL";
      break;
    case "1":
      minZweiteStelleText = "EINS";
      break;
    case "2":
      minZweiteStelleText = "ZWEI";
      break;
    case "3":
      minZweiteStelleText = "DREI";
      break;
    case "4":
      minZweiteStelleText = "VIER";
      break;
    case "5":
      minZweiteStelleText = "FÜNF";
      break;
    case "6":
      minZweiteStelleText = "SECHS";
      break;
    case "7":
      minZweiteStelleText = "SIEBEN";
      break;
    case "8":
      minZweiteStelleText = "ACHT";
      break;
    case "9":
      minZweiteStelleText = "NEUN";
      break;
    default:
      console.log("Sorry, Fehler!");
  }

  // ============= Generieren des richtigen Ausgabetextes =============

  let minuten_Text;
  if (minString.length < 2) {
    minuten_Text = `${minZweiteStelleText}`;
  } else if (minZweiteStelle == 0) {
    minuten_Text = `${minErsteStelleText}`;
  } else if (minErsteStelle == 1 && minZweiteStelle == 1) {
    minuten_Text = "ELF";
  } else if (minErsteStelle == 1 && minZweiteStelle == 2) {
    minuten_Text = "ZWÖLF";
  } else if (minErsteStelle == 1) {
    minuten_Text = `${minZweiteStelleText}${minErsteStelleText}`;
  } else {
    minuten_Text = `${minZweiteStelleText} UND ${minErsteStelleText}`;
  }

  return minuten_Text;
  // console.log(minErsteStelle, minZweiteStelle);
}

function stundenText() {
  let stunden_Text;

  switch (stunde) {
    case 0:
      stunden_Text = "NULL";
      break;
    case 1:
      stunden_Text = "EIN";
      break;
    case 2:
      stunden_Text = "ZWEI";
      break;
    case 3:
      stunden_Text = "DREI";
      break;
    case 4:
      stunden_Text = "VIER";
      break;
    case 5:
      stunden_Text = "FÜNF";
      break;
    case 6:
      stunden_Text = "SECHS";
      break;
    case 7:
      stunden_Text = "SIEBEN";
      break;
    case 8:
      stunden_Text = "ACHT";
      break;
    case 9:
      stunden_Text = "NEUN";
      break;
    case 10:
      stunden_Text = "ZEHN";
      break;
    case 11:
      stunden_Text = "ELF";
      break;
    case 12:
      stunden_Text = "ZWÖLF";
      break;
    default:
      console.log("Sorry,Fehler!");
  }
  return stunden_Text;
}

let sichtbar = 0;
function sekundenBlink() {
  if (sichtbar == 0) {
    sichtbar = 1;
    noStroke();
    fill("hsl(0,60%,40%)");
    rect(width - 25, 0, width - 25, height);
  } else {
    sichtbar = 0;
  }
}

Drehender Minuten-Text

Nach dem Entwurf von Mia Ellerstorfer

Im Code befindet sich auch die Funktion "ausgabeTextErzeugen()": Darin werden die digitalen Minuten-Angaben (z.b. "43") in analoge Minutenangaben (z.B. "Dreiundvierzig") umgewandelt. Das kann bestimmt auch bei anderen Ideen verwendet werden…

Demo

Schaut Euch die Demo an – oder ladet das komplette Paket runter!

p5.js

let xMitte, yMitte;
let r;
let winkel, winkelwert;
let min, stunde;

function setup() {
  const meinCanvas = createCanvas(960, 550);
  meinCanvas.parent("canvasContainer");

  // damit fangen die Striche bei 1 Uhr an
  winkelwert = radians(300);
  winkel = winkelwert;

  xMitte = width / 2;
  yMitte = height / 2;
  r = height / 2 - 15;

  frameRate(1);
}

function draw() {
  background(255);

  ziffernblatt();

  min = minute();
  stunde = hour();

  // zum Testen auskommentieren und verschiedene Minuten- und Stundenwerte eingeben
  // min = 43;
  // stunde = 7;

  // wenn Uhrzeit > 12 ist, 12 abziehen, sonst Stundenstriche doppelt
  if (stunde <= 12) {
  } else {
    stunde = stunde - 12;
  }

  stundenstriche();
  minutenAnzeige();

  // wieder zurücksetzen
  winkel = winkelwert;
}

function ziffernblatt() {
  // einfacher Kreis außenrum
  noFill();
  stroke("hsl(0,0%,97%)");
  strokeWeight(3);
  ellipse(xMitte, yMitte, r * 2);

  // Kreis bei 12 Uhr zur Orientierung
  fill("#CCC");
  noStroke();
  ellipse(xMitte, yMitte - r, 10);
}

function minutenAnzeige() {
  noStroke();

  fill("#000");
  textSize(24);
  textStyle(BOLD);

  push();

  translate(xMitte, yMitte);

  if (stunde <= 6) {
    // 30° Schritte von 12-Uhr-Punkt
    rotate(radians(270 + 30 * stunde));
    textAlign(LEFT);
    text(ausgabeTextErzeugen(), 4, 9);
  } else {
    // 30° Schritte von 6-Uhr-Punkt
    rotate(radians(90 + 30 * stunde));
    textAlign(RIGHT);
    text(ausgabeTextErzeugen(), -4, 9);
  }

  pop();
}

function stundenstriche() {
  noFill();
  stroke("red");
  strokeWeight(10);

  for (var i = 1; i <= stunde; i++) {
    push();

    // in die Mitte verschieben
    // der Drehpunkt liegt hier bei (xMitte, yMitte);
    translate(xMitte, yMitte);
    rotate(winkel);

    line(r - 10, 0, r + 10, 0);

    pop();
    winkel = winkel + radians(30);
    // console.log(winkel);
  }
}

function ausgabeTextErzeugen() {
  // umwandeln der min in einen String
  // um die Länge abzufragen
  let minString = min.toString();

  let minErsteStelle, minZweiteStelle;

  if (minString.length < 2) {
    // einstellige Minuten
    minErsteStelle = "0"; // besonderer Eintrag, weil hier die 1. Stelle nicht vorhanden ist!
    minZweiteStelle = minString.charAt(0);
  } else {
    minErsteStelle = minString.charAt(0);
    minZweiteStelle = minString.charAt(1);
  }

  // console.log(minErsteStelle, minZweiteStelle);

  // ============== Ausgabe der zweiten Stelle als Text ==============

  let minErsteStelleText;

  switch (minErsteStelle) {
    case "0":
      minErsteStelleText = "NULL";
      break;
    case "1":
      minErsteStelleText = "ZEHN";
      break;
    case "2":
      minErsteStelleText = "ZWANZIG";
      break;
    case "3":
      minErsteStelleText = "DREIZIG";
      break;
    case "4":
      minErsteStelleText = "VIERZIG";
      break;
    case "5":
      minErsteStelleText = "FÜNFZIG";
      break;
    default:
      console.log("Sorry, Fehler!");
  }

  // ============== Ausgabe der zweiten Stelle als Text ==============

  let minZweiteStelleText;

  switch (minZweiteStelle) {
    case "0":
      minZweiteStelleText = "NULL";
      break;
    case "1":
      minZweiteStelleText = "EINS";
      break;
    case "2":
      minZweiteStelleText = "ZWEI";
      break;
    case "3":
      minZweiteStelleText = "DREI";
      break;
    case "4":
      minZweiteStelleText = "VIER";
      break;
    case "5":
      minZweiteStelleText = "FÜNF";
      break;
    case "6":
      minZweiteStelleText = "SECHS";
      break;
    case "7":
      minZweiteStelleText = "SIEBEN";
      break;
    case "8":
      minZweiteStelleText = "ACHT";
      break;
    case "9":
      minZweiteStelleText = "NEUN";
      break;
    default:
      console.log("Sorry, Fehler!");
  }

  // ============= Generieren des richtigen Ausgabetextes =============
  let ausgabeText;
  if (minString.length < 2) {
    ausgabeText = `${minZweiteStelleText}`;
  } else if (minZweiteStelle == 0) {
    ausgabeText = `${minErsteStelleText}`;
  } else if (minErsteStelle == 1 && minZweiteStelle == 1) {
    ausgabeText = "ELF";
  } else if (minErsteStelle == 1 && minZweiteStelle == 2) {
    ausgabeText = "ZWÖLF";
  } else if (minErsteStelle == 1) {
    ausgabeText = `${minZweiteStelleText}${minErsteStelleText}`;
  } else {
    ausgabeText = `${minZweiteStelleText}UND${minErsteStelleText}`;
  }

  return ausgabeText;

  // console.log(minErsteStelle, minZweiteStelle);
}

Elemente bei MouseClick zeigen

Das Anklicken von Elementen in p5.js ist ziemlich mühsam. Man muss die Position und Größe der Elemente wissen und diese als Bedingungen bei mousePressed() eingeben…

Demo

Schaut Euch die Demo an – oder ladet das komplette Paket runter!

p5.js

// variable, die festlegt, ob was sichtbar ist oder nicht
// hier erst mal unsichtbar
let sichtbar = 0;

function setup() {
  const meinCanvas = createCanvas(960, 550);
  meinCanvas.parent("canvasContainer");

  frameRate(30);
}

function draw() {
  background(255);

  // das anzuklickende Element zum SichtbarMachen
  fill("blue");
  noStroke();
  rectMode(CORNER);
  rect(0, 0, 300, 80);
  fill("white");
  textSize(50);
  textAlign(CENTER);
  text("ein", 150, 50);

  // das anzuklickende Element zum UnSichtbarMachen
  fill("green");
  noStroke();
  rectMode(CORNER);
  rect(width - 300, 0, 300, 80);
  fill("white");
  textSize(50);
  textAlign(CENTER);
  text("aus", width - 150, 50);

  // das Element, das erst mal unsichtbar ist
  fill("red");
  noStroke();
  rectMode(CENTER);
  if (sichtbar === 1) {
    rect(width / 2, height / 2, 500, 200);
  }
}

function mousePressed() {
  // beachte, die Bereiche entsprechen genau den Flächen der Rechtecke!

  // nur wenn sich der MouseZeiger über dem blauen Element befindet
  // soll das rote Rechteck sichtbar werden
  if (mouseX > 0 && mouseX < 300 && mouseY > 0 && mouseY < 80) {
    sichtbar = 1;
  }

  // nur wenn sich der MouseZeiger über dem grünen Element befindet
  // soll das rote Rechteck wieder sichtbar werden
  if (mouseX > width - 300 && mouseX < width && mouseY > 0 && mouseY < 80) {
    sichtbar = 0;
  }
}

Danke

Weitere Vorträge: