Felix Riesterer: Drag&Drop mit Zielhighlight?

Liebe Javascriptler,

ich hatte bereits geschrieben, dass ich eine Explorer-artige Drag&Drop-Steuerung implementieren möchte.

Ich habe da einen Versuch online gestellt, dessen reines Drag&Drop aber noch nicht störungsfrei verläuft. Es wird zwar jedes <li>-Element der Liste bei Bedarf beweglich gemacht, aber die Bewegungsfähigkeit beläuft sich auf zwei bis drei Pixel...

Der Drag-Mechanismus wird offensichtlich von Internet-Explorer und Mozilla Firefox durch eigene Drag&Drop-Mechanismen gestört, weshalb nach zwei bis drei Pixeln Bewegung der durchgestrichene Kreis als Mauszeiger erscheint und mein Dragging endet. Der negative Nebeneffekt ist der, dass ab sofort das bewegliche Element unter dem Mauszeiger "klebt" und nur durch einen weiteren Klick wieder "abgeschüttelt" werden kann.

Interessanterweise tritt diese Störung in Opera9 nicht auf. Hatte jemand soetwas schon einmal?

Liebe Grüße aus Ellwangen,

Felix Riesterer.

  1. Ich habe da einen Versuch online gestellt, dessen reines Drag&Drop aber noch nicht störungsfrei verläuft. Es wird zwar jedes <li>-Element der Liste bei Bedarf beweglich gemacht, aber die Bewegungsfähigkeit beläuft sich auf zwei bis drei Pixel...

    Die Drag Funktionen müssen ein return false zurückgeben.

    Struppi.

    --
    Javascript ist toll (Perl auch!)
    1. Lieber Struppi,

      Die Drag Funktionen müssen ein return false zurückgeben.

      danke! Das hilft mir ein gutes Stück weiter. Jetzt kann ich mich endlich an die "Zielerfassung" wagen...

      Liebe Grüße aus Ellwangen,

      Felix Riesterer.

  2. Update. ;-)

    Ich habe da einen Versuch online gestellt

    ... der mittlerweile im Firefox ziemlich zuverlässig das tut, was er soll. Jedoch ist das Ziehen des Elementes noch eine rechte Flimmerei.

    Das Flimmern kommt daher, da ich versucht habe, durch sehr kurze Ausblendungen des zu verschiebenden Elementes einen mouseover-Event im darunterliegenden zu provozieren. Das klappt auch ziemlich gut. Nur ist der Zeitabstand für das Auge unangenehm lange, sodass ein richtiges Flimmern sichtbar ist. Schuld daran ist, dass die setTimeout-Methode zu langsam reagiert. Selbst bei einer Millisekunde ist der Effekt im Firefox so deutlich, wie beim zehnfachen Wert. - Aber ohne diese Timeout-Methode ist die Ausblendung zu kurz...

    In Opera scheint ein Minimum von fünf Milisekunden notwendig zu sein, dass auch wirklich jedes Zielelement erreichbar wird, bevor das Drag-Element wieder durch seine Sichtbarkeit ein mouseover-Event unmöglich macht.

    Im IE habe ich eine noch nicht ergründete Verschiebung des Drag-Elements um ca. 20 Pixel nach oben links, sodass die Maus nicht mehr darauf deutet, da es sich zuweit oberhalb befindet. Naja, der IE wieder einmal!

    Liebe Grüße aus Ellwangen,

    Felix Riesterer.

    1. Update[2]. ;-)

      Ich habe da einen Versuch online gestellt

      ... dessen Flimmern konzept-bedingt ist. Um das unter meinem bewegten Element von der Maus anvisierte Zielelement zu erreichen, schalte ich das bewegte Element kurz auf display:none, um ein mouseover-Event im Zielelement zu provozieren. Das führt natürlich zu einem heftigen Flimmern des beweglichen Elements, da es ständig an- und ausgeschaltet wird.

      Aber jetzt konnte ich das Flimmern etwas reduzieren. Da ja nicht bei exakt jedem mousemove (der mitunter nur wegen eines Pixels Differenz zur vorherigen Position ausgelöst wird) ein Unsichtbarschalten vonnöten ist, habe ich einen Countdown eingebaut, der ein paar Zyklen einfach auslässt, bevor das Element wieder unsichtbar wird.

      Anscheinend gibt es deutliche Unterschiede im Timing bei Opera im Vergleich zu Mozilla Firefox. Daher habe ich zunächst auf navigator.appName getestet und für "Opera" und "Netscape" verschiedene Werte ausprobiert und im Script fest vergeben. IE bekommt auch noch sinnvolle Werte, wenn ich das Abstandsproblem zum Mauszeiger wieder in den Griff bekommen habe.

      Wenn mir jemand Erfahrungen in mir zunächst unzugänglichen Browsern berichten möchte, dann wäre ich sehr dankbar, denn mich interessiert natürlich, inwieweit das auf anderen Systemen (FF & Konqueror auf SuSE10 teste ich noch) aussieht.

      Liebe Grüße aus Ellwangen,

      Felix Riesterer.

      1. IE bekommt auch noch sinnvolle Werte, wenn ich das Abstandsproblem zum Mauszeiger wieder in den Griff bekommen habe.

        Das habe ich nun, und was passiert??? Dasselbe Problem wie vorher mit Firefox: Der Browser springt in seinen eigenen Drag&Drop-Modus, erkennt dass da nix wirklich Verschiebbares herumliegt und verändert nach wenigen Pixeln den Mauszeiger in den durchgestrichenen Kreis. Mist!

        Anscheinend hat der IE eine eigene Drag&Drop-API (oder wie man das nennt), mit eigenen Eventhandlern (ich las von ondragstart und Konsorten). Muss ich die benutzen und für den IE einen eigenen Programmzweig entwickeln, oder kann ich ihm die bisherige in Firefox und Opera funktionierende Methode "antrainieren"? Struppis Tipp mit dem return false wirkt hier leider nicht...

        Liebe Grüße aus Ellwangen,

        Felix Riesterer.

        1. Nachtrag...

          ich kriege den IE nicht zum braven Draggen. Irgendwie komme ich alleine gerade nicht weiter. Nach ein paar Pixeln blockiert der IE das weitere Verschieben des zu draggenden Elementes.

          Die Rückgabewerte der Eventhandler scheinen nicht daran beteiligt zu sein, sie stehen alle brav auf false.

          Wenn sich jemand das Ganze zum Testen herunterladen möchte, so kann er oder sie das hier tun: explorer-test.zip (37,3KB)

          Liebe Grüße aus Ellwangen,

          Felix Riesterer.

  3. Hallo, Felix!

    schau dir mal windows live mail an, das funktioniert bei mir sowohl im ie, als auch im firefox. der trick scheint zu sein, das symbol des zu bewegenden objektes nicht direkt unter, sondern knapp neben der maus anzuordnen.
    darüberhinaus kannst du der maus im firefox z.b. auch einen eigenen cursor zuweisen ('url(objmove.gif), move'). wie sich das im ie verhält, entzieht sich mangels interesse meiner kenntnis.

    freundl. Grüsse aus Berlin, Raik

    --
    Der IE ist wichtig. Man benötigt ihn, um sich einen Browser zu besorgen.
    Resizeable Textarea 0.1d # docked JS-Console 0.1
    1. Lieber Raik,

      danke für Deinen Tipp! Ich kenne windows live mail nicht, aber wenn die das Schiebeelement neben der Maus anzeigen, dann geht ja das beabsichtigte bekannte Windoow-Explorer-Gefühl weg... Dieses Gefühl will ich aber gerade erreichen!

      darüberhinaus kannst du der maus im firefox z.b. auch einen eigenen cursor zuweisen ('url(objmove.gif), move'). wie sich das im ie verhält, entzieht sich mangels interesse meiner kenntnis.

      Das wäre auch keine Lösung, da der Mauszeiger neben dem Datei- oder Ordner-Icon auch noch die Beschriftung (Datei-/Ordnername) transportieren soll. Dafür müsste ich mal eben schnell eine Grafik entwickeln, die das zu verschiebende Element _komplett_ abbildet, und das ist in Javascript völlig unmöglich. Da wäre eine Flash-Variante wahrscheinlich eher dazu in der Lage. Aber ich versuche es ja gerade mit Javascript!

      Liebe Grüße aus Ellwangen,

      Felix Riesterer.

  4. Moin!

    Ich habe mit SeaMonkey und Safari auf Mac getestet.

    SeaMonkey:
    Sieht okay aus, nur: Wie kann man in Bereiche verschieben, die Momentan nicht sichtbar sind? Wenn man an den Rand kommt, wird nicht gescrollt.
    Wer kein Scrollrad hat, ist aufgeschmissen.

    Safari:
    Das Schiebeelement wird oberhalb des Mauszeigers dargestellt, nicht, wie bei SeaMonkey unterhalb. Allerdings stört (mich) das nicht. Nur: Vielleicht ist das die Lösung für Dein "Flackerproblem"!? Stell das Schiebeelement um einen Pixel vom Mauszeiger verssetzt dar und Du mußt es nicht immer ausschalten um einen over-Effekt für den Zielort zu bekommen.
    Wer bei Safari ein Scrollrad an der Maus besitzt kann zwar in vorher nicht sichtbar Bereiche verschieben, allerdings springt das Schiebeelement fröhlich durch die Gegend: Einmal Hochgescrollt springt das Schiebeelement um denselben Betrag nach unten, ist also recht weit vom Mauszeiger entfernt.

    SeaMonkey 1.0.5
    Safari 2.0.4
    auf
    Mac OS X 10.4.6

    -- Skeeve

    1. Liebe(r) Skeeve,

      Ich habe mit SeaMonkey und Safari auf Mac getestet.

      das ist großartig! Zu diesen Browsern habe ich zur Zeit keinen Zugang, da ich an kein Mac-System komme.

      Sieht okay aus, nur: Wie kann man in Bereiche verschieben, die Momentan nicht sichtbar sind? Wenn man an den Rand kommt, wird nicht gescrollt.
      Wer kein Scrollrad hat, ist aufgeschmissen.

      Das wird tatsächlich noch nicht unterstützt. Das Betätigen des Scrollrades beachte ich in meinen Events noch nicht. Das wäre also noch nachzurüsten. Meines Wissens gibt es für das Mausrad auch einen Eventlistener... Danach könnte man ja die Mausposition erneut auslesen lassen, um das Element wieder an seine zur Maus relative Position zurückzuversetzen.

      Safari:
      Das Schiebeelement wird oberhalb des Mauszeigers dargestellt, nicht, wie bei SeaMonkey unterhalb.

      Aha... Auch in den diversen IEs kann ich es noch nicht zuverlässig an der aktuellen Mausposition verankern. Irgendwie stimmt in meinem Script da noch eine Kleinigkeit nicht. Dass Safari hier ebenfalls abweicht ist ärgerlich!

      Vielleicht ist das die Lösung für Dein "Flackerproblem"!? Stell das Schiebeelement um einen Pixel vom Mauszeiger verssetzt dar und Du mußt es nicht immer ausschalten um einen over-Effekt für den Zielort zu bekommen.

      Um das Drag&Drop so "echt" wie möglich wirken zu lassen, habe ich die Position des Elements relativ zur Mausposition zum Zeitpunkt des "Anfassens" beibehalten. Egal, ob ich das Element vorne, hinten, oben oder mehr in der Mitte anfasse, es verbleibt genau so unter dem Mauszeiger "kleben". Deshalb muss es flackern. Eine Lösung bei der das Schiebe-Element unterhalb des Mauszeigers (also um einige Pixel versetzt) angezeigt wird, geht der Drag-Effekt fast schon flöten, da es sich nicht mehr wie im Windoof Explorer "anfühlt". Natürlich wäre eine solche Lösung leichter umzusetzen, aber sie würde auch weniger spektakulär oder gar irritierend wirken.

      Wer bei Safari ein Scrollrad an der Maus besitzt kann zwar in vorher nicht sichtbar Bereiche verschieben, allerdings springt das Schiebeelement fröhlich durch die Gegend: Einmal Hochgescrollt springt das Schiebeelement um denselben Betrag nach unten, ist also recht weit vom Mauszeiger entfernt.

      Das stimmt. Aber wie schon oben angesprochen müsste ich in einem weiteren Entwicklungsprozess die Betätigung des Scrollrades abfragen. Inwieweit das von allen aktuellen Browsern unterstützt wird, muss ich noch in Erfahrung bringen.

      Dir ganz lieben Dank für das ausgiebige Testen meines Scripts!

      Liebe Grüße aus Ellwangen,

      Felix Riesterer.

      1. Wer kein Scrollrad hat, ist aufgeschmissen.

        Das wird tatsächlich noch nicht unterstützt. Das Betätigen des Scrollrades beachte ich in meinen Events noch nicht. Das wäre also noch nachzurüsten. Meines Wissens gibt es für das Mausrad auch einen Eventlistener...

        Nach meinen Recherchen gibt es window.onscroll, welches aber anscheinend nicht in allen Browsern auf das Mausrad hin anspricht. Im Firefox vor 1.5 soll ein Browserbug das Mausrad ignoriert haben.

        Weiß jemand von noch mehr Browsern, bei denen dieses Event nicht zuverlässig feuert, wenn man auf einer Seite scrollt?

        Liebe Grüße aus Ellwangen,

        Felix Riesterer.

        1. Hallo,

          Nach meinen Recherchen gibt es window.onscroll, welches aber anscheinend nicht in allen Browsern auf das Mausrad hin anspricht. Im Firefox vor 1.5 soll ein Browserbug das Mausrad ignoriert haben.

          Ich hab mir vor ein paar Tagen mal diese Cross-Browser-Variante für Mausrad-Events  gebookmarkt, allerdings nicht näher angeschaut oder ausgetestet: http://adomas.org/javascript-mouse-wheel/

          Offenbar gibt es im IE-Land den Eventhandler onmousescroll, während Mozilla zusätzlich noch für XUL den Event DOMMouseScroll implementiert hat. In den offiziellen DOM Events Spezifikationen wird noch das DOM Level 0 Event scroll definiert. Chaos also. ;)

          Tim