Closed kickmyassp closed 6 years ago
If you don't know how to break down the SVG, properly, how should the software be able to do that automatically for you?
If you are looking for a simple tiling approach, that of course is easy to achieve: simply render the same svg using different viewports onto the various pages.
@yGuy Can you point me to a few more details on the approach you mention above?
If you are looking for a simple tiling approach, that of course is easy to achieve: simply render the same svg using different viewports onto the various pages.
You can try something like this:
svg:
<svg id="svg-image" xmlns="http://www.w3.org/2000/svg" width="200px" height="100px" viewBox="0 0 200 100">
<rect x="10" y="10" width="80" height="80" fill="red"></rect>
<rect x="110" y="10" width="80" height="80" fill="red"></rect>
</svg>
js:
const svgElement = document.getElementById('svg-image')
const doc = new jsPDF('l', 'pt', [100, 100])
svgElement.setAttribute("width", "100px")
svgElement.setAttribute("height", "100px")
svgElement.setAttribute("viewBox", "0 0 100 100")
svg2pdf(svgElement, doc, {})
doc.addPage()
svgElement.setAttribute("viewBox", "100 0 100 100")
svg2pdf(svgElement, doc, {})
I've almost got the paging to working, but I'm losing my margin on the right and bottom. Am I missing something?
public convertSvgToPdf(svgElement: Element, size: Size, margins: Insets) {
svgElement = svgElement.cloneNode(/*deep*/true) as Element;
const margin = margins ? Math.max(margins.left, margins.right, margins.top, margins.bottom) : Defaults.PdfDocumentMargin;
const pdfPageWidth = 792;
const pdfPageHeight = 612;
svgElement.setAttribute('width', pdfPageWidth + 'px');
svgElement.setAttribute('height', pdfPageHeight + 'px');
const jsPdf = new jsPDF('l', 'pt', [pdfPageWidth, pdfPageHeight]);
const pagesWideWithMargins = Math.floor((size.width + (pdfPageWidth - 1)) / (pdfPageWidth - (margin * 2)));
const pagesHighWithMargins = Math.floor((size.height + (pdfPageHeight - 1)) / (pdfPageHeight - (margin * 2)));
for (let i = 0; i < pagesHighWithMargins; i++) {
for (let j = 0; j < pagesWideWithMargins; j++) {
svgElement.setAttribute('viewBox', this.getViewboxAttribute(j, i, pdfPageWidth, pdfPageHeight, margin));
svg2pdf(svgElement, jsPdf, {
xOffset: 0,
yOffset: 0,
scale: 1
});
jsPdf.addPage([pdfPageWidth, pdfPageHeight], 'landscape');
}
}
return jsPdf.output('datauristring');
}
private getViewboxAttribute(horizontalPageNumber: number, verticalPageNumber, pdfPageWidth, pdfPageHeight, margin) {
const value = String((pdfPageWidth - (margin * 2)) * horizontalPageNumber) + ' ' + ((pdfPageHeight - (margin * 2)) * verticalPageNumber) + ' ' + (pdfPageWidth - (margin * 2)) + ' ' + (pdfPageHeight - (margin * 2));
return value;
}
I guess this has something to do with svg2pdf not clipping the svg at the viewport. You could try and add a clipping rect with the size of the current viewport and also update this for each page.
Could you please verify if this is correct? The bottom/right margin portion of each page should be duplicated on the next page.
No, I don't intend to have any graph content delicates from page to page. I want a small default margin so it can be printed on printers that can't do borderless and I'll probably add a little extra border at the bottom to accommodate row and column numbers to help users reassemble printed pages into the graph.
On Tue, Apr 16, 2019, 9:13 AM Lukas Holländer notifications@github.com wrote:
I guess this has something to do with svg2pdf not clipping the svg at the viewport. You could try and add a clipping rect with the size of the current viewport and also update this for each page.
Could you please verify if this is correct? The bottom/right margin portion of each page should be duplicated on the next page.
— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/yWorks/svg2pdf.js/issues/37#issuecomment-483677227, or mute the thread https://github.com/notifications/unsubscribe-auth/Abz4wZ__ITyETCXN_HAm45tnIeIyeQ-Eks5vhdqNgaJpZM4Q10Lq .
I've got this close to what I want after adding the clip rect and the height and width on the svg element. A couple of things I can't figure out:
Any ideas appreciated.
public convertSvgToPdf(svgElement: Element, size: Size, margins: Insets) {
svgElement = svgElement.cloneNode(/*deep*/true) as Element;
const margin = margins ? Math.max(margins.left, margins.right, margins.top, margins.bottom) : Defaults.PdfDocumentMargin;
const pdfPageWidth = 792;
const pdfPageHeight = 612;
const pdfPageWidthContent = pdfPageWidth - (margin * 2);
const pdfPageHeightContent = pdfPageHeight - (margin * 2);
svgElement.setAttribute('width', pdfPageWidthContent + 'px');
svgElement.setAttribute('height', pdfPageHeightContent + 'px');
const jsPdf = new jsPDF('l', 'pt', [pdfPageWidth, pdfPageHeight]);
const pagesWideWithMargins = Math.floor((size.width + (pdfPageWidth - 1)) / pdfPageWidthContent);
const pagesHighWithMargins = Math.floor((size.height + (pdfPageHeight - 1)) / pdfPageHeightContent);
for (let verticalPageIndex = 0; verticalPageIndex < pagesHighWithMargins; verticalPageIndex++) {
for (let horizontalPageIndex = 0; horizontalPageIndex < pagesWideWithMargins; horizontalPageIndex++) {
const svgXOffset = pdfPageWidthContent * horizontalPageIndex;
const svgYOffset = pdfPageHeightContent * verticalPageIndex;
this.addClipRectDefinition(svgElement, svgXOffset, svgYOffset, pdfPageWidthContent, pdfPageHeightContent);
svgElement.setAttribute('viewBox', this.getViewboxAttribute(svgXOffset, svgYOffset, pdfPageHeightContent, pdfPageWidthContent));
svgElement.setAttribute('clip-path', 'url(#view-clip)');
svg2pdf(svgElement, jsPdf, {
xOffset: margin,
yOffset: margin,
scale: 1
});
jsPdf.addPage();
}
}
return jsPdf.output('datauristring');
}
private addClipRectDefinition(element: Element, xOffset, yOffset, width, height) {
element.removeChild(element.lastChild);
const definitionElement = document.createElement('defs');
element.appendChild(definitionElement);
const clipPathElement = document.createElement('clipPath');
clipPathElement.setAttribute('id', 'view-clip');
definitionElement.appendChild(clipPathElement);
const rectElement = document.createElement('rect');
rectElement.setAttribute('x', xOffset);
rectElement.setAttribute('y', yOffset);
rectElement.setAttribute('width', width);
rectElement.setAttribute('height', height);
clipPathElement.appendChild(rectElement);
}
private getViewboxAttribute(xOffset, yOffset, captureHeight, captureWidth) {
const value = xOffset + ' ' + yOffset + ' ' + captureWidth + ' ' + captureHeight;
return value;
}
First page:
Second page:
I found a more elegant version for the clipping: simply add a clipping rect to the pdf directly. I also slightly modified the loop. This code works for me:
function convertSvgToPdf(svgElement, size, margins) {
const margin = Math.max(margins.left, margins.right, margins.top, margins.bottom);
const pdfPageWidth = 210;
const pdfPageHeight = 210;
const contentWidth = pdfPageWidth - (margin * 2);
const contentHeight = pdfPageHeight - (margin * 2);
svgElement.setAttribute('width', contentWidth + 'px');
svgElement.setAttribute('height', contentHeight + 'px');
const jsPdf = new jsPDF('l', 'pt', [pdfPageWidth, pdfPageHeight]);
for (var xOffset = 0; xOffset < size.width; xOffset += contentWidth) {
for (var yOffset = 0; yOffset < size.height; yOffset += contentHeight) {
svgElement.setAttribute('viewBox', this.getViewboxAttribute(xOffset, yOffset, contentHeight, contentWidth));
jsPdf.advancedAPI()
jsPdf.rect(margin, margin, contentWidth, contentHeight).clip().discardPath()
svg2pdf(svgElement, jsPdf, {
xOffset: margin,
yOffset: margin,
scale: 1
});
jsPdf.compatAPI()
if (xOffset + contentWidth < size.width || yOffset + contentHeight < size.height) {
jsPdf.addPage()
}
}
}
return jsPdf.output('datauristring');
}
function getViewboxAttribute(xOffset, yOffset, captureHeight, captureWidth) {
return xOffset + ' ' + yOffset + ' ' + captureWidth + ' ' + captureHeight;
}
Thanks for pdf lesson Lukas! I also now realize that my source graph has a ~5px top and left border that was throwing me off. Your help is much appreciated!
Is it possible to convert a single SVG to PDF in multiple pages of Letter or A4 size?
I suppose dividing the original SVG into smaller ones may work but in my case the SVG is created by another javascript and hence not easy to break down (at least I don't know how).