marc plogas: übergabe von variablen an mit settimeout ausgeführte funktion

hallo und frohe weihnacht miteinander:

seit mehreren tagen versuche ich folgender funktion eine timeout-funktionalität beizubringen. hab schon hier im forum gestöbert und ähnliche fälle gefunden, aber die entsprechende lösung hilft auch bei mir nicht.
und aus diversen setTimeout Manuals werde ich in diesem speziellen fall auch nicht schlau. hier mal das script:

<script language="javascript">
/*var curr_XPos, curr_YPos, end_XPos, end_YPos, scr_Speed;*/
// mit globalen variablen geht es auch nicht, war ja im prinzip klar...

function accessStyle(objectID)
{
if (document.getElementById)
 {
 return document.getElementById(objectID).style;
 }
else
{
 alert("browser momentan nicht unterstuetzt.\nExiting.");
 return 0;
}
}

function moveLayer(objectID,end_XPos,end_YPos,scr_Speed)
//objectID = layerID; end_XPos = Ziel-X-Wert; end_YPos = Ziel-Y-Wert; scr_Speed = Scrollgeschwindigkeit;
{
//variablen
/*iW = parseInt(document.body.clientWidth);
iH = parseInt(document.body.clientHeight);*/
curr_XPos = parseInt(accessStyle(objectID).left);
curr_YPos = parseInt(accessStyle(objectID).top);
var test = 0;

//schleife um a)herauszufinden in welche richtung der layer bewegt werden soll und b) um den layer dann halt auch zu bewegen
while ((end_XPos != curr_XPos)||(end_YPos != curr_YPos))
 {
 XDiff = end_XPos - curr_XPos;
 YDiff = end_YPos - curr_YPos;
  if (XDiff > 0)
        {
   accessStyle(objectID).left = curr_XPos++;
  }
  else if (XDiff < 0)
  {
   accessStyle(objectID).left = curr_XPos--;
  }
  if (YDiff > 0)
        {
   accessStyle(objectID).top = curr_YPos++;
  }
  else if (YDiff < 0)
  {
   accessStyle(objectID).top = curr_YPos--;
  }

}
 test = setTimeout('movelayer('+objectID+','+end_XPos+','+end_YPos+')',scr_speed);
 alert(test); //warum gibt test hier riesige zahlen aus??
}
</script>

das ganze wird dann über ein onclick event auf dem layer aufgerufen:
<div id="testlayer" style="position: absolute; top: 0px; left: 0px;"><a href="#" onclick="moveLayer('testlayer',100,100,1000)">blabla</a></div>

der layer bewegt sich auch zu den gewollten koordinaten, nur mit dem timeout gibt es große problem. warum weiss ich beim besten willen nicht.

danke im voraus

marc plogas

  1. Hallo,

    test = setTimeout('movelayer('+objectID+','+end_XPos+','+end_YPos+')',scr_speed);
    alert(test); //warum gibt test hier riesige zahlen aus??

    Du hast Dich einfach mit den Hochkommata verdaddelt - damit wird das meiste zum String und ansonsten wird end_XPos + end_YPos + scr_Speed aufaddiert. So wie ich das sehe sollte das eher test = setTimeout(movelayer(objectID,end_XPos,end_YPos,scr_speed)); heißen.

    Grüße,

    Utz

    1. Hallo,

      öhm...voriges Posting bitte einfach vergessen und so tun als wäre es nie dagewesen - ich hatte eine falsche Syntax von setTimeout() im Kopf und fand es zuerst nicht nötig, lieber nochmal nachzuschauen *schäm*

      Grüße,

      Utz

      1. Es ist doch weihnachten, das fest der liebe und der vergebung ;-)

  2. Hallo Marc,

    hallo und frohe weihnacht miteinander:

    Ebenfalls frohe Weihnachten ebenfalls!

    Oh, jeh. Ich geh deinen Quelltext mal der Reihe nach durch:

    //schleife um a)herauszufinden in welche richtung der layer bewegt werden soll und b) um den layer dann halt auch zu bewegen
    while ((end_XPos != curr_XPos)||(end_YPos != curr_YPos))

    Wenn du hier eine Schleife notierst, wird das ganze solange ausgeführt, bis sich der div an der gewünschten Position befindet. Da dazwischen keine Pausen eingehalten werden, läuft die Bewegung mit "unendlicher Geschwindigkeit" ab (Rechenzeiten einmal vernachlässigt). Der div wird also sofort zu seiner Zilposition bewegt. Was du brauchst, ist eine if-Selektion:

    if (end_XPos != curr_XPos || end_YPos != curr_YPos )

    accessStyle(objectID).left = curr_XPos++;

    Damit weist du der Eigenschaft "left" *zuerst* den Wert der Variablen "curr_XPos" zu und erhöst *anschließend* den Wert von "curr_XPos". Wenn also beispielsweise curr_XPos vor dieser Anweisung den Wert 12 hat, dann wird der div zur x-Koordinate 12 bewegt und danach wird der Wert von curr_XPos auf 13 gesetzt. Du willst wahrscheinlich in wirklichkeit das hier:

    accessStyle(objectID).left = ++curr_XPos;

    oder - was ich sinnvoller finde, da der Wert von curr_XPos ja anschließend nicht mehr gebraucht wird:

    accessStyle(objectID).left = curr_XPos + 1;

    accessStyle(objectID).left = curr_XPos--;

    Hier genauso:

    accessStyle(objectID).left = curr_XPos - 1;

    accessStyle(objectID).top = curr_YPos++;

    accessStyle(objectID).top = curr_YPos + 1;

    accessStyle(objectID).top = curr_YPos--;

    accessStyle(objectID).top = curr_YPos - 1;

    test = setTimeout('movelayer('+objectID+','+end_XPos+','+end_YPos+')',scr_speed);

    Das ist die "Killeranweisung":

    Erstens musst du hier das L in moveLayer groß schreiben, weil du das in der Funktionsdefinition auch so gemacht hast. Das zweite S in scr_Speed natürlich genauso. An der Groß- und Kleinschreibung verzweifle ich in JavaScript auch oft.

    Dann musst du dir vorstellen, was der Interpreter mit dieser Zeile machen würde: Er würde die einzelnen String-Literale und Variablen zu einem String zusammensetzen, den er dann als Anweisung interpretiert und nach einer Sekunde ausführt.

    Wenn objectID == "testlayer" und end_Xpos == 100 und end_YPos == 100 ergibt das folgende Anweisung:

    moveLayer(testlayer,100,100);

    • testlayer ist hier als String-Literal gedacht, muss also in Anführungsstriche.
    • die Parameterübergabe von scr_Pos fehlt

    Richtig heißt di Zeile also so:

    test = setTimeout('moveLayer("' + objectID + '",'+end_XPos+','+end_YPos+',' + scr_Speed + ')',scr_Speed);

    Mit diesen Korrekturen sollte es funktionieren. Wenn ich aber schon mal dabei bin, zu Antworten, lass mich auch gleich mal meinen Senf dazu geben, wie man es IMHO einfacher machen könnte:

    Wenn du unterschiedliche x- und y-Zielkoordinaten angibst, wirst du merken, dass die Bewegung zuerst diagonal verläuft, dann einen "Knick" macht und den Rest geradlienig weiterläuft. Also z.B. so:

    +-------+
    | START |
    +-------+
        \      \       \        \         \          \           \                    +------+
               \___________________| ZIEL |
                                   +------+

    Ich weiß jetzt nicht, ob du das nicht auch genau so wolltest, nehme es aber nicht an.

    Mit dieser Funktion:

    function bewegen2(objectID,xZiel,yZiel,zeit)
    {
      objektStyle = accessStyle(objectID);  /* nur einmal Abfragen und wiederverwenden - ist IMHO eleganter */
      xPos = parseInt(objektStyle.left);
      yPos = parseInt(objektStyle.top);

    /* schrittzahl ermitteln: Anzahl der Bewegungsschritte, die ausgeführt werden */
      if (Math.abs(xZiel - xPos) > Math.abs(yZiel - yPos))  schrittzahl = Math.abs(xZiel - xPos);
      else  schrittzahl = Math.abs(yZiel - yPos);

    /* Wenn die Bewegung zu langsam ist, kannst du sie mit
      schrittzahl = Math.round(schrittzahl / 2);
       schneller machen. Wichtig ist das Runden auf ganze Zahlen */

    if (schrittzahl == 0)  schrittzahl = 1;  /* damit keine Division durch 0 entsteht */

    /* xSpeed und ySpeed: Anzahl der Pixel, die das Objekt in jedem Schritt nach rechts bzw. unten verschoben wird */
      xSpeed = (xZiel - xPos) / schrittzahl;
      ySpeed = (yZiel - yPos) / schrittzahl;

    intervall = setInterval("schrittzahl--; xPos += xSpeed; yPos += ySpeed; objektStyle.left = Math.round(xPos) + 'px'; objektStyle.top = Math.round(yPos) + 'px'; if (schrittzahl == 0) clearInterval(intervall);",zeit);
    }

    wird das vermieden. Allerdings musst du hier aufpassen, da alle Variablen global sind, damit sie in setInterval referenziert werden können. Wenn du das nicht willst (beispielsweise wenn sich mehrere Objekte gleichzeitig bewegen sollen), musst du die Anweisungen in setIntervall in eine eigene Funktion packen.

    Viel Erfolg,
    Robert

    1. Viel Erfolg,
      Robert

      Hallo Robert, dankeschön für die ausführliche hilfe. nun hab ich ja über die freien, bevorstehenden tage wieder was zu tun.
      werde es gleich mal probieren

      gruß

      marc

      1. Hallo Marc,

        nun hab ich ja über die freien, bevorstehenden tage wieder was zu tun.

        Aber bitte nicht das Feiern vergessen...
        Sonst bin ich nämlich daran schuld ;-)

        soweit,
        Robert

        1. Nagut, ich habs heute halt schon mal umgesetzt, obwohl ich den nachmittag eigentlich anders geplant hab, meine weihnachtsfee ist sowieso auch arbeiten ...
          Das script funzt sehr gut, aber wenn ich nun die festen werte eingebe, wo es hinscrollen soll (z.b. 200,200) scrollt es irgendwie weit ausserhalb des bildes. Woran liegt das?
          Werden die xZiel/YZiel Werte prozentual oder relativ behandelt?

          aso, und feiern werde ich schon nicht vergessen.
          ;-)

          gruss
          Marc

          1. Hallo Marc,

            Das script funzt sehr gut, aber wenn ich nun die festen werte eingebe, wo es hinscrollen soll (z.b. 200,200) scrollt es irgendwie weit ausserhalb des bildes. Woran liegt das?

            Was meinst du mit "weit ausserhalb des Bildes"?

            Werden die xZiel/YZiel Werte prozentual oder relativ behandelt?

            Sie sollten absolut behandelt werden. Das heißt, nach der Bewegung befindet sich das Objekt genau an den Koordinaten (xZiel | yZiel), egal wo es vorher war. Funktioniert bei mir in einer Testseite auch so, auch wenn sich der div vor der Bewegung an einer anderen Position als (0|0) befindet. Geht das bei dir nicht?

            Robert

            1. Hallo Robert,
              sorry hab gestern net antworten können, da war ja weihnachten. und dem fest der liebe zuliebe hab ich meinen compi nicht angemacht ;-)

              Was meinst du mit "weit ausserhalb des Bildes"?

              Wenn der layer bei mir die koordinaten left: 0 top:16 hat und ich lasse ihn zu 200,200 scrollen geht der layer zur absoluten position (grob geschätzt -vierfache auflösung oder so) 5120,4048. Interessanterweise, wenn ich die bewegung verlangsame (also 1000ms), springt der layer nicht punkteweise, sondern eher 1/3 der bildschirmdiagonale. Mit nem alert drin ist die Schrittzahl in dem eben geschilderten Szenario 200 und die wird dann halt runtergearbeitet. nacht tippfehlern hab ich eben schon gesucht, habe aber keine gefunden.

              Vielleicht fällt dir ja noch was ein

              Danke schonmal im voraus. Ist auch erstmal nicht so dringend weil ja feiertage und familienfeste sind ;-)
              Da sind compis, glaube ich, geächtet

              Marc

              1. Hallo Marc,

                Wenn der layer bei mir die koordinaten left: 0 top:16 hat und ich lasse ihn zu 200,200 scrollen geht der layer zur absoluten position (grob geschätzt -vierfache auflösung oder so) 5120,4048.

                Welchen Browser verwendest du denn? Ich hab' das unter IE 6 und NC 7 getestet, da gings. Ich habe auf einem Screenshot nachgemessen, der "Ankunftsort" könnte ungefähr 200,200 sein. Nur Opera 7 beta 2 macht komischerweise gar nichts - weiß jemand warum?

                Ich schick dir mal den Quellcode, mit dem ich getestet habe. Es ist noch die gleiche Funktion, nur die Schrittzahl wird jetzt anders ermittelt, weil ich das so irgendwie doch sinnvoller finde. Es funktioniert bei mir aber auch mit der bisherigen Schrittzahlermittelung.

                Der Code:

                <html>
                <head>
                <script language="JavaScript" type="text/javascript">
                <!--
                function accessStyle(objectID)
                {
                  if (document.getElementById) {
                    return document.getElementById(objectID).style;
                  } else {
                    alert("browser momentan nicht unterstuetzt.\nExiting.");
                    return 0;
                  }
                }

                function bewegen2(objectID,xZiel,yZiel,zeit)
                {
                  objektStyle = accessStyle(objectID);
                  xPos = parseInt(objektStyle.left);
                  yPos = parseInt(objektStyle.top);

                schrittzahl = Math.round(Math.sqrt((xZiel-xPos)*(xZiel-xPos) + (yZiel-yPos)*(yZiel-yPos)));
                  if (schrittzahl == 0)  schrittzahl = 1;
                 
                  xSpeed = (xZiel - xPos) / schrittzahl;
                  ySpeed = (yZiel - yPos) / schrittzahl;
                  intervall = setInterval("schrittzahl--; xPos += xSpeed; yPos += ySpeed; objektStyle.left = Math.round(xPos) + 'px'; objektStyle.top = Math.round(yPos) + 'px'; if (schrittzahl == 0) clearInterval(intervall);",zeit);
                }
                //-->
                </script>
                </head>
                <body>

                <div id="testlayer" style="position: absolute; top: 16px; left: 0px;"><a href="javascript:bewegen2('testlayer',200,200,100)">blabla</a></div>

                </body>
                </html>

                Würde mich wundern, wenn das bei dir nicht funktioniert, denn bei mir läuft's und ich sehe auch keine Fehler.

                Viel Erfolg und noch frohe Weihnachten,
                Robert

                1. Hallo Robert,

                  Welchen Browser verwendest du denn? Ich hab' das unter IE 6 und NC 7 getestet, da gings.

                  MS IE 6.0.26

                  Ich schick dir mal den Quellcode, mit dem ich getestet habe.

                  Mit dem Code funktioniert es...

                  Würde mich wundern, wenn das bei dir nicht funktioniert, denn bei mir läuft's und ich sehe auch keine Fehler.

                  Dann werde ich mal schauen was ich falsch gemacht hab. Vielleicht hab ich ja irgendwelche Variablen vertauscht, oder was weiss ich. Ich schreib dir, wenn ich den Fehler gefunden hab...

                  Dankeschön nochmal, hast mir wirklich sehr geholfen.

                  Gruß
                  Marc