Aufgaben vom 2.6.2004 (Woche 14)

Bearbeitungszeit: bis Dienstag, 8. Juni 2004, 17:30 Uhr
Bewertungsschema

Aufgabe 1: DHTML - Ausführung Teil 2

Mit einigen Einschränkungen erlaubt DHTML auch die Programmierung von Animationen. Die Einschränkungen ergeben sich daraus, dass DHTML (und damit JavaScript) zumindest derzeit keine Befehle zum Zeichnen von Linien und nicht-rechteckigen Flächen kennt. Um mit solchen Objekte zu arbeiten, ist man auf entsprechende GIF- oder PNG-Grafiken mit transparentem Hintergrund angewiesen, was trotz der Möglichkeit, deren Höhe und Breite dynamisch zu ändern, nicht immer ganz befriedigend ist.

Animationen bestehen aus einer Reihe von Schritten mit einem gewissen zeitlichen Abstand. Damit dieser Zeitabstand eingehalten wird, muss ein Wartebefehl eingebaut werden. In praktisch allen Programmiersprachen gibt es einen solchen Befehl, der meistens sleep() heisst und als Argument die Wartezeit (z.B. in Millisekunden) erwartet. Eine Animation wird dann etwa so programmiert:


for(i = 0; i < AnzahlSchritte; i++) {
   AnimationsSchritt(i); // Eine selbst programmierte Funktion 
   sleep(50); // nach 50 ms = 1/20 s der naechste Schritt
}
  

In JavaScript fehlt eine solche Funktion. Statt dessen gibt es die Befehle setInterval() und setTimeout(). Diese Funktionen erwarten als erstes Argument einen beliebigen Programmierbefehl inkl. abschliessenden Strichpunkt, eingeschlossen in einfache oder doppelte Gänsefüsschen (ein absoluter Schandfleck für eine Programmiersprache). Als zweites Argument erwarten sie eine Zeitangabe in Millisekunden. Im Fall von setInterval() wird dieser Befehl von da an immer wieder ausgeführt, im Abstand von so vielen Millisekunden, wie im zweiten Argument angegeben wird. Bei setTimeout() wird der Befehl nur einmal, nach entsprechend vielen Millisekunden, ausgeführt. Will man setTimeout() für eine Animation verwenden, muss man es nach jedem Schritt erneut aufrufen, hat dann aber gegenüber setInverval() den Vorteil, dass man die Zeit zwischen zwei Schritten variieren kann.

Mit setTimeout() sieht das obige Beispiel, nach JavaScript übertragen, so aus:


var i = 0;   // ausserhalb von allen Funktionen definieren

function naechsterSchritt() {
   Animationsschritt(i); // Eine selbst programmierte Funktion 
   if(++i < AnzahlSchritte)
      setTimeout('naechsterSchritt();', 50);
}

naechsterSchritt();  // Dieser Befehl setzt die Animation in Gang

Um das Beispiel zu konkretisieren und auch gleich zu zeigen, wie dieser allgemeine Rahmen im konkreten Fall variieren kann, lassen wir eine Überschrift quer über den Bildschirm laufen. Dazu müssen wir zuerst die Breite des Fensters ermitteln, was einige hässliche Programmzeilen erfordert, weil Mozilla und Internet Explorer die Fensterbreite in unterschiedlichen Variablen speichern. Wir setzten dann einen <div>-Bereich ganz rechts an den Bildschirm und schieben ihn Stück für Stück nach links. Wenn er links verschwunden ist, beginnen wir rechts erneut:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
  "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="de">
<head>
<title>Laufschrift</title>
<meta http-equiv="Content-type" content="text/html; charset=iso-8859-1" />  
</head>
<body onload="javascript:naechsterSchritt()">
<div style="width:100%; overflow:hidden">
<div id="laufschrift" style="position:relative; visibility:hidden"><h1>Laufschrift</h1></div>
</div>
<script type="text/javascript">
//<![CDATA[
var i, j, rechts;   // ausserhalb von allen Funktionen definieren

j = 0;
if(
window.innerWidth) // falls die Variable innerWidth existiert
   
rechts = innerWidth; // (z.B. bei Netscape und Mozilla)
else if(document.body.offsetWidth) // falls document.body.offsetWidth existiert
   
rechts = document.body.offsetWidth;  // (z.B. beim Internet Explorer)
else                    // falls nicht
   
rechts = 1024;       // raten wir mal.  
i = rechts;
marquee = document.getElementById("laufschrift");
marquee.style.left = i+"px";
marquee.style.visibility = "visible";


function
naechsterSchritt() {
   
Animationsschritt(i); // Eine selbst programmierte Funktion
   
i -= 5;               // i zaehlt hier die Pixel von links
   
if(i < -300)          // wenn die Schrift links verschwunden ist
   
i = rechts;           // geht es rechts neu los
   
setTimeout('naechsterSchritt();', 50);
}

function
Animationsschritt() {
   
marquee.style.left = i + "px";  // Eine eigene Funktion fuer diese Zeile waere
}                           // nicht wirklich noetig

//
]]>
</script>

<p>
<a href="http://validator.w3.org/check/referer"><img style="border:0"
src="valid-xhtml11.png" alt="Valid XHTML 1.1!" /></a>
<a href="http://jigsaw.w3.org/css-validator/check/referer"><img style="border:0"
src="vcss.png" alt="Valid CSS!" /></a>
</p>
</body>
</html>

Um die Laufschrift in Aktion zu sehen, klicken Sie hier.

Will man zwei oder mehr Animationen parallel laufen lassen, so muss die Funktion Animationsschritt() einfach mehrere Objekte pro Schritt bewegen. So kann man zum Beispiel zwei Lauftexte ineinander laufen lassen. Der entsprechende Code sieht dann so aus:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
  "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="de">
<head>
<title>Laufschrift</title>
<meta http-equiv="Content-type" content="text/html; charset=iso-8859-1" />  
<style type="text/css">
.background { position:absolute; width:98%; top:30px; overflow:hidden }
.marquee { position:relative; font-family:Times New Roman; font-size:20pt; font-weight:bold; top:0px; visibility:hidden }
</style>
</head>
<body onload="javascript:naechsterSchritt()">
<div class="background">
<span id="marquee_l" class="marquee">Laufschrift</span>
</div>
<div class="background">
<span id="marquee_r" class="marquee">Laufschrift</span>
</div>
<script type="text/javascript">
//<![CDATA[
var schritt = 10;
var
links, rechts, r, l;   // ausserhalb von allen Funktionen definieren
var marquee_l, marquee_r;


marquee_l = document.getElementById("marquee_l");
marquee_r = document.getElementById("marquee_r");
if(
window.innerWidth) // falls die Variable innerWidth existiert
   
rechts = innerWidth; // (z.B. bei Netscape und Mozilla)
else if(document.body.offsetWidth) // falls document.body.offsetWidth existiert
   
rechts = document.body.offsetWidth;  // (z.B. beim Internet Explorer)
else                    // falls nicht
   
rechts = 1024;       // raten wir mal.  
links = -170;
r = rechts;
l = links;
marquee_l.style.left = links+"px";
marquee_r.style.left = rechts+"px";
marquee_l.style.visibility = "visible";
marquee_r.style.visibility = "visible";

function
naechsterSchritt() {
   
Animationsschritt();  // Eine selbst programmierte Funktion
   
r -= schritt;
   
l += schritt;
   if(
r > l)             
      
setTimeout('naechsterSchritt();', 50);
   else {
      
r = l;
      
Animationsschritt(); // letzter Schritt: beide am gleichen Ort
   
}
}

function
Animationsschritt() {
   
marquee_l.style.left = l+"px";  
   
marquee_r.style.left = r+"px";
}


//]]>
</script>
<p style="padding-top:50px">
<a href="http://validator.w3.org/check/referer"><img style="border:0"
src="valid-xhtml11.png" alt="Valid XHTML 1.1!" /></a>
<a href="http://jigsaw.w3.org/css-validator/check/referer"><img style="border:0"
src="vcss.png" alt="Valid CSS!" /></a>
</p>
</body>
</html>

In dem Beispiel ist zu beachten, dass beide Texte je relativ zu einem <div>-Bereich positioniert werden, der aber in beiden Fällen absolut und identisch positioniert ist. Nur so lässt sich, zusammen mit der Angabe overflow:hidden, verhindern, dass die anfangs über den Bilschirmrand hinauslappenden Bereiche einen vertikalen Scrollbalken erzeugen, der die Animation stört. Beim Internet Explorer 5 für Macintosh (Classic oder OS X) führt allerdings gerade diese Massnahme dazu, dass die Laufschrift überhaupt nicht angezeigt wird.

Will man mehrere Animationen hintereinander laufen lassen, braucht man in der Funktion naechsterSchritt() eine zusätzliche Variable, um zu zählen, welche Animation gerade am laufen ist. Um dies zu zeigen, wurde das obige Beispiel noch um eine Sequenz erweitert, in der sich die zusammengelaufenen Schriften rot färben. Der Quelltext ist im folgenden aufgelistet, für das lauffähige Beispiel (wieder nicht auf IE 5 für Mac) klicken Sie hier.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
  "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="de">
<head>
<title>Laufschrift</title>
<meta http-equiv="Content-type" content="text/html; charset=iso-8859-1" />  
<style type="text/css">
.background { position:absolute; width:98%; top:30px; overflow:hidden }
.marquee { position:relative; font-family:Times New Roman;
           font-size:20pt; font-weight:bold; top:0px;
           color:rgb(0,0,0); visibility:hidden }
</style>
</head>
<body onload="javascript:naechsterSchritt()">
<div class="background">
<span id="marquee_l" class="marquee">Laufschrift</span>
</div>
<div class="background">
<span id="marquee_r" class="marquee">Laufschrift</span>
</div>
<script type="text/javascript">
//<![CDATA[
var schritt = 10, farbschritt = 5, anim_no = 1;
var
links, rechts, r, l, f;   // ausserhalb von allen Funktionen definieren
var marquee_l, marquee_r;


marquee_l = document.getElementById("marquee_l");
marquee_r = document.getElementById("marquee_r");
if(
window.innerWidth) // falls die Variable innerWidth existiert
   
rechts = innerWidth; // (z.B. bei Netscape und Mozilla)
else if(document.body.offsetWidth) // falls document.body.offsetWidth existiert
   
rechts = document.body.offsetWidth;  // (z.B. beim Internet Explorer)
else                    // falls nicht
   
rechts = 1024;       // raten wir mal.  
links = -170;
r = rechts;
l = links;
marquee_l.style.left = links+"px";
marquee_r.style.left = rechts+"px";
marquee_l.style.visibility = "visible";
marquee_r.style.visibility = "visible";

function
naechsterSchritt() {
   if(
anim_no == 1) {
      
Animationsschritt1();  // Eine selbst programmierte Funktion
      
r -= schritt;
      
l += schritt;
      if(
r < l) {
         
r = l;
         
Animationsschritt1(); // letzter Schritt: beide am gleichen Ort
         
anim_no = 2;
         
f = 0;
      }
      
setTimeout('naechsterSchritt();', 50);
   } else if(
anim_no == 2) {
      
Animationsschritt2();
      
f += farbschritt;
      if(
f < 255)
         
setTimeout('naechsterSchritt();', 50);
      else {
         
f = 255;
         
Animationsschritt2(); // letzter Schritt: knallrot
         
anim_no = 3;          // fertig
      
}
   }
}

function
Animationsschritt1() {
   
marquee_l.style.left = l+"px";  
   
marquee_r.style.left = r+"px";
}

function
Animationsschritt2() {
   
marquee_l.style.color = 'rgb(' + f + ',0,0)';
   
marquee_r.style.color = 'rgb(' + f + ',0,0)';
}

//]]>
</script>

<p style="padding-top:50px">
<a href="http://validator.w3.org/check/referer"><img style="border:0"
src="valid-xhtml11.png" alt="Valid XHTML 1.1!" /></a>
<a href="http://jigsaw.w3.org/css-validator/check/referer"><img style="border:0"
src="vcss.png" alt="Valid CSS!" /></a>
</p>
</body>
</html>

Ihre Aufgabe

Schreiben Sie selbst eine kleine Animation, mit der Sie z.B. Ihre Willkommensseite schmücken können. Versuchen Sie, etwas möglichst eigenes herzustellen, also nicht einfach einen Lauftext von links nach rechts, der grün wird und auch keinen Lauftext von oben nach unten, der später auf zwei Seiten auseinander wandert.

Valid XHTML 1.1! Valid CSS!