Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Joint.js Drag and Drop Element between two papers

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>
like image 707
Achilles Avatar asked Jul 08 '15 05:07

Achilles


1 Answers

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>
like image 70
François-Xavier Aeberhard Avatar answered Nov 09 '22 05:11

François-Xavier Aeberhard