I have an HTML page which has some draggable elements. Our specs say that hovering mouse on such element the cursor must be grab , and during drag cursor must be grabbing .
I know it is possible to set dropEffect which changes cursor appearance above drop zone, but there are very little options: copy, move, link, and none -- no custom or alike.
I have tried to change cursor with Javascript and CSS, like setting cursor: grabbing; when ondragstart is fired. But browser default move cursor appears instead when dragging on drop zone.
So the question is: What am I missing to show grabbing cursor () during drag?
Unfortunately I cannot use JQuery or other helping libraries in the solution. Thanks in advance!
var onDragStart = function(event) {
event.dataTransfer.setData("Text", event.target.id);
event.currentTarget.classList.add("being-dragged");
};
var onDragEnd = function(event) {
event.currentTarget.classList.remove("being-dragged");
};
var onDragOver = function(event) {
event.preventDefault();
};
.dropzone {
width: 500px;
height: 200px;
background-color: silver;
}
.block {
position: absolute;
background-color: pink;
margin: 10px;
border: 20px solid pink;
}
.draggable {
cursor: -webkit-grab;
cursor: grab;
}
.being-dragged {
cursor: -webkit-grabbing;
cursor: grabbing;
background-color: red;
}
<div class = "dropzone"
ondragover = "onDragOver(event);"
>
Grab and drag block around
<div class = "draggable block"
draggable = "true"
ondragstart = "onDragStart(event);"
ondragend = "onDragEnd(event);"
>
I'm draggable
</div>
</div>
It seems that browsers don't allow changing the cursor at the beginning of a drag & drop operation. I don't know why but it's a known issue, I believe they will in the future.
If jQuery is not an option, a possible way around is to implement a drag & drop from scratch, using mouse events and cloning the source element:
var onDragStart = function (event) {
event.preventDefault();
var clone = event.target.cloneNode(true);
clone.classList.add("dragging");
event.target.parentNode.appendChild(clone);
var style = getComputedStyle(clone);
clone.drag = {
x: (event.pageX||(event.clientX+document.body.scrollLeft)) - clone.offsetLeft + parseInt(style.marginLeft),
y: (event.pageY||(event.clientY+document.body.scrollTop)) - clone.offsetTop + parseInt(style.marginTop),
source: event.target
};
};
var onDragMove = function (event) {
if (!event.target.drag) {return;}
event.target.style.left = ((event.pageX||(event.clientX+document.body.scrollLeft)) - event.target.drag.x) + "px";
event.target.style.top = ((event.pageY||(event.clientY+document.body.scrollTop)) - event.target.drag.y) + "px";
};
var onDragEnd = function (event) {
if (!event.target.drag) {return;}
// Define persist true to let the source persist and drop the target, otherwise persist the target.
var persist = true;
if (persist || event.out) {
event.target.parentNode.removeChild(event.target);
} else {
event.target.parentNode.removeChild(event.target.drag.source);
}
event.target.classList.remove("dragging");
event.target.drag = null;
};
var onDragOver = function (event) {
event.preventDefault();
};
.dropzone {
width: 500px;
height: 200px;
background-color: silver;
}
.block {
position: absolute;
background-color: pink;
margin: 10px;
border: 20px solid pink;
}
.draggable {
position: absolute;
cursor: pointer; /* IE */
cursor: -webkit-grab;
cursor: grab;
}
.dragging {
cursor: -webkit-grabbing;
cursor: grabbing;
background-color: red;
}
<div class="dropzone" onmouseover="onDragOver(event);">
Grab and drag block around
<div class = "draggable block"
onmousedown = "onDragStart(event);"
onmousemove = "onDragMove(event);"
onmouseup = "onDragEnd(event);"
onmouseout = "event.out = true; onDragEnd(event);"
>
I'm draggable
</div>
</div>
It is a known issue reported here
While dragging, the cursor will automatically changed to normal.
My tries gave me the following. Gave an active on the element with grabbing cursor. While it is active, the cursor will change but once you start the drag, it will change automatically.
I tried to set body cursor to grabbing on dragstart but no result. Even it is not working.
var onDragStart = function(event) {
event.dataTransfer.setData("Text", event.target.id);
event.currentTarget.classList.add("being-dragged");
};
var onDragEnd = function(event) {
event.currentTarget.classList.remove("being-dragged");
};
var onDragOver = function(event) {
event.preventDefault();
};
.dropzone {
width: 500px;
height: 200px;
background-color: silver;
}
.block {
position: absolute;
background-color: pink;
margin: 10px;
border: 20px solid pink;
}
.draggable {
cursor: -webkit-grab;
cursor: grab;
}
.draggable:active{
cursor : -moz-grabbing;
cursor: -webkit-grabbing;
cursor: grabbing;
}
.being-dragged{
background-color: red;
cursor : -moz-grabbing;
cursor: -webkit-grabbing;
cursor: grabbing;
}
<div class = "dropzone"
ondragover = "onDragOver(event);"
>
Grab and drag block around
<div class = "draggable block"
draggable = "true"
ondragstart = "onDragStart(event);"
ondragend = "onDragEnd(event);"
>
I'm draggable
</div>
</div>
I went through a lot of pain trying to figure this out. The accepted answer was the best answer on the web, but best practices now would be to use the element's .setPointerCapture event, which allows you to listen to and act upon drag like behaviors on an element without being boxed into the narrow behavior of the Drag API. One way to do it would be like so:
el.onpointerdown = ev => {
el.onpointermove = pointerMove
el.setPointerCapture(ev.pointerId)
}
pointerMove = ev => {
console.log('Dragged!')
}
el.onpointerup = ev => {
el.onpointermove = null
el.releasePointerCapture(ev.pointerId)
}
The obvious gift being the fact that there is no cursor hijacking to be found sneaking in the backdoor here.
I know just a little bit about draggable elements with pure JavaScript and I'm sorry that I can't explain the following.
The problem was that the onDragEnd never get fired so I've searched something and find this example with draggable elements.
Now, if you change the function of the onDragStart event it will work but I think you have to change the cursor in another way like to change the class of the body onDragStart
var onDragStart = function(event) {
event.dataTransfer.setData("Text", event.target.id);
event.currentTarget.classList.add("being-dragged");
};
All in one
var onDragStart = function(event) {
event.dataTransfer.setData("Text", event.target.id);
event.currentTarget.classList.add("being-dragged");
};
var onDragEnd = function(event) {
event.currentTarget.classList.remove("being-dragged");
};
var onDragOver = function(event) {
event.preventDefault();
};
.dropzone {
width: 500px;
height: 500px;
background-color: silver;
}
.block {
width: 200px;
height: 50px;
background-color: pink;
}
.draggable1 {
cursor: -webkit-grab;
cursor: grab;
}
.being-dragged {
cursor: -webkit-grabbing;
cursor: grabbing;
background-color: red;
}
<div class="dropzone" ondragover="onDragOver(event);">
<div class="draggable1 block" draggable="true" ondragstart="onDragStart(event);" ondragend="onDragEnd(event);">
I'm draggable
</div>
</div>
Try this ! It works for me !
.draggable {
cursor: -webkit-grab;
cursor: grab;
}
.draggable:active {
cursor: -webkit-grabbing;
cursor: grabbing;
}
I spent sometime to find solution for this, ended with this trick. I feel this is best way less code and apt work.
.drag{
cursor: url('../images/grab.png'), auto;
}
.drag:active {
cursor: url('../images/grabbing.png'), auto;
}
Related
I'm currently building a simple drag and drop Quiz but I'm allowed only to use html css and vanilla javascript.
The idea is there is a div with the answers and a div with the questions. In the questions text there are some blank divs where you can drop the draggable answers.
For example you have the answers "a,b,c" and "x,y,z" and the question is "The 1st three letters of the alphabet are: ___"
I need help on two main things:
I want to have the question's blank divs allow only one element drop per div. (I can stack them atm)
After drop I want to check if the answers in the current questions divs are correct.
How can I do?
P.S. I'm a newbie on html/css/js so maybe tell me just if it's not possible to impement this without external libraries and php.
/* Events fired on the drag target */
document.addEventListener("dragstart", function(event) {
// The dataTransfer.setData() method sets the data type and the value of the dragged data
event.dataTransfer.setData("Text", event.target.id);
// Output some text when starting to drag the p element
document.getElementById("demo").innerHTML = "Started to drag the p element.";
// Change the opacity of the draggable element
event.target.style.opacity = "0.4";
});
// While dragging the p element, change the color of the output text
document.addEventListener("drag", function(event) {
document.getElementById("demo").style.color = "red";
});
// Output some text when finished dragging the p element and reset the opacity
document.addEventListener("dragend", function(event) {
document.getElementById("demo").innerHTML = "Finished dragging the p element.";
event.target.style.opacity = "1";
});
/* Events fired on the drop target */
// When the draggable p element enters the droptarget, change the DIVS's border style
document.addEventListener("dragenter", function(event) {
if ( event.target.className == "droptarget" ) {
event.target.style.border = "3px dotted red";
}
});
// By default, data/elements cannot be dropped in other elements. To allow a drop, we must prevent the default handling of the element
document.addEventListener("dragover", function(event) {
event.preventDefault();
});
// When the draggable p element leaves the droptarget, reset the DIVS's border style
document.addEventListener("dragleave", function(event) {
if ( event.target.className == "droptarget" ) {
event.target.style.border = "";
}
});
/* On drop - Prevent the browser default handling of the data (default is open as link on drop)
Reset the color of the output text and DIV's border color
Get the dragged data with the dataTransfer.getData() method
The dragged data is the id of the dragged element ("drag1")
Append the dragged element into the drop element
*/
document.addEventListener("drop", function(event) {
event.preventDefault();
if ( event.target.className == "droptarget" ) {
document.getElementById("demo").style.color = "";
event.target.style.border = "hidden";
var data = event.dataTransfer.getData("Text");
event.target.appendChild(document.getElementById(data));
}
});
.droptarget {
display: inline-block;
min-width: 50px;
height: 25px;
border: 1px solid #aaaaaa;
color: #000;
text-align: center;
}
.container {
display: inline-block;
padding: 15px;
margin: 10px;
background: #eee;
border: 2px solid black;
border-radius: 5px;
box-sizing:border-box;
}
.dragtarget {
background-color: red;
padding: 5px;
border-radius: 5px;
color: #fff;
font-weight: bold;
text-align: center;
}
.domande {
display: inline-block;
padding: 15px;
margin: 10px;
background: #eee;
border: 2px solid black;
border-radius: 5px;
box-sizing:border-box;
}
<p>Trascina la risposta nel quadrato giusto</p>
<div class="container">
<p draggable="true" class="dragtarget" id="dragtarget">A,B,C</p>
<p draggable="true" class="dragtarget" id="dragtarget">1,2,3</p>
</div>
<div class="domande">
<h3>Prime tre lettere dell'alfabeto<div class="droptarget"></div></h3>
<h3>Primi tre numeri<div class="droptarget"></div></h3>
</div>
<p id="demo"></p>
Using the same id is really bad, it can only get the first element encounter with getElementById. Instead, I'll capture dragging DOM with dragstart and use it later on drop. In drop you just need to check if is there any child element inside of it. If it does, append that child back to .container.
You didn't include any details about how you will check so it's hard to help, I can only help you get the question and answer out.
var dragP;
/* Events fired on the drag target */
document.addEventListener("dragstart", function (event) {
// The dataTransfer.setData() method sets the data type and the value of the dragged data
// event.dataTransfer.setData("Text", event.target.id);
dragP = event.target;
// Output some text when starting to drag the p element
document.getElementById("demo").innerHTML = "Started to drag the p element.";
// Change the opacity of the draggable element
event.target.style.opacity = "0.4";
});
// While dragging the p element, change the color of the output text
document.addEventListener("drag", function (event) {
document.getElementById("demo").style.color = "red";
});
// Output some text when finished dragging the p element and reset the opacity
document.addEventListener("dragend", function (event) {
document.getElementById("demo").innerHTML = "Finished dragging the p element.";
event.target.style.opacity = "1";
});
/* Events fired on the drop target */
// When the draggable p element enters the droptarget, change the DIVS's border style
document.addEventListener("dragenter", function (event) {
if (event.target.className == "droptarget") {
event.target.style.border = "3px dotted red";
}
});
// By default, data/elements cannot be dropped in other elements. To allow a drop, we must prevent the default handling of the element
document.addEventListener("dragover", function (event) {
event.preventDefault();
});
// When the draggable p element leaves the droptarget, reset the DIVS's border style
document.addEventListener("dragleave", function (event) {
if (event.target.className == "droptarget") {
event.target.style.border = "";
}
});
/* On drop - Prevent the browser default handling of the data (default is open as link on drop)
Reset the color of the output text and DIV's border-color
Get the dragged data with the dataTransfer.getData() method
The dragged data is the id of the dragged element ("drag1")
Append the dragged element into the drop element
*/
document.addEventListener("drop", function (event) {
event.preventDefault();
let targetDiv = event.target;
if (targetDiv.className == "droptarget") {
document.getElementById("demo").style.color = "";
targetDiv.style.border = "hidden";
if (targetDiv.childElementCount != 0){
let childP = targetDiv.getElementsByTagName("p")[0];
document.getElementById("answer").appendChild(childP);
}
targetDiv.appendChild(dragP);
dragP = null;
}
});
document.getElementById("checkAnswer").addEventListener("click", function () {
let questions = document.getElementsByClassName("question");
let resultP = document.getElementById("result");
resultP.innerHTML = "";
for (let index = 0; index < questions.length; index++) {
const element = questions[index];
let childP = element.getElementsByTagName("p")[0];
let question = element.childNodes[0].textContent;
let answer = childP != undefined ? childP.innerText : "no answer";
resultP.append(`${question} : ${answer} ; `);
}
})
.droptarget {
display: inline-block;
min-width: 50px;
height: 25px;
border: 1px solid #aaaaaa;
color: #000;
text-align: center;
}
.container {
display: inline-block;
padding: 15px;
margin: 10px;
background: #eee;
border: 2px solid black;
border-radius: 5px;
box-sizing: border-box;
}
.dragtarget {
background-color: red;
padding: 5px;
border-radius: 5px;
color: #fff;
font-weight: bold;
text-align: center;
}
.domande {
display: inline-block;
padding: 15px;
margin: 10px;
background: #eee;
border: 2px solid black;
border-radius: 5px;
box-sizing: border-box;
}
<p>Trascina la risposta nel quadrato giusto</p>
<div class="container" id="answer">
<p draggable="true" class="dragtarget" id="dragtarget">A,B,C</p>
<p draggable="true" class="dragtarget" id="dragtarget">1,2,3</p>
</div>
<div class="domande">
<h3 class="question">Prime tre lettere dell'alfabeto<div class="droptarget"></div>
</h3>
<h3 class="question">Primi tre numeri<div class="droptarget"></div>
</h3>
</div>
<p id="demo"></p>
<button id="checkAnswer">Check</button>
<p id="result"></p>
I want to find out when an element is dragged and dropped outside of its parent:
element.addEventListener('dragend', function(event) {
// check if element is dropped outside its parent
}, false)
This technique identifies whether or not the dragged element was dropped inside its parent by:
storing dragParent element upon 'dragstart'
adding 'drop' event event listener to window
using drop event's event.target to determine drop target
walking up event target's DOM tree to search for dragParent
// the parent of the dragged element
let dragParent = null;
function handleDragstart(ev) {
// record the dragged element's parent
dragParent = ev.target.parentElement;
// set a 'drop' listener to the window
window.addEventListener('drop', handleDrop);
}
// handle a 'drop' event to the window
function handleDrop(ev) {
ev.preventDefault();
// remove the 'drop' listener
window.removeEventListener('drop', handleDrop);
// search up target's DOM tree for dragParent
for (let el = ev.target; el.tagName !== 'HTML'; el = el.parentElement) {
if (el === dragParent) {
alert('#p1 was dropped inside dragParent');
return;
}
}
alert('#p1 was dropped outside dragParent');
}
// these event handers are required to make an element into a drop zone
function handleDragover(ev) {
ev.preventDefault();
}
function handleDragend(ev) {}
// convert some elements into drop zones
// ref: https://developer.mozilla.org/en-US/docs/Web/API/HTML_Drag_and_Drop_API#define_a_drop_zone
//
function makeDropZone(el) {
el.addEventListener('dragover', handleDragover);
el.addEventListener('drop', handleDragend);
}
for (const elId of ['sibling', 'parent', 'stranger']) {
const element = document.getElementById(elId);
makeDropZone(element);
}
makeDropZone(document.body);
// make `#p1` draggable
document.getElementById('p1').addEventListener('dragstart', handleDragstart);
body {
padding: 0.4rem 0 2rem 0.4rem;
height: calc(100% - 0.5rem);
width: calc(100% - 2rem);
border: 1px solid #888;
font-family: sans-serif;
}
div {
padding: 0.6rem;
}
#parent {
background-color: #ddd;
width: 90%;
padding: 0.3rem;
}
#p1 {
background-color: white;
padding: 0.1rem;
width: 30%;
}
#sibling {
background-color: #bbb;
width: 50%;
height: 3rem;
}
#stranger {
background-color: #ddd;
margin: 0.5rem 0;
width: 90%;
height: 80px;
padding: 0.3rem;
}
<body>
body
<h3>Drag <code>#p1</code> onto <code>#sibling</code>, <code>#parent</code>, or
<code>body</code></h3>
<div id="parent">
#parent
<p id="p1" draggable="true">
#p1 (draggable)
</p>
<div id="sibling">
#sibling
</div>
</div>
<div id="stranger">
#stranger
</div>
</body>
In my web app, there is a draggable element.
I need to set the left position of this element when the element reaches a certain limit while dragging.
Using jQuery draggable widget, I have access to the position of the element:
function drag(e, ui) {
console.log(ui.position.left);
}
Let say my left attribute is setted to 1100px, I need to set it to 500px and this, without stopping the dragging.
I have three functions: dragStart, drag, and gradEnd.
Currently, I managed to get only one result: when setting ui.position.left = 500; on the drag function (using a condition), the left position is set to 500 but of course, the element is then stuck at 500px. The reason is that every time the drag function is triggered, the left position is setted to 500.
If the code runs only once the line ui.position.left = 500; the position left attribute is set to 500, but directly reset to 1100.
How can I set the left attribute once and for all?
$("#divId").draggable({
drag: drag,
})
function drag(e, ui) {
if (ui.position.top > 50) {
ui.position.left = 100;
}
}
#divId {
height: 70px;
background-color: white;
border: 4px solid #000000;
text-align: center;
color: black;
cursor: grab;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<div id="divId">
Bubble
</div>
I am not sure how jQuery Draggable handles things under the hood, but even after setting ui.position.left = 100, it does not register in the event until after dragging has stopped - that is why I opted to check the actual CSS property of the element that is being targeted.
I have also provided an example (closure/functional based) which demonstrates how to handle this without having to check CSS..
First example:
$("#divId").draggable({
drag: drag
});
function drag(e, ui) {
if (ui.position.top > 50) {
$("#container").css('padding-left', '100px');
$(this).css('left', '0px');
}
if (ui.position.left < 0) {
ui.position.left = 0
}
}
#divId {
height: 70px;
background-color: white;
border: 4px solid #000000;
text-align: center;
color: black;
width: 300px;
cursor: grab;
}
#container {
height: 100vh;
width: 1000px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<div id="container">
<div id="divId">
Bubble
</div>
</div>
Second example, more of a 'closure based functional approach': does not require you to check CSS..
$("#divId").draggable({
drag: drag()
});
function drag(e, ui) {
let TRIGGER = false, TOP_THRESHOLD = 50, LEFT_POSITION = 100;
return function(e, ui) {
if (TRIGGER) {
ui.position.left = LEFT_POSITION;
} else if (ui.position.top > TOP_THRESHOLD) {
TRIGGER = true;
ui.position.left = LEFT_POSITION;
}
}
}
#divId {
height: 70px;
background-color: white;
border: 4px solid #000000;
text-align: center;
color: black;
cursor: grab;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<div id="divId">
Bubble
</div>
I am trying to change the cursor of the draggable item in chrome. Everything i tried it is not working. There are solution on Stackoverflow but they are all outdated and not working with the actual chrome version.
On drag the item is copied to a container which is the dragimage for the draggable.
What i want is to have a grabbing cursor while dragging. How would that be possible? Any Ideas?
See my code snippet for an example.
new Vue({
el: '#app',
data: {
text_drop: 'Droppable Area',
text_drag: 'Drag Area',
drag_elements: [
{text: 'one', selected: true},
{text: 'two', selected: false},
{text: 'three', selected: false},
{text: 'four', selected: false},
]
},
computed: {
selected_elements(){
let selected = [];
this.drag_elements.map((drag) => {
if(drag.selected){
selected.push(drag);
}
})
return selected;
}
},
methods: {
drag_it(event){
let html = document.getElementById("dragElement");
let drop_docs = this.selected_elements;
if(drop_docs.length > 1){
let multiple = document.createElement('div');
multiple.classList.add('dragMultiple');
multiple.innerHTML = drop_docs.length + ' items';
html.innerHTML = '';
html.appendChild(multiple)
}else{
html.innerHTML = event.target.outerHTML;
}
event.dataTransfer.setData('text/plain', '' );
event.dataTransfer.setDragImage(html, 0, 0);
event.dataTransfer.effectAllowed = "move";
},
drag_over(event){
document.documentElement.style.cursor="-webkit-grabbing";
},
drag_end(event){
document.documentElement.style.cursor="default";
},
select(event, drag_element){
if(event.metaKey || event.shiftKey){
drag_element.selected = !drag_element.selected;
} else {
this.drag_elements.map((drag) => {
if(drag === drag_element){
drag.selected = true;
}else{
drag.selected = false;
}
})
}
}
}
})
#Dragme{
width: 200px;
height: 50px;
margin-left: 20px;
text-align: center;
border:1px solid black;
float:left;
}
#Dragme:hover {
cursor: -webkit-grab;
}
#Dragme:active {
cursor: -webkit-grabbing;
}
#Dropzone{
float: left;
width: 500px;
height: 100px;
border: 1px solid;
margin-bottom: 50px;
}
.selected{
border: 2px solid yellow !important;
}
.dragMultiple{
border: 1px solid black;
padding: 10px;
background-color: white;
}
#dragElement{
position: absolute;
top: 400px;
}
<script src="https://vuejs.org/js/vue.min.js"></script>
<div id="app">
<div id="Dropzone">{{text_drop}}</div>
<div id="drag_elements">
<div v-for="drag in drag_elements"
#dragstart="drag_it"
#dragover="drag_over"
#dragend="drag_end"
#mouseup="select($event, drag)"
draggable="true"
:class="{selected: drag.selected}"
id="Dragme">{{drag.text}}</div>
</div>
</div>
<div id="dragElement">
</div>
Update
Actually it can be solved with the following answer
CSS for grabbing cursors (drag & drop)
It is important to add the dndclass
thx
Blockquote
#Carr for the hint
Update
After Dragend or drop the cursor is not set to default. Only when moved it changes back. Any Ideas?
Update
With they command key on mac or the shift key multiple items can be selected and dragged. A new dragitem is created for that purpose but the cursor does not allways fall back after dragend or drop.
Update
Integrate method to from answer -by Carr
In fact, setDragImage api is to set the image for replacing that plain document icon which be aside with default cursor, not cursor itself. So your code about '.dragElement' is not working as you expected, it's unstable and causes weird effect when I am testing, I have removed them in my answer.
What I've done below is a little bit tricky, but I think it's at least in correct logic. However, maybe there is a more elegant solution.
new Vue({
el: '#app',
data: {
text_drop: 'Droppable Area',
text_drag: 'Drag Area'
},
methods: {
drag_it(event){
event.dataTransfer.setData('text/plain', '' );
event.dataTransfer.effectAllowed = "move";
},
drag_over(event){
document.documentElement.style.cursor="-webkit-grabbing";
},
drag_end(event){
document.documentElement.style.cursor="default";
}
}
})
#Dragme{
width: 200px;
height: 50px;
text-align: center;
border:1px solid black;
float:left;
}
#Dragme:hover {
cursor: -webkit-grab;
}
#Dragme:active {
cursor: -webkit-grabbing;
}
#Dropzone{
float: left;
width: 300px;
height: 100px;
border: 1px solid;
margin-bottom: 50px;
}
<script src="https://vuejs.org/js/vue.min.js"></script>
<div id="app">
<div id="Dropzone">{{text_drop}}</div>
<div #dragstart="drag_it"
#dragover="drag_over"
#dragend="drag_end"
draggable="true"
id="Dragme">{{text_drag}}</div>
</div>
Update - derivative problems about original question
"dragImage" sticks at bottom, all elements are disappeared, or flashing sometimes.
And here is still a weird part, id attribute should be unique:
And add quote from MDN document about setDragImage, I wrongly recalled svg in comment, it should be canvas :
... The image will typically be an <image> element but it can also be a
<canvas> or any other image element. ...
We could draw text in canvas, it's another question.
Is it possible to somehow set my custom html object to event.dataTransfer.setDragImage(myCustomHtml,0,0) ?
I tried like this
var x=$doc.getElementById("row_selected_notification");
event.dataTransfer.setDragImage(x, 100, 100);
but it didn't work.
As I'm doing this through Java, I'm using native methods so jQuery is not an option for me.
You can either create a custom element on drag or use an existing element.
If you are crating an element you have to make sure it is not visible after adding it to the DOM. I've just added a negative top value to the create element to hide it, but i am sure that there are other ways to fix this as well.
Here is an example with one existing element and one that will be created.
var foo = document.getElementsByClassName("drag-me").item(0),
bar = document.getElementsByClassName("drag-me").item(1);
// Drag foo and create custom element.
foo.addEventListener("dragstart", function(e) {
var elem = document.createElement("div");
elem.id = "drag-ghost";
elem.textNode = "Dragging";
elem.style.position = "absolute";
elem.style.top = "-1000px";
document.body.appendChild(elem);
e.dataTransfer.setDragImage(elem, 0, 0);
}, false);
// Drag bar and use foo as ghost image
bar.addEventListener("dragstart", function(e) {
e.dataTransfer.setDragImage(foo, 0, 0);
}, false);
// Let's remove the created ghost elem on dragend
document.addEventListener("dragend", function(e) {
var ghost = document.getElementById("drag-ghost");
if (ghost.parentNode) {
ghost.parentNode.removeChild(ghost);
}
}, false);
.drag-me {
width: 100px;
padding: 30px 0;
text-align: center;
color: white;
display: inline-block;
}
.drag-me:nth-child(1) {
background-color: green;
}
.drag-me:nth-child(2) {
background-color: red;
}
#drag-ghost {
width: 200px;
height: 200px;
background-color: yellow;
}
<div class="drag-me" draggable="true">Drag Me Foo</div>
<div class="drag-me" draggable="true">Drag Me Bar</div>