9

I am implementing drag and drop between two papers .But I am stuck with the syncing of offset of dragged element with cursor position as I have two papers in my html body.I have very minute experience with css which may be causing problem of positioning of elements.

Use Case:-

User clicks on element from paper 2 and starts dragging and go to paper 1. On Pointer up a clone of that element is added to paper 1 on the position of cursor in paper 1.

My strategy to handle this is :-

When the user clicks mousedown

1.Dynamically create a div

2.Create a third paper, say call it "flypaper" in the new div Make a copy of the element that you want to clone, and add it to "flypaper"

3.Create a mousemove listener that will move the div containing "flypaper" with the mouse

4.Add a mouseup event that will add a clone of the element to the "paper2" when the user releases the button.

5.Clean up the "flypaper" div and events.

<body>
<div id="paper" class="paper" style="border-style: solid;border-width: 5px;width:600px"></div>
<div id="paper2" class="paper" style="border-style: solid;border-width: 5px;width:600px;display:inline-block" ondrop="drop(event)" ondragover="allowDrop(event)"></div>
<script>
    var graph = new joint.dia.Graph;
    var paper = new joint.dia.Paper({
        el: $('#paper'),
        width: 600,
        height: 200,
        model: graph,
        gridSize: 1

    });
    var rect = new joint.shapes.basic.Rect({
        position: { x: 100, y: 30 },
        size: { width: 100, height: 30 },
        attrs: { rect: { fill: 'blue' }, text: { text: 'my box', fill: 'white' } }
    });
    graph.addCells([rect]);
    ////////////////////////////////////////////////////////
    var graph2 = new joint.dia.Graph;
    var paper2 = new joint.dia.Paper({
        el: $('#paper2'),
        width: 600,
        height: 200,
        model: graph2,
        gridSize: 1
    });
    paper2.on('cell:pointerup',function (cellView, evt, x, y) {
        var rect4 = new joint.shapes.basic.Rect({
            position: { x: 10, y: 50 },
            size: { width: 100, height: 30 },
            attrs: { rect: { fill: 'blue' }, text: { text: 'my box', fill: 'white' } }
        });

        graph.addCells([rect4]);
    });
    paper2.on('cell:pointerdown',function (cellView, evt, x, y) {
        $('body').append('<div id="flyPaper" class="box" style="position: fixed;z-index: 100;display:block;opacity:.7;"></div>');
        var graph3 = new joint.dia.Graph;
        var paper3 = new joint.dia.Paper({
            el: $('#flyPaper'),
            width: 600,
            height: 200,
            model: graph3,
            gridSize: 1
        });
        var rect3 = new joint.shapes.basic.Rect({
            position: { x: 10, y: 50 },
            size: { width: 100, height: 30 },
            attrs: { rect: { fill: 'blue' }, text: { text: 'my box', fill: 'white' } }
        });

        graph3.addCells([rect3]);
        $('body').mousemove(function(e){
            var mouseX   =  e.pageX; //get mouse move position
            var mouseY   =  e.pageY;
            $( "div.box" ).offset({ top: mouseY, left: mouseX });
            // $('div.box',this).css({'top': boxPositionY,'left': boxPositionX})
        });

    });

    var rect2 = new joint.shapes.basic.Rect({
        position: { x: 10, y: 50 },
        size: { width: 100, height: 30 },
        attrs: { rect: { fill: 'blue' }, text: { text: 'my box', fill: 'white' } }
    });
    graph2.addCells([rect2]);
</script>
</body>
xpy
  • 5,481
  • 3
  • 29
  • 48
Achilles
  • 519
  • 7
  • 27

1 Answers1

25

I had the same problem (and have clients who won't pay for rappid which adds this feature to jointjs). So here's a snippet that may help others (see below).

The steps are th same as you pointed out:
1.Dynamically create a div
2.Create a third paper, say call it "flypaper" in the new div Make a copy of the element that you want to clone, and add it to "flypaper"
3.Create a mousemove listener that will move the div containing "flypaper" with the mouse
4.Add a mouseup event that will add a clone of the element to the "paper2" when the user releases the button.
5.Clean up the "flypaper" div and events.

The solution to your problem was to use cellView.model.clone() to add the right element and then some computation with $.offset, $.width() & $.height() to get the right flyingpaper postion and to check if the drop event occured on the target paper.

View on codepen

<body>
<div id="paper" class="paper" style="border-style: solid;border-width: 5px;width:600px"></div>
<div id="paper2" class="paper" style="border-style: solid;border-width: 5px;width:600px;display:inline-block"></div>
<script>
    // Canvas where sape are dropped
    var graph = new joint.dia.Graph,
      paper = new joint.dia.Paper({
        el: $('#paper'),
        model: graph
      });

    // Canvas from which you take shapes
    var stencilGraph = new joint.dia.Graph,
      stencilPaper = new joint.dia.Paper({
        el: $('#stencil'),
        height: 60,
        model: stencilGraph,
        interactive: false
      });

    var r1 = new joint.shapes.basic.Rect({
      position: {
        x: 10,
        y: 10
      },
      size: {
        width: 100,
        height: 40
      },
      attrs: {
        text: {
          text: 'Rect1'
        }
      }
    });
    var r2 = new joint.shapes.basic.Rect({
      position: {
        x: 120,
        y: 10
      },
      size: {
        width: 100,
        height: 40
      },
      attrs: {
        text: {
          text: 'Rect2'
        }
      }
    });
    stencilGraph.addCells([r1, r2]);

    stencilPaper.on('cell:pointerdown', function(cellView, e, x, y) {
      $('body').append('<div id="flyPaper" style="position:fixed;z-index:100;opacity:.7;pointer-event:none;"></div>');
      var flyGraph = new joint.dia.Graph,
        flyPaper = new joint.dia.Paper({
          el: $('#flyPaper'),
          model: flyGraph,
          interactive: false
        }),
        flyShape = cellView.model.clone(),
        pos = cellView.model.position(),
        offset = {
          x: x - pos.x,
          y: y - pos.y
        };

      flyShape.position(0, 0);
      flyGraph.addCell(flyShape);
      $("#flyPaper").offset({
        left: e.pageX - offset.x,
        top: e.pageY - offset.y
      });
      $('body').on('mousemove.fly', function(e) {
        $("#flyPaper").offset({
          left: e.pageX - offset.x,
          top: e.pageY - offset.y
        });
      });
      $('body').on('mouseup.fly', function(e) {
        var x = e.pageX,
          y = e.pageY,
          target = paper.$el.offset();

        // Dropped over paper ?
        if (x > target.left && x < target.left + paper.$el.width() && y > target.top && y < target.top + paper.$el.height()) {
          var s = flyShape.clone();
          s.position(x - target.left - offset.x, y - target.top - offset.y);
          graph.addCell(s);
        }
        $('body').off('mousemove.fly').off('mouseup.fly');
        flyShape.remove();
        $('#flyPaper').remove();
      });
    });
</script>
</body>
  • If drag and drop has to work for links, what changes needs to be made ? – Vinay Prabhakaran Nov 28 '16 at 13:53
  • Hi @François-XavierAeberhard. I am trying your code, but what if i need to change the name of process after dragging, if i drag to rectangles i want ti give two different names for two rectangles – Keerthi Reddy Yeruva Aug 22 '18 at 09:26
  • @Keerthi Reddy Yeruva, I have the same requirement. Did you find the solution? Thanks! – Joshua Sep 24 '19 at 08:30
  • @konekoya Can you elaborate, not sure i understand the question – François-Xavier Aeberhard Sep 25 '19 at 07:37
  • Thanks for replying @François-XavierAeberhard! Your snippet works out pretty well for me. But I have a requirement which was mentioned in the above comments by Keerthi: what if i need to change the name of process after dragging? Maybe something like a prompt or a text editor? – Joshua Sep 26 '19 at 08:08
  • This is for double click event. Similarly there is drop event paper.on('cell:pointerdblclick', (cellView, e, x, y) => { graph.getCell(cellView.model.id).attributes.attrs['.label'].text = "changedname"; }); – Neethu George Nov 20 '20 at 11:09
  • I noticed that the flyPaper variable is unused. Is there some sort of quirk that makes it still necessary? – Egor Hans Nov 16 '21 at 10:50