create-gojs-kit
Version:
A CLI for downloading GoJS samples, extensions, and docs
195 lines (173 loc) • 8.62 kB
HTML
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Minimal GoJS Sample Generating PDF</title>
<meta name="description" content="A simple demonstration of generating a PDF file in the browser, showing it in the page, and downloading it as a file." />
<!-- Copyright 1998-2025 by Northwoods Software Corporation. -->
<meta charset="UTF-8" />
<script src="https://cdn.jsdelivr.net/npm/gojs"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.6/require.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/svg-to-pdfkit"></script>
<script id="code">
// This just creates and initializes a Diagram.
// The details do not really matter for this demo.
var myDiagram = null;
function init() {
myDiagram = new go.Diagram('myDiagramDiv', {
'undoManager.isEnabled': true,
});
myDiagram.nodeTemplate =
new go.Node('Auto')
.add(
new go.Shape('RoundedRectangle', { strokeWidth: 0, fill: 'white' })
.bind('fill', 'color'),
new go.TextBlock({ margin: 8 })
.bind('text')
);
myDiagram.model = new go.GraphLinksModel(
[
{ key: 1, text: 'Alpha', color: 'lightblue' },
{ key: 2, text: 'Beta', color: 'orange' },
{ key: 3, text: 'Gamma', color: 'lightgreen' },
{ key: 4, text: 'Delta', color: 'pink' },
],
[
{ from: 1, to: 2 },
{ from: 1, to: 3 },
{ from: 2, to: 2 },
{ from: 3, to: 4 },
{ from: 4, to: 1 },
]
);
}
// This common function is called both when showing the PDF in an iframe and when downloading a PDF file.
// The options include:
// "pageSize", either "A4" or "LETTER" (the default)
// "layout", either "portrait" (the default) or "landscape"
// "margin" for the uniform page margin on each page (default is 36 pt)
// "padding" instead of the Diagram.padding when adjusting the Diagram.documentBounds for the area to render
// "imgWidth", size of diagram image for one page; defaults to the page width minus margins
// "imgHeight", size of diagram image for one page; defaults to the page height minus margins
// "parts", "background", "showTemporary", "showGrid", all are passed to Diagram.makeSvg
function generatePdf(action, diagram, options) {
if (!(diagram instanceof go.Diagram)) throw new Error('no Diagram provided when calling generatePdf');
if (!options) options = {};
const pageSize = (options.pageSize || 'LETTER').toUpperCase();
if (pageSize !== 'LETTER' && pageSize !== 'A4') throw new Error('unknown page size: ' + pageSize);
// LETTER: 612x792 pt == 816x1056 CSS units
// A4: 595.28x841.89 pt == 793.71x1122.52 CSS units
let pageWidth = ((pageSize === 'LETTER' ? 612 : 595.28) * 96) / 72; // convert from pt to CSS units
let pageHeight = ((pageSize === 'LETTER' ? 792 : 841.89) * 96) / 72;
const layout = (options.layout || 'portrait').toLowerCase();
if (layout !== 'portrait' && layout !== 'landscape') throw new Error('unknown layout: ' + layout);
if (layout === 'landscape') {
const temp = pageWidth;
pageWidth = pageHeight;
pageHeight = temp;
}
const margin = options.margin !== undefined ? options.margin : 36; // pt: 0.5 inch margin on each side
const padding = options.padding !== undefined ? options.padding : diagram.padding; // CSS units
const imgWidth = options.imgWidth !== undefined ? options.imgWidth : pageWidth - (margin / 72) * 96 * 2; // CSS units
const imgHeight = options.imgHeight !== undefined ? options.imgHeight : pageHeight - (margin / 72) * 96 * 2; // CSS units
const pageOptions = {
size: pageSize,
margin: margin, // unit is pt
layout: layout,
};
require(['blob-stream', 'pdfkit'], (blobStream, PDFDocument) => {
const doc = new PDFDocument(pageOptions);
const stream = doc.pipe(blobStream());
const bnds = diagram.documentBounds;
// add some descriptive text
//doc.text(diagram.nodes.count + " nodes, " + diagram.links.count + " links Diagram size: " + bnds.width.toFixed(2) + " x " + bnds.height.toFixed(2));
const db = diagram.documentBounds.copy().subtractMargin(diagram.padding).addMargin(padding);
const p = db.position;
// render just a single page
const makeOptions = {};
if (options.parts !== undefined) makeOptions.parts = options.parts;
if (options.background !== undefined) makeOptions.background = options.background;
if (options.showTemporary !== undefined) makeOptions.showTemporary = options.showTemporary;
if (options.showGrid !== undefined) makeOptions.showGrid = options.showGrid;
makeOptions.scale = Math.min(1, Math.min(imgWidth / db.width, imgHeight / db.height));
makeOptions.position = new go.Point(p.x, p.y);
makeOptions.size = new go.Size(db.width, db.height);
// render image contents "inline" using a Data URL
makeOptions.elementFinished = (graphobject, svgelement) => {
const pic = graphobject;
if (!(pic instanceof go.Picture) || !(svgelement instanceof SVGImageElement)) return;
const img = pic.element;
if (img) {
const canvas = document.createElement('canvas');
canvas.width = img.width;
canvas.height = img.height;
const ctx = canvas.getContext('2d');
ctx.drawImage(img, 0, 0);
try {
svgelement.setAttribute('href', canvas.toDataURL());
} catch (ex) {
console.log('Error drawing ' + pic.toString() + '\n ' + ex.toString());
}
}
};
const svg = diagram.makeSvg(makeOptions);
let x = 0;
// horizontally center the image within the page
//x = Math.max(0, ((imgWidth - (makeOptions.scale*db.width))*72/96) / 2);
SVGtoPDF(doc, svg, margin + x, margin, null);
doc.end();
stream.on('finish', () => action(stream.toBlob('application/pdf')));
});
}
// Two different uses of generatePdf: one shows the PDF document in the page,
// the other downloads it as a file and the user specifies where to save it.
const pdfOptions =
// shared by both ways of generating PDF
{
// layout: "landscape", // instead of "portrait"
// pageSize: "A4" // instead of "LETTER"
};
function showPdf() {
generatePdf(
blob => {
const datauri = window.URL.createObjectURL(blob);
const frame = document.getElementById('myFrame');
if (frame) {
frame.style.display = 'block';
frame.src = datauri; // doesn't work in IE 11, but works everywhere else
setTimeout(() => window.URL.revokeObjectURL(datauri), 1);
}
},
myDiagram,
pdfOptions
);
}
function downloadPdf() {
generatePdf(
blob => {
const datauri = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.style = 'display: none';
a.href = datauri;
a.download = 'myDiagram.pdf';
document.body.appendChild(a);
requestAnimationFrame(() => {
a.click();
window.URL.revokeObjectURL(datauri);
document.body.removeChild(a);
});
},
myDiagram,
pdfOptions
);
}
</script>
</head>
<body onload="init()">
<div id="sample">
<div id="myDiagramDiv" style="border: solid 1px black; width: 400px; height: 400px"></div>
<div><button onclick="showPdf()">Show PDF</button> <button onclick="downloadPdf()">Download PDF</button></div>
<iframe id="myFrame" style="display: none; width: 1000px; height: 1000px"></iframe>
</div>
</body>
</html>