Best way to visualize project networks

Hello!

I have a Vaadin application, in which I want to visualize directed graph structures like these:

What is the best way to do it in Vaadin?

At the moment, I am looking at
canviz
, which uses dot as input and produces
nice
graphics using JavaScript.

Best regards

Dmitri

You could wrap canviz to a Vaadin component and use it. If you do, please contribute the result as an addon in the vaadin directory.

If you decide to build a graph rendering by yourself, I would recommend to use
GWT Graphics
.

Hello!

I tried to use canviz, but then turned to
JUNG2
framework. It’s much easier to integrate it into a Vaadin application.

The image of JUNG2 graph can be wrapped as Embedded instance:


        final VerticalLayout layout = new VerticalLayout();

        final Embedded image = createSampleGraph();
        layout.addComponent(image);
        layout.setSizeFull();

        this.addComponent(layout);

createSampleGraph method looks like this:


    private Embedded createSampleGraph() {
        Embedded imageComponent = null;

        try {
            final DocumentBuilderFactory docBuilderFactory =
                    DocumentBuilderFactory
                            .newInstance();
            final DocumentBuilder docBuilder =
                    docBuilderFactory.newDocumentBuilder();
            final Document document = docBuilder.newDocument();
            final Element svgelem = document.createElement("svg");
            document.appendChild(svgelem);

            final SVGGraphics2D graphic2d = new SVGGraphics2D(document);

            final Graph<String, String> graph = createGraph();
            final VisualizationImageServer<String, String> server =
                    createServer(graph);

            server.printAll(graphic2d);

            final Element el = graphic2d.getRoot();
            el.setAttributeNS(
                    null,
                    "viewBox",
                    "0 0 ${width} ${height}".replace("${width}",
                            String.valueOf(DEFAULT_WIDTH_PIXELS))
                            .replace("${height}",
                                    String.valueOf(DEFAULT_HEIGHT_PIXELS)));
            el.setAttributeNS(null, "style", "width:100%;height:100%;");

            ByteArrayOutputStream bout = null;
            
                bout = new ByteArrayOutputStream();

                final Writer out = new OutputStreamWriter(bout, "UTF-8");
                graphic2d.stream(el, out);                
            

            final JungResource source =
                    new JungResource(bout, this.renderingMode);

            TPTApplication.getCurrentApplication().addResource(source);

            imageComponent = new Embedded("", source);

            imageComponent.setWidth(DEFAULT_WIDTH_PIXELS, UNITS_PIXELS);
            imageComponent.setHeight(DEFAULT_HEIGHT_PIXELS, UNITS_PIXELS);

            imageComponent.setMimeType(JungResource.MIME_TYPE_SVG);

            addComponent(imageComponent);
        } catch (final UnsupportedEncodingException exception) {
            LOGGER.error(ErrorCodes.M_001_UNSUPPORTED_ENCONDING, exception);
        } catch (final SVGGraphics2DIOException exception) {
            LOGGER.error(ErrorCodes.M_002_SVG_GRAPHICS_2D_IO, exception);
        } catch (final ParserConfigurationException exception) {
            LOGGER.error(ErrorCodes.M_003_PARSER_CONFIGURATION, exception);
        }
        return imageComponent;
    }

    private VisualizationImageServer<String, String> createServer(
            final Graph<String, String> aGraph) {
        final Layout<String, String> layout = new FRLayout<String, String>(
                aGraph);

        layout.setSize(new Dimension(DEFAULT_WIDTH_PIXELS,
                DEFAULT_HEIGHT_PIXELS));

        final VisualizationImageServer<String, String> vv =
                new VisualizationImageServer<String, String>(
                        layout, new Dimension(DEFAULT_WIDTH_PIXELS,
                                DEFAULT_HEIGHT_PIXELS));
        vv.getRenderContext().setVertexLabelTransformer(
                new ToStringLabeller<String>());

        return vv;
    }

    private Graph<String, String> createGraph() {
        final Graph<String, String> graph =
                new DirectedSparseMultigraph<String, String>();
        initialEventVertex = "IE";
        final String vertex2 = "P1";
        final String vertex3 = "P2";
        final String vertex4 = "P3";
        finalEventVertex = "FE";

        graph.addVertex(initialEventVertex);
        graph.addVertex(vertex2);
        graph.addVertex(vertex3);
        graph.addVertex(vertex4);
        graph.addVertex(finalEventVertex);

        graph.addEdge("1", initialEventVertex, vertex2, EdgeType.DIRECTED);
        graph.addEdge("2", vertex2, vertex3, EdgeType.DIRECTED);
        graph.addEdge("3", vertex3, finalEventVertex, EdgeType.DIRECTED);
        graph.addEdge("4", initialEventVertex, vertex4, EdgeType.DIRECTED);
        graph.addEdge("5", vertex4, finalEventVertex, EdgeType.DIRECTED);
        return graph;
    }

Finally, you need the JungResource class:


class JungResource implements ApplicationResource {
    public static final String MIME_TYPE_PNG = "image/png";
    public static final String MIME_TYPE_SVG = "image/svg+xml";
    private static final long serialVersionUID = 1L;
    private static final Logger LOGGER = LoggerFactory
            .getLogger(JungResource.class);

    private transient ByteArrayInputStream bytestream = null;
    private transient ByteArrayOutputStream originalOutputStream;

    private RenderingMode mode;

    public JungResource(final ByteArrayOutputStream aOutputStream,
            final RenderingMode aMode) {
        this.originalOutputStream = aOutputStream;
        this.mode = aMode;
    }

    @Override
    public String getMIMEType() {
        if (RenderingMode.SVG == mode) {
            return MIME_TYPE_SVG;
        } else {
            return MIME_TYPE_PNG;
        }

    }

    @Override
    public DownloadStream getStream() {
        DownloadStream downloadStream = new DownloadStream(
                getByteStream(), getMIMEType(), getFilename());
        return downloadStream;

    }

    private InputStream getByteStream() {
        this.bytestream = new ByteArrayInputStream(
                originalOutputStream.toByteArray());
        return this.bytestream;
    }

    @Override
    public Application getApplication() {
        return TPTApplication.getCurrentApplication();
    }

    @Override
    public String getFilename() {
        return "projectnetwork.svg";

    }

    @Override
    public long getCacheTime() {
        return 0;
    }

    @Override
    public int getBufferSize() {
        try {
            return getByteStream().available();
        } catch (final IOException exception) {
            LOGGER.error("", exception);
            return 0;
        }
    }

}

That renders the graph as an SVG image, which is viewable in most browsers. IE, prior to version 9, did not support SVG.

If you need to support IE <9, it’s necessary to render the graph as PNG or as SVG, depending on the browser.

An example for that can be found in the class JFreeChartWrapper of JFreeChart project.

Best regards

Dmitri

How about making an add-on out of this?

Hello!

Is there a tutorial about making a Vaadin add-on?

If there is, I’ll try to make it.

Best regards

Dmitri

Not exactly a tutorial but
instructions here
.

There are two ways to package an add-on: as a simple JAR or as a ZIP that contains such a JAR and possibly other resources (JARs, documentation, …).

If you are using Eclipse and the Vaadin Eclipse plugin, packaging a JAR add-on is very easy - there is an export wizard that creates a Vaadin add-on JAR, asking you about the required manifest fields etc.

Making a ZIP package involves a few more manual steps, see the instructions.