0 Reaktionen

Drag & Drop, mousemove und der Internet Explorer mit jQuery

Geschätzte Lesedauer:

Heute ist mal wieder so ein Tag… Da hat mich der Internet Explorer (in diesem Fall Version 8 ) fast zur Verzweiflung gebracht.

Aufgabenstellung ist eine Seite, auf der viele einzelne Bilder durch Drag & Drop angeordnet werden können, allerdings auf vordefinierten Positionen und nicht mit <img> Tags sondern <div> mit Hintergrundbildern und Child-Nodes.
Natürlich gibt es für solche Aufgaben das ein oder andere jQuery-Plugin, allerdings waren diese für die Aufgabe entweder ungeeignet oder einfach viel zu aufgebläht. Also an die Arbeit und etwas Kleines mit jQuery selbst erstellt.
Grob vereinfacht mit solchem Code:

[pastacode lang=“javascript“ message=“JavaScript“ highlight=““ provider=“manual“]

$(document).ready(function() {
    var dragActive = false;
    var dragEl = $('#dragelement');
    var atX = 0;
    var atY = 0;
    function _storeMousePos(event) {
        if(!event) event = window.event;
 
        if(typeof event.pageX == 'number') {
            atX = event.pageX;
            atY = event.pageY;
        } else {
            atX = event.clientX;
            atY = event.clientY;
            var oIEBody;
            if(document.documentElement) oIEBody = document.documentElement;
            else oIEBody = document.body;
            if (typeof oIEBody.scrollTop == "number") {
                atX += oIEBody.scrollLeft;
                atY += oIEBody.scrollTop;
            }
        }
    }
 
    function _moveElToMouse() {
        var toX = atX - subX;
        var toY = atY - subY;
 
        if(toX < -130) toX = -130;
        else if(toX > 650) toX = 650;
        if(toY < 0) toY = 0;
        else if(toY > 500) toY = 500;
 
        dragEl.css({ 'left': toX, 'top': toY });
    }
 
    $(document).mouseup(function(e) {
        if(dragActive == false) return;
 
        dragEl.hide();
        // stop dragging if dragging is active
        dragActive = false;
    });
 
    $(document).mousemove(function(event) {
        if(dragActive == false) return;
        if(!event) event = window.event;
        _storeMousePos(event);
        event.preventDefault();
        _moveElToMouse();
    });
 
    $('.draggable').each(function() {
        var obj = $(this);
         
        obj.unbind('click');
        obj.unbind('mousedown');
        obj.unbind('mouseup');
 
        obj.click(function(event) { event.preventDefault(); return false; });
        obj.select(function(event) { event.preventDefault(); return false; });
        obj.dblclick(function(event) { event.preventDefault(); return false; });
 
        obj.mousedown(function(event) {
            _storeMousePos(event);
            _moveElToMouse();
            dragActive = true;
            event.preventDefault();
            dragEl.show();
        });
    });
});

[/pastacode]

Das ist zwar nicht der vollständige Code (es fehlen z.B. Teile wie die Drop-Aktionen etc.), dürfte jedoch alles notwendige enthalten um den Vorgang zu verstehen.

Während im Firefox und Opera alles recht schnell funktionierte, stellte der Internet Explorer meine Geduld auf die Probe:
Die Bilder blieben während des Ziehens einfach an ihrem ursprünglichen Ort – erst wenn die Maus dann losgelassen wurde sprangen sie an die neue Position.

Erster Teil der Lösung:
Die Bildelemente sind alle mit position: absolute in einem anderen <div> Element positioniert. Scheinbar reicht hier das mousemove Event vom document Objekt nicht aus, also den entsprechenden JavaScript Block kopieren:

[pastacode lang=“javascript“ message=“JavaScript“ highlight=““ provider=“manual“]

$('#container_div').mousemove(function(event) {
    if(dragActive == false) return;
    if(!event) event = window.event;
    _storeMousePos(event);
    event.preventDefault();
    _moveElToMouse();
});

[/pastacode]

Besser. Nun ließ sich zumindest ein wenig was bewegen. Allerdings nur sehr sporadisch und in großen Sprüngen. Nach längerem Google-Suchen, dann der Ansatz: Scheinbar zeichnet der Browser das Element einfach nicht neu.
Hier fand ich schließlich einen Ansatz dieses Problem zu umgehen.

Da das gesamte Plugin zu viel unnötigen Code für mich enthielt also erstmal ein Test mit einer simplen Codeänderung nach Vorbild des forcedraw-Plugins:

[pastacode lang=“javascript“ message=“JavaScript“ highlight=““ provider=“manual“]

function _moveElToMouse() {
    var toX = atX - subX;
    var toY = atY - subY;
 
    if(toX < -130) toX = -130;
    else if(toX > 650) toX = 650;
    if(toY < 0) toY = 0;
    else if(toY > 500) toY = 500;
 
    dragEl.css({ 'left': toX, 'top': toY }).addClass('forceReloadDummy').removeClass('forceReloadDummy');
}

[/pastacode]

Kein Effekt. Also wohl doch den ganzen Rattenschwanz des Plugins? Erst noch ein weiterer Test. Denn in der Beschreibung des Plugins stand ja etwas von „padding ändern“…

[pastacode lang=“javascript“ message=“JavaScript“ highlight=““ provider=“manual“]

function _moveElToMouse() {
    var toX = atX - subX;
    var toY = atY - subY;
     
    if(toX < -130) toX = -130;
    else if(toX > 650) toX = 650;
    if(toY < 0) toY = 0;
    else if(toY > 500) toY = 500;
     
    dragEl.css({ 'left': toX, 'top': toY, 'padding': 0 });
}

[/pastacode]

Und siehe da… Es läuft nun auch im Internet Explorer. Zwar nur deutlich langsamer als in Firefox und Opera, aber das liegt wohl an den vielen PNG Bildern mit Transparenz, die ich verwende. Da soll mal jemand verstehen, warum das Setzen eines paddings die Lösung ist, selbst wenn der Wert identisch bleibt…

Unabhängige Berichterstattung unterstützen.

Unterstütze wirklich unabhängige und Fakten-basierte Berichterstattung zu Mozilla, welche nicht das Ziel hat, Schlagzeilen zu produzieren, sondern objektiv zu informieren.

Dieser Artikel wurde von Marius Burkard verfasst.

Marius Burkard ist Diplom-Wirtschaftsinformatiker und arbeitet seit 2006 als selbstständiger Software-Entwickler und Linux-Server-Administrator mit der Firma pixcept KG. Er ist unter anderem mitverantwortlich für die Projekte Was-lese-ich.de und ISPProtect.

Und jetzt du! Deine Meinung?

Erforderliche Felder sind mit einem Asterisk (*) gekennzeichnet. Die E-Mail-Adresse wird nicht veröffentlicht.
  1. Nach Absenden des Kommentar-Formulars erfolgt eine Verarbeitung der von Ihnen eingegebenen personenbezogenen Daten durch den datenschutzrechtlich Verantwortlichen zum Zweck der Bearbeitung Ihrer Anfrage auf Grundlage Ihrer durch das Absenden des Formulars erteilten Einwilligung.
    Weitere Informationen