我使用以下代码将DOM元素渲染为画布数据,然后使用它们制作PDF。
我必须为此创建一个循环,因为如果它只是一个图像,则无法正确地将数据放在多个页面上。
$scope.pdfMaker = function() {
var content = [];
var pdfElement = document.getElementsByClassName("pdfElement");
for (var i = pdfElement.length - 1; i >= 0; i--) {
html2canvas(pdfElement[i], {
onrendered: function(canvas) {
var data = canvas.toDataURL();
content.push({
image: data,
width: 500,
margin: [0, 5]
});
console.log(canvas);
}
});
}
var docDefinition = {
content: content
};
setTimeout(function() {
pdfMake.createPdf(docDefinition).download("Score_Details.pdf");
}, 10000);
}
的问题:
我有令人讨厌的10秒超时以便有时间进行处理,我如何重构我的代码以允许在执行所有画布数据后制作PDF。
我的画布元素在转换时会变得混乱,正确的顺序是必不可少的。如何维护DOM元素的顺序?
答案 0 :(得分:3)
似乎html2canvas返回一个promise:
$scope.pdfMaker = function() {
var promises = [];
var pdfElements = document.getElementsByClassName("pdfElement");
for (var i = 0; i < pdfElements.length; i++) {
promises.push(
html2canvas(pdfElements[i]).then(function(canvas) {
console.log('finished one!');
return {
image: canvas.toDataURL(),
width: 500,
margin: [0, 5]
};
})
);
}
console.log('done calling');
$q.all(promises).then(function(content) {
console.log('all done');
pdfMake.createPdf({ content: content }).download("Score_Details.pdf");
console.log('download one');
}, function(err) {
console.error(err);
})
}
答案 1 :(得分:1)
要使代码正常工作,只需要几个mod。
您的描述中的问题是html2canvas的渲染时间会有所不同,因此它们会以不确定的顺序出现。如果你在for循环中使代码成为一个函数并将索引传递给它,函数将关闭参数变量,你可以在onrendered回调中使用该索引,因为(也将关闭索引)放置渲染html在内容数组的正确位置。
要知道何时完成所有渲染并且可以转换为pdf,请保留已启动的html2canvas渲染器数量的计数。当调用onrendered回调时,将计数减1。当计数为零时,您知道所有文档都已呈现,因此您可以调用createPdf。
以下是更改
$scope.pdfMaker = function() {
var i,pdfElement,content,count,docDefinition;
function makeCanvas(index){ // closure ensures that index is unique inside this function.
count += 1; // count the new render request
html2canvas(pdfElement[index], {
onrendered: function(canvas) { // this function closes over index
content[index] = { // add the canvas content to the correct index
image: canvas.toDataURL(),
width: 500,
margin: [0, 5]
};
count -= 1; // reduce count
if(count === 0){ // is count 0, if so then all done
// render the pdf and download
pdfMake.createPdf(docDefinition).download("Score_Details.pdf");
}
}
});
}
// get elements
pdfElement = document.getElementsByClassName("pdfElement");
content = []; // create content array
count = 0; // set render request counter
docDefinition = {content: content}; //
for (i = pdfElement.length - 1; i >= 0; i--) { //do the loop thing
makeCanvas(i); // call the makeCanvas function with the index
}
}
我唯一不确定的是您希望pdfElements出现的顺序。这些更改会将呈现的内容按照document.getElementsByClassName("pdfElement");
获取的顺序放入内容数组中。
如果您希望逆转顺序中的文档在计数回零时调用content.reverse(),并且您已准备好创建pdf。
Closure是Javascript的一个非常强大的功能。如果您不确定封闭是如何工作的,那么审查是值得的。
MDN closures和任何一个开始都是一个好地方,网上有大量资源需要学习。