Drag & Drop, mousemove und der Internet Explorer mit jQuery
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…
Füge diese URL in deine WordPress-Website ein, um sie einzubetten
Füge diesen Code in deine Website ein, um ihn einzubinden