Can mxGraph export graphs as PDFs?
Asked Answered
W

2

7

I am working on a project that uses mxGraph where I am required to export a high resolution output in PDF for a service process diagram. I've tried recreating the graph using JGraphX, the Java Swing client and exporting that to a PDF, but the result is not close to what the browser displays.

There's no PDF export in JavaScript on the client, does mxGraph have any explicit support for PDF generation from JavaScript?

Warring answered 8/11, 2013 at 20:0 Comment(0)
R
4

I'll explain the case of a client initiated request, where the diagram is displayed on the browser when the request is made. This is the standard case, mxGraph transmits an XML representation of the graph using custom graphics primitives and these are received on the server and decoded either by the Java or .NET back-ends.

The reason for the need for the graph being displayed is there are certain text measurements that are hard to recreate outside of a browser environment.

On the client side you need to create the required immediate XML using, say, the diagrameditor.html example as a guide:

var exportImage = function(editor)
{
    var graph = editor.graph;
    var scale = graph.view.scale;
    var bounds = graph.getGraphBounds();

        // New image export
    var xmlDoc = mxUtils.createXmlDocument();
    var root = xmlDoc.createElement('output');
    xmlDoc.appendChild(root);

    // Renders graph. Offset will be multiplied with state's scale when painting state.
    var xmlCanvas = new mxXmlCanvas2D(root);
    xmlCanvas.translate(Math.floor(1 / scale - bounds.x), Math.floor(1 / scale - bounds.y));
    xmlCanvas.scale(scale);

    var imgExport = new mxImageExport();
    imgExport.drawState(graph.getView().getState(graph.model.root), xmlCanvas);

    // Puts request data together
    var w = Math.ceil(bounds.width * scale + 2);
    var h = Math.ceil(bounds.height * scale + 2);
    var xml = mxUtils.getXml(root);

    // Requests image if request is valid
    if (w > 0 && h > 0)
    {
        var name = 'export.png';
        var format = 'png';
        var bg = '&bg=#FFFFFF';

        new mxXmlRequest(editor.urlImage, 'filename=' + name + '&format=' + format +
                bg + '&w=' + w + '&h=' + h + '&xml=' + encodeURIComponent(xml)).
                simulate(document, '_blank');
    }
};

Where editor.urlImage is the URL of the image generating servlet, in the case for a Java back-end.

On the server-side, in the case of Java, look at the java/examples/com/mxgraph/examples/web/ExportServlet.java. That looks at the "format" parameter passed up, and if 'pdf', the writePdf() method is invoked.

That method creates an PdfWriter and renders the graphics primitives to a Java Swing Graphics2D using the Java favoured part of mxGraph.

This example writes the PDF result directly to the outstream of the servlet repsonse in this line:

PdfWriter writer = PdfWriter.getInstance(document, response.getOutputStream());

You could map the output to any stream.

Note that you need to setup iText to map every font you need in the PDF. This isn't always ideal for a large number of fonts. It's worth testing a few cases of the export to see if the output is good enough for your requirements. We're currently researching the use of PhantomJS for the export. If the Java export isn't good enough, please post another question regarding using PhantomJS and I'll detail the process for that.

iText is provided as an example PDF library to use, it's easier since it's under an open source library. It's possibly not the best suited library, we didn't find it easy to work with for this specific scenario. You might also want to investigate other Java PDF generation libraries.

Also note that the .NET back-end only supports raster image generation in dotnet/aspnet/Export.ashx, there's no known open source PDF library to supply as an example there.

Rook answered 10/11, 2013 at 22:43 Comment(0)
M
0

Full vector solution:

  1. Set mxClient.NO_FO = true;
  2. Export SVG to PDF by svg2pdf.js
  3. Write all DIV's text to pdf by jsPDF

Example:

let pdf = new jsPDF('p', 'pt', 'a4', false, false);
mxClient.NO_FO = true;
let graph = Draw(drawdiv, false);
let svgEl = drawdiv.children[1];
//draw svg:
svg2pdf(svgEl, pdf, {
  xOffset: pdfPageDefaultOffsetX,
  yOffset: pdfOffsetY,
  scale: divToPdfRatio
});
//draw text:
for (let child of drawdiv.children) {
  if (child.tagName === 'DIV') {
    let splitText = pdf.splitTextToSize(child.innerText, Math.ceil((childSizes.width) * divToPdfRatio));
    pdf.text(pdfPageDefaultOffsetX + (child.offsetLeft * divToPdfRatio), textPositionTop, splitText, {
      align: child.style.textAlign,
      lineHeightFactor: 1,
    });
  }
}
pdf.save('Test.pdf');
Makhachkala answered 29/7, 2020 at 14:50 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.