feat(flowchart): export to editable Visio .vsdx (C14)

New 'Export Visio' toolbar button sends the current graph to the
main process, which generates an OOXML .vsdx zip with JSZip and
writes it to a user-chosen path. The result is fully editable in
Microsoft Visio, draw.io, Lucidchart, and any other tool that
accepts the format — not an embedded image.

Architecture follows the existing pure-module pattern:

  - src/flowchart/flowchart-vsdx-export.js: pure translator that
    produces (a) page1.xml describing each node as a Visio Shape
    with correct geometry (PinX/PinY/Width/Height in inches, with
    the Y-axis flipped to match Visio's bottom-up coords), each
    edge as a Connect entry, and (b) the seven static boilerplate
    XML files that make a .vsdx zip valid ([Content_Types].xml,
    _rels/.rels, visio/document.xml, visio/pages/pages.xml, etc.).

  - src/main.js: new 'export-vsdx' IPC handler requires the pure
    module + JSZip, builds the zip, writes to disk, returns
    { canceled, path } | { canceled: false, error }.

  - src/preload.js: flowchart.exportVsdx(graph) bridge.

  - src/renderer/flowchart-bundle.js: btnExportVsdx handler, status
    feedback for cancel / save / error paths.

  - src/flowchart-generator.html: button next to Export JPG.

Tests: 7 new (1362 total) cover graphBounds (empty / single /
multi-node), XML escaping of label text, Connect emission, the 5
node kinds mapping to 5 distinct master names, and that all
boilerplate files start with the XML declaration.

Amit Haridas
This commit is contained in:
2026-09-30 22:17:15 +05:30
parent e967af77a7
commit d90be20a72
6 changed files with 430 additions and 0 deletions
+24
View File
@@ -941,6 +941,7 @@
btnExportSvg: document.getElementById('fc-btn-export-svg'),
btnExportPng: document.getElementById('fc-btn-export-png'),
btnExportJpg: document.getElementById('fc-btn-export-jpg'),
btnExportVsdx: document.getElementById('fc-btn-export-vsdx'),
btnUndo: document.getElementById('fc-btn-undo'),
btnRedo: document.getElementById('fc-btn-redo'),
historyCount: document.getElementById('fc-history-count'),
@@ -1689,6 +1690,29 @@
);
}
// v4.13.0 — Export to editable Visio .vsdx. Sends the graph JSON to
// the main process which generates the OOXML zip and writes it.
if (els.btnExportVsdx) {
els.btnExportVsdx.addEventListener('click', async () => {
if (!_store || !api.exportVsdx) return;
try {
const graph = _store.getGraph();
const result = await api.exportVsdx(graph);
if (!result || result.canceled) {
setStatus('Export cancelled');
} else if (result.path) {
setStatus('Saved Visio to ' + result.path);
} else if (result.error) {
setStatus('Export failed: ' + result.error);
} else {
setStatus('Saved Visio');
}
} catch (err) {
setStatus('Visio export failed: ' + (err && err.message ? err.message : err));
}
});
}
// v4.13.0 — Open from .mmd/.md file. Pops a system Open dialog,
// strips the ```mermaid fence (if any), parses via fromMermaid()
// (inlined above) and replaces the current graph. Confirms