| 
drag and drop
Einer der "spektakulärsten" Effekte,
die man mit DHTML produzieren kann, ist drag and drop, das
heisst die Möglichkeit, irgendein x-beliebiges Element
einer HTML Seite zu packen und irgendwo hinzusetzen. Wenn
man diesen Effekt ohne weiteres cross browser compatibel programmieren
könnte, gäbe es sicher auch schon einige Anwendungen,
vor allem Spiele, die diesen Effekt einsetzen. Allmählich
nähern sich Netscape und Explorer im Hinblick auf DHTML
einander an, so dass man diesem Effekt wohl öfter im
Netz begegnen wird. Möglich wäre es zum Beispiel
ein Puzzle wie das unten stehende zu kreieren, das der User
dann via drag and drop zu einem Bild zusammenbauen kann.

Alles klar ? Wenn wir über einem Bild die
rechte Maustaste drücken "packen" wir das Bild
und können es bei gedrückter Maustaste über
den Bildschirm ziehen. Lassen wir die Maustaste los, ist das
Bild wieder frei. So können wir das Puzzel zusammenbauen.
Der Skript, der uns das produziert, sieht so aus.
<html>
<head>
<title>drag and drop</title>
<script language="JavaScript">
document.onmousedown=packmich;
document.onmouseup=beenden;
ganzoben=1;
function packmich(e)
{
if(!document.all)
{
objekt=e.target.id;
}
else
{
objekt=event.srcElement.id;
}
if(objekt)
{
if(!document.all)
{event=e;}
startX=event.clientX;
startY=event.clientY;
document.getElementById(objekt).style.zIndex=ganzoben;
ganzoben++;
XpositionAlt=document.getElementById(objekt).style.left;
YpositionAlt=document.getElementById(objekt).style.top;
document.onmousemove=bewegen;
return false;
}
}
function bewegen(e)
{
if(objekt)
{
if(!document.all)
{event=e;}
Xwert=event.clientX-startX;
Ywert=event.clientY-startY;
document.getElementById(objekt).style.left=parseInt(XpositionAlt)+Xwert;
document.getElementById(objekt).style.top=parseInt(YpositionAlt)+Ywert;
}
return false;
}
function beenden()
{
objekt=false;
}
</script>
</head>
<body>
<img src=beispiele/puzzle/1.gif id="1" style="position:absolute;top:160;left:20">
<img src=beispiele/puzzle/2.gif id="2" style="position:absolute;top:160;left:320">
<img src=beispiele/puzzle/3.gif id="3" style="position:absolute;top:160;left:620">
<img src=beispiele/puzzle/4.gif id="4" style="position:absolute;top:380;left:20">
<img src=beispiele/puzzle/5.gif id="5" style="position:absolute;top:380;left:320">
<img src=beispiele/puzzle/6.gif id="6" style="position:absolute;top:380;left:620">
</body>
</html>
Unter Umständen erleichtert es jetzt das
Verständnis, wenn man sich das unter dynamic html Gesagte
nochmal in Erinnerung ruft. Gehen wir den Skript Schritt für
Schritt durch. Zu Beginn haben wir
document.onmousedown=packmich;
document.onmouseup=beenden;
Das heisst, wir definieren für das gesamte
Dokument, dass bei onmousedown die Funktion packmich() aufgerufen
wird und bei onmouseup die Funktion beenden. Man muss jetzt
sehen, dass wir für onmousemove erstmal nichts definieren,
da wir ja nicht wollen, dass die Bilder immer der Maus hinterlaufen.
Wir wollen, dass die Bilder nur dann der Maus hinterherlaufen,
wenn der User die Maustaste gedrückt hält. Wir wollen
des weiteren auch nicht, dass jedes Element verschoben werden
kann, wir wollen nur zulassen, dass die Bilder verschoben
werden können. Wir müssen also in der Funktion packmich()
dafür sorgen, dass der even handler onmousemove, der
die Funktion bewegen() aufruft, nur dann aktiv ist, wenn erstens
die Maustaste gedrückt ist und sich zweitens die Maus
über einem der Bilder befindet befindet. Schauen wir
uns also die Funktion packmich() genauer an.
function packmich(e)
{
if(!document.all)
{
objekt=e.target.id;
}
else
{
objekt=event.srcElement.id;
}
if(objekt)
{
if(!document.all)
{event=e;}
startX=event.clientX;
startY=event.clientY;
XpositionAlt=document.getElementById(objekt).style.left;
YpositionAlt=document.getElementById(objekt).style.top;
document.onmousemove=bewegen;
return false;
}
}
Nochmal. Die Funktion packmich() wird immer
aufgerufen, wenn der User irgendwo auf der Seite die Maustaste
drückt. Innerhalb der Funktion wird dann aber entschieden,
ob dann auch tatsächlich etwas passiert. Wir interessieren
uns jetzt für die id des Objektes, über dem die
Maustaste gedrückt wurde. Obwohl sich die Konzepte des
Internet Explorers und von Netscape 6+ angenähert haben,
sind sie doch noch nicht ganz identisch. Wird mit
document.onmousedown=packmich;
eine Funktion aufgerufen, haben wir schon
einen Unterschied. Beide Browser speichern alle Informationen
zu einem Event in einem Objekt. Beim Explorer allerdings ist
diese Objekt als globale Variable überall vorhanden,
während Netscape dieses Event Objekt als Parameter übergibt.
Das ist aber leider nicht der einzige Unterschied. Auch die
Art und Weise, wie man die Kindobjekte und die Eigenschaften
unterhalb des Event Objektes anspricht, unterscheidet sich.
Wir wollen wissen, welche id das Objekt hat, über dem
die Maus gedrückt wurde, weil wir ja nachher dieses und
kein anderes Objekt bewegen wollen. Dies ermitten wir bei
Netscape mit
objekt=e.target.id;
und beim Internet Explorer mit
objekt=event.srcElement.id;
Als nächstes wollen wir noch wissen, wo
auf die Maustaste gedrückt wurde, denn dies wird es uns
später erlauben, zu ermitteln, um wieviel die Maus bewegt
wurde. Allerdings interessiert uns das nur, wenn das Objekt
vorhanden ist, denn sonst wollen wir ja nix bewegen. Die Variable
Objekt hat aber nur dann einen Inhalt, wenn auf etwas geklickt
wurde, was eine id hat. Wir machen also alle folgenden Befehle
von der Frage abhängig, ob die Variable Objekt einen
Inhalt hat ( irgendein Inhalt ist in der Perl Logik mit true
identisch.) Als nächstes sorgen wir noch dafür,
dass das Element, dass wir angeclickt haben, das oberste ist,
also nicht von einem anderen Bild verdeckt wird, wenn wir
es über ein anderes Bild schieben. Wir haben am Anfang
die Variable ganzoben mit dem Wert 1 initialisiert. Jedesmal,
wenn wir über einem Bild die Maustaste drücken,
erhöhen wir diesen Wert. Dann weisen wir diesem Wert
dem zIndex zu, der angibt, wo sich das entsprechende Objekt
in der Hierarchie befindet. Da ganzoben ja immer um eins erhöht
wird, ist das angeklickte Element das höchste.
document.getElementById(objekt).style.zIndex=ganzoben;
ganzoben++;
Das mit dem zIndex ist wohl das, was man quick
and dirty programming nennt. Es hat aber den unbestechlichen
Charme, dass es funktionniert. Sehen wir einmal von der Tatsache
ab, dass das Event Objekt in Netscape als Parameter übergeben
wird und im Explorer als globale Variable event überall
vorhanden ist, ist die Syntax gleich. Wir weisen event den
Wert e zu und können dann die Position des Mauszeigers
zum Zeitpunkt des events ermitteln.
if(!document.all)
{event=e;}
startX=event.clientX; startY=event.clientY;
Kurz noch eine Bemerkung zu document.all. document.all braucht
man nicht mehr, da jetzt getElementById, getElementsByName
etc. zur Verfügung steht. Nach wir vor hat der Explorer
dieses Objekt, das alle Elemente eines documentes beinhaltet.
Wenn also ein Browser !document.all nicht hat, dann ist es
auf jeden Fall nicht der Explorer. Jetzt haben wir erstmal
alles, was wir brauchen. Wir kennen das Objekt, über
dem die Maus gedrückt wurde und wir kennen die Position
des Mauszeigers, als die Maustaste gedrückt wurde. Da
wir es folglich mit einer Situation zu tun haben, wo wir etwas
bewegen wollen, schieben wir mit
document.onmousemove=bewegen;
die Funktion bewegen an. Vorher ermitteln wir
noch, wo das Bild, das wir verschieben wollen, im Moment positionniert
ist, denn auch das werden wir nachher brauchen.
XpositionAlt=document.getElementById(objekt).style.left;
YpositionAlt=document.getElementById(objekt).style.top;
Die Funktion bewegen sieht dann so aus.
function bewegen(e)
{
if(objekt)
{
if(!document.all)
{event=e;}
Xwert=event.clientX-startX;
Ywert=event.clientY-startY;
document.getElementById(objekt).style.left=parseInt(XpositionAlt)+Xwert;
document.getElementById(objekt).style.top=parseInt(YpositionAlt)+Ywert;
}
return false;
}
Die Funktion bewegen() tut nur etwas, wenn
ein Objekt vorhanden ist, das heisst, wenn der User mal über
einem Bild die Maustaste gedrückt hat, siehe oben. Wir
müssen alle Funktionalitäten der Funktion bewegen()
kapseln, da wir eine Möglichkeit brauchen, den Vorgang
zu stoppen. Wir tun das nachher in der Funktion beenden(),
die die Variable objekt wieder auf false setzt. Aus den oben
bereits erwähnten Gründen, muss zuerst der Wert
der Variablen e der Variablen event zugewiesen werden.
if(!document.all)
{event=e;}
Anschliessend ermitteln wir um wieviel der Mauszeiger
bewegt wurde.
Xwert=event.clientX-startX;
Ywert=event.clientY-startY;
event.clientX ist hierbei der horizontale Abstand
zum rechten Rand des Dokumentes, event.ClientY der horizontale.
Von diesen Werten ziehen wir die Werte ab, die wir hatten,
als das Event ausgelöst wurde und haben dann die Strecke,
die der Mauszeiger zurückgelegt hat. Die neue Position
des Bildes ergibt sich aus der alten Position des Bildes +
der Differenz.
document.getElementById(objekt).style.left=parseInt(XpositionAlt)+Xwert;
document.getElementById(objekt).style.top=parseInt(YpositionAlt)+Ywert;
Wenn wir die Maustaste loslassen, lösen
wir die Funktion beenden aus. Wir erinnern uns, der event
handler onmouseup ist im ganzen Dokument aktiv, wir hatten
zu Beginn
document.onmouseup=beenden;
Die Funktion beenden() tut nicht viel, sie weist
lediglich der Variablen objekt einen neuen Wert zu, nämlich
false, was dann bewirkt, dass die Funktion bewegen() zwar
noch aktiv ist, aber nichts mehr tut, so dass wir mit der
Funktion beenden() das Verschieben des Objektes stoppen können.
|
 |