Skip to main content

Magnetizing diagram elements

· 4 min read
Simon Porritt

The Toolkit has support for layouts baked in, shipping with a Force Directed layout, Hierarchy layout, Balloon layout and Circular layout, as well as supporting Absolute positioned nodes and a powerful and simple api for creating custom layouts.

Sometimes, though, you just want to make small adjustments to the elements in your UI to neaten things up a bit, and the jsPlumb Toolkit offers a very handy utility for doing so - the magnetizer. It's a collection of tools you can use to nudge elements around.

On demand magnetize

In this first example someone has carelessly left node 2 on top of node 1. Don't worry, though - if you tap on one of the nodes we'll invoke the magnetizer and push the other one away:

We set this up with a tap listener on the node definition in our view:

nodes:{
default:{
template:`<div>{{id}}</div>`,
events:{
[EVENT_TAP]:(p) => {
mySurface.magnetize(p.obj)
}
}
}
}

When you invoke the magnetizer in this way it uses the center of the object you pass in as the focus point, and it automatically excludes the object you passed in from being moved.

After drag magnetize

You can also set this up to happen after a drag - try dragging a node in this next canvas onto another node and see what happens:

This was configured in the `magnetizer` options to our render call:
toolkit.render(someElement, {

...,
magnetize:{
afterDrag:true
}

})

Setting this up on your canvas can be a quick usability win for your users.

In the above example the node that you have just dragged displaces any node(s) it was dragged onto, but you can switch that behaviour around and have the dragged node move if you want:

toolkit.render(someElement, {

...,
magnetize:{
afterDrag:true,
repositionDraggedElement:true
}

})

Constant magnetize

It's also possible to have the magnetizer permanently switched on while dragging. This one's quite fun:

toolkit.render(someElement, {

...,
magnetize:{
constant:true
}

})

Magnetize after layout

Here are some nodes that have been positioned absolute and are overlapping:

[
{ id:"1", left:50, top:50 },
{ id:"2", left:100, top:100 },
{ id:"3", left:450, top:0 },
]

You can switch on the magnetizer so that it runs after a layout has run:

toolkit.render(someElement, {

...,
magnetize:{
afterLayout:true
}

})

This is the same few overlapping nodes rendered with afterLayout:true set in the magnetize options:

Gathering elements

As you've probably noticed, the magnetizer operates as if every element in your canvas has the same magnetic charge, and they therefore repel each other. But what if you want the opposite? You can also use the magnetizer to gather elements - try clicking on an element in this canvas:

This is configured in much the same way as the first example, except we use the gather method instead of magnetize:

nodes:{
default:{
template:`<div>{{id}}</div>`,
events:{
[EVENT_TAP]:(p) => {
mySurface.gather(p.obj)
}
}
}
}

Group expand

Here we see a collapsed group and a node positioned nearby. Tap on the group to toggle its collapsed state - the node will be magnetized out of the way:

toolkit.render(someElement, {

...,
magnetize:{
afterGroupExpand:true
}

})

Group collapse

Here we see a group and a node, which is connected to one of the group's children, positioned at some distance. Try tapping on the group now - you'll see node 3 be gathered in next to it:

toolkit.render(someElement, {

...,
magnetize:{
afterGroupCollapse:true
}

})

afterGroupCollapse and afterGroupExpand can of course be used at the same time.


Summary

The magnetizer is a useful tool for adding an extra level of polish to your applications. If you've got users working on diagrams with a lot of elements, having the canvas automatically nudge elements around can be a real productivity boost.


Start a free trial

Sending your evaluation request...

Interested in the concepts discussed in this article? Start a free trial and see how jsPlumb can help bring your ideas to market in record time.


Get in touch!

If you'd like to discuss any of the ideas/concepts in this article we'd love to hear from you - drop us a line at hello@jsplumbtoolkit.com.