Silve2611
Silve2611

Reputation: 2278

Changing cursor for draggable not working in chrome using vue.js

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

Upvotes: 1

Views: 5467

Answers (1)

Carr
Carr

Reputation: 2771

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

Upvotes: 1

Related Questions