HTML5 Drag and Drop - No transparency?

JavascriptHtmlCss

Javascript Problem Overview


When I drag and drop an element on my page the element becomes "ghosted". Basically it gets some transparency value.

Is there some way to make it opacity: 1;?

Javascript Solutions


Solution 1 - Javascript

It looks like it can't be done. The dragged element is put into container that has it's own, lower than 1, opacity. This means that while you can lower the opacity of the dragged element you can't get it higher than the opacity of the encapsulating element.

It might be possible to override default browser settings for such element, but since nothing is added to DOM during the drag it would be very tricky at best.

Solution 2 - Javascript

As others have suggested, you will need some sort of mechanism that will:

  1. Hide the element that is being dragged.
  2. Make a clone of the element that is being dragged.
  3. Put the clone in place of the element that is being dragged.
  4. Listen to the drag event to position the clone element.

In practise, looks like this:

function Drag (subject) {
    var dative = this,
        handle,
        dragClickOffsetX,
        dragClickOffsetY,
        lastDragX,
        lastDragY;

    subject.draggable = true;

    dative.styleHandle(subject);

    subject.addEventListener('dragstart', function (e) {    
        handle = dative.makeHandle(subject);

        dragClickOffsetX = e.layerX;
        dragClickOffsetY = e.layerY;

        this.style.opacity = 0;
    });

    subject.addEventListener('drag', function (e) {
        var useX = e.x,
            useY = e.y;

        // Odd glitch
        if (useX === 0 && useY === 0) {
            useX = lastDragX;
            useY = lastDragY;
        }

        if (useX === lastDragX && useY === lastDragY) {
            return;
        }

        dative.translate(useX - dragClickOffsetX, useY - dragClickOffsetY, handle, subject);

        lastDragX = useX;
        lastDragY = useY;
    });

    subject.addEventListener('dragend', function (e) {
        this.style.opacity = 1;

        handle.parentNode.removeChild(handle);
    });
};

/**
 * Prevent the text contents of the handle element from being selected.
 */
Drag.prototype.styleHandle = function (node) {
    node.style['userSelect'] = 'none';
};

/**
 * @param {HTMLElement} subject
 * @return {HTMLElement}
 */
Drag.prototype.makeHandle = function (subject) {
    return this.makeClone(subject);
};

/**
 * Clone node.
 * 
 * @param {HTMLElement} node
 * @return {HTMLElement}
 */
Drag.prototype.makeClone = function (node) {
    var clone;

    clone = node.cloneNode(true);

    this.styleClone(clone, node.offsetWidth, node.offsetHeight);

    node.parentNode.insertBefore(clone, node);

    return clone;
};

/**
 * Make clone width and height static.
 * Take clone out of the element flow.
 *
 * @param {HTMLElement} node
 * @param {Number} width
 * @param {Nubmer} height
 */
Drag.prototype.styleClone = function (node, width, height) {
    node.style.position = 'fixed';
    node.style.zIndex = 9999;
    node.style.width = width + 'px';
    node.style.height = height + 'px';
    node.style.left = '-9999px';

    node.style.margin = 0;
    node.style.padding = 0;
};

/**
 * Used to position the handle element.
 * 
 * @param {Number} x
 * @param {Number} y
 * @param {HTMLElement} handle
 * @parma {HTMLElement} subject
 */
Drag.prototype.translate = function (x, y, handle, subject) {
    handle.style.left = x + 'px';
    handle.style.top = y + 'px';
};

Start with attaching an element:

new Drag(document.querySelector('.element'));

And you have a working drag and drop with full control over the looks of the draggable element. In the above example, I clone the original element to use it as the handle. You can extend the Drag function to customise the handle (e.g. use image to represent the draggable element).

Before you get too excited, there are couple of things to consider:

Update:

I have written a library for touch enabled implementation of WHATWG drag and drop mechanism, https://github.com/gajus/pan.

Solution 3 - Javascript

If you are not dragging and dropping elements from outside of the web page (from the operating system) then you could solve this problem easily by implementing your own drag and drop. There are numerous examples of pure javascript drag and drop which will function perfectly in an HTML5 environment and would be completely customizable by you.

answer: (use the old way)

Solution 4 - Javascript

Please see this working fiddle

I have a solution for making an opaque image in the place of ghost and it works fine in chrome.But its not working in FF.I need some body to help me to make it work in Firefox and other browsers. steps 1.We will make our own ghost image and will set it as the drag image.

document.addEventListener("dragstart", function(e) {
var img = document.createElement("img");
img.src = "img/hackergotchi-simpler.png";
e.dataTransfer.setDragImage(img, 5000, 5000);//5000 will be out of the window
}, false);

2.We will clone the image and append it to DOM ondrag

var crt,dragX,dragY;
function drag(ev) {
	crt = ev.target.cloneNode(true);
    crt.style.position = "absolute"; 
    document.body.appendChild(crt);
	ev.dataTransfer.setData("text", ev.target.id);
}

3.Then we will make the clone to move with cursor

    document.addEventListener("dragover", function(ev){
ev = ev || window.event;
dragX = ev.pageX; dragY = ev.pageY;
crt.style.left=dragX+"px";crt.style.top=  dragY+"px";
console.log("X: "+dragX+" Y: "+dragY);
}, false);

4.At Last we will make the clone visibility gone

   document.addEventListener("dragend", function( event ) {crt.style.display='none';});

Solution 5 - Javascript

As of 2021, You need not clone the element. The browser creates a semi-transparent clone that follow the mouse pointer on drag event. Meanwhile the original dragged item remains intact without any changes.

If you wish to show the original element being dragged to follow the mouse pointer then here's the trick.

Setup:

<!- HTML Code Sample ->
<div draggable="true" 
    ondragstart="onDragStart(event)" ondrag="onDrag(event)"
                    ondragend="onDragEnd(event)">

<!- JS Code Sample ->
var dx = 0, dy = 0, draggedItem = undefined;
function onDragStart(e) {}
function onDrag(e) {}
function onDragEnd(e) {}

Step 1: Save the difference between dragged item's (x, y) co-ordinates and mouse pointer co-ordinates as delta.

function onDragStart(e) {
    draggedItem = e.target;
    dx = e.clientX - draggedItem..getBoundingClientRect().x;
    dy = e.clientY - draggedItem..getBoundingClientRect().y;
    draggedItem.style.position = 'absolute';
}

Step 2: Update the dragged item's position with that of mouse pointer's (x, y) co-ordinates. Remember to subtract the delta.

function onDrag(e) {
    draggedItem.style.left = e.ClientX - dx;
    draggedItem.style.top = e.ClientY - dy;
}

Step 3: Depending upon whether to retain new position for the dragged item or run some custom logic.

function onDragEnd(e) {

    if('retain new position ???'){
        draggedItem.style.left = e.ClientX - dx;
        draggedItem.style.top = e.ClientY - dy;
    } else {
        draggedItem.style.position = 'static';

        // Add your custom logic to handle drag completion
    }

    // Clear temporary data
    draggedItem = undefined;
    dx = dy = 0;
}

This will make the original dragged item to follow the semi-transparent dragged clone which overcomes the effect of opacity. onDrag event is fired every 350ms and creates a decent visualization.

Solution 6 - Javascript

For those (like me) disappointed by the drag&drop html5 implementation, here is a basic, vanilla, cross-browser, pitfalls-free and fully customizable solution:

html:

<div class="dropzone"></div>
<div class="dropzone"></div>
<div class="draggable"></div>

js:

var currentElement, currentDropzone, offsetX, offsetY;
function findZoneUnderPoint(x, y) {
  var dropzones = preview.querySelectorAll(".dropzone");
  for (var i = 0; i < dropzones.length; i++) {
    var box = dropzones[i].getBoundingClientRect();
    if (x > box.left && x < box.right && y > box.top && y < box.bottom) {
      return dropzones[i];
    }
  }
}
function onMouseDown(event) {
  currentElement = event.target.closest(".draggable");
  if (currentElement) {
    var box = currentElement.getBoundingClientRect();
    offsetX = event.clientX - box.x;
    offsetY = event.clientY - box.y;
    currentElement.classList.add("drag");           
    currentElement.style.width = box.width.toFixed()+"px";
    currentElement.style.height = box.height.toFixed()+"px";    
    currentElement.style.left = (event.clientX - offsetX) + "px";
    currentElement.style.top = (event.clientY - offsetY) + "px";
    currentElement.style.position = "fixed";
    currentElement.style.zIndex = "999";
    this.addEventListener("mousemove", onMouseMove);
    this.addEventListener("mouseup", onMouseUp);
  }
}
function onMouseMove(event) {
  currentElement.style.left = (event.clientX - offsetX) + "px";
  currentElement.style.top = (event.clientY - offsetY) + "px";
  var dropzone = findZoneUnderPoint(event.clientX, event.clientY);
  if (dropzone !== currentDropzone) {
    if (dropzone) {
      // -> drag enter zone
    }
    if (currentDropzone) {
      // -> drag leave zone
    }
    currentDropzone = dropzone;
  }
}
function onMouseUp(event) {
  var dropzone = findZoneUnderPoint(event.clientX, event.clientY);
  if (dropzone) {
    // -> drag complete
  } else {
    // -> drag canceled
  }
  currentElement = null;
  document.removeEventListener("mouseup", onMouseUp);
  document.removeEventListener("mousemove", onMouseMove);
}
document.addEventListener("mousedown", onMouseDown);

Note: Element.closest() polyfill is needed for ie support.

Solution 7 - Javascript

as already mentioned, this is handled by the browser -> you cannot change this behavior, but if you really need this effect try to look for mouse move when mouse is down (short: dragging), check what element is selected and create a copy on the fly that follows your mouse cursor. looks like an ideal job for jQuery ;)

but if you don't need it desperately I wouldn't try to change the browsers' default values, as people are used to it and may be confused if something behaves in another (unknown) way

Solution 8 - Javascript

altough this is propably not the real solution of the core problem, I have an idea what might work, at least I tested this in one of my GWT project some time ago and it worked, so I guess it might work in native JS as well altough I have no code example:

  1. Instead of using the dragging function, create a new element which equals the element that should be dragget at the original position of the element to be dragged. The original Element to be dragged should be made invisible now. Implement a logic that restores the orignal element and removes the clone as soon as the mouse isn't pressed anymore.

  2. Make the clone Element stick to the mouse's position. The event that removes the clone has also to check if the mouse is released while the element to drag is positioned over an area where the original ement could be dragged to.

  3. If true, remove the clone and move the original element to the target container.

There is definitely a lot of adjustment work to do in CSS and JS as well, but It might be a trick to overwhelm the JS standard.

Solution 9 - Javascript

I think the transparency doesn't come from the web contents but from the browser and OS. If you want to change the opacity, you must to tweak or hack the browser and OS

Solution 10 - Javascript

A working example out of 2012 can be viewed on chrome (you have to use chrome) under "chrome://apps/". If you'd like to know exactly how they did it open the dev tools (strg + shift + i since left click is used for a custom context menu) and start reverse engineering (line 7241 in index.html is a good starting point).

Here is a quick summery:

They cloned the dragged element on dragstart, added it into some top-level container and positioned it to the cursor on drag. In order to avoid blocking the events to the actual elements, they styled the clone with pointer-events: none;

Solution 11 - Javascript

hide original image using event.dataTransfer.setDragImage(new Image(), 0, 0); on dragstart. onDrag get the ghost image , update position using event.pageX, event.pageY

Solution 12 - Javascript

Please don't ask me why this works, but if you set the opacity to 0.99999 instead of 1 it works for me. I'm really curious to why so if anyone knows, please post your thoughts.

Solution 13 - Javascript

If you are using JavaScript then in the function which handles the dragStart event include set the style opacity to 1 example:

function dragStartHandler(e) {
   this.style.opacity = '1.0';
}

Solution 14 - Javascript

Suggestion, do the following, now for this I m using jQuery, try it, before saying something wont work, we are not here to give answers, but here to point you in the right direction.

function dragStartHandler(e) { 
   $("span.{CLASS}")addClass('overdrag'); 
} 

then you need to come up with away to tell that it has stoped draging and dropped into position, and then to RemoveClass('overdrag');

This is not hard to do, so I think you should be able to do it. I want to thank @DonaldHuckle as this is really his solution not mine.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJohan LindskogenView Question on Stackoverflow
Solution 1 - Javascriptc2h5ohView Answer on Stackoverflow
Solution 2 - JavascriptGajusView Answer on Stackoverflow
Solution 3 - JavascriptJoshuaView Answer on Stackoverflow
Solution 4 - JavascriptRohith K PView Answer on Stackoverflow
Solution 5 - JavascriptAlpesh PatilView Answer on Stackoverflow
Solution 6 - Javascriptmaxime schoeniView Answer on Stackoverflow
Solution 7 - JavascriptPeterView Answer on Stackoverflow
Solution 8 - JavascriptCorsairView Answer on Stackoverflow
Solution 9 - JavascriptmigomigoView Answer on Stackoverflow
Solution 10 - JavascriptMaximilianMairingerView Answer on Stackoverflow
Solution 11 - Javascriptyelendi sureshView Answer on Stackoverflow
Solution 12 - JavascriptPelleLVView Answer on Stackoverflow
Solution 13 - Javascriptdhuckle3View Answer on Stackoverflow
Solution 14 - JavascriptRussellHarrowerView Answer on Stackoverflow