Galileo Computing < openbook >
Galileo Computing - Professionelle Buecher. Auch fuer Einsteiger.
Galileo Computing - Professionelle Buecher. Auch fuer Einsteiger.


Kompendium der Informationstechnik
 von Sascha Kersken
EDV-Grundlagen, Programmierung, Mediengestaltung
Buch: Kompendium der Informationstechnik
gp Kapitel 19 JavaScript
  gp 19.1 JavaScript-Einführung
  gp 19.2 JavaScript im HTML-Dokument
    gp 19.2.1 Erstes Beispiel: Ausgabe ins Dokument
  gp 19.3 Formulare und Event-Handler
    gp 19.3.1 Zugriff auf Formulare und ihre Elemente
    gp 19.3.2 Neufassung des Rechners mit einem Formular
    gp 19.3.3 Die Hintergrundfarbe dynamisch ändern
    gp 19.3.4 Formularauswertung
  gp 19.4 Datums- und Uhrzeit-Funktionen
    gp 19.4.1 Datums- und Uhrzeit-Methoden
    gp 19.4.2 Das Timeout – die JavaScript-»Stoppuhr«
    gp 19.4.3 Ein ausführliches Beispiel
  gp 19.5 Manipulation von Bildern
    gp 19.5.1 Erstes Beispiel: Austauschen eines Bildes auf Knopfdruck
    gp 19.5.2 Vorausladen von Bildern
    gp 19.5.3 Eine gut funktionierende Rollover-Lösung
    gp 19.5.4 Weitere Beispiele
  gp 19.6 Browser- und Fenster-Optionen
    gp 19.6.1 Browser-Eigenschaften
    gp 19.6.2 Automatische Hyperlinks – History und Location
  gp 19.7 DHTML und die Objektmodelle der Browser
    gp 19.7.1 W3C-DOM
    gp 19.7.2 Das klassische Internet-Explorer-Modell
    gp 19.7.3 Das klassische Netscape-Modell
    gp 19.7.4 Browserübergreifende Lösungen
  gp 19.8 Zusammenfassung

gp

Prüfungsfragen zu diesem Kapitel (extern)


Galileo Computing

19.5 Manipulation von Bildern  downtop

Ein Bildobjekt im HTML-Dokument kann mit Hilfe von klassischem JavaScript nicht geändert werden: Die Position, die Anzeigegröße auf der Seite und der visuelle Inhalt eines bestimmten Bildes sind vordefiniert. Es besteht jedoch die Möglichkeit, an der Position, an der ein Bild angezeigt wird, nachträglich ein anderes anzuzeigen: Für JavaScript ist ein Bildobjekt eine Anzeigeposition für Bilder im Dokument; die wichtigste Eigenschaft – die Quell-URL src – kann nachträglich geändert werden.

Alle Bilder im Dokument befinden sich in dem Array document.images[]. Jedes Bild kann entsprechend durch seine Position im Dokument angesprochen werden:

document.images[0]  // erstes Bild im Dokument
document.images[7]  // achtes Bild im Dokument usw.

Benannte Bilder

Alternativ ist es möglich, einem Bild einen Namen zu geben. Dafür müssen Sie zu dem HTML-Tag <img> das Attribut name="Bildname" hinzufügen. Wie bei Formularen entstehen dadurch zwei weitere Zugriffsmöglichkeiten:

gp  Der Bildname als Objektbezeichner: document.Bildname
gp  Der Bildname als Hash-Index: document.images ["Bildname"]

Die Eigenschaft eines Bildes, die geändert wird, um ein anderes Bild an die entsprechende Stelle zu setzen, ist Bildobjekt.src – der neue Wert muss eine gültige URL sein.


Galileo Computing

19.5.1 Erstes Beispiel: Austauschen eines Bildes auf Knopfdruck  downtop

Auf einer Seite wird das 100 x 40 Pixel große Bild vorher.gif angezeigt. Bei Klick auf einen daneben stehenden Link wird es durch das Bild nachher.gif ersetzt.

JavaScript-Hyperlinks

Die einfachste Art, einen Hyperlink mit dem Aufruf von JavaScript zu beauftragen, besteht in der Verwendung einer "javascript:"-Pseudo-URL:

Es wird also nicht das (ebenfalls funktionierende)

<a href="#" onclick="tuWas();">Los!</a>

verwendet, sondern die einfachere Form:

<a href="javascript:tuWas();">Los!</a>

Der fertige HTML-Code im Body sieht folgendermaßen aus:

<img src="vorher.gif" name="bild" width="100" height="40" 
alt="Das Wechselbild" />
<a href="javascript:wechsel();">&Auml;ndern!</a>

Die im Head definierte Funktion wechsel lautet so:

function wechsel()
{
      document.images[0].src = "nachher.gif";
}

Die eigentliche Bildwechselanweisung

document.images[0].src = "nachher.gif";

funktioniert in dieser Schreibweise allerdings nur dann, wenn es sich bei dem auszutauschenden Bild um das erste auf der Seite handelt. Sicherer sind die Schreibweisen

document.bild.src = "nachher.gif";

oder

document.images["bild"].src = "nachher.gif";

– wie Sie oben im HTML-Code sehen, wurde dem Bild das name-Attribut mit dem Wert "bild" zugewiesen.

Rollover-Effekte

Um daraus ein einfaches Rollover zu basteln, können Sie den separaten Hyperlink weglassen und stattdessen das Bild selbst als Hyperlink verwenden. Die beiden Event-Handler onmouseover und onmouseout sorgen dafür, dass ein Link für Mausberührungen empfindlich wird.

Diese beiden Event-Handler rufen die selbst definierten Funktionen rollover() und rollout() auf:

function rollover()
{
   document.bild.src = "nachher.gif";
}
 
function rollout()
{
   document.bild.src = "vorher.gif";
}

Im HTML-Body wird folgender Link- und Bild-Code notiert:

<a href="#" onmouseover="rollover();" onmouseout="rollout();">
<img src="vorher.gif" name="bild" width="100" height="40" 
alt="Rollover-Bild" border="0" /></a>

Galileo Computing

19.5.2 Vorausladen von Bildern  downtop

Ein großes Problem bei den bisherigen Rollover-Lösungen besteht darin, dass das Austauschbild erst dann geladen wird, wenn der Mauszeiger das ursprüngliche Bild berührt, sodass sich eine zu große Verzögerung ergibt.

Die Lösung besteht darin, dass Bilder mit Hilfe von JavaScript vorausgeladen werden können. Sie können also geladen werden, obwohl sie nicht im HTML-Code eines Dokuments angefordert werden.

Image-Objekte

Zu diesem Zweck werden unabhängige Bild-Objekte (Image-Objekte) eingesetzt. Wie Bilder auf einer Seite besitzen diese Objekte die Eigenschaft src, die Quell-URL. Sobald diese zugewiesen wird, beginnt der Browser im Hintergrund mit dem Laden des entsprechenden Bildes; wenn es dann später durch Rollover angefordert wird, befindet es sich bereits im Browser-Cache.

Ein Image-Objekt wird folgendermaßen erzeugt:

RefVar = new Image();

Anschließend wird eine Bilddatei in das Image-Objekt geladen:

RefVar.src = "Bild_URL";

Für das erste Rollover-Beispiel müsste also über den Funktionen der folgende globale Code ergänzt werden:

var ladebild = new Image();
ladebild.src = "nachher.gif";

Alternativ kann dieser Code auch in einer separaten Funktion stehen, die onload aufgerufen wird.


Galileo Computing

19.5.3 Eine gut funktionierende Rollover-Lösung  downtop

In den letzten Jahren habe ich immer wieder mit verschiedenen Rollover-Ansätzen experimentiert. Herausgekommen ist inzwischen eine recht brauchbare und allgemein gültige Lösung, die es ermöglicht, auf einer Seite beliebig viele Rollover-Hyperlinks an jeder gewünschten Stelle einzusetzen.

Listing 19.5 zeigt zunächst den vollständigen HTML-Code eines Dokuments, das diese Lösung einsetzt – die numerischen JavaScript- und HTML- Kommentare 1 bis 7 beziehen sich auf die weiter unten folgende technische Dokumentation.

Listing 19.6   Ein Dokument mit Rollover-Funktionen

<html>
  <head>
    <title>Sicheres Rollover</title>
      <script language="JavaScript" 
      type="text/javascript">
      <!--  
        /* Bilder vorausladen */
 
        // Grundbildnamen anlegen:
        var bildnamen = new Array 
             ("home", "news", "mail");     // - 1 -  
        // Die verschiedenen Bildobjekt-Arrays anlegen:
        var normbilder = new Array ();
        var rollbilder = new Array ();
           // Die einzelnen Bildobjekte erzeugen und die 
        // Bilddateien hineinladen:
 
        for (i = 0; i < bildnamen.length; i++)  { 
            // - 2 -
            var key = bildnamen[i];         // - 3 -
            normbilder[key] = new Image();  // - 4 -
            normbilder[key].src = key + "0.gif"; 
            rollbilder[key] = new Image(); 
            rollbilder[key].src = key + "1.gif"; 
        }  
        /* Die eigentliche Austausch-Funktion */  
        function swapImage (bildname, zustand) 
        { // - 5 -
           if (zustand == 1) { // - 6 -
              // zustand 1 ist Rollover:
              document.images[bildname].src = 
                 rollbilder[bildname].src; 
           } else { 
              // Zurück zum Normalzustand:
              document.images[bildname].src = 
                   normbilder[bildname].src; 
           } 
        }  
    //-->
    </script>
  </head>
  <body>
    <h1>Nur Test...</h1>
    <!-- 7 -->
    <a href="#" onmouseover="swapImage ('home', 1);" 
    onmouseout="swapImage ('home', 0);"><img 
    src="home0.gif" name="home" width="50" height="30" 
    alt="Home" border="0" /></a><br />
 
    <a href="#" onmouseover="swapImage ('news', 1);" 
    onmouseout="swapImage ('news', 0);"><img 
    src="news0.gif" name="news" width="50" height="30" 
    alt="News" border="0" /></a><br />
 
    <a href="#" onmouseover="swapImage ('mail', 1);" 
    onmouseout="swapImage ('mail', 0);"><img 
    src="mail0.gif" name="mail" width="50" height="30" 
    alt="Mail" border="0" /></a><br />
 
    <h2>Das war's...</h2>
  </body>
</html> 

Konventionen zur Verwendung des Skripts

Die folgenden Grundregeln müssen beachtet werden, wenn Sie diese Lösung für eigene Dokumente einsetzen möchten:

gp  Die Reihenfolge der Rollover-Bilder im Dokument ist egal – obwohl es logischer ist, ihre Namen im Skript in der gleichen Reihenfolge zu definieren, wie sie im Body auftauchen.
gp  Es ist erst recht egal, wie viele Nicht-Rollover-Bilder davor oder dazwischen eingeschoben werden – dies beseitigt eine der Hauptschwächen der üblichen Rollover-Lösungen.
gp  Jedes Bildpaar aus »Normal«- oder »Grund«-Bild und Rollover-Bild benötigt einen eindeutigen Grundnamen: Beispielsweise könnte der Grundname home lauten; die beiden konkreten Bilder wären dann home0.gif und home1.gif für den Normal- beziehungsweise Rollover-Zustand.
gp  Der Name des Normalbildes muss die 0 hinter dem Grundnamen tragen, beim Rollover-Bild ist es die 1.
gp  Ist die Endung .jpg oder .png statt .gif, so müssen Sie dies nicht nur im Body beim Einbetten der Bilder anpassen, sondern auch beim Vorausladen. Beispiel:
rollbilder[key].src = key + "1.jpg"; 
    Innerhalb einer Seite funktioniert diese Lösung jedoch immer nur mit GIFs, nur mit JPEGs oder nur mit PNGs.
       
    Um diese Einschränkung zu umgehen, müssten Sie mehrere Funktionen (swapGIFs(), swapJPEGs() und so weiter) und je mehrere Sätze globaler Variablen wie rollgifs, normgifs, gifnamen und rolljpegs, normjpegs, jpegnamen anlegen. Selbst dann benötigt immer noch jedes einzelne Bild einen individuellen Grundnamen.
       
gp  Wenn die Bilder in einem anderen Verzeichnis liegen als das HTML-Dokument, müssten Sie auch das beim Vorausladen angeben. Befinden sich die Bilder beispielsweise in ../bilder, dann wird der Code folgendermaßen angepasst:
normbilder[key].src = "../bilder/" + key + "0.gif"; 
gp  Im Body muss ein Bild, das diese Funktionalität nutzen soll, auf diese Weise eingebettet werden (hier am Beispiel eines Bildes mit dem Grundnamen test):
<a href="Ziel-URL" onmouseover="swapImage ('test', 1);" 
onmouseout="swapImage ('test', 0);">
<img src="test0.gif" name="test" ... /></a>  
    Wichtig sind hier vor allem diese Punkte:
       
Der Grundname muss als erstes Argument in den Funktionsaufrufen bei den Event-Handlern angegeben werden. Je nach Event-Handler muss der korrekte Zustand als zweites Argument beim Funktionsaufruf angegeben werden: 1 bei onmouseover, 0 bei onmouseout.
gp  Im src-Attribut von <img> muss der korrekte Bilddateiname angegeben werden: [grundname]0.gif (siehe Diskussion oben bezüglich anderem Dateityp oder anderem Pfad).
gp  Im name-Attribut muss der Grundname als Wert angegeben werden.

Technische Erläuterungen

Die Nummern der folgenden Aufzählung beziehen sich auf die nummerierten Kommentare im Listing weiter oben.

1. Es wird ein neues Array namens bildnamen angelegt, in dem die »Grundnamen« der beteiligten Bilder aufgelistet sind. Diese werden verwendet
       
als Hash-Indizes (Schlüssel) für den Zugriff auf die Arrays, die die Bildobjekte enthalten; als Hash-Indizes für den Zugriff auf die Bilder im Dokument (document.images[]) sowie als »Wurzelbestandteil« zur Komposition der Bild-Dateinamen.
    Diese identische Benennung auf drei wichtigen Ebenen (Bildobjekte im Dokument, Bilddateinamen und unabhängige Bildobjekt-Arrays) vereinfacht den Zugriff und das Zusammenspiel aller Komponenten.
       
2. Alle Elemente des Bildnamen-Arrays – und damit alle vorauszuladenden Bilder – werden nacheinander in einer Schleife behandelt:
       
for (i = 0; i < bildnamen.length; i++) 
    Die Zählervariable i beginnt bei 0, dem Index für das erste Element von bildnamen. Dabei muss i so viele Durchläufe erleben, wie bildnamen Elemente besitzt. Die Anzahl der Elemente eines Arrays erhalten Sie durch die Eigenschaft ArrayVar.length.
       
3. Das aktuelle Element des Arrays bildnamen, das im momentanen Schleifendurchlauf an der Reihe ist, wird in der Variablen key abgelegt. Rein theoretisch können Sie sich diesen Schritt sparen und überall, wo im weiteren Verlauf des Schleifenrumpfs key steht, synonym bildnamen[i] eintragen. Allerdings wären Formulierungen wie diese ein wenig umständlich:
       
normbilder [bildnamen [i]] = new Image ();
normbilder [bildnamen [i]].src = 
      bildnamen [i] + "0.gif"; 
4. Für das aktuelle Element des Bildobjekte-Arrays normbilder[] wird ein neues Bildobjekt erstellt. Beachten Sie, dass der Index für dieses Array nicht der numerische Wert i ist, sondern der Zeichenkettenwert, der in Schritt 3 aus bildnamen[] heraus in der Variablen key abgelegt wurde.
       
    In der nächsten Zeile wird als Quell-URL (src) des neuen Bildobjekts der zusammengesetzte Dateiname festgelegt: Der in key gespeicherte Grundbildname, die 0 für »Normalzustand« und die Endung (hier .gif) werden verkettet. Sollten die Bilder in einem anderen Verzeichnis liegen, dann muss dies noch vor dem Wert key angegeben werden. Durch diese zweite Zeile wird das eigentliche Vorausladen in Gang gesetzt.
       
    Dasselbe geschieht in den nächsten beiden Zeilen für das entsprechende Rollover-Bild. Das Array ist hier allerdings nicht normbilder[], sondern rollbilder[], und statt der 0 als Namensbestandteil für ein »Normalbild« wird die 1 für ein Rollover-Bild notiert.
       
5. Der Funktionskopf der Funktion swapImage() ist so definiert, dass die Funktion zwei Argumente erwartet, nämlich Werte für die Parametervariablen bildname und zustand.
       
    Wenn die Funktion später aus Event-Handlern im Body aufgerufen wird, müssen stets zwei Werte übergeben werden: bildname enthält dabei den jeweiligen Grundnamen; zustand bezeichnet die Zustände »Normal« oder »Rollover« wieder durch 0 beziehungsweise 1.
       
6. Hat der übergebene Wert von zustand den Wert 1, dann handelt es sich um den Rollover-Zustand: Die Quell-URL des durch den Index bildname bezeichneten Bildes im Dokument (document.images[bildname].src) wird auf die Quell-URL des entsprechenden Elementes im Array rollbilder[] gesetzt, also auf den Wert rollbilder[bildname].src.
       
    Ebenso läuft das Ganze ab, wenn der else-Teil aktiviert wird. Dieser ist für den Zustand 0 zuständig; es wird entsprechend das aktuelle Normalbild eingestellt, indem das durch bildname indizierte Bild im Dokument auf die Quell-URL des entsprechenden Elementes von normbilder[] gesetzt wird.
       
7. In den Hyperlinks im Dokument rufen die beiden Event-Handler onmouseover und onmouseout jeweils die Funktion swapImage() auf. onmouseover bedeutet, dass der Mauszeiger den Bereich des Links berührt, und löst deshalb zum Beispiel die folgende Anweisung aus:
       
swapImage ('home', 1); 
    'home' muss hier natürlich je nach konkretem Bild ausgetauscht werden; die 1 beschreibt dagegen stets den Zustand »Rollover«.
       
    onmouseout bedeutet dagegen, dass der Mauszeiger den Linkbereich verlässt, weshalb in dem entsprechenden Aufruf
       
swapImage ('home', 0); 
    der Zustandswert 0 verwendet wird.
       

Galileo Computing

19.5.4 Weitere Beispiele  toptop

Die drei folgenden Beispiele zeigen andere Anwendungsmöglichkeiten für das Austauschen von Bildern: Eine Diashow, eine Digitaluhr aus Bildern und ein Memory-Spiel verdeutlichen die vielfältigen Fähigkeiten dieser Funktion.

Die Diashow

Auf vielen Websites werden JavaScript-Diashows eingesetzt, um größere Mengen von Bildern zu präsentieren. Die folgende Beispiellösung bietet eine Reihe von Buttons für verschiedene Funktionen:

gp  Stopp auf Knopfdruck
gp  Start auf Knopfdruck
gp  Richtungswechsel
gp  Manuell weiter
gp  Manuell zurück
gp  Erhöhen und Vermindern der Geschwindigkeit (1 bis 5 Sekunden im Sekundenabstand)

Abbildung 19.2 zeigt eine Momentaufnahme der fertigen Diashow.

Diashow-Grundfunktion

Im Grunde funktioniert eine Diashow recht ähnlich wie das Rollover: Eine Anzahl von Bildern (hier sechs Stück) namens dia0.jpg, dia1.jpg und so weiter wird nacheinander an einer Stelle im Dokument angezeigt. Die einzige Besonderheit gegenüber dem Rollover ist, dass die Diashow überhaupt erst beginnen sollte, wenn alle Bilder fertig geladen sind. Um dies herauszufinden, wird die Eigenschaft Bildobjekt.complete aller vorausgeladenen Bilder abgefragt. Sie hat den Wert true, wenn das jeweilige Bild bereits geladen ist, ansonsten false.


Abbildung 19.2   Die Diashow in Aktion

Abbildung
Hier klicken, um das Bild zu Vergrößern


Listing 19.6 zeigt den vollständigen Code.

Listing 19.7   Eine JavaScript-Diashow

<html>
  <head>
    <title>Die Diashow</title>
      <script language="JavaScript" 
      type="text/javascript">
      <!--
 
        // Globale Variablen; anpassbar
        var bildname = "dia"; // Grundbildname
        var maxbild = 5;      // letztes Bild (Anz. -1)
        var beschr = new Array ("Winterwald", 
           "Tagliatelle Pesto", "Paprika", 
           "Blaue Berge", "Sonnenuntergang / Meer", 
           "Seelilien"); 
                               // Bildbeschriftungen
 
        // Globale Variablen, die feste Werte haben
        var bildnr = 0;        // Aktuelles Dia
        var laeuft = true;     // automatisch laufend?
        var richtung = 1;      // vorwärts
        var dauer = 2;         // Dauer pro Dia 2 Sek.
        var geladen = false;   // noch nicht geladen
 
        // Das Bilder-Array erzeugen und vorausladen
        var bilder = new Array();
        for (i = 0; i <= maxbild; i++)  {
              bilder[i] = new Image();
              bilder[i].src = bildname + i + ".jpg";
        }
 
        // Die Lade-Prüfungs-Funktion
        function wait ()
        {
           // Annahme: fertig geladen
           geladen = true;
           // Bilder einzeln überprüfen
           for (i = 0; i <= maxbild; i++)  {
              if (!bilder[i].complete) {
                 // Aha! NICHT fertig geladen!
                 geladen = false;
              }
           }
           // Neuer Durchlauf, wenn noch nicht geladen
           if (!geladen)
              setTimeout ("warten();", 100);
           else
              diashow();
        }
 
        function doPlay ()
        {
           // Play-Button gedrückt
           if (geladen)  {
              laeuft = true;
           }
        }
 
        function doStop ()
        {
           // Stopp-Button gedrückt
           if (geladen) {
              laeuft = false;
           }
        }
           function doForward ()
        {
           // Vorwärts-Button gedrückt
           if (geladen) {
              bildnr++;
              if (bildnr > maxbild)
                 bildnr = 0;
              document.dia.src = bilder[bildnr].src;
              document.panel.beschr.value 
                   = beschr[bildnr];
           }
        }
           function doBack ()
        {
           // Rückwärts-Button gedrückt
           if (geladen) {
              bildnr--;
              if (bildnr < 0)
                 bildnr = maxbild;
              document.dia.src = bilder[bildnr].src;
              document.panel.beschr.value 
                   = beschr[bildnr];
           }
        }
           function doTurn ()
        {
           // Richtungswechsel gedrückt
           if (geladen) {
              richtung = -richtung;
           }
        }
           function doPlus ()
        {
           // "Schneller" gedrückt
           if (geladen) {
              if (dauer < 5)
                 dauer++;
              document.panel.speed.value = dauer;
           }
        }
           function doMinus ()
        {
           // "Langsamer" gedrückt
           if (geladen) {
              if (dauer > 1)
                 dauer--;
              document.panel.speed.value = dauer;
           }
        }
           function diashow ()
        {
           if (laeuft) {
              bildnr += richtung;
              if (bildnr < 0)
                 bildnr = maxbild;
              else if (bildnr > maxbild)
            bildnr = 0;
              document.dia.src = bilder[bildnr].src;
              document.panel.beschr.value 
                   = beschr[bildnr];
           }
           setTimeout ("diashow();", dauer * 1000);
        }
          //-->
    </script>        </head>
  <body bgcolor="#000000" onload="wait();">
    <table border="0" width="100%" height="100%">
      <tr>
        <td align="center" valign="middle">
          <img src="load.gif" name="dia" width="400" 
          height="300" alt="Das Dia." />
          <br />
          <form name="panel">
            <input type="button" value="PLAY" 
            onclick="doPlay();" />
            <input type="button" value="STOP" 
            onclick="doStop();" />
            <input type="button" value="TURN" 
            onclick="doTurn();" />
            <input type="button" value=" &gt; " 
            onclick="doForward();" />
            <input type="button" value=" &lt; "  
           onclick="doBack();" />
            <input type="button" value=" + " 
            onclick="doPlus();" />
            <input type="button" value=" - " 
            onclick="doMinus();" />
            <input type="text" name="speed" value="2" 
            size="4" readonly="true" />
            <br />
            <input type="text" name="beschr" size="50" 
            readonly="true" />
          </form>
        </td>
      </tr>
    </table>
  </body>
</html>

Die »Bilderuhr«

Im folgenden Beispiel werden die Ziffern einer Digitaluhr als Bilder angezeigt – speichern Sie einfach die Ziffern Ihrer Lieblingsschrift als gleich große Bilder mit den Namen 0.gif bis 9.gif ab. Hinzu kommt ein Doppelpunkt-Bild mit dem Namen trenn.gif – dieses kann ruhig schmaler sein als die anderen Bilder.

Wenn Sie das ganze Kapitel bis hier durchgearbeitet haben, müssten Sie das Beispiel ohne weitere Erläuterung verstehen.

Im Head des Dokuments steht das Skript aus Listing 19.7.

Listing 19.8   Eine Digitaluhr aus austauschbaren Bildern

// Bilder vorausladen
var ziffern = new Array ();
for (i = 0; i <= 9; i++) {
   ziffern[i] = new Image ();
   ziffern[i].src = i + ".gif";
}
 
function uhr ()
{
   // Schon geladen?
   var fertig = true;
   for (i = 0; i <= 9; i++) {
      if (!ziffern[i].complete)
         fertig = false;
   }
   // - Ja? Dann los!
   if (fertig) {
      var jetzt = new Date ();
      var std = jetzt.getHours ();
      var min = jetzt.getMinutes ();
      var sek = jetzt.getSeconds ();
 
      /* Nun wird vor alle Zeitangaben, die kleiner 
                     als 10 sind, eine 0 gesetzt. 
               */
      std = (std < 10) ? "0" + std : "" + std;
      min = (min < 10) ? "0" + min : "" + min;
      sek = (sek < 10) ? "0" + sek : "" + sek;
 
      /* Die Zeitangaben werden in ihre beiden 
         einzelnen Stellen zerlegt. 
                 */
      var sth = std.charAt (0);
      var stn = std.charAt (1);
      var mnh = min.charAt (0);
      var mnn = min.charAt (1);
      var skh = sek.charAt (0);
      var skn = sek.charAt (1);
 
      /* jedes einzelne Bild wird auf das "seiner" 
         Zeitangabenziffer entsprechende Element 
         des Bilder-Arrays 'ziffern' gesetzt. 
      */
      document.stdh.src = ziffern[sth].src;
      document.stdn.src = ziffern[stn].src;
      document.minh.src = ziffern[mnh].src;
      document.minn.src = ziffern[mnn].src;
      document.sekh.src = ziffern[skh].src;
      document.sekn.src = ziffern[skn].src;
 
      /* In GERADEN Sekunden werden die beiden 
         Zwischenräume auf das Doppelpunkt-Bild 
         gesetzt; in ungeraden auf ein leeres Bild
         -> sie scheinen zu blinken! 
               */
      if (sek % 2 == 0)
      {
         document.trenn1.src = "trenn.gif";
         document.trenn2.src = "trenn.gif";
      }
      else
      {
         document.trenn1.src = "leer.gif";
         document.trenn2.src = "leer.gif";
      }
   }
 
   /*  Die Ausführung wird bereits nach 50 
       Millisekunden wiederholt. 
                   */
   setTimeout ("uhr ();", 500);
}
 
 

Anschließend werden die Bilder wie folgt im Body angeordnet:

<img src="0.gif" name="stdh" width=30 height=50>
<img src="0.gif" name="stdn" width=30 height=50>
<img src="trenn.gif" name="trenn1" width=20 height=50>
<img src="0.gif" name="minh" width=30 height=50>
<img src="0.gif" name="minn" width=30 height=50>
<img src="trenn.gif" name="trenn2" width=20 height=50>
<img src="0.gif" name="sekh" width=30 height=50>
<img src="0.gif" name="sekn" width=30 height=50>

Ein Memory-Spiel

Das letzte Beispiel für die Arbeit mit Bildern ist ein ausgewachsenes Spiel. Es handelt sich um eine Variante des bekannten Memory®-Spiels: Acht Kartenpaare liegen »verdeckt« (dargestellt durch ein spezielles »Rückseiten-Bild« in einem 4x4-Quadrat) und sollen durch Anklicken (als Hyperlinks) »aufgedeckt« werden. Werden zwei gleiche Karten gefunden, dann verschwinden sie; zwei verschiedene werden dagegen durch Anklicken der nächsten Karte automatisch geschlossen. Wenn alle Karten abgeräumt sind, erscheint die Meldung, wie viele Versuche benötigt wurden.

Zufallsgenerator

Für dieses Spiel muss der JavaScript-Zufallsgenerator verwendet werden: Die argumentlose Methode Math.random() erzeugt eine pseudozufällige Fließkommazahl zwischen 0 und 1. Durch entsprechende Umrechnung kann eine Zufallszahl aus dem gewünschten Zahlenbereich erzeugt werden. Beispielsweise können Sie folgendermaßen einen Würfelwurf simulieren (eine Ganzzahl von 1 bis 6):

parseInt (Math.random() * 6) + 1

Eine Lottozahl (Wertebereich 1 bis 49) wird dagegen so erzeugt:

parseInt (Math.random() * 49) + 1

Ein weiteres Problem beim Memory-Spiel besteht darin, dass es jede Karte genau zweimal gibt; es muss also jeweils überprüft werden, ob die zufällig erzeugte Karte bereits verteilt wurde oder nicht.

Lottozahlen

Als kleine Vorstufe zeigt das folgende Skript eine Simulation der offiziellen Ziehung der Lottozahlen: Aus dem Zahlenraum 1 bis 49 müssen insgesamt sieben Zahlen (sechs plus Zusatzzahl) ausgewählt werden, ohne dass eine von ihnen doppelt vorkommen darf.

Die Zahlen sollen per Skript im Dokument ausgegeben werden. Das Listing sieht so aus:

var lottozahlen = new Array();
for (i = 0; i < 7; i++) {
   do {
      // Zufallszahl erzeugen:
      var zahl = parseInt (Math.random() * 49) + 1;
      // War diese Zahl schon da?
      // Annahme: Nein!
      var schonda = false;
      // Alle bisherigen Zahlen überprüfen:
      for (j = 0; j < i; j++) {
         if (lottozahlen[j] == zahl)
            schonda = true;
      }
   } while (schonda);
}
// Ausgabe:
for (i = 0; i < 6; i++) {
   document.write 
       (lottozahlen[i] + "&nbsp;&nbsp;&nbsp;");
}
document.write ("<br />");
document.write 
   ("<b>Zusatzzahl: " + lottozahlen[6] + "</b>");

Nach diesen Vorarbeiten kann nun das eigentliche Memory-Spiel implementiert werden.

In einem Array werden die Entsprechungen der 16 Karten zur Bildung der Grunddateinamen und zum Mischen abgelegt. Dabei sollten die beiden Karten eines Paares sich unterscheiden – beispielsweise könnten "a0" und "b0" für die beiden Karten des ersten Paares verwendet werden. In diesem ersten Array liegen die Paare in geordneter Reihenfolge vor, sodass sie durch eine Schleife gebildet werden können:

var vorrat = new Array();
for (i = 0; i < 7; i++) {
   vorrat.push ("a" + i);
   vorrat.push ("b" + i);
}

push( ) und pop( )

Die Array-Methode Array.push(Ausdr) hängt den Wert von Ausdr an das Ende des Arrays an. Array.pop()erhält dagegen als Wert das letzte Element des Arrays, das dadurch tatsächlich aus dem Array entfernt wird. Leider versteht der Internet Explorer für Macintosh diese Methode nicht. Deshalb muss sie durch entsprechende Wertzuweisungen ersetzt werden. Ein hervorragendes Verfahren, das Verhalten von push() zu simulieren, ist folgendes:

Array[Array.length] = Neues_Element;

Da die Eigenschaft Array.length immer die Anzahl der bisher vorhandenen Elemente anzeigt, entspricht eine Wertzuweisung an ein Element mit diesem Index dem Hinzufügen eines neuen Wertes am Ende des Arrays.

In einem anderen Array wird die eigentliche Verteilung der Karten vorgenommen – es enthält pro möglicher Position ein Element, auf das genau eine Karte gelegt wird. Die Karten werden per Zufallsgenerator aus dem vorherigen Array verteilt; dabei findet eine Kontrolle statt, welche Karten bereits verteilt sind (wie bei den Lottozahlen):

var karten = new Array();
for (i = 0; i < 16; i++) {
   do {
      // Zufällige Karte wählen
      var karte = parseInt (Math.random (16));
      // War diese Zahl schon da?
      var schonda = false;
      for (j = 0; j < i; j++) {
         if (karten[j] == karte)
            schonda = true;
      }
   } while (schonda);
   karten.push (karte);
}

Schließlich wird noch ein drittes Array benötigt, das den aktuellen Status jeder einzelnen Karte speichert: Ist sie noch verfügbar oder schon weg? Anfangs sind natürlich alle Karten noch vorhanden:

var nochda = new Array();
for (i = 0; i < 16; i++) {
   nochda.push (true);
}

Nun folgen die letzten Vorbereitungen: Es muss eine Variable geben, die die Anzahl der Versuche zählt – versuche – sowie eine weitere, die die aktuell offenen Karten zählt (0, 1 oder 2):

var versuche = 0;
var offene = 0;

Die Variable paare zählt die bereits gefundenen Kartenpaare:

var paare = 0;

Die nächsten beiden Variablen merken sich die Karten, die aufgedeckt wurden:

var offen1, offen2;

Das Timeout zum automatischen Schließen beider Karten muss ebenfalls global gespeichert werden, damit es bei vorzeitigem Klick auf eine weitere Karte wieder zurückgesetzt werden kann:

var stoppuhr = null;

Schließlich werden die acht möglichen Karten in das Array kartenbilder vorausgeladen.

Wird eine Karte angeklickt, so muss eine Funktion aufgerufen werden, die die folgenden Aufgaben erledigt:

gp  Überprüfen, ob die Karte bereits weg ist. Falls dem so ist, wird nichts weiter getan.
gp  Überprüfen, ob bereits zwei Karten offen sind. In diesem Fall müssen die beiden Karten geschlossen werden; anschließend wird die neue Karte geöffnet.
gp  Überprüfen, ob die angeklickte Karte bereits offen ist. Sollte sie offen sein, wird ein Fehler-alert() ausgegeben.
gp  Das Kartenbild der angeklickten Karte auswechseln: Statt der »Rückseite« wird das entsprechende Bild angezeigt.

Falls die Karte, die gerade geöffnet wird, die zweite Karte ist, müssen einige weitere Überprüfungen stattfinden: Die neue Karte wird mit der anderen geöffneten verglichen. Falls sie übereinstimmen, werden beide entfernt: An ihre Positionen wird ein leeres Bild gesetzt; ihr Status wird auf »weg« geändert. Falls sie nicht übereinstimmen, wird dagegen das Timeout gesetzt, um sie nach einer gewissen Zeit automatisch zu schließen.

gp  Die Anzahl der Versuche um 1 erhöhen.
gp  Die Anzahl der bereits gefundenen Paare überprüfen. Sind alle gefunden, erscheint eine Gewinnmeldung und das Spiel ist zu Ende.

Im Body müssen nun die 16 Bilder eingebettet werden. Für das erste Bild sieht das beispielsweise so aus:

<a href="javascript:klick(0);">
<img src="rueck.gif" name="k0" width="100" height="100" 
border="0"></a>

Für alle weiteren Bilder werden die Nummer im klick()-Aufruf und die Nummer im Bildnamen entsprechend erhöht.

Listing 19.8 zeigt nun das gesamte HTML-Dokument; die erforderlichen Änderungen für den Mac-Explorer sind als Kommentare angegeben.

Listing 19.9   Das fertige Memory-Spiel

<html>
  <head>
    <title>JavaScript-Memory</title>
    <script language="JavaScript"     type="text/javascript">
    <!--
 
    // Vorausladen der Kartenbilder
    var kartenbilder = new Array();
    for (i = 0; i < 8; i++) {
       kartenbilder[i] = new Image();
       kartenbilder[i].src = "karte" + i + ".jpg";
    }
       // Die Menge aller existierenden Karten definieren
    var vorrat = new Array();
    for (i = 0; i < 8; i++) {
       vorrat.push ("a" + i);
       vorrat.push ("b" + i);
       // Der IE für Mac versteht push() nicht, dort:
       // vorrat[vorrat.length] = "a" + i;
       // vorrat[vorrat.length] = "b" + i;
    }
    // Die Karten mischen und "auslegen"
    var karten = new Array();
    for (i = 0; i < 16; i++) {
       do {
          // Zufällige Karte wählen
          var karte = parseInt (Math.random () * 16);
          // War diese Zahl schon da?
          var schonda = false;
          for (j = 0; j < i; j++) {
             if (karten[j] == karte)
                schonda = true;
          }
       } while (schonda);
       karten.push (karte);
       // IE/Mac:
       // karten [i] = karte;
    }
        // Status der Karten
    var nochda = new Array();
    for (i = 0; i < 16; i++) {
       nochda.push (true);
       // IE/Mac:
       // nochda[i] = true;
    }
        // Anzahl der Versuche und der zz. offenen Karten
    var versuche = 0;
    var offene = 0;
        // Bereits gefundene Kartenpaare
    var paare = 0;
        // Die beiden zz. offenen Karten
    var offen1, offen2;
        // Speichervariable für das Timeout zum Schließen
    var stoppuhr = null;
        function klick(karte)
    {
       // Ist diese Karte schon weg?
       if (!nochda [karte])
          return;
       // Sind bereits zwei offen?
       if (offene == 2) {
          offene = 0;
          document.images["k" + offen1].src 
               = "rueck.gif";
          document.images["k" + offen2].src 
               = "rueck.gif";
          if (stoppuhr) {
             clearTimeout (stoppuhr);
             stoppuhr = null;
          }
       }
       // Eine Karte wurde geöffnet:
       offene++;
       // Die aktuell angeklickte Karte "umdrehen"
       var kartenbild = vorrat [karten [karte]];
       var bildnr = kartenbild.charAt(1);
       document.images ["k" + karte].src 
            = kartenbilder[bildnr].src;
       // Ist dies die erste Karte?
       if (offene == 1) {
          offen1 = karte;
          return;
       }
       // HIER sind auf jeden Fall ZWEI offen.
       offen2 = karte;
       // Ist dies DIESELBE Karte?
       if (offen2 == offen1) {
          alert ("Zweimal dieselbe ist verboten!");
          offene = 1;
          return;
       }
       var kartenbild1 = vorrat [karten [offen1]];
       var kartenbild2 = vorrat [karten [offen2]];
       var bildnr1 = kartenbild1.charAt (1);
       var bildnr2 = kartenbild2.charAt (1);
       // Die beiden Karten vergleichen:
       if (bildnr1 == bildnr2) {
          // Die beiden Karten sind identisch!
          // Die beiden Karten verschwinden lassen
          document.images ["k" + offen1].src 
             = "leer.gif";
          document.images ["k" + offen2].src 
             = "leer.gif";
          nochda[offen1] = false;
          nochda[offen2] = false;
          // Es wurde ein Paar gefunden!
          paare++;
          offene = 0;
       } else {
          // Die beiden Karten sind verschieden -
          // Vorbereiten zum Schließen in 1 Sekunde:
          stoppuhr = setTimeout 
               ("schliessen();", 1000);
       }
       // Dies war ein weiterer Versuch:
       versuche++;
       // Alle gefunden?
       if (paare == 8) {
          alert ("Gewonnen in " + versuche 
               + " Versuchen!");
       }
    }
       function schliessen ()
    {
       // Die beiden offenen Karten zurücksetzen:
       document.images ["k" + offen1].src 
            = "rueck.gif";
       document.images ["k" + offen2].src 
            = "rueck.gif";
       offene = 0;
       stoppuhr = null;
    }
       //-->
    </script>
  </head>
  <body bgcolor="#000000" text="#FFFFFF">
    <table border="0" width="100%" height="100%">
      <tr>
        <td align="center" valign="middle">
          <h1>JavaScript-Memory</h1>
          <a href="javascript:klick(0);"><img 
          src="rueck.gif" name="k0" width="100" 
          height="100" border="0"></a>
          <a href="javascript:klick(1);"><img 
          src="rueck.gif" name="k1" width="100" 
          height="100" border="0"></a>
          <a href="javascript:klick(2);"><img 
          src="rueck.gif" name="k2" width="100" 
          height="100" border="0"></a>
          <a href="javascript:klick(3);"><img 
          src="rueck.gif" name="k3" width="100" 
          height="100" border="0"></a>
          <br />
          <a href="javascript:klick(4);"><img 
          src="rueck.gif" name="k4" width="100" 
          height="100" border="0"></a>
          <a href="javascript:klick(5);"><img 
          src="rueck.gif" name="k5" width="100" 
          height="100" border="0"></a>
          <a href="javascript:klick(6);"><img '
          src="rueck.gif" name="k6" width="100" 
          height="100" border="0"></a>
          <a href="javascript:klick(7);"><img 
          src="rueck.gif" name="k7" width="100" 
          height="100" border="0"></a>
          <br />
          <a href="javascript:klick(8);"><img 
          src="rueck.gif" name="k8" width="100" 
          height="100" border="0"></a>
          <a href="javascript:klick(9);"><img 
          src="rueck.gif" name="k9" width="100" 
          height="100" border="0"></a>
          <a href="javascript:klick(10);"><img 
          src="rueck.gif" name="k10" width="100" 
          height="100" border="0"></a>
          <a href="javascript:klick(11);"><img 
          src="rueck.gif" name="k11" width="100" 
          height="100" border="0"></a>
          <br />
          <a href="javascript:klick(12);"><img 
          src="rueck.gif" name="k12" width="100" 
          height="100" border="0"></a>
          <a href="javascript:klick(13);"><img 
          src="rueck.gif" name="k13" width="100" 
          height="100" border="0"></a>
          <a href="javascript:klick(14);"><img 
          src="rueck.gif" name="k14" width="100" 
          height="100" border="0"></a>
          <a href="javascript:klick(15);"><img 
          src="rueck.gif" name="k15" width="100" 
          height="100" border="0"></a>
      </td>
    </tr>
  </table>
</body>
</html>
  

Einstieg in PHP 5

Einstieg in Java

C von A bis Z

Einstieg in C++

Einstieg in Linux

Einstieg in XML

Apache 2




Copyright © Galileo Press GmbH 2004
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das <openbook> denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt. Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.


[Galileo Computing]

Galileo Press GmbH, Gartenstraße 24, 53229 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, info@galileo-press.de