A Funnel Chart in JavaScript

In this blog post we will create a funnel chart that demonstrates education enrollment. We will use the JavaScript chart library.

I. Chart Setup.

The Charting library requires a few JavaScript files, which we copy in a folder named Scripts. The files are:

  • config.js
  • MindFusion.Charting.js
  • MindFusion.Common.js
  • MindFusion.Gauges.js
  • require.js

Those files are redistributed with the chart library. If you plan to use different directory structure in your project you must edit the config.js file.

Now we create two files – an HTML page FunnelChart.html and a funnelchart.js file, which will contain the code for the chart. In the FunnelChart.html file we add two references:

<script type="text/javascript" src="Scripts/config.js"></script>
<script data-main="funnelchart" src="Scripts/require.js"></script>

One to the config file and the other to the require.js file. Note that the data-main attribute points exactly to the name of the javascript code-behind file that we’ll use to create and customize the chart.

II. Create the Chart

The chart needs a canvas and we add one to the web page:

<canvas id="funnelChart" width="400" height="500"></canvas>

The size determines the size of the chart, the id is important because we’ll use it to access the canvas from code.

The code for each JavaScript chart is in a single method:

define(["require", "exports", 'MindFusion.Charting'], function (require, exports, m) {
    "use strict";
    var Charting = m.MindFusion.Charting;
    var Controls = m.MindFusion.Charting.Controls;
    var Collections = m.MindFusion.Charting.Collections;
    var Drawing = m.MindFusion.Charting.Drawing;

    //create the chart
    var funnelChartEl = document.getElementById('funnelChart');
	
    var funnelChart = new Controls.FunnelChart(funnelChartEl);

     .......
     //chart customization
     .......
     .......
     funnelChart.draw();
});

 

The chart object is created with the help of the FunnelChart canvas element, which we get from the html page using the id.

III. Data

Data for the funnel chart is a single list with values. That is why we use the SimpleSeries class. It takes two arguments – one list with the data and one with the labels. We initialize the two arrays:

//initialize data and labels
var data = new Collections.List([100, 90, 80, 37, 17, 7]);
var labels = new Collections.List(["Elementary school", "Middle School", "High school", "Bachelor", "Master", "Doc"]);

 

Then we create the series and assign it to the series property of the funnelChart object.

//assign a series
funnelChart.series = new Charting.SimpleSeries(data, labels); 

 

IV. Appearance Customization

We don’t need a legend for the chart that is why we set:

funnelChart.showLegend = false;

 

A chart needs a title and we set one:

funnelChart.title = "Education Enrollment";

 

MindFusion JavaScript chart library has a flexible styling model, which allows us to customize the pens and brushes of a chart either directly through the theme property or through styles. A combination of both is possible and that’s what we’ll use. First, we will use the PerElementSeriesStyle for coloring the chart element. This style uses each of the Brush-es that were added to it to paint just one element from the chart. If necessary, the control cycles through the provided Brush -es.

var brushes = new Collections.List([	
	new Drawing.Brush("#193e4e"),
        new Drawing.Brush("#5a7444"),
        new Drawing.Brush("#8eb848"),
        new Drawing.Brush("#678b99"),
        new Drawing.Brush("#a1d0d8"),
        new Drawing.Brush("#c5b28a"),
		
	]);
	
	var seriesBrushes = new Collections.List();
	seriesBrushes.add(brushes);

 

The PerElementSeriesStyle expects a nested list with Brushes – because a chart can have many series with many elements into it. The same is true for the strokes, but we will add just one Brush, because we want all elements to have one common outlinig:

var strokes = new Collections.List([
	new Drawing.Brush("#f2ebcf"),
        ]);
	
var seriesStrokes = new Collections.List();
seriesStrokes.add(strokes);

 

We repeat the process for StrokeThickness-es and then we create the style object:

funnelChart.plot.seriesStyle = new Charting.PerElementSeriesStyle(seriesBrushes, seriesStrokes, serieStrokeThicknesses);

 

The theme property exposes many fields that help us customize our chart. We adjust the font and change the highlight stroke, which renders when a chart element is selected:

funnelChart.theme.titleFontSize = 18;
funnelChart.theme.titleFontName = "Roboto";
funnelChart.theme.titleFontStyle = Drawing.FontStyle.Bold;
	
funnelChart.theme.dataLabelsFontName = "Roboto";
funnelChart.theme.dataLabelsFontSize = 14;
	
funnelChart.theme.highlightStroke = new Drawing.Brush("#ffcc33");

 

V. Tooltips

We want our chart to render tooltips. The SimpleSeries does not include tooltips by default and we must do some code twisting to make it show them. First, we create a field tooltips, that is assigned to a list with the desired tooltips:

var tooltips = new Collections.List(["32.7%", "29.5%", "26.2%", "12%", "5%", "2%"]);
funnelChart.series.tooltips = tooltips; 

 

Then we have to override the supportedLabels property of the Series class to make it return LabelKinds.ToolTip in addition to LabelKinds.InnerLabel.

Object.defineProperty(m.MindFusion.Charting.SimpleSeries.prototype, "supportedLabels", {
            get: function () { return m.MindFusion.Charting.LabelKinds.InnerLabel | m.MindFusion.Charting.LabelKinds.ToolTip; },
            enumerable: true,
            configurable: true
 });

 

Finally, we must return the appropriate tooltip and the appropriate label, when asked. This is done by overriding the getLabel method of the SimpleSeries class.

m.MindFusion.Charting.SimpleSeries.prototype.getLabel = function (index, kind) {
	if ((kind & m.MindFusion.Charting.LabelKinds.ToolTip) != 0 && this.tooltips)
		return this.tooltips.items()[index];
	
	if (this.labels == null)
		return null;
	return this.labels.items()[index];
};

 

With that the work on our funnel chart is done and we can enjoy the result:

A Funnel chart in JavaScript

A Funnel chart in JavaScript

Complete source code including the libraries is available for direct download from the link below:

Download the Funnel Chart Sample

About MindFusion JavaScript Chart Library: MindFusion JS Chart is an interactive library for charts and gauges written purely in JavaScript. It supports all common chart types, multiple series, custom data,financial charts, funnel charts, a large selection of gauges and rich styling capabilities. The elegant architecture of the library allows you to create dashboards, charts with multiple different types of series in a single plot, unlimited number of axes, reusable styling themes, various oval and linear gauges. The innovative approach to data lets you define your own data classes by implementing a single interface.
The library also boasts a rich event set, zoom, pan, dragging of the legend and a set of many popular gauges. It is designed and implemented to provide JS developers with the perfect tool to create beautiful, interactive dashboards fast and easy. Download trial directly at http://mindfusion.eu/JavaScript.Chart.zip Get your license today at http://www.javascript-chart-buy.html

A Class Diagram Tool in Java with the Flowchart Library – II

This is the second part of MindFusion step-by-step tutorial on how to create a Java application that reads the contents of a *.jar file and renders class diagram of its API. In the previous blog post we looked at the UI elements that build the application – the UI, the legend panel, the diagram elements. Now we continue with reading the class data and building the class diagram.

I. Reading the Data

The data that we need – the name of the API member, its fields, its type – enum, class, interface as well inherited classes – is stored in a helper class that we’ve created for the purpose and that is called MemberInfo.java. It is a simple class that does nothing else than storing data:

 public MemberInfo( String name, String fullName )
    {
        this.name = name;
        this.fullName = fullName;

        //lists for the methods, fields and constructors.
        methods = new ArrayList();
        fields = new ArrayList();
        constructors = new ArrayList();
        inheritsFrom = "";
        packageName = "";
        isInterface = false;
        isEnum = false;
    }

There is a list with the methods, fields and constructors, as well properties for the name of the package, the class this class inherits from as well boolean values that indicate if this is an enum or interface.

For reading the data we use only classes and methods from the official Java packages – no third party tools or libraries:

      try
        {
            //try to open the jar
            JarFile jarFile = new JarFile(pathToJar);

            //explore the elements found in the *.jar.
            Enumeration e = jarFile.entries();

            URL[] urls = {new URL("jar:file:" + pathToJar + "!/")};
            URLClassLoader cl = URLClassLoader.newInstance(urls);
            //if a class is found - read its data
            while (e.hasMoreElements())
            {
                JarEntry je = e.nextElement();
                if (je.isDirectory() || !je.getName().endsWith (".class")) {
                    continue;
                }
                // -6 because of .class file extension.
                String className = je.getName().substring(0, je.getName().length() - 6);
                className = className.replace('/', '.');
                .....

In a cycle we read all classes in the jar, parse the data we are interested in and filter data that is no relevant to us – private methods, abstract classes etc. The data we acquire for each class is stored in a new MemberInfo object that we add to a collection.

II. Diagram Elements

The diagram elements that we use to render each class are TableNode-s. We use the caption field to show the name of the class. In addition, we use the capabilities of the Java diagram library to render formatted text and add to the caption the name of the package – drawn on a new line.

            //create the TableNode
            TableNode _table = diagram.getFactory().createTableNode(10, 10, 5, 5, 2, info.memberCount());
            //set the name of the member and the package as table caption.
            String caption = "" + info.getName() + "";
            if(info.getPackageName().length() > 0)
                caption += "\n" + info.getPackageName();
            _table.setCaption(caption);
            //center the caption
            _table.setCaptionFormat((new TextFormat(Align.Center, Align.Center)));
            //increase the default caption height
            _table.setCaptionHeight(10f);
           .....

It is important to note here that we add an identifier for each table – this will help us find the right TableNode when we later create connections:


 _table.setId(info.getFullName());

By default TableNode-s are drawn with blue. We check if the current object is enum or interface and change the color scheme accordingly:

            //add enums to the list and paint them green
            if(info.isEnum()) {
                _table.setBrush(new SolidBrush(new Color((int) 210, (int) 250, (int) 208)));
                enums.add(_table);
            }//add interfaces to the list and paint them yellow
            else if(info.isInterface()) {
                _table.setBrush(new SolidBrush(new Color((int) 250, (int) 235, (int) 140)));
                interfaces.add(_table);
            }
            else //the class nodes are blue
                _table.setBrush(new SolidBrush(new Color((int)197, (int)223, (int)238)));

Then we add table rows for the constructors, methods and fields. Each row has a cell for the image and for the definition of the member:

            //fill the first cells with data for the constructors.
            for (String constructor : info.getConstructors())
            {
                _table.getCell(0, index).setImage(constructorImage);
                _table.getCell(1, index).setText(constructor);
                index++;
            }

Finally, we look at all MemberInfo objects and draw DiagramLink between each class and the class it derives from, if any:

  for (MemberInfo info : membersList)
        {
            if(!info.getParent().isEmpty())
            {
                DiagramNode node = diagram.findNodeById (info.getFullName());
                DiagramNode parent = diagram.findNodeById( info.getParent());

                //add inheritance link
                if(node != null && parent != null)
                {
                    DiagramLink link = diagram.getFactory ().createDiagramLink(node, parent);

                .......

III. Containers

Interfaces and enums are drawn in groups at the end of the TableNode-s for classes. This is done using ContainerNode-s. First, we calculate the dimensions of the ContainerNode by measuring all TableNode-s that must fit into it:

            //calculate the location of the node
            int side = (int)Math.ceil(Math.sqrt(tables.size()));
            int rows = (int)Math.ceil((double)tables.size() / side);
            double singleWidth = tables.get(0).getBounds().getWidth();
            double width = 5 * (side + 1) * coef + singleWidth * side;
            double height = (5 * (rows + 1) + 5) * coef;

            double[] rowHeights = new double[rows];
            for (int i = 0; i < tables.size(); i++)
                rowHeights[i / side] = Math.max(tables.get(i).getBounds().getHeight(), rowHeights[i / side]);

            for (double h : rowHeights)
                height += h;


            //initialize the container
            ContainerNode b = diagram.getFactory().createContainerNode (0, 0, width, height);
            ....

Here the variable tables is a list with the TableNode-s that must fit into the container. After the ContainerNode is created, the tables must be added and positioned in it:

            int index = 0;
            for (TableNode e : tables)
            {
                b.add(e);

                double x = (index % side) * (5 + singleWidth);
                double y = 0;

                for (int r = 0; r < index / side; r++)
                    y += 5 * coef + rowHeights[r];

                //adjust the size of the node
                e.setBounds(new Rectangle2D.Double(x + 5 * coef, y + 10 * coef,                   e.getBounds().getWidth(), e.getBounds ().getHeight()));

                index++;
            }

Finally we adjust the appearance of the ContainerNode to make it look better and in line with the TableNode-s:

            //customize the container
            b.setCaption(name);
            b.setCaptionFormat((new TextFormat(Align.Center,  Align.Center)));
            b.setHandlesStyle( HandlesStyle.HatchHandles3 );
            b.setFont(new Font("Verdana", Font.BOLD, 4));
            b.setIgnoreLayout(true);
            b.setTag(tag);
            //no shadow
            b.setShadowOffsetX(0f);
            b.setShadowOffsetY(0f);

It’s important to note that the bounds of the container must be updated for the changes to take effect:

            //update the container size.
            b.updateBounds();

IV. Diagram Layout

The last part of the application deals with diagram layout. This is very important because in the common scenario we expect to read *.jar files with tens of classes and proper visual arrangement of the flowchart is the key to its usability.

We decide to use the TreeLayout, which is meant exactly to arrange diagrams with nodes on several levels as we expect the class hierarchies to be. It is easy to apply the layout – we create an instance of it and after setting some initial customization we call its arrange method:

         TreeLayout layout = new TreeLayout();

        //the layout type is Centered
        layout.setType(TreeLayoutType.Centered);
        //allow reversed links
        layout.setReversedLinks(true);
        //the type of links will be cascading
        layout.setLinkStyle(TreeLayoutLinkType.Cascading3);
        //specify the distance between levels of tree nodes
        layout.setLevelDistance(25);
        //groups must be preserved.
        layout.setKeepGroupLayout(true);

        layout.arrange(diagram);

It is easy to understand the type of the settings we’ve used – thanks to the self-explanatory names of the layout class you can see that we specify that the TreeLayout will be centered, the links will be reversed, then we change the link style and the distance between levels. Finally, we specify that the layout of groups must be preserved.

The interesting part is at the end. We must find the ContainerNode-s with the enums and interfaces and move them to the end of the diagram. Here is how:

        // Place enums and delegates at the end
        DiagramNode enums = diagram.findNode(":enums");
        DiagramNode delegates = diagram.findNode(":interfaces");

        double x = 0;
        //calculate the location of each node to find out the last one
        for (DiagramNode node : diagram.getNodes())
        {
        	if (node instanceof TableNode)
            {
        		x = Math.max(x, node.getBounds().getX() +  node.getBounds().getWidth());
            }
        }

        //move enums to the right of the last class node.
        if (enums != null)
        {
            enums.moveTo((float)x + 5f, (float)5);
            x = enums.getBounds().getX() + enums.getBounds().getWidth ();
        }

        if (delegates != null)
        {
            delegates.moveTo((float)x + 5, 5);
        } 

We cycle through each TableNode and always move the containers to the end of the rightmost TableNode that we find. Let’s not forget to resize the diagram after we are done:

 
diagram.resizeToFitItems(5);

With this our application is ready and we test it with an arbitrary *.jar file. Here is the result:

Class Diagram Application in Java

Class Diagram Application in Java

You can download the complete source code of the sample from here:

Download the Class Diagram Tool in Java Application

MindFusion support team welcomes your questions about the Java diagram library or any other of our programming tools at the discussion board or per e-mail at support@mindfusion.eu

About Diagramming for Java Swing: MindFusion.Diagramming for Java Swing provides your Java application with all necessary functionality to create and customize a diagram. The library is very easy to integrate and program. There are numerous utility methods, rich event set, more than 100 predefined shapes. The tool supports a variety of ways to render or export the diagram, advanced node types like TreeView nodes, hierarchical nodes, tables, container nodes and many more. There are 15 automatic layouts, various input / output options and fully customizable appearance. A detailed list with JDiagram’s features is uploaded here. You can check the online demo to see some of the functionality implemented.

Diagramming for Java Swing is royalty free, there are no distribution fees. Licenses depend on the count of developers using the tool – check here the prices.

Collaborative drawing with MindFusion.Diagramming and SignalR

In this post we’ll show how to use the ASP.NET MVC diagram library and SignalR to implement collaborative drawing of diagrams. This can be useful in visual planning tools where users work together on a task, such as project management or mind-mapping applications.

The complete sample project is available here –
CollabMindMap.zip

Start by creating an ASP.NET MVC application in Visual Studio. Open Tools -> Library Package Manager -> Package Manager Console and install the MindFusion.Diagramming.Mvc package –

Install-Package MindFusion.Diagramming.Mvc 

While we are there, also install the SignalR package –

install-package Microsoft.AspNet.SignalR

From the project’s context menu, Add submenu, select OWIN startup class and add SignalR to the OWIN pipeline by calling –

app.MapSignalR();

Now lets add a diagram view to the home page at Views/Home/Index.cshtml, load the necessary script files and wire up diagram event handlers that will send change notifications to the hub –

@using MindFusion.Diagramming
@using MindFusion.Diagramming.Mvc

@{
    var diagView = new DiagramView("diagramView")
        .NodeCreatedScript("onNodeCreated")
        .NodeModifiedScript("onNodeModified")
        .NodeTextEditedScript("onNodeTextEdited")
        .LinkCreatedScript("onLinkCreated")
        .LinkModifiedScript("onLinkModified")
        .LinkTextEditedScript("onLinkTextEdited")
        .ControlLoadedScript("onDiagramLoaded")
        .SetAllowInplaceEdit(true);

    diagView.Diagram.DefaultShape = Shapes.Ellipse;
}

@Html.DiagramView(diagView, new { style = "width:700px; height:600px;" })

@section scripts
{
    @Scripts.Render("~/Scripts/jquery.signalR-2.0.0.js")
    @Scripts.Render("~/Scripts/MindMap.js")
    @Scripts.Render("~/signalr/hubs")
}

The hub will synchronize operations done on the diagram by one client by sending a notification to all other connected clients. From the project context menu add a SignalR hub class, naming it DiagramHub. The model class we’ll use to describe node changes looks like this –

public class NodeModel
{
    [JsonProperty("x")]
    public double X { get; set; }

    [JsonProperty("y")]
    public double Y { get; set; }

    [JsonProperty("width")]
    public double Width { get; set; }

    [JsonProperty("height")]
    public double Height { get; set; }

    [JsonProperty("id")]
    public string Id { get; set; }

    [JsonProperty("text")]
    public string Text { get; set; }
}

Add these three methods to the hub class to synchronize node creation, move, resize and edit-text operations –

public void NodeCreated(NodeModel clientModel)
{
    Clients.AllExcept(Context.ConnectionId).nodeCreated(clientModel);
}
public void NodeModified(NodeModel clientModel)
{
    Clients.AllExcept(Context.ConnectionId).nodeModified(clientModel);
}
public void NodeTextEdited(NodeModel clientModel)
{
    Clients.AllExcept(Context.ConnectionId).nodeTextEdited(clientModel);
}

The diagram event handlers in MindMap.js fill in the model objects and call respective hub methods –

function onNodeCreated(s, e)
{
    var hubId = $.connection.hub.id;
    e.node.id = hubId + s.getItems().length;

    var r = e.node.bounds;
    var model =
    {
        id: e.node.id,
        x: r.x,
        y: r.y,
        width: r.width,
        height: r.height
    };
    
    diagramHub.server.nodeCreated(model);
}

function onNodeModified(s, e)
{
    var r = e.node.bounds;
    var model =
    {
        id: e.node.id,
        x: r.x,
        y: r.y,
        width: r.width,
        height: r.height
    };
    diagramHub.server.nodeModified(model);
}

function onNodeTextEdited(s, e)
{
    var model =
    {
        id: e.node.id,
        text: e.getNewText()
    };
    diagramHub.server.nodeTextEdited(model);
}

Handle notifications sent from server to clients by updating the diagram from received model objects –

$(function ()
{
    diagramHub = $.connection.diagramHub;
    diagramHub.client.nodeCreated = function (model)
    {
        var node = diagram.factory.createShapeNode(
            model.x, model.y, model.width, model.height);
        node.id = model.id;
    };
    diagramHub.client.nodeModified = function (model)
    {
        var node = findNode(model.id);
        node.setBounds(
            new MindFusion.Drawing.Rect(
                model.x, model.y, model.width, model.height),
            true);
    };
    diagramHub.client.nodeTextEdited = function (model)
    {
        var node = findNode(model.id);
        node.setText(model.text);
    };
    $.connection.hub.start();
});

Finally add these helper functions for finding items and storing a global diagram reference –

function onDiagramLoaded(s, e)
{
    diagram = s;
}

function findNode(id)
{
    for (var i = 0; i < diagram.nodes.length; i++)
    {
        var node = diagram.nodes[i];
        if (id == node.id)
            return node;
    }
    return null;
}

function findLink(id)
{
    for (var i = 0; i < diagram.links.length; i++)
    {
        var link = diagram.links[i];
        if (id == link.id)
            return link;
    }
    return null;
}

Start several copies of the application in separate browser instances on your system (or even on different machines if you publish it on IIS or Azure). Now start drawing nodes, moving them or editing their text – changes done on the diagram in one browser will be immediately reflected in all other browsers connected to the hub. However we aren’t yet synchronizing link operations; lets fix that –

public class LinkModel
{
    [JsonProperty("id")]
    public string Id { get; set; }

    [JsonProperty("originId")]
    public string OriginId { get; set; }

    [JsonProperty("destinationId")]
    public string DestinationId { get; set; }

    [JsonProperty("text")]
    public string Text { get; set; }
}

Add following hub methods in server class –

public void LinkCreated(LinkModel clientModel)
{
    Clients.AllExcept(Context.ConnectionId).linkCreated(clientModel);
}
public void LinkModified(LinkModel clientModel)
{
    Clients.AllExcept(Context.ConnectionId).linkModified(clientModel);
}
public void LinkTextEdited(LinkModel clientModel)
{
    Clients.AllExcept(Context.ConnectionId).linkTextEdited(clientModel);
}

Call them from respective JavaScript handlers of diagram link events –

function onLinkCreated(s, e)
{
    var hubId = $.connection.hub.id;
    e.link.id = hubId + s.getItems().length;

    var model =
    {
        id: e.link.id,
        originId: e.link.getOrigin().id,
        destinationId: e.link.getDestination().id,
    };
    
    diagramHub.server.linkCreated(model);
}

function onLinkModified(s, e)
{
    var hubId = $.connection.hub.id;
    var model =
    {
        id: e.link.id,
        originId: e.link.getOrigin().id,
        destinationId: e.link.getDestination().id,
    };
    diagramHub.server.linkModified(model);
}

function onLinkTextEdited(s, e)
{
    var model =
    {
        id: e.link.id,
        text: e.getNewText()
    };
    diagramHub.server.linkTextEdited(model);
}

Handle link-related client notifications by creating or modifying links –

diagramHub.client.linkCreated = function (model)
{
    var link = diagram.factory.createDiagramLink(
        findNode(model.originId), findNode(model.destinationId));
    link.id = model.id;
};
diagramHub.client.linkModified = function (model)
{
    var link = findLink(model.id);
    link.setOrigin(findNode(model.originId));
    link.setDestination(findNode(model.destinationId));
};
diagramHub.client.linkTextEdited = function (model)
{
    var link = findLink(model.id);
    link.setText(model.text);
};

Now the application will also synchronize link operations across all connected clients. Here’s a small diagram synchronized between three different browsers –
collaborative mind map

The sample above uses MindFusion’s ASP.NET MVC API. Code for other frameworks will look similar as MindFusion maintains same diagramming model for multiple platforms. You can download the trial version of any MindFusion.Diagramming component from this page.

Enjoy!

A Class Diagram Tool in Java with the Flowchart Library – I

This blog post is a step-by-step guide on how to create a tool that parses *.jar files and builds the class hierarchy. The visualization of the diagram is performed by MindFusion Java Swing Diagram library.

Here is an image of the final application:

Class Library Tool in Java

Class Library Tool in Java

In part one we will take a look at the controls that build the user interface for the application.

I. UI Controls

We will use three controls from the diagram library:

    private Diagram diagram;
    private DiagramView diagramView;
    private ZoomControl zoomer;

One JScrollPane:

private JScrollPane _scrollPane;

and a JPanel for the legend and a JMenuBar.

    JPanel controlsPanel = new JPanel();
    JMenuBar menuBar;

Those controls build the user interface. At the top is the menu bar with menus for handling the *.jar files. In the center is a scrollable area that contains the diagram. Right to it is a zoom control. At the bottom is the panel with the legend – images and text that explain the colors and symbols on the class diagram.

II. The Diagram Controls

The three diagram controls are the Diagram, the DiagramView and the ZoomControl. The diagram needs a diagramView to render itself onto. The diagramView users a scrollPane to provide scroll functionality for the flowchart. The zoomControl is a typical Java Swing control, we set a few customization options on it to make it pass the layout of our application.

       //diagram initialization
        diagram = new Diagram();
        diagram.setAutoResize(AutoResize.RightAndDown);

We set auto resize for the diagram and assign it to the diagramView:

        //initialize a diagramView that will render the diagram.
        diagramView = new DiagramView(diagram);
        diagramView.setVisible(true);

The scrollPane is initialized with the diagramView and scrolls automatically when the view is bigger than the available size:

         //use a scroll pane to host large diagrams
        _scrollPane = new JScrollPane(diagramView);
        _scrollPane.setVisible(true);
        _scrollPane.setAutoscrolls(true);

The zoomControl is also attached to the diagramView. It’s important that we set its Dimension, the width will be used by the Java layout manager to calculate the available space for it on the application.

        //provide a zoomer for the diagram
        zoomer = new ZoomControl();
        zoomer.setView(diagramView);
        zoomer.setPreferredSize(new Dimension(70, 50));
        zoomer.setVisible(true); 

The arrangement of the controls in the JFrame is done with the BorderLayout. It’s important that we set the layout before we start adding the controls:

     getContentPane().setLayout(new BorderLayout());
     this.add(zoomer, BorderLayout.EAST);
     this.add(createLegendPanel(), BorderLayout.SOUTH);

The zoomer is to the right, the legend panel is at the bottom. The last control that we add is the scrollPane with the diagram, we align it to the center, which means that all the available space would be allocated to her.

     this.add(_scrollPane, BorderLayout.CENTER);

Finally, we create the menu bar.

     this.setJMenuBar(createMenuBar());

III. The Legend Panel

The legend panel is a JPanel with BoxLayout of type “LINE_AXIS”.

        JPanel controlsPanel = new JPanel();
        controlsPanel.setLayout(new BoxLayout(controlsPanel, BoxLayout.LINE_AXIS));
        controlsPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
        controlsPanel.add(Box.createHorizontalGlue());

The legend items are ImageIcon-s – for each symbol in the diagram there’s an icon. We have also created images for the colors of the diagram. Each icon is rendered with explanation label.

Generally, each item on the LegendPanel is initialized like this:

        //create labels for each item on the legend
        JLabel label = new JLabel("Constructor", constructorIcon, JLabel.CENTER);
        label.setAlignmentX(JComponent.CENTER_ALIGNMENT);
        controlsPanel.add(label);
        controlsPanel.add(Box.createRigidArea(new Dimension(10, 0)));
        controlsPanel.add(Box.createHorizontalGlue());

The layout distributes evenly the available space between the items and we get an easy-to-read legend at the bottom of the application.

IV. The Menu

The menu at the top is implemented as a JMenuBar, which uses mnemonic keys and accelerators to grant access to the menu items with keyboard shortcuts. The only menu item and submenu items currently present are File -> Open jar.

        //Build the first menu.
        menu = new JMenu("File");
        menu.setMnemonic(KeyEvent.VK_F);
        menu.getAccessibleContext().setAccessibleDescription(
                "File operations");
        menuBar.add(menu);

The “Open jar” command uses action listener, which brings up the Open File diagolg. This is a JFileChooser, which filters all files except *.jar files.

     //the method that handles events
    public void actionPerformed(ActionEvent e)
    {
        //identify the command
        if ("open_jar".equals(e.getActionCommand())) {

            //a list with MemberInfo objects that hold class info
            ArrayList membersList = new ArrayList();
            fileChooser = new JFileChooser();

            //set the default directory to this file's directory
            fileChooser.setCurrentDirectory(currFile);

            //filter only *.jar files
            FileFilter filter = new FileNameExtensionFilter(null, "jar");
            fileChooser.setFileFilter(filter);
            fileChooser.removeChoosableFileFilter(fileChooser.getAcceptAllFileFilter());
            .......

If the method confirms that the user has selected a valid jar, the path to the file is provided to the method that reads and parses the jar, which will be topic for the second part of this tutorial.

The whole sample is available for direct download from this link:

Download the Class Diagram Tool in Java Application

MindFusion support team welcomes your questions about the Java diagram library or any other of our programming tools at the discussion board or per e-mail at support@mindfusion.eu

About Diagramming for Java Swing: MindFusion.Diagramming for Java Swing provides your Java application with all necessary functionality to create and customize a diagram. The library is very easy to integrate and program. There are numerous utility methods, rich event set, more than 100 predefined shapes. The tool supports a variety of ways to render or export the diagram, advanced node types like TreeView nodes, hierarchical nodes, tables, container nodes and many more. There are 15 automatic layouts, various input / output options and fully customizable appearance. A detailed list with JDiagram’s features is uploaded here. You can check the online demo to see some of the functionality implemented.

Diagramming for Java Swing is royalty free, there are no distribution fees. Licenses depend on the count of developers using the tool – check here the prices.

JavaScript Chart Library, V1.1 Released

The new version of the JavaScript Chart library contains the following new features:

FunnelChart

Funnel charts are often used to represent stages in a sales process and show the amount of potential revenue at each stage. In MindFusion.Charting for JavaScript funnel charts can be created by utilizing the FunnelChart or FunnelRenderer classes. FunnelChart inherits from the base Chart class and offers additional customization through its segmentSpacing and bottomBase properties.

Funnel chart in JavaScript

Funnel chart in JavaScript

Theme XML serialization
Themes now can be serialized to and from XML through the use of the respective loadFrom and saveTo methods.

Miscellaneous

Download the latest version directly from here:

Download JavaScript Chart Library, V1.1 Trial

Technical support is available at the JS Chart forum, per email at support@mindfusion.eu or at the HelpDesk. Either way MindFusion attentive support team would be glad to answer your questions.

About MindFusion JavaScript Chart Library: MindFusion JS Chart is an interactive library for charts and gauges written purely in JavaScript. It supports all common chart types, multiple series, custom data,financial charts, funnel charts, a large selection of gauges and rich styling capabilities. The elegant architecture of the library allows you to create dashboards, charts with multiple different types of series in a single plot, unlimited number of axes, reusable styling themes, various oval and linear gauges. The innovative approach to data lets you define your own data classes by implementing a single interface.
The library also boasts a rich event set, zoom, pan, dragging of the legend and a set of many popular gauges. It is designed and implemented to provide JS developers with the perfect tool to create beautiful, interactive dashboards fast and easy. Download trial directly at http://mindfusion.eu/JavaScript.Chart.zip Get your license today at http://www.javascript-chart-buy.html