How to make a paper draggable
Asked Answered
M

3

7

If the paper is too big for the div it's shown in, I'd like to make the paper draggable.

I tried the papers blank:pointerdown and pointerup events but was not able to just follow the mousemovement. I also tried to make the element of the paper draggable via jquery, but nothing seems to do the trick...

Is there any way to do this?

Malarkey answered 10/2, 2015 at 12:12 Comment(0)
R
6

I suggest the following:

  1. register a handler for the paper blank:pointerdown event that will initiate the paper dragging (store a flag which you'll use in your mousemove handler to recognize the paper is in the "panning" state).
  2. Put the big paper in a <div> container with CSS overflow: auto. This <div> will be your little window to the large paper.
  3. register a handler for document body mousemove event (because you most likely want the paper to be dragged even if the mouse cursor leaves the paper area?). In this handler, you'll be setting the scrollLeft and scrollTop properties of your <div> container making the paper "panning". For adjusting the scrollLeft and scrollTop properties, you'll use the clientX and clientY properties of the event object together with the same properties that you stored previously in your blank:pointerdown handler. (in other words, you need those to find the offset of the panning from the last mousemove/blank:pointerdown).
  4. register a handler for document body mouseup and in this handler, clear your paper dragging flag that you set in step 1.
Roseannaroseanne answered 11/2, 2015 at 10:16 Comment(1)
This is pure genius. I couldn´t get how to do it. Thank you. JointJS is just brilliant.Averi
B
30

This can be achieved with a combination of JointJS events and document events. The graph display is encapsulated in a div:

<div id='diagram'></div>

Then add the event handlers for JointJS, first the pointerdown event where we store the start position of the drag:

paper.on('blank:pointerdown',
    function(event, x, y) {
        dragStartPosition = { x: x, y: y};
    }
);

Then the end of the drag (pointerup) when we delete the variable we store the position in (it also acts as a flag whether there is an active drag in progress):

paper.on('cell:pointerup blank:pointerup', function(cellView, x, y) {
    delete dragStartPosition;
});

As JointJS does not expose a "paper pointer move" event, we need to use the mousemove document event. For example, with JQuery:

$("#diagram")
    .mousemove(function(event) {
        if (dragStartPosition)
            paper.translate(
                event.offsetX - dragStartPosition.x, 
                event.offsetY - dragStartPosition.y);
    });

We get the drag start coordinates and the current pointer position and update the paper position using the paper.translate() call.

WARNING: if you scale the paper (using paper.scale()), you have to also scale the starting position of the drag:

var scale = V(paper.viewport).scale();
dragStartPosition = { x: x * scale.sx, y: y * scale.sy};

The calls to paper.translate() will then update to the proper position.

Boxhaul answered 22/3, 2016 at 10:22 Comment(5)
This worked really well (together with the scaling), no additional libs required either. Thanks a lot.Derosa
In jointjs v1.1, paper.setOrigin(x, y) has been deprecated in favor of paper.translate(x, y). resources.jointjs.com/docs/jointjs/v1.1/joint.htmlViscid
Excellent stuff, thank you. Would have been much quicker though if you had posted all of the code in one block because I had difficulty reassembling it correctly. :)Nacreous
This works perfectly, except if you're in strict mode you want to change the delete to delete dragStartPosition.x; delete dragStartPosition.y;, since you're only allowed to delete object properties and the condition to typeof dragStartPosition.x !== 'undefined' && typeof dragStartPosition.y !== 'undefined'.Nasturtium
This worked well! Highly recommend this solution. For those using zooming/scaling, use suggested code from OP like so: paper.on('blank:pointerdown', function(event, x, y) { var scale = V(paper.viewport).scale(); dragStartPosition = { x: x * scale.sx, y: y * scale.sy}; } ); Also V is in from jointjs.Peaceful
F
14

I know this is a slightly old thread, but I was stuck with this for a while and came across a neat solution using the SVG Pan and Zoom library. Git hub link here

EDIT - I created a plunker of the steps below (plus some extras) here: SVG panning with Jointjs

First step after creating the paper is to initialise SVG Pan and Zoom:

    panAndZoom = svgPanZoom(targetElement.childNodes[0], 
        {
            viewportSelector: targetElement.childNodes[0].childNodes[0],
            fit: false,
            zoomScaleSensitivity: 0.4,
            panEnabled: false
        });

Where targetElement is the div that the jointjs paper has gone into. Jointjs will create a SVG element within that (hence the childNodes[0]) and within that element the first element is the viewport tag (hence childNodes[0].childNodes[0] in the viewportselector). At this stage pan is disabled, because in my use case it would intefer with drag and drop elements on the paper. Instead what I do is keep a reference to the panAndZoom object and then switch pan on and off on the blank:pointerdown and blank:pointerup events:

paper.on('blank:pointerdown', function (evt, x, y) {
        panAndZoom.enablePan();
    });
paper.on('cell:pointerup blank:pointerup', function(cellView, event) {
            panAndZoom.disablePan();

});

Just another way of tackling the issue I guess, but I found it a bit easier, plus it gives you zoom too and you can adjust the sensitivity etc.

Fotinas answered 2/2, 2016 at 9:11 Comment(6)
Hi Luke, thanks so much for the link. I am struggling to get it working though, probably because of the target element ;) if I have paper = new joint.dia.Paper({el: $('#myId'), Should I be using var panAndZoom = svgPanZoom($('#myId').childNodes[0] ? If so, I'm getting the error "TypeError: Cannot read property '0' of undefined"Anlage
a jsfiddle of how you've done this would be really helpful ;)Anlage
Hey jmls im away at the moment but i should be able to sort you out with a jsfiddle on monday night. In the meantime when you setup svgpanzoom you need to tell it the svg element. So if #myid gives you the id of the svg element then you dont need the childnodes part. If #myid gives you the div above the svg then you do need the childnodes part. Id suggest using the chrome devtools window to look through the html to find how you get the svg element.Fotinas
thanks for getting back - I will really need that fiddle ;) I just can't get it to work. Keep getting the "TypeError: Cannot read property '0' of undefined"Anlage
Hey jmls - I've added a plunker link into the original answer. I think somewhere there's an extra [0] needed. Sorry about that! Note, that's probably not a great way I've used to get to the html element needed (which is the svg element), so you may want to find a better way at some point. And, added bonus - I've included a grid function as well.Fotinas
Hi, your plunker example is broken as the joinjs.com links aren't activate anymore.Buyers
R
6

I suggest the following:

  1. register a handler for the paper blank:pointerdown event that will initiate the paper dragging (store a flag which you'll use in your mousemove handler to recognize the paper is in the "panning" state).
  2. Put the big paper in a <div> container with CSS overflow: auto. This <div> will be your little window to the large paper.
  3. register a handler for document body mousemove event (because you most likely want the paper to be dragged even if the mouse cursor leaves the paper area?). In this handler, you'll be setting the scrollLeft and scrollTop properties of your <div> container making the paper "panning". For adjusting the scrollLeft and scrollTop properties, you'll use the clientX and clientY properties of the event object together with the same properties that you stored previously in your blank:pointerdown handler. (in other words, you need those to find the offset of the panning from the last mousemove/blank:pointerdown).
  4. register a handler for document body mouseup and in this handler, clear your paper dragging flag that you set in step 1.
Roseannaroseanne answered 11/2, 2015 at 10:16 Comment(1)
This is pure genius. I couldn´t get how to do it. Thank you. JointJS is just brilliant.Averi

© 2022 - 2024 — McMap. All rights reserved.