Kategorie-Archiv: Software

Ein einfacher Slider für HTML Seiten

Da ich auf meiner Hauptseite viele Bilder in Galerieform habe, bin ich mit dem Standard-Slider unzufrieden. Er ist nicht einfach zu bedienen und zeigt die Bilder nicht leicht durchblätterbar und in voller Bildschirmgröße an. Ich habe mir deshalb mal einige Slider aus dem Internet angesehen und habe nicht das richtige gefunden. Zum einen arbeiten einige Slider nicht sauber mit dem Firefox Browser zusammen. Insbesondere die reinen CSS Slider machen so viele Verrenkungen, dass es mich nicht wundert, das es an allen Ecken und Kanten hakt. Ich denke, dass einige Web Entwickler nur noch auf Chrome testen. Zum anderen muss man bei fast allen Slidern die html Seite anpassen. Ich habe keinen generischen Slider gesehen, der über Parameter gesteuert werden kann.

Im Nachhinein muss ich erkennen, dass ich länger nach einem brauchbaren Slider gesucht habe als die Eigenentwicklung Zeit gekostet hat. Wichtig für mich war, dass der Slider die Bilder aus dem WordPress Media Pool anzeigen kann, er sollte nicht für jede Galerie eine eigene Web Seite benötigen und er sollte per Maus und Tastatur gesteuert werden können. Und das Wichtigste: er sollte die Bilder in voller Größe anzeigen. Ein reiner CSS Slider war für mich hingegen nicht erstrebenswert. Wegen der Parametrisierbarkeit benötige ich ohnehin JavaScript. Ein einfacher CSS Aufbau hingegen ist ein echter Vorteil.

Das komplette Projekt besteht nur aus einer Datei, sie kann von meinem Github Repository herunter geladen werden: https://github.com/Matthias-Thiele/HTML-Image-Slider

Der Grundgedanke beruht wie bei vielen Slidern darauf, dass die Bilder übereinander gestapelt werden und immer nur ein Bild angezeigt wird. Das kann man über CSS leicht mit „display: none;“ steuern. Der Image Bereich ist bei mir zum Start leer, er wird beim Aufruf der Seite aus der Parameterliste heraus gefüllt.

          <div id="imagelist">
          </div>

Der JavaScript Code dazu ist überschaubar. Die Bilder können entweder durchnummeriert kommen oder mit einem beschreibenden Namen. Es wird ein IMG Element erzeugt, der Pfad zum Bild eingefügt und das Element in die imagelist eingehangen.

for (var i = imgStart; i <= imgEnd; i++) {
        var img = document.createElement("img");
        var imgSrc;

        if (descriptionName) {
            imgSrc = this.startPath + imgName + this.description[i] + "." + imgExt;
        } else {
            var num = (i < 10) ? (pendingZero + i) : i;
            imgSrc = this.startPath + imgName + num + "." + imgExt;
        }

        img.src = imgSrc;
        if (i === imgStart) {
            img.className = "active";
        }
        listRoot.appendChild(img);
        this.items.push(img);
    }

Die Statuszeile überlagert halb-transparent den unteren Bildteil. Vielleicht erweitere ich es später mal so, dass man sie auch ausblenden kann. In den meisten Fällen wird sie aber nicht stören.

          <nav class="slider-nav">
              <button class="previous" data-key="true" style="width:52%; text-align: right">
              <span>
                  <i>&lt;</i>
              </span>
            </button>
            <button class="next" data-key="false" style="text-align: left">
              <span>
                <i>&gt;</i>
              </span>
            </button>
              <span id="counter" style="float:right; width: 100pt; padding: 2pt;">1/6</span>
          </nav>
        </div>

Die Bild-Weiterschaltung läuft im Kreis. Wenn man am letzten Bild angekommen wird, wird als nächstes das erste Bild angezeigt und umgekehrt. Damit man die Orientierung nicht verliert und X-mal im Kreis läuft, wird in der Statuszeile angezeigt, wie viele Bilder es gibt und auf welchem Bild man gerade steht.

            Slider.prototype.advance = function(leftRight) {
                this.items[this.count].classList.remove('active');
                this.count += (leftRight) ? -1 : 1;
                
                if (this.count < 0) {
                    this.count = this.items.length -1;
                } else if (this.count >= this.items.length) {
                    this.count = 0;
                }
                
                this.items[this.count].classList.add('active');
                this.updateView();
            };
            
            Slider.prototype.updateView = function() {    
                var status = document.getElementById("counter");
                status.innerText = " " + (this.count + 1) + " / " + this.items.length; 
                
                var desc = document.getElementById("description");
                if (this.count >= this.description.lengt || !this.description[this.count]) {
                    desc.style = "display: none";
                } else {
                    desc.innerText = this.description[this.count];
                    desc.style = "display: inline-block";
                }
            };

Die Tastatursteuerung ist einfach. Es gibt nur zwei Kommandos – vorwärts und zurück. Diese können über Pfeil links/ rechts und über Bild hoch/ runter ausgelöst werden.

            Slider.prototype.keyPress = function(event) {
                event = event || window.event;
                var slider = document.querySelector('.next').slider;
                var keyCode = event.keyCode;
                
                if (keyCode === 33 || keyCode === 37) {
                  slider.advance(true);
                } else if (keyCode === 34 || keyCode === 39) {
                  slider.advance(false);
                }
            };

Die HTML Datei enthält keine Informationen zu den Bildern. Diese wird beim Aufruf der Seite über Parameter mitgegeben. Somit kann man die Seite irgendwo hinterlegen und aus beliebigen Anwendungen heraus aufrufen. Innerhalb der Web Seite kann man optional den Start des Pfades der Quelle hinterlegen. Damit kann man erzwingen, dass ein bestimmter Bereich nicht einfach verlassen werden kann und zusätzlich ist dann der Parametersatz etwas kürzer, da dieser Teil nicht jedes mal mit angegeben werden muss.

            var slider = new Slider("imagelist", "https://mmth.de/wp-content/uploads/");

Der erste Parameter gibt die id des DIV Elements an welches die Imageliste enthalten soll und der zweite Parameter den Start der URL jedes Bildes. Man kann diesen auch auf einen Leerstring setzen (nicht einfach weglassen).

http://localhost:8080/SliderTest/slider.html?name=2023/09/&ext=jpg&desc=Mainau1~Mainau2~Mainau3~Mainau5

Folgende Parameter gibt es:

nameEnthält den festen Namensanteil des Bildes. Bei durchnummerierten Bildern wird die Nummer am Ende automatisch angefügt. Falls der Startpfad aus der html Datei noch um Unterverzeichnisse ergänzt werden muss, kommen diese hier vor den Namen. Bei Bildern deren Name aus der Beschreibung generiert wird, kann man hier den Verzeichnispfad hinterlegen.name=Mainau
name=2023/Mainau
startBei durchnummerierten Bilder wird hier die Nummer des ersten Bilds angegeben. Im Normalfall wird das 1 sein, das muss aber nicht zwingend so sein. Wenn man nur eine Teilsequenz anzeigen möchte, kann man hier auch eine höhere Zahl angeben.
Falls die Bilder nicht Bild1, Bild2, .., Bild9, Bild10 durchnummeriert sind, sondern mit fester Nummernbreite Bild01, Bild 02, .., Bild09, Bild10 bezeichnet wurden, muss man beim Startwert auch eine führende 0 einfügen: start=01
start=1
endHier wird die Nummer des letzten Bildes eingetragenend=5
extAlle Bilddateien müssen vom gleichen Typ sein, da man nur eine Extension (ohne Punkt) angeben kann. Der Name setzt sich dann aus Startpfad + Name + Nummer + Punkt + Extension zusammen.ext=jpg
descBei durchnummerierten Bildern ist der Beschreibungsteil optional. Wenn er vorhanden ist, wird die Beschreibung zu jedem Bild oben links eingeblendet. Bei Bilddateinamen aus der Beschreibung muss dieser Parameter eine Liste aller Namen der Bilddateien enthalten.desc=Haus~Auto~Boot

Test eines einfachen Ultraschall Sensors für 80 Cent

In diesem Video teste ich einen einfachen Ultraschallsensor, der bei Aliexpress gerade mal 80 Cent kostet. Die Ansteuerung ist sehr einfach und schnell (wenn man keine unnötigen Fehler macht) und die Ergebnisse sind erstaunlich gut.

#include <Arduino.h>

const int TRIG_PIN = 12;
const int ECHO_PIN = 13;
const int ITEM_COUNT = 50;

long simpleMultiMeasure();

void setup() {
  Serial.begin(9600);
  pinMode(TRIG_PIN,OUTPUT);
  digitalWrite(TRIG_PIN, LOW);

  pinMode(ECHO_PIN,INPUT);
}

void loop() {
  long duration = simpleMultiMeasure();
  long distanceMm;
 
  // convert the time into a distance
  distanceMm = duration * 100l / 582l;
 
  if (distanceMm <= 0)
  {
    Serial.println("Out of range");
  }
  else 
  {
    Serial.print(duration);
    Serial.print(" ticks, ");
    Serial.print(distanceMm);
    Serial.print(" mm");
    Serial.println();
  }
  
  delay(500);
}

long simpleMultiMeasure() {
  long sum = 0;

  for (int i = 0; i < ITEM_COUNT; i++) {
    digitalWrite(TRIG_PIN, HIGH);
    delayMicroseconds(20);
    digitalWrite(TRIG_PIN, LOW);
    sum += pulseIn(ECHO_PIN,HIGH);
    delayMicroseconds(20000);
  }

  return sum / ITEM_COUNT;
}


Ein RISC-V Test mit dem Sipeed Longan Nano Board

Ich wollte schon lange mal mit einem RISC-V Prozessor experimentieren. Mit dem Longan Nano Board für 2,50 Euro steht in Development Board zur Verfügung bei dem man nicht lange nachdenken muss. Für ein Euro Aufpreis bekommt man noch ein farbiges LCD dazu.

Falls jemand an dem winzigen Assembler Programm aus dem Video interessiert ist, kann man es hier kopieren:

.section .text
.align 2
.global toggle

.equ GPIO_PORT_B_CONTROL, 0x40010c10
.equ SET_ALL_BITS, 0x0000ffff
.equ RESET_ALL_BITS, 0xffff0000


toggle:
  li t0, GPIO_PORT_B_CONTROL
  li t1, SET_ALL_BITS
  li t2, RESET_ALL_BITS

loop:
  sw t1, (t0)
  sw t2, (t0)
  sw t1, (t0)
  sw t2, (t0)
  j loop

Startbild: RISC V prototype chip – crop of File:Yunsup Lee holding RISC V prototype chip.jpg. Wikimedia, Creative-Commons-Lizenz „CC0 1.0 Verzicht auf das Copyright“

Ein computergesteuerter Messplatz mit einem ESP 32, Teil 2

In diesem zweiten Teil wird die Software zu dem Projekt beschrieben. Sie besteht aus drei Teilen.

  1. Ein Platform IO Projekt mit einem C++ Programm welches auf dem ESP32 läuft.
  2. Ein Netbeans Projekt in Java welches auf dem PC ein Framework zur Verwendung des Messplatzes zur Verfügung stellt. Weiterhin enthält es einen komfortablen Weg zur Erstellung von CSV (comma separated values) Dateien.
  3. Ein Netbeans Projekt welches die Verwendung der DataIO jar Datei zeigt.

Touchsensor TTP223 Test

Ich wollte mal ausprobieren, ob sich die Touchsensoren für den Aufbau von Stellpulten eignen. Die Verwendung ist einfach und sie funktionieren gut, es gibt aber auch ein paar Schattenseiten.

#define TOUCH_INPUT 2
#define SIGNAL 3
#define SETTLE_TIME 100

void setup() {
pinMode( TOUCH_INPUT, INPUT );
pinMode( SIGNAL, OUTPUT );
}

void loop() {
int isTriggered = digitalRead( TOUCH_INPUT );
digitalWrite( SIGNAL, switchState( isTriggered ) );
}

boolean actState = false;
boolean lastActive = false;
boolean switchState( boolean signal ) {
boolean deb = debounce( signal );
if ( deb ) {
if ( !lastActive ) {
lastActive = true;
actState = !actState;
}
} else {
lastActive = false;
}

return actState;
}

int trig = 0;
boolean debounce( boolean signal ) {
if ( signal ) {
if (trig == 0) {
trig = millis();
} else {
int now = millis();
if ( now – trig > SETTLE_TIME ) {
return true;
}
}
} else {
trig = 0;
}

return false;
}

Ein kleines JavaScript Spielprogramm

In der letzten Woche habe ich durch Zufall ein JavaScript Spielprogramm gefunden. Die Spielidee ist einfach: es gibt ein Array von verschieden farbigen Kacheln. Der Anwender kann diese paarweise auswählen – was dazu führt, dass die beiden Kacheln vertauscht werden. Dabei können aber nur direkt benachbarte Kacheln getauscht werden. Wenn es mehr als 3 zusammenhängende gleichfarbige Kacheln in einer Zeile oder Spalte gibt, war der Spielzug gültig und es werden einem Punkte dafür gut geschrieben.

Das Original war mit einer recht kurzen Zeitschranke versehen. Ich wollte aber wissen, ob das Spiel zwingend irgendwann zum Ende kommt, weil es keine weiteren Kombinationen mehr gibt, die durch einen einfachen Austausch zu erreichen wären. Mein erster Versuch dazu war, dass ich im Browser versucht habe, den Timer stillzulegen. Das Programm hat sich aber gegen Veränderungen gewehrt, deshalb habe ich mich entschlossen, es gleich nachzuprogrammieren.

Meine Version hat keine Zeitbeschränkung und zudem auch eine Hilfefunktion. Wenn man an einem Punkt nicht weiter weiß, kann man sich über eine Tipp Funktion eine Möglichkeit markieren lassen – falls es noch eine gibt. Ich habe noch nicht beobachtet, dass die Tipp-Funktion eine Möglichkeit übersehen hat. Schon nach kurzer Zeit hat sich gezeigt, dass es im Allgemeinen ein Ende gibt. Manchmal schon nach 200 Spielzügen. Ich habe aber auch schon 1500 Spielzüge überstanden, ohne dass ein Ende absehbar war. Ich gehe aber davon aus, dass sich jedes Spiel irgendwann in einer Situation befindet, in dem es keine weiteren gültigen Spielzüge mehr gibt.

Das Spiel ist komplett in html / CSS / JavaScript programmiert. Es gibt noch nicht mal eine Image Datei. Es wird auch kein Framework, wie z.B. JQuery, verwendet. Ich wollte auch mal ausprobieren, wie gut man zu Fuß mit Animationen zurecht kommt. Das eine oder andere könnte man mit CSS Animationen noch besser machen. Für mich war der aktuelle Stand aber gut genug.

Die Animationen, wie z.B. das Verschieben der Kacheln sowie ein- und ausblenden des Hilfe-Dialogs werden über Timer-Callback Funktionen durchgeführt. Das Skript ist relativ kurz und hat deshalb nur drei Klassen: das Spiel-Objekt, das Gitternetz im Spiel und ein Kachel-Objekt. Insgesamt etwa 100 Zeilen CSS für die Formatierung und 600 Zeilen JavaScript für die Spielausführung.

THM-Flip: hier geht’s zum Spiel

ThmFlip