Friday, March 15, 2013

Fun with JIT, part2

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.





Friday, January 18, 2013

Fun with JIT, part1

Over the past year, I've been integrating JIT  (thejit.org) with my GWT application.  Javascript is not something for the faint of heart and personally I try to stay far away from it instead allowing  GWT to generate the Javascript for me based on my Java implementation code.  But to make use of, extend, and better control the canvas based layout tool JIT, I had to take on some Javascript.  So here's some things I did with it.  Any code snippets here should be considered pseudo-code and are for representation only.


Saving & Restoring Node Positions

The Force-Directed Graph has a built in layout algorithm that draws a graph as best as it can.  However, each time the graph is rendered, the layout algorithm produces a different layout.  We offer the user the ability to control the layout somewhat, specifying spacing between nodes and how many iterations the algorithm should use based on a complexity setting and some others:


Once the layout has been run, we then let the user drag the nodes and links around the screen to better position items to their liking.  To fully make this work, we need to save the node positions so that the next time we view the graph, we put all the nodes back into their original positions.  This also provides a big performance boost, in that we never run the layout algorithm a second time, but instead tell JIT where we want the nodes.

Save Positions:

// We store the node positions using our string object id, and the x,y values.
HashMap<String, ArrayList<Integer>> nodePositions;

// We iterate over the graph, getting the positions of each node.
mygraph.graph.eachNode(function(n) {
saveNodeData(n.id, Math.floor(n.getPos().x), Math.floor(n.getPos().y));
});

saveNodeData(String id, int x, int y)
{
    ArrayList<Integer> locations = new ArrayList<Integer>();
    locations.add(x);
    locations.add(y);
    nodePositions.put(id, locations);
}

Restore Positions:

// Lood our JSON data
nativeGraph.loadJSON(data);

// Put the nodes at the positions we want. No need to run the layout algorithm.

iterate over the saved node positions data and call this:
setNodePosition(JavaScriptObject nativeGraph, String id, int x, int y)
{
    node = nativeGraph.graph.getNode(id);
    if (node != null) {
        node.setPos(new $wnd.$jit.Complex(x,y), 'current');
        nativeGraph.plot();
    }
}


Resizing the Graph

JIT comes with some built-in functionality on many of their graphs that allows the user to scroll their mouse wheel which then causes the canvas to scale in and out, making the drawn objects grow or shrink.  I found this functionality to be somewhat difficult to control and also I wanted to control how large and how small I would allow the screen to scale to.  



I implemented two push buttons on my graph that allow the user to scale up or down as they are pressed.  One jumps 125% and the other jumps 80% which provides an even up/down scaling so that they user can always return to the default, 100%.

Scaling In:

Scaling in makes the objects larger.  Each time the user presses the "+" button, I ask JIT to:

nativeGraph.canvas.scale(1.25, 1.25);


Scaling Out:

Scaling out makes the objects smaller.  Each time the user presses the "-" button, I ask JIT to:

nativeGraph.canvas.scale(.8, .8);


Searching the Graph

Since my graph can get quite large with many of the objects off the edges of the viewable area, I implemented the ability to search for any node by name.  Once found, the node would be selected and the graph would be centered on the object, bringing the object into view for the user.  Here's how.


Find Node:

findNode(JavaScriptObject nativeGraph, String name)
{
    var p = new RegExp(name.replace("*", ".*"));
    
    nativeGraph.graph.eachNode(function(node) {
        if (p.test(node.name)) {
            // Found the node, we can get the x,y positions of this node.
    centerScreen(node.getPos().x, node.getPos().y);
}
}

centerScreen(String x, String y)
{
    // We are using a scroll panel with scroll bars as the parent of our JIT canvas
    // so we just adjust these scrollbars.
    graphContainer.setScrollLeft(((graphWidth / 2) -
(getOffsetWidth() / 2)) + x);
    graphContainer.setScrollTop(((graphHeight / 2) -
(getOffsetHeight() / 2) + y);
}

...More Fun with JIT, part2 coming soon.






Tuesday, December 18, 2012

All Artists Need A Canvas

In designing user interfaces, the widgets provide the starting point.  The widget set typically includes lists, tables, trees, buttons, menus, and dialogs, and provides the interface designer with his tools.   Mapping data into a tree or a table, styling the widgets for a branded look and feel, adding scrolling, sorting, and selection behavior brings a user interface to life and provides the end user with instant visibility.

But sometimes these basic widgets don't go far enough with their ability to convey real world concepts. If a picture is truly worth a thousand words, a graphical four column table with rows of data does not a picture make.  So what alternatives are there?  What if I need to display objects arranged in a circular fashion with relationships between them?  What if I need to show a grab bag of elements that share various connections with each other?  How do I give the user that one picture worth a thousand words?

Given my requirements, I went searching for my etch-a-sketch that would both allow me to arrange objects and at the same time help me with the organization of them.  Enter JIT - Javascript InfoVis Toolkit.  A compact, simple, extendable and powerful canvas drawing and manipulation tool that could be easily integrated into my GWT-based application that was already underway.

In conjunction with the JIT documentation, examples and experts on the Google-groups, I was able to build a view that would provide our users with a visual rendition of network components and their connections between each other as shown.

Network View


We achieved support for:

  • Search by name with the resulting object being selected and centered on the screen
  • User draggable elements for user positioning or JIT auto layout algorithm activation
  • Saving of all element positions to redraw later using the same layout 
  • Zoom in and Zoom out functions for canvas scaling controlled with a "+" and "-" button press
  • Spacing between elements, canvas size, font size and name truncation controlled with view options
  • Full element selection, extended selection and right click popups for shortcut operations
  • Full link (or edge) selection, extended selection and right click popups for operations
  • Dynamic view refreshing using "sum" and "morph" JIT technologies via JSON data
  • Much more to come....

What about being able to show a set of objects related to each other in both directions?  A set of elements that form a ring?  Something that supports selection and can show elaborate connections, but that auto layouts the diagram perfectly each time?

Ring View




With the sunburst layout we achieved support for:

  • Search by name with the resulting object being selected on the screen 
  • Zoom in and Zoom out functions for canvas scaling controlled with a "+" and "-" button press
  • Ring size and spacing, font size and name truncation controlled with view options
  • Full element selection and right click popups for shortcut operations
  • Link (edge) highlighting using various colors based on search or selection criteria
  • Dynamic view refreshing
  • Much more to come....

By combining the asynchronous processing power and speed of GWT with a simple javascript canvas drawing and manipulation tool, we are well on our way to building an interface that fills trees, tables, buttons, menus and dialogs and provides that thousand word picture.



Wednesday, October 10, 2012

You Can Go Home Again

Who says you can't go home again?

As a newly graduated computer scientist, my own backyard was full of companies to go to work for - Data General, Wang, DEC, Apollo, and others.  These companies were booming and were gobbling up my classmates.  Living in New Hampshire, I chose DEC and landed at the Spit Brook road facility that included the famous ZK1, ZK2 and ZK3 buildings.

I traveled to California, Vegas, even Valbonne France as Digital grew and grew.  I sat next to seasoned consulting engineers that knew how to build fantastic software.  I learned.  I saw the creation of computer graphics via DECWindows based on the X Windows framework and later to Motif.  I was hooked with UI design.  I originally worked on DECPlan (basically Microsoft Project before there was a Microsoft) and to this day, it had features that no project management system has.

Mid-90's....the downturn starts.  Competition heats up, the PC is born, Wang starts to collapse, DEC has layoffs and salary freezes, change is brewing.  After 10 years, it's time to move on.  There's some new up and coming companies called Cabletron, Wellfleet, Cisco out there that are the next big things.

And so, some 25 years after beginning in ZK3, I have returned to Spit Brook road.  It's no longer one company...the buildings have been updated, carved up to house numerous companies.  I recently took a walk to some of the uninhabited floors and areas.  I found a conference room with some very interesting information printed on the wall:




The list of VMS features spanned from BL5 (which boasted 100 customers) all the way to version 5.0. It was almost eerie.....like the engineers had just packed up and left and now only dust was living here.

The buildings have also undergone some cosmetic changes as well.  All the entrances have been redone, the heated outside tile gone, and a more engineered entrance in place.



The interior hallways have new carpet, and a new paint scheme with more modern lighting.



A piece of DEC history has also been restored.  Many old timers will remember the barcode on the entrance to ZK2, where the main entrance and credit union used to be.  It spelled out Digital  Software Engineering at some point and has long been removed.  But this past summer, this showed up on the cafeteria wall:


With a plaque that reminded everyone of the barcode DEC used to have and that this new barcode, in the spirit of the original one, spells out Nashua Tech Park.




In my travels about the buildings, I found a three ring binder with a Digital logo on it.  I've put some of my Plexxi documents into it.  There's good karma in these buildings.  Maybe the next big thing is coming from this historic location.  You CAN go home again.


Tuesday, September 4, 2012

Browsers, Browsers, Browsers

After several years of working with HTML, CSS and now GWT and Javascript, it has become quite clear that each browser is going to do things slightly different than others.  This just keeps the engineer on their toes; adds some danger to the mix; provides for some fun with borders and gradients and colors and buttons.

Here's some lessons I've learned recently in getting my GWT application to run across Safari, Chrome, Firefox, Internet Explorer and the Webkit mobile phone browsers.

1. Drawing on a canvas.  My application uses a third party javascript drawing package that uses a canvas for drawing elaborate diagrams.  This works great on all my browsers, except Internet Explorer. Nothing is drawn.  Alas, Internet Explorer doesn't have this native canvas built into it and must be given one.  In my main html file the addition of:

       <!--[if IE]><script language="javascript" type="text/javascript" src="excanvas.js"></script><![endif]-->

did the trick.

2. Right click popup menus.  Any right click you do in a browser produces the typical browser popup menu.  The one to View Source, or Open in New Window.  However, what about when I want to implement my own right click popups and put up my own menus.  In my main html file the addition of:


<body oncontextmenu = "return false;">


did the trick here too.  Now only my popup menus show up and nothing else.


3.  Gradients.  Those light to dark or dark to light backgrounds that make your screen really stand out and look slick.  The following displays a white to blue gradient and works on all browsers.


filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFFFF', endColorstr='#F3F7FB'); /* IE compatible */

background: -webkit-gradient(linear, left top, left bottom, from(#FFFFFF), to(#F3F7FB)); /* Webkit compatible */

background: -moz-linear-gradient(top,  #FFFFFF,  #F3F7FB); /* Firefox compatible */ 

4. Mobile phone.  Any browser based application, like GWT, should also run on all the mobile platform browsers by default.  But what if you application is just too big to fit nicely or to be useable on a mobile platform?  In this case, you should think about presenting the data in a different view on a mobile device as opposed to being on laptop/desktop computer with adequate screen real estate.  Here's two critical things I did to build a mobile version of my GWT app:

 First - how to detect if my application is trying to be run on Android or iPhone?

        // Is this an Android or iPhone device?
        if (Navigator.getUserAgent() != null)
        {
            if (Navigator.getUserAgent().toLowerCase().contains("android") ||
                Navigator.getUserAgent().toLowerCase().contains("iphone"))
            {
                mobileDevice = true;
            }
        }

Second - how to scale my view to fill the screen on the detect smartphone?

<meta name="viewport" content="width=device-width,initial-scale=1.0" />

Was added to my main html file.  In my case, rather than show my entire GWT application on a mobile device, I chose to show just a list of objects with the ability to touch each one and see more details.  Something simple, something usable, something informative, something that fits on the phone.

As I continue down the path of GWT....I'm sure there will be more browser tweaks needed...keeps me on my toes.

  


Thursday, August 2, 2012

GWT Tricks #3

I love when a simple and elegant solution can be easily integrated into my software.  That doesn't always happen, but I truly believe in the KISS principle, especially when architecting and building complex UI applications that have lots of moving parts.

It was brought to my attention that my empty GWT tables were displaying "1-1 of 0" for my SimplePager display.  This was not my code, but was coming from Googles GWT pager implementation.  A web search showed this was an issue that a lot of folks were complaining about.

To be fair, there's no data in the table, and it clearly says "0" items.   Some web searches showed solutions about overriding GWT code and reimplementing the counter mechanisms.  That led me on my way to a solution.  If my table was empty, I want to display my own text, something like "0 of 0", otherwise, I want to let GWT do the calculation.

The solution was to create my own class that extends the GWT SimplePager and then override the createText() method that displays the counter information:



public class MyPager extends SimplePager
{
    public MyPager(final TextLocation center, final Resources pagerResources, final boolean showFastForwardButton,
                       final int fastForwardRows, final boolean showLastPageButton)
    {
        super(center, pagerResources, showFastForwardButton, fastForwardRows, showLastPageButton);
    }


    // Bug with pager that says 1-1 of 0 when the list is empty. fix it to say 0 of 0.
    @Override
    protected String createText()
    {
        final HasRows display = getDisplay();
        final int dataSize = display.getRowCount();

        if (dataSize == 0)
        {
            return "0 of 0";
        }
        else
        {
            return super.createText();
        }
    }
}

Then just use this new pager for my table:

MyPager pager = new MyPager(SimplePager.TextLocation.CENTER, pagerResources, false, 0, true);


Friday, June 1, 2012

GWT - Flash - Swing [Lessons learned]

Approximately one year ago I joined a new startup company and had to decide what technology would be used to build a new highly graphical application.  The requirements were :

  • display dashboard pseudo realtime charts and tables
  • display graphs of objects and their associations and links
  • make it feel like a state of the art application with some coolness factor
  • make it usable and intuitive
  • make it scale
So I built some sample screens using Java Swing, the Google Web Toolkit and Adobe's Flash.  I was able to somewhat build the same screen using each of these technologies.  Long story short.....Java Swing was eliminated since we wanted to run in a web browser with no installation required.  Adobe Flash was eliminated since it would not run on various Apple devices and required a lot of specialization.  This left the Google Web Toolkit.  I had never used it, but had just come off learning Oracle's ADF Technology which actually has a lot in common.   Also, the development environment would be Java with Google doing the javascript generation for me. Being a Java Swing expert put me right in the driver's seat.  

- Advice to any Java Swing experts out there.....learn GWT.  It's a very easy transition. -

To get a jump, I bought the Essential GWT book and started reading and experimenting.  I also started reading and experimenting with the copious online documentation about GWT.  Turns out that the stackoverflow web site would prove extremely valuable for answering detailed technical questions.

My first task was to architect the directory structure and modeling for the application.  Using a MVP (Model, View, Presenter) model was the way to go.  This would allow me to later change the view code to use any widgets (maybe Droid stuff?) without changing the model or presenter code.  I may never do this with my application, but at least it's architected to get there someday.  In a nutshell, the View classes do the widget creation and layout.  The Presenter code handles all callbacks and handlers to push data to the widgets.  The Model code gets data from my db into data structures that I can access asynchronously using rpc AsyncCallback mechanisms.

Everything seemed to fall into place as the application was built.   A spot for images, dialogs, events, tables, panels and third party javascript integration was created.  At this point, any new feature is more of a cut and paste of an existing feature, which is exactly where a product starts to mature.  

I am very impressed with the GWT performance as well.  Drawing tables and charts and lists is very quick and efficient.  Integration with some javascript tools has been quite easy and reliable with the JSNI implementation.  CSS overriding of the GWT widgets has allowed me to completely brand the application to our company style and give it a sophisticated look and feel.  No gwt-ext or ext-gwt here.

Here's to releasing the product and showing some screen shots here soon....