Zied Hf
Zied Hf

Reputation: 581

HTML5 native Drag and Drop : Is it possible to change the preview while dragging an element?

I would like to change the preview while dragging an element. (see setDragImage)

Like using another element if the user hit ctrl or shift for instance while dragging ?

This is an example here. This example display an image when you start the drag action. However if you want to change it on the fly it's quite chanllenging !

Is it even possible ?

Upvotes: 6

Views: 920

Answers (1)

yorg
yorg

Reputation: 664

I don think it is possible by using only the native API since the setDragImage docs begin by "When a drag occurs, ...". Invoking setDragImage on other events does not thow error but does not seems to work.

However it is possible to implement a dynamic dragImage by using a custom sprite :

const areas=[
  {
    dom:document.querySelector('.zone-rabbits'),
    headSprite:'🐰',
    bodySprite:'🐇',
  },
  {
    dom:document.querySelector('.zone-rats'),
    headSprite:'🐭',
    bodySprite:'🐀',
  }
];
const traveller={
  current:0,
  dom: document.querySelector('.traveller')
};
const sprite=document.querySelector('.drag-sprite');
const blank=document.querySelector('.drag-blank');

const mouseMove=evt=>{
  // Change sprite position
  sprite.style.left=(evt.pageX-15)+'px';
  sprite.style.top=(evt.pageY-15)+'px';
};

traveller.dom.draggable = true;
traveller.dom.ondragstart = evt => {
  // Sets blank image so we can replace it with our sprite
  evt.dataTransfer.setDragImage(blank, 0, 0);
  // Init sprite contents ,visibility and position
  sprite.innerHTML=areas[traveller.current].headSprite;
  sprite.style.display='block';
  mouseMove(evt);
};
traveller.dom.ondragend = evt => {
  // Hide sprite
  sprite.style.display='none';
};

areas.forEach((area,id)=>{
  area.dom.ondragover = evt => {
    evt.preventDefault();
    // Move sprite
    mouseMove(evt);
  };
  area.dom.ondragenter = evt => {
    evt.preventDefault();
    // Modify sprite
    // NB : Sprite behaviour can be changed at any
    // moment between dragstart & dragend 
    sprite.innerHTML = areas[id].headSprite;
  };

  area.dom.ondrop = evt => {
    evt.preventDefault();
    traveller.current=id;
    traveller.dom.innerHTML=areas[id].bodySprite;
    area.dom.appendChild(traveller.dom);
  };
});
.world{
  display:flex;
}
.zone{
  width:100px;
  height:100px;
  border:solid 1px;
}
.zone-rats{
  color:#00f;
  background-color:#eef;
}
.zone-rabbits{
  color:#f00;
  background-color:#fee;
}
.traveller{
  cursor:default;
}
.drag-sprite{
  position:fixed;
  /* drag image sprite and its contents
     must not interfere with pointer events */
  pointer-events:none;
}
.drag-blank{
  width:'1px';
  height:'1px';
  opacity:0;
}
<div class="world">
  <div class="zone zone-rabbits">
    Rabbits
    <div class="traveller">
    &#128007;
    </div>
  </div>
  <div class="zone zone-rats">
    Rats
  </div>
</div>
<div class="drag-sprite"></div>
<div class="drag-blank"></div>

Upvotes: 1

Related Questions