Here's some more neat things I've done with my GWT JIT integration. The code snippets here are to represent what is possible and your mileage may vary.
Dragging Objects
In many of the JIT renderings, you can drag objects around the screen and can have full control over what you allow to be dragged. You start by getting a callback when dragging is occurring:
onDragMove : function(node, eventInfo, e) {
where the "node" is the object that is being dragged and "eventInfo" has position information. For a Force Directed JIT graph type, to allow dragging of your objects, you simply do
this inside the onDragMove function:
var pos = eventInfo.getPos();
node.pos.setc(pos.x, pos.y);
fd.plot();
By the way, "fd" is an instance of the Force Directed graph.
As you drag the object around the screen, it will be moved and the graph will be replotted to show the update. If the object you are dragging has any edges attached to it, they will automatically be moved as well. But what if you have relationships on your display? What if you have a parent object that has several children connected to it and when you drag the parent, you want the children to be dragged as well. At Plexxi, we display a RING object with Plexxi Switches connected to the ring. If a user drags our ring object, we want the switches to go with it. Here's how:
onDragMove : function(node, eventInfo, e) {
var pos = eventInfo.getPos();
if (node.getData('type') == "plexxiring") {
node.eachAdjacency(function(a) {
childnode = fd.graph.getNode(a.nodeTo.id);
childnode.pos.setc(childnode.getPos().x - (node.getPos().x - pos.x),
childnode.getPos().y - (node.getPos().y - pos.y));
});
node.pos.setc(pos.x, pos.y);
fd.plot();
What we do is get all the nodes connected to our dragged node and move them as well. This performs surprisingly well in our application. You can take this further and re-curse through all your objects moving even more when a single one is dragged.
Mouseover Tool Tips
On some occasions, you may want a tooltip or a text box to show up on the screen as the user moves the mouse over your nodes. To insure good performance, you will want to add the tooltip text to a private JSON data object so that this text is instantly available to you at any time. If you have to go back to your database of make some other calls to get your tooltip text, you may suffer from bad performance in rendering them.
Here's how I did Tips with my Force Directed graph:
Tips : {
enable : true,
type : 'Native',
offsetX : 10,
offsetY : 10,
onShow : function(tip, node) {
tip.innerHTML = node.getData('tooltip');
},
Auto Refreshing
One of the biggest issues with any graphical application is refreshing. Does your user have to press a refresh button? Does that waste time retrieving data from your database, destroying whatever you are currently displaying and rebuilding the display with new data?
By using GWT and the built-in RPC mechanism, I am able to ask my GWT Server if any data has changed and then act of it. This is a topic for another blog....but let's say my Force Directed graph is showing 5 different types of objects on it. I ask the GWT Server to coordinate with my backend database to keep a cache of the objects I'm displaying and if any of these objects is modified, or deleted, let me know. When I find out something that I am displaying has changed, then I take action. The most common events are creating or deleting a link (edge), deleting an object or changing the name of an object. Here's how they are handled as called by my GWT code:
private native void createLink(JavaScriptObject nativeGraph, String link, String from, String to)/*-{
if (nativeGraph.graph.getAdjacence(from, to) == null) {
var fromNode = nativeGraph.graph.getNode(from);
var toNode = nativeGraph.graph.getNode(to);
var adj = nativeGraph.graph.addAdjacence(fromNode, toNode,
{
'linkUuid' : link,
'selected' : 'false',
'linkcolor' : '#FF0000'
});
nativeGraph.plot();
}
}-*/;
private native void deleteLink(JavaScriptObject nativeGraph, String linkUuid)/*-{
nativeGraph.graph.eachNode(function(n) {
n.eachAdjacency(function(a) {
if (a.data.linkUuid == linkUuid) {
a.setData('alpha', '0');
nativeGraph.graph.removeAdjacence(a.nodeFrom.id,
a.nodeTo.id);
nativeGraph.plot();
return;
}
});
});
}-*/;
private native void deleteNode(JavaScriptObject nativeGraph, String nodeUuid)/*-{
nativeGraph.graph.eachNode(function(n) {
if (n.id == nodeUuid) {
n.setData('alpha', 0, 'end');
nativeGraph.removeNode(nodeUuid, {
type: 'fade:seq',
duration: 1000,
hideLabels: false,
transition: $jit.Trans.Quart.easeOut
}); }
});
}-*/;
private native void updateNodeName(JavaScriptObject nativeGraph, String uuid, String newName)/*-{
var node = nativeGraph.graph.getNode(uuid);
if (node != null) {
node.name = newName;
nativeGraph.plot();
}
}-*/;
fun with JIT part3 might be in the works......enjoy.