I am trying to create a drag and drop menu where a user can drag an image thumbnail from a div to a canvas.
The issue is the source div uses a sprite to display its a background thumbnail, so I have to use the setDragImage to allow an image to be displayed whilst dragging the div.
I can successfully drag the div to the canvas and drop the image fine, however my problem is whilst dragging the ghost image is not shown until the second time I drag the div.
I use this code from a previous answer: [HTML5 Drag and Drop events and setDragImage browser support
and here's my slightly modified version of this code:
var isIE = (typeof document.createElement("span").dragDrop === "function");
$.fn.customDragImage = function(options) {
var offsetX = 0,
offsetY = 0;
var createDragImage = function($node, x, y) {
var $img = $(options.createDragImage($node));
icon = "icon" + window.draggedimgsrc;
offsetX = window[icon][2] / 2;
offsetY = window[icon][3] / 2;
$img.css({
"top": Math.max(0, y-offsetY)+"px",
"left": Math.max(0, x-offsetX)+"px",
"position": "absolute",
"pointerEvents": "none"
}).appendTo(document.body);
setTimeout(function() {
$img.remove();
});
return $img[0];
};
if (isIE) {
$(this).on("mousedown", function(e) {
var originalEvent = e.originalEvent,
node = createDragImage($(this), originalEvent.pageX, originalEvent.pageY);
node.dragDrop();
});
}
$(this).on("dragstart", function(e) {
var originalEvent = e.originalEvent,
dt = originalEvent.dataTransfer;
if (typeof dt.setDragImage === "function") {
node = createDragImage($(this), originalEvent.pageX, originalEvent.pageY);
console.log("node="+node);
dt.setDragImage(node, offsetX, offsetY);
}
});
return this;
};
$("[draggable='true']").customDragImage({
createDragImage: function($node) {
//init icon [0] = icon filename | [1] = icon set | [2] = icon width | [3] = icon height
icon = "icon" + window.draggedimgsrc;
window.draggedimgset = window[icon][1];
image="/boards/markers/soccerm/set" + window[icon][1] + "/" + window[icon][0] + ".png";
return $node.clone().css("width", window[icon][2]).css("height", window[icon][3]).css("background", "transparent url(" + image + ") no-repeat center"); }
}).on("dragstart", function(e) {
e.originalEvent.dataTransfer.setData("Text", "Foo");
});
What's strange is that when I pop a border on the $node.clone() it gets set when i do the first drag it just doesn't seem to put the image in there.
I've also put a manual width and height in so I know its not the size of the image.
And I preload the image before the menu appears.
Any ideas?
Pre-loading the drag feedback images outside of the event listener seems to avoid the issue where the drag image does not appear on the first drag. There are a variety of ways to do this and the best one is highly dependent on exactly what you are trying to do. Following is an approach, where the url for the drag image is stored in a data attribute on the draggable element and the drag feedback image for each element is created and stored in an object beforehand.
Following are jQuery and vanilla JS examples: