Вывод файлов SVG из mxGraph

Моя команда и я рассматриваем возможность использования mxGraph для программного создания диаграмм. Мы создали график и сохранили его в виде XML-файла. Как нам перейти оттуда к файлу SVG?

Я понимаю, что mxGraph изначально использует файлы SVG для отображения и что он может записывать файлы SVG с закодированным в них XML, чтобы их можно было повторно открыть в диаграммах.net. Как я могу заставить mxGraph поместить наш график на холст SVG, а затем сериализовать его на диск?

// from https://stackoverflow.com/a/57829704
const jsdom = require("jsdom");
const { JSDOM } = jsdom;
const dom = new JSDOM();
const fs = require('fs');

global.window = dom.window;
global.document = window.document;
global.XMLSerializer = window.XMLSerializer;
global.navigator = window.navigator;

const mxgraph = require("mxgraph")({
    mxImageBasePath: "./src/images",
    mxBasePath: "./src"
});


const {mxGraph, mxCodec, mxUtils, mxConstants, mxSvgCanvas2D} = mxgraph;

function makeHelloWorld() {
  // Extracted from https://github.com/jgraph/mxgraph/blob/master/javascript/examples/helloworld.html
  const graph = new mxGraph();

  // Gets the default parent for inserting new cells. This
  // is normally the first child of the root (ie. layer 0).
  var parent = graph.getDefaultParent();

  // Adds cells to the model in a single step
  graph.getModel().beginUpdate();
  try {
    var v1 = graph.insertVertex(parent, null, 'Hello,', 20, 20, 80, 30);
    var v2 = graph.insertVertex(parent, null, 'World!', 200, 150, 80, 30);
    var e1 = graph.insertEdge(parent, null, '', v1, v2);
  } finally {
    // Updates the display
    graph.getModel().endUpdate();
  }
  return graph;
}

const helloWorldGraph = makeHelloWorld();

function graphToXML(graph) {
    var encoder = new mxCodec();
    var result = encoder.encode(graph.getModel());
    return mxUtils.getXml(result);
}

const xml = graphToXML(helloWorldGraph);

fs.writeFileSync('./graph.xml', xml);

Все до этого момента работает — мы можем вывести файл XML. Теперь нам нужно перейти оттуда к SVG.

Я создал холст SVG, например:

function createSvgCanvas(graph) {
    const svgDoc = mxUtils.createXmlDocument();
    const root = (svgDoc.createElementNS != null) ? svgDoc.createElementNS(mxConstants.NS_SVG, 'svg') : svgDoc.createElement('svg');
    if (svgDoc.createElementNS == null) {
        root.setAttribute('xmlns', mxConstants.NS_SVG);
        root.setAttribute('xmlns:xlink', mxConstants.NS_XLINK);
    } else {
        root.setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:xlink', mxConstants.NS_XLINK);
    }
    const bounds = graph.getGraphBounds();
    root.setAttribute('width', (bounds.x + bounds.width + 4) + 'px');
    root.setAttribute('height', (bounds.y + bounds.height + 4) + 'px');
    root.setAttribute('version', '1.1');
    svgDoc.appendChild(root);
    const svgCanvas = new mxSvgCanvas2D(root);
    return svgCanvas;
}

Проблемы:

  1. Размер нового холста соответствует графику, но на нем еще нет графика.
  2. Мне нужно выяснить, как превратить холст SVG в файл SVG на диске.

РЕДАКТИРОВАТЬ: я добавил следующее в конец программы:

const canvas = createSvgCanvas(helloWorldGraph);
const imgExport = new mxImageExport();
imgExport.drawState(helloWorldGraph.getView().getState(helloWorldGraph.model.root), canvas); // adapted from https://jgraph.github.io/mxgraph/docs/js-api/files/util/mxImageExport-js.html

const xml2 = mxUtils.getXml(canvas)

const svgString = '<?xml version="1.0" encoding="UTF-8"?>\n'
+ '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">\n'
+ xml2
fs.writeFileSync('./graph.svg', svgString);

Это вызывает у меня Uncaught TypeError: не удалось выполнить «serializeToString» в «XMLSerializer»: параметр 1 не имеет типа «узел». Я пробовал кое-что, но я недостаточно знаком с mxGraph, чтобы получить нужный узел из моего холста.


person DawnPaladin    schedule 15.12.2020    source источник


Ответы (2)


Что касается пункта 1, вы можете просмотреть код draw.io, в котором подробно описано, как настроить холст.

Но этот код предназначен для использования в браузере, поэтому у вас могут возникнуть проблемы при запуске скрипта, основанного на JSDOM.

Вам нужно будет использовать mxImageExport для использования холста. Затем оберните созданный узел для создания строки svg (в следующем svgRoot это элемент, созданный пользовательским кодом и обновленный mxImageExport)

'<?xml version="1.0" encoding="UTF-8"?>\n'
 + '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">\n'
 + mxUtils.getXml(svgRoot)

Для пункта 2 в скрипте, когда у вас есть строка svg, вы можете записать ее непосредственно в файл, как вы сделали для сохранения модели mxgraph в файле xml.

Для пункта 2 в браузере вы можете использовать атрибуты загрузки и href элемента Anchor (https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a#Attributes)

Во-первых, сгенерируйте данные href, содержащие значение кодировки строки svg, созданной с помощью точки 1.

'data:image/svg+xml' + encodeURIComponent(svg)

Затем создайте якорь с этими данными href и активируйте его, например, при нажатии на кнопку. Подробнее см. в https://ourcodeworld.com/articles/read/189/how-to-create-a-file-and-generate-a-download-with-javascript-in-the-browser-без-сервера

person redfish4ktc    schedule 18.12.2020
comment
Спасибо за Ваш ответ! Обновил мой вопрос с некоторым прогрессом, которого я добился. - person DawnPaladin; 31.12.2020

Чтобы сгенерировать файлы SVG из XML, вы можете загрузить настольную версию диаграмм.net с http://get.diagrams.net и запустите его в командной строке.

Документацию по флагам командной строки можно найти здесь или работает draw.io --help.

/Applications/draw.io.app/Contents/MacOS/draw.io -x -f svg graph.xml

Однако в созданных таким образом файлах SVG отсутствуют встроенные данные XML, которые позволили бы повторно открыть их в диаграммах.net. Эти данные можно повторно вставить с помощью регулярного выражения или другого метода.

person DawnPaladin    schedule 31.12.2020