1

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

Carr
  • 2,691
  • 1
  • 19
  • 27
Silve2611
  • 2,198
  • 2
  • 34
  • 55

1 Answers1

1

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.

enter image description here

  • And here is still a weird part, id attribute should be unique:

enter image description here

  • 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. ...

Carr
  • 2,691
  • 1
  • 19
  • 27
  • unfortunately i need the dragelement. if i drag multiple icons i am using this as an cointainer to write in. "dragging 2 items". So i have to have this dragelement. – Silve2611 Mar 03 '18 at 18:54
  • @Silve2611 I think it is ok to remain that element and do something on it, just separate the logic of "grabbing cursor" thing's away? By the way, I haven't learned on multiple dragging before, according to this https://developer.mozilla.org/en-US/docs/Web/API/HTML_Drag_and_Drop_API/Multiple_items It seems it is only available on Firefox? – Carr Mar 03 '18 at 19:29
  • And in my understanding, `setDragImage` api only accepts `img` or `svg` element. – Carr Mar 03 '18 at 19:38
  • look at my updated answer. it works. your can set html as an image. – Silve2611 Mar 04 '18 at 00:46
  • @Silve2611 I see that, but still as I said, in my test, it's very unstable, most of time whole elements behind just disappear, and sometime your "dragImage" is not aside your cursor, it sticks at the bottom, I have uploaded a screenshot to show that on my answer. However, as I said, it is ok to integrate my solution to yours, they would not have conflict logically. I've edited yours, up to you to accept it :) – Carr Mar 04 '18 at 04:04