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
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.