JavaScriptsExperimentelles

dynamic puzzle

Zerlegt ein Bild in ein Raster aus Kacheln, die sich fortlaufend von selbst austauschen — ein Puzzle in ständiger Bewegung.

Mit diesem JavaScript von Peter Dematté könnt ihr aus einem beliebigen Bild ein „lebendes" Puzzle erstellen lassen: Das Script zerschneidet das Bild in ein Raster aus quadratischen Kacheln und tauscht danach in unregelmäßigen Abständen immer wieder einzelne Kacheln aus. Das Bild bleibt also nie stehen, sondern verändert sich fortlaufend von selbst.

Die Demo braucht keine Bedienung — einfach eine Weile zuschauen. Als Vorlage dient hier ein Bild vom Tafelberg; die Bilddatei enthält mehrere quadratische Motive nebeneinander (wie ein Filmstreifen), und das Script mischt nach und nach Kacheln aus allen Motiven in das Puzzle. Jedes Motiv hat dabei seinen eigenen Takt, manche Kacheln landen absichtlich an der falschen Position — so entsteht ein sich ständig wandelndes Mosaik.

Für die eigene Seite gilt: Das Bild muss auf eurem Webspace liegen. In der Voreinstellung erwartet das Script eine Datei namens puzzle.jpg im selben Verzeichnis wie die Seite; über die Variable bild am Scriptanfang könnt ihr aber auch jeden anderen Pfad eintragen. Mit der Variablen grid legt ihr fest, wie fein das Raster sein soll (3 bis 10). Ist euer Bild nicht quadratisch, zeigt das Script nur einen quadratischen Ausschnitt.

Mehr Infos zum Script gibt es (auf Englisch) beim Autor unter dematte.at/puzzle/. Und wenn ihr noch mehr aus unserer Experimentier-Ecke sehen wollt: Auch Anzahl der Wörter Zählen wohnt in dieser Kategorie.

Experimentelles Baujahr 2010 läuft in deinem Browser

Das Puzzle verändert sich von selbst — einfach eine Weile zuschauen.

Script von Peter Dematté

So funktioniert das Script

Das Script ist das anspruchsvollste unserer Experimentier-Ecke, aber es zerfällt in überschaubare Teile: Es lädt das Bild, berechnet daraus Kachelgröße und Motivanzahl, erzeugt per Schleife die Kacheln samt passender CSS-Regeln — und lässt danach mehrere Zeitgeber laufen, die immer wieder einzelne Kacheln austauschen. Die Funktionsweise wurde beim Modernisieren nicht verändert, nur document.write() durch einen festen Container ersetzt und var durch const/let.

const grid = 5;       // Rastergröße (3 bis 10)
const bild = 'puzzle.jpg'; // Pfad zu eurem Bild

Ganz oben stehen die beiden Einstellungen. Sie werden unten an die eigentliche Puzzle-Funktion übergeben — zusammen mit weiteren Parametern wie imageTime (die Taktzeiten in Millisekunden) und scrumble (welche Motive durcheinandergewürfelt werden dürfen).

img.src = image;
img.onload = function () { … };

Das Script legt ein unsichtbares img-Element an und wartet auf dessen onload-Ereignis. Erst wenn das Bild vollständig geladen ist, kennt der Browser nämlich dessen Breite und Höhe — und die braucht das Script für alles Weitere.

const squareXY = Math.floor(img.height / grid);
let pixCount = Math.floor(img.width / img.height);
if (pixCount > 9) pixCount = 9;

squareXY ist die Kantenlänge einer Kachel in Pixeln: Bildhöhe geteilt durch die Rastergröße. pixCount zählt, wie viele quadratische Motive nebeneinander in der Bilddatei stecken — ein quadratisches Bild ergibt 1, ein „Filmstreifen" aus sieben Quadraten ergibt 7 (mehr als 9 werden gekappt). Genau deshalb wirkt die Demo so lebendig: Ihre Bilddatei enthält mehrere Motive, die sich gegenseitig ins Bild mischen.

CSSText.push('.puzzle div{width:' + squareXY + 'px;height:' + squareXY +
  'px;float:left;background-image:url(' + image + ')}');
CSSText.push('.puzzle .c' + k + n + m + '{background-position:-' + … + 'px}');

Die Kacheln sind ein klassischer CSS-Sprite-Trick: Jede Kachel ist ein leeres div, das als Hintergrund das komplette Bild trägt — nur eben per background-position so verschoben, dass genau der richtige Ausschnitt sichtbar ist. Für jede Kombination aus Motiv k, Zeile n und Spalte m erzeugt das Script eine eigene CSS-Klasse namens c<Motiv><Zeile><Spalte>. Alle Regeln werden gesammelt und am Ende als style-Element in den Seitenkopf gehängt.

HTMLText.push('<div class="c' + … + '"></div>');
flaeche.innerHTML = HTMLText.join('');
obj.appendChild(flaeche);

Parallel dazu entsteht für jedes Rasterfeld ein div mit seiner Startklasse — in der Demo starten alle Kacheln mit dem letzten Motiv an der jeweils richtigen Position, sodass zu Beginn ein komplettes Bild zu sehen ist. Der fertige HTML-Text wird in den Container #dynpuzzle eingehängt; im Original erledigte das noch document.write().

function dynPuzzle(pix) {
  const d = Math.floor(Math.random() * grid * grid);
  DIVs[d].className = 'c' + pix +
    (scrumble && scrumble[pix] ? Math.floor(Math.random() * grid) : Math.floor(d / grid)) +
    (scrumble && scrumble[pix] ? Math.floor(Math.random() * grid) : d % grid);
}

Hier passiert der eigentliche Zaubertrick: dynPuzzle() würfelt ein zufälliges Rasterfeld d aus und gibt ihm eine neue Klasse — also einen neuen Bildausschnitt. Steht für das Motiv pix im Array scrumble eine 1, wird auch die Position innerhalb des Motivs zufällig gewählt (die Kachel sitzt dann „falsch"); sonst berechnet sich aus d die korrekte Zeile (Math.floor(d / grid)) und Spalte (d % grid, der Rest der Division).

for (let n = 0; n < pixCount; n++) {
  if (imageTime[n] > 25) setInterval(function () { dynPuzzle(n); }, imageTime[n]);
}

Zum Schluss bekommt jedes Motiv seinen eigenen Zeitgeber: setInterval ruft dynPuzzle für Motiv n immer wieder im Abstand von imageTime[n] Millisekunden auf. Weil jedes Motiv in einem anderen Takt „tropft", entsteht der unregelmäßige, organische Wechsel. Das Original übergab hier noch einen Text an setInterval ('dynPuzzle(' + n + ')') — heute nimmt man dafür eine Funktion, das ist sicherer und schneller.

Zum Anpassen: Mit grid steuert ihr die Rasterfeinheit, mit den Werten im imageTime-Array das Tempo der einzelnen Motive (kleinere Zahl = schnellerer Wechsel; Werte unter 26 schalten das Motiv ab). Setzt ihr im scrumble-Array eine 1 auf 0, landen die Kacheln dieses Motivs immer an der korrekten Position — das Bild „repariert" sich dann mit der Zeit von selbst. Und natürlich lohnt es sich, mit einer eigenen Filmstreifen-Datei aus mehreren quadratischen Motiven zu experimentieren.

Script für die eigene Homepage

Kopiert euch den kompletten Code und fügt ihn an der Stelle eurer Seite ein, an der das Script erscheinen soll. Er läuft ohne weitere Dateien und ohne fremde Server.

Mehr aus der Kategorie Experimentelles