4

I'm implementing a nested layers component in vue with vuedraggable. I try to keep it close to Adobe's layers panel (for example in Illustrator).

The desired behaviour is: While dragging an item, it remains at it's position and only a black line is indicating where the item would be inserted after releasing the drag.

The black line could be realised by styling vue draggable's ghost. But how can I prevent the item from being removed from its original position while dragging?

Adobe Illustrator layers example

Arnoson
  • 71
  • 1
  • 6
  • there is a ```pull: 'clone' ``` option .... how about use that then delete the original item after the clone is dropped – Mischa Oct 23 '19 at 14:39
  • As far as I understand the pull option, this would only clone the element if I drop it to another draggable. But for my use case it should be temporarily cloned even if moving it in the same draggable – Arnoson Oct 25 '19 at 10:06

3 Answers3

1

I now use a similar approach to Death Waltz's answer, but without manipulating the DOM directly.

Instead I make a copy of the item in the list...

start(event) {
    // Make a clone of the choosen item and add it to the
    // layers list.
    const index = event.oldIndex
    const item = this.layers[index]
    this.layers.splice(index + 1, 0, {
    ...item,
    // Vue requires unique keys.
    id: item.id + '_clone',
    // Set a isClone flag to be able to delete the clone
    // afterwards.
    isClone: true
  })
},

...and delete it afterwards

end() {
    // Delete the clone from the layers.
    this.layers = this.layers.filter(layer => !layer.isClone)
}

here is the full example: https://jsfiddle.net/arnoson/587L0nx9/45/

I'm still not sure if this is the most elegant solution and wish there would be a built in way to do this.

Arnoson
  • 71
  • 1
  • 6
1

So I ended up using sl-vue-tree which does basically everything I need to simulate Adobe Illustrators layer panel.

Arnoson
  • 71
  • 1
  • 6
0

In essence, create a copy of the item on click, then set the selected item to invisible. On mouse-up, hide the copy and make the item visible again.

An example:

ball.onmousedown = function(event) { // (1) start the process

  // (2) prepare to moving: make absolute and on top by z-index

  var ball2 = ball; //set the balls current position so it doesn't appear to move
  ball.style.position = 'absolute';
  ball.style.visibility = "hidden"; //make the moving item invisible

  document.body.append(ball);
  // ...and put that absolutely positioned ball under the pointer

  moveAt(event.pageX, event.pageY);

  // centers the ball at (pageX, pageY) coordinates
  function moveAt(pageX, pageY) {
    ball.style.left = pageX - ball.offsetWidth / 2 + 'px';
    ball.style.top = pageY - ball.offsetHeight / 2 + 'px';

  }

  function onMouseMove(event) {
    moveAt(event.pageX, event.pageY);
  }

  // (3) move the ball on mousemove
  document.addEventListener('mousemove', onMouseMove);

  // (4) drop the ball, remove unneeded handlers
  ball.onmouseup = function() {
    ball.style.visibility = "visible"; //makes the moved ball visible again
    ball2.style.visibility = "hidden"; //makes the copy invisible
    document.removeEventListener('mousemove', onMouseMove);
    ball.onmouseup = null;
  };

};
Vendetta
  • 2,078
  • 3
  • 13
  • 31
  • Thanks for the answer, but I'm using Vue and so I try to avoid manipulating the DOM manually – Arnoson Oct 25 '19 at 10:16
  • Alright, well if push comes to shove and you can't find another way to do it, this should work. Hope you find a better solution! – Vendetta Oct 25 '19 at 14:09