I'm trying to output this SVG to a pdf. The SVG is generated by mermaid.js
I found an existing answer on stack for converting SVG to PDF. This answer defined a function downloadPDF
which converts SVG to PDF and triggers the PDF download.
When I run this function in the below minimal example, I get output, but the output looks all grayed-out. Can someone help me output the given SVG to PDF correctly?
Here is a minimal example:
<!DOCTYPE html>
<html lang="en" style="height: auto;">
<head>
</head>
<body>
<div class="mermaid">
graph TD;
A-->B;
A-->C;
B-->D;
C-->D;
C[Action 1 </br> Can code preserve line breaks?];
</div>
</body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/mermaid/8.13.4/mermaid.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/pdfkit@0.10.0/js/pdfkit.standalone.js"></script>
<script src="https://bundle.run/blob-stream@0.1.3"></script>
<script src="https://cdn.jsdelivr.net/npm/svg-to-pdfkit@0.1.8/source.js"></script>
<script>
mermaid.init({
flowchart: { useMaxWidth: false },
"theme": "default",
"themeVariables": {
"fontFamily": "Helvetica"
}
}, document.querySelectorAll(".mermaid"));
</script>
<script>
function downloadPDF(svg, outFileName) {
let doc = new PDFDocument({compress: false});
SVGtoPDF(doc, svg, 0, 0);
let stream = doc.pipe(blobStream());
stream.on('finish', () => {
let blob = stream.toBlob('application/pdf');
const link = document.createElement('a');
link.href = URL.createObjectURL(blob);
link.download = outFileName + ".pdf";
link.click();
});
doc.end();
}
var svg = document.querySelector('svg');
</script>
To produce the PDF, paste this into the browser development console: downloadPDF(svg, "test")
Here is the svg image produced by minimal example:
Here is the image output from the downloadPDF
function (run downloadPDF(svg, "test")
in broswer development console):
Note: I'm getting this same output with Firefox and Edge browsers.
Update: I edited the function downloadPDF and now I get the colors correctly, however, node text is still not displayed:
function downloadPDF(svg, outFileName) {
let doc = new PDFDocument({compress: false});
SVGtoPDF(doc, svg, 0, 0, {useCSS:true});
let stream = doc.pipe(blobStream());
stream.on('finish', () => {
let blob = stream.toBlob('application/pdf');
const link = document.createElement('a');
link.href = URL.createObjectURL(blob);
link.download = outFileName + ".pdf";
link.click();
});
doc.end();
}
New pdf output without node text:
If anyone could help figure out the node text portion I would really appreciate it!
Update 2:
So I noticed that if I change the foreignObject's in the svg nodes to <text>
elements and remove the div, I get the text, but now the issue is the text is offset also I have no idea if this will preserve fonts.
Below I take each svg node and use replaceAll to modify the innerHTML of the nodes
for(i = 0; i< svg.getElementsByClassName("node").length; i++){
svg.getElementsByClassName("node")[i].innerHTML = svg.getElementsByClassName("node")[i].innerHTML.replaceAll("<div xmlns=\"http://www.w3.org/1999/xhtml\" style=\"display: inline-block; white-space: nowrap;\">", "").replaceAll("</div>", "").replaceAll("foreignObject", "text");
}
downloadPDF(svg, "test")
Update
It became really easy with browser print functions
I slightly modified this function which I found in this answer.
var printSVG = function()
{
var popUpAndPrint = function()
{
var container = $('.mermaid')[0];
var width = Math.max(1000, parseFloat(svg.getAttribute("width")))
var height = Math.max(1000, parseFloat(svg.getAttribute("height")))
var printWindow = window.open('', 'PrintMap',
'width=' + width + ',height=' + height);
printWindow.document.writeln($(container).html());
printWindow.document.close();
printWindow.print();
printWindow.close();
};
setTimeout(popUpAndPrint, 500);
};
Thanks to everyone for the help!