'Generate 1000 pdf with survey pdf
I'm trying to generate more than one thousand pdf files using surveyPDF.
The problem is that i can generate only 80 pdf files...
I'm passing an array with more than 1000 pdf to generate.
Code :
query.map(async items => {
const { generatePdf } = await import("~/lib/survey");
const filename = kebabCase(
`${campaign.title} - ${items.employee.fullName.toLowerCase()} -${moment().format("DD/MM/YYYY - HH:mm")} `
);
return generatePdf(campaign.template.body, items, filename, 210, 297);
});
The code which generate each pdfs :
import autoTable from "jspdf-autotable";
import { SurveyPDF, CommentBrick, CompositeBrick, PdfBrick, TextBrick } from "survey-pdf";
import { format } from "~/utils/date";
class AutoTableBrick extends PdfBrick {
constructor(question, controller, rect, options) {
super(question, controller, rect);
this.margins = {
top: controller.margins.top,
bottom: controller.margins.bot,
right: 30,
left: 30,
};
this.options = options;
}
renderInteractive() {
if (this.controller.doc.lastAutoTable && !this.options.isFirstQuestion) {
this.options.startY = this.yTop;
}
autoTable(this.controller.doc, {
head: [
[
{
content: this.question.title,
colSpan: 2,
styles: { fillColor: "#5b9bd5" },
},
],
],
margin: { ...this.margins },
styles: { fillColor: "#fff", lineWidth: 1, lineColor: "#5b9bd5", minCellWidth: 190 },
alternateRowStyles: { fillColor: "#bdd6ee" },
...this.options,
});
}
}
export async function generatePdf(json, data, filename, pdfWidth, pdfHeight) {
if (!json) {
return Promise.reject("Invalid json for pdf export");
}
for (const page of json.pages) {
page.readOnly = true;
}
const surveyPDF = new SurveyPDF(json, {
fontSize: 11,
format: [pdfWidth, pdfHeight],
commercial: true,
textFieldRenderAs: "multiLine",
});
surveyPDF.showQuestionNumbers = "off";
surveyPDF.storeOthersAsComment = false;
//TODO This does not work well with dynamic dropdown, bug declared
// surveyPDF.mode = "display";
surveyPDF.mergeData({ ...data, _: {} });
surveyPDF.onRenderQuestion.add(function(survey, options) {
const { bricks, question } = options;
if (question.getType() === "comment" && question.value && bricks.length > 0) {
for (const brick of bricks) {
if (brick.value) {
brick.value = question.value.replace(/\t/g, " ");
}
if (brick instanceof CompositeBrick) {
const { bricks } = brick;
for (const brick of bricks) {
if (brick instanceof CommentBrick) {
brick.value = question.value.replace(/\t/g, " ");
}
}
}
}
}
});
surveyPDF.onRenderQuestion.add(async function(survey, options) {
const {
point,
bricks,
question,
controller,
module: { SurveyHelper },
} = options;
if (question.getType() === "multipletext") {
const body = [];
let extraRows = 0;
let rows = question.getRows();
for (let i = 0; i < rows.length; i++) {
for (let j = 0; j < rows[i].length; j++) {
let { title, value, inputType } = rows[i][j];
if (inputType === "date") {
value = format(value);
}
if (typeof value === "string" && value.length > 0) {
const valueEstRows = value.match(/.{1,70}/g).length;
if (valueEstRows > 1) {
extraRows += valueEstRows;
}
}
body.push([title, value || "N/A"]);
}
}
//TODO Use SurveyHelper helperDoc do calculate the height of the auto table
const startY = point.yTop;
const height = 21.5 * (body.length + 1) + 8.5 * extraRows;
const isFirstQuestion = question.title === question.parent.questions[0].title;
options.bricks = [
new AutoTableBrick(question, controller, SurveyHelper.createRect(point, bricks[0].width, height), {
startY,
body,
isFirstQuestion,
}),
];
}
});
surveyPDF.onRenderQuestion.add(async function(survey, options) {
const {
point,
question,
controller,
module: { SurveyHelper },
} = options;
if (question.getType() === "text") {
//Draw question background
const { default: backImage } = await import("~/public/assets/images/block.png");
const backWidth = SurveyHelper.getPageAvailableWidth(controller);
const backHeight = SurveyHelper.pxToPt(100);
const imageBackBrick = SurveyHelper.createImageFlat(point, null, controller, backImage, backWidth, backHeight);
options.bricks = [imageBackBrick];
point.xLeft += controller.unitWidth;
point.yTop += controller.unitHeight;
const oldFontSize = controller.fontSize;
const titleBrick = await SurveyHelper.createTitleFlat(point, question, controller);
controller.fontSize = oldFontSize;
titleBrick.unfold()[0]["textColor"] = "#6a6772";
options.bricks.push(titleBrick);
//Draw text question text field border
let { default: textFieldImage } = await import("~/public/assets/images/input.png");
let textFieldPoint = SurveyHelper.createPoint(imageBackBrick);
textFieldPoint.xLeft += controller.unitWidth;
textFieldPoint.yTop -= controller.unitHeight * 3.3;
let textFieldWidth = imageBackBrick.width - controller.unitWidth * 2;
let textFieldHeight = controller.unitHeight * 2;
let imageTextFieldBrick = SurveyHelper.createImageFlat(
textFieldPoint,
null,
controller,
textFieldImage,
textFieldWidth,
textFieldHeight
);
options.bricks.push(imageTextFieldBrick);
textFieldPoint.xLeft += controller.unitWidth / 2;
textFieldPoint.yTop += controller.unitHeight / 2;
let textFieldValue = question.value || "";
if (textFieldValue.length > 90) {
textFieldValue = textFieldValue.substring(0, 95) + "...";
}
const textFieldBrick = await SurveyHelper.createBoldTextFlat(
textFieldPoint,
question,
controller,
textFieldValue
);
controller.fontSize = oldFontSize;
textFieldBrick.unfold()[0]["textColor"] = "#EFF8FF";
options.bricks.push(textFieldBrick);
}
});
surveyPDF.onRenderQuestion.add(async function(survey, options) {
const {
point,
question,
controller,
module: { SurveyHelper },
} = options;
if (question.getType() === "radiogroup" || question.getType() === "rating") {
options.bricks = [];
const oldFontSize = controller.fontSize;
const titleLocation = question.hasTitle ? question.getTitleLocation() : "hidden";
let fieldPoint;
if (["hidden", "matrix"].includes(titleLocation)) {
fieldPoint = SurveyHelper.clone(point);
} else {
const titleBrick = await SurveyHelper.createTitleFlat(point, question, controller);
titleBrick.xLeft += controller.unitWidth;
titleBrick.yTop += controller.unitHeight * 2;
controller.fontSize = oldFontSize;
titleBrick.unfold()[0]["textColor"] = "#6a6772";
options.bricks.push(titleBrick);
fieldPoint = SurveyHelper.createPoint(titleBrick);
fieldPoint.yTop += controller.unitHeight * 1.3;
}
//Draw checkbox question items field
const { default: itemEmptyImage } = await import("~/public/assets/images/unchecked.png");
const { default: itemFilledImage } = await import("~/public/assets/images/checked.png");
const itemSide = controller.unitWidth;
let imageItemBrick;
const choices = question.getType() === "rating" ? question.visibleRateValues : question.visibleChoices;
for (const choice of choices) {
const isItemSelected =
question.getType() === "rating" ? question.value === choice.value : choice === question.selectedItem;
imageItemBrick = SurveyHelper.createImageFlat(
fieldPoint,
null,
controller,
isItemSelected ? itemFilledImage : itemEmptyImage,
itemSide,
itemSide
);
options.bricks.push(imageItemBrick);
const textPoint = SurveyHelper.clone(fieldPoint);
textPoint.xLeft += itemSide + controller.unitWidth / 2;
textPoint.yTop += itemSide / 12;
const itemValue = choice.locText.renderedHtml;
const checkboxTextBrick = await SurveyHelper.createTextFlat(
textPoint,
question,
controller,
itemValue,
TextBrick
);
checkboxTextBrick.unfold()[0]["textColor"] = "#6a6772";
fieldPoint.yTop = imageItemBrick.yBot + SurveyHelper.GAP_BETWEEN_ROWS * controller.unitHeight;
options.bricks.push(checkboxTextBrick);
}
}
});
surveyPDF.onRenderFooter.add(function(survey, canvas) {
canvas.drawText({
text: canvas.pageNumber + "/" + canvas.countPages,
fontSize: 10,
horizontalAlign: "right",
margins: {
right: 12,
},
});
});
return await surveyPDF.raw(`./pdf/${filename}.pdf`);
}
The error :
FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory
I have already try to increase the node memory using $env:NODE_OPTIONS="--max-old-space-size=8192"
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|
