Дублированный контент в pdf, созданный с помощью jsPDF
Я использую jsPDF для преобразования html в pdf. В некоторых случаях, когда html имеет svg-диаграммы, некоторые данные дублируются в сгенерированном PDF файле.
например. Если в диаграммах есть легенды, они дублируются. См. Снимок экрана ниже. Имена городов и проценты повторяются.
![введите описание изображения здесь]()
Ниже приведен код для создания pdf.
pdf.addHTML($("#page1"), options, function(){
pdf.addPage();
pdf.addHTML($("#page2"), options, function(){
pdf.addPage();
pdf.output('dataurlnewwindow');
});
});
РЕДАКТИРОВАТЬ 1:
Это то, что я догадался до сих пор.
<div id="outerDiv">
<div id="pieChart"></div>
</div>
Когда я это сделаю, pdf.addHTML($("#pieChart")
, здесь нет проблем.
Но, когда я это делаю, pdf.addHTML($("#outerDiv")
, метки повторяются.
и именно так я создаю диаграммы c3js
var pieChart = c3.generate({
bindto: '#pieChart',
РЕДАКТИРОВАТЬ 2: -
Ниже приведен весь мой код.
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.js"></script>
<link rel="stylesheet" type="text/css" href="#" onclick="location.href='https://cdnjs.cloudflare.com/ajax/libs/c3/0.4.10/c3.min.css'; return false;">
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/c3/0.4.10/c3.min.js"></script>
<script type="text/javascript" src="https://code.jquery.com/jquery-2.2.0.min.js"></script>
<script type="text/javascript" src="http://gabelerner.github.io/canvg/rgbcolor.js"></script>
<script type="text/javascript" src="http://gabelerner.github.io/canvg/StackBlur.js"></script>
<script type="text/javascript" src="http://gabelerner.github.io/canvg/canvg.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/1.2.61/jspdf.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/0.5.0-alpha1/html2canvas.js"></script>
<script type='text/javascript'>
function replaceAllSVGsWithTempCanvas(elemSelector) {
var svgElements = $(elemSelector).find('svg');
//replace all svgs with a temp canvas
svgElements.each(function() {
var canvas, xml;
// canvg doesn't cope very well with em font sizes so find the calculated size in pixels and replace it in the element.
$.each($(this).find('[style*=em]'), function(index, el) {
$(this).css('font-size', getStyle(el, 'font-size'));
});
canvas = document.createElement("canvas");
canvas.className = "screenShotTempCanvas";
//convert SVG into a XML string
xml = (new XMLSerializer()).serializeToString(this);
// Removing the name space as IE throws an error
xml = xml.replace(/xmlns=\"http:\/\/www\.w3\.org\/2000\/svg\"/, '');
//draw the SVG onto a canvas
canvg(canvas, xml);
$(canvas).insertAfter(this);
//hide the SVG element
$(this).attr('class', 'tempHide');
$(this).hide();
});
}
jQuery(document).ready(function($) {
genChart();
});
function genPDF() {
var options = {
background: '#fff'
};
var pdf = new jsPDF('p', 'pt', 'a4');
replaceAllSVGsWithTempCanvas(".content");
pdf.addHTML($("#chartOuter"), options, function() {
pdf.output('dataurlnewwindow');
$(".content").find('.screenShotTempCanvas').remove();
$(".content").find('.tempHide').show().removeClass('tempHide');
});
}
function genChart() {
var chart = c3.generate({
data: {
columns: [
['data1', 30],
['data2', 120],
],
type: 'pie'
}
});
}
</script>
</head>
<body class="content">
<table width="100%">
<tr>
<td width="50%">
<div id="chartOuter">
<div id="chart"></div>
</div>
</td>
</tr>
<tr>
<td colspan="2" align="left">
<input type="button" onclick="genPDF();" value="Generate PDF" />
</td>
</tr>
</table>
</body>
</html>
РЕДАКТИРОВАТЬ 3: -
Я попытался просто преобразовать html в холст с помощью html2canvas. Это также дает ту же проблему.
Изменить 4:
Я мог бы исправить дублирующую проблему сейчас. Но диаграммы и текст, написанный в формате pdf, немного размыты. В принципе, я добавил функцию replaceAllSVGsWithTempCanvas, а затем использовал это при записи в pdf. Но, похоже, эта функция делает что-то плохое для html, что делает контент, написанный в формате pdf, размытым. На самом деле круговые диаграммы и т.д. Больше не кругах, а овальной форме.
Отредактировал вопрос с помощью модифицированных js.
Ответы
Ответ 1
Похоже, что это ошибка в html2canvas. Вы должны добавить нижний код после загрузки html2canvas, чтобы исправить это (Credits переходит на этот парень):
NodeParser.prototype.getChildren = function(parentContainer) {
return flatten([].filter.call(parentContainer.node.childNodes, renderableNode).map(function(node) {
var container = [node.nodeType === Node.TEXT_NODE && node.parentElement.tagName !== "text" ? new TextContainer(node, parentContainer) : new NodeContainer(node, parentContainer)].filter(nonIgnoredElement);
return node.nodeType === Node.ELEMENT_NODE && container.length && node.tagName !== "TEXTAREA" ? (container[0].isElementVisible() ? container.concat(this.getChildren(container[0])) : []) : container;
}, this));
};
Fiddle
Так как html2canvas загружается как модуль, вы должны прямо найти NodeParser.prototype.getChildren
в исходном коде и отредактировать его, чтобы он соответствовал выше. Это означает, что вы не можете загрузить его из CDN.
Ответ 2
Я думаю, что он работал правильно в два этапа.
Во-первых, Я прокомментировал "addhtml plugin", потому что у меня была эта ошибка в моей консоли:
Refused to execute script from 'https://raw.githubusercontent.com/MrRio/jsPDF/master/plugins/addhtml.js' because its MIME type ('text/plain') is not executable, and strict MIME type checking is enabled.
Во-вторых, Я изменил источник pdf с #chartOuter
на #chart
.
pdf.addHTML($("#chart"), options, function () {
var string = pdf.output('datauristring');
$('.preview-pane').attr('src', string)
});
И больше нет дедублирования.
-----
EDIT (поскольку я сначала не понял этот вопрос)
Необходимо использовать внешний div... И, возможно, полную страницу.
Хорошо... Честно говоря, я не знаю, почему этот текст возникает.
Но я заметил, что дублирующийся текст имеет засечку, даже если она указана как "sans-serif".
Поэтому я сосредоточился на этом.
Я попытался изменить размер шрифта... Это повлияло на дубликат, но текст не соответствовал правилу css. Хорошо.
Затем я попытался просто удалить текст перед частью создания pdf... И magic!
;)
$(".c3 svg").css({"font-size":"0px"});
Вот полный script, я не касался остальной части вашего исходного кода.
jQuery(document).ready(function ($) {
genChart();
});
function genPDF() {
var options = { background: '#fff'};
var pdf = new jsPDF('p', 'pt', 'a4');
$(".c3 svg").css({"font-size":"0px"}); // <-- This does the trick !
pdf.addHTML($("#chartOuter"), options, function () {
var string = pdf.output('datauristring');
$('.preview-pane').attr('src', string)
});
}
function genChart() {
var chart = c3.generate({
data: {
columns: [
['data1', 30],
['data2', 120],
],
type : 'pie'
}
});
}
Ответ 3
Вы можете попробовать использовать ChartJS вместо C3.
Я адаптировал ваш код и пробовал его с успехом.
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.js"></script>
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/c3/0.4.10/c3.min.css">
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/c3/0.4.10/c3.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.1.3/Chart.min.js"></script>
<script type="text/javascript" src="https://code.jquery.com/jquery-2.2.0.min.js"></script>
<!-- <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/1.2.61/jspdf.debug.js"></script> -->
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/1.2.61/jspdf.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/0.5.0-alpha1/html2canvas.js"></script>
<script type="text/javascript" src="https://raw.githubusercontent.com/MrRio/jsPDF/master/plugins/addhtml.js"></script>
<script type='text/javascript'>
jQuery(document).ready(function ($) {
genChart();
});
function genPDF() {
var options = { background: '#fff'};
var pdf = new jsPDF('p', 'pt', 'a4');
pdf.addHTML($("#chartOuter"), options, function () {
var string = pdf.output('datauristring');
$('.preview-pane').attr('src', string)
});
}
function genChart () {
var ctx = $("#chart");
var options = {};
var myPieChart = new Chart(ctx, {
type: 'pie',
data: {
labels: [
"data1",
"data2"
],
datasets: [{
data: [30, 120],
backgroundColor: [
"#FF6384",
"#36A2EB"
],
hoverBackgroundColor: [
"#FF6384",
"#36A2EB"
]
}]
},
options: options
});
}
</script>
</head>
<body>
<table width="100%">
<tr>
<td width="50%">
<div id="chartOuter">
<!-- <div id="chart"></div> -->
<canvas id="chart" width="400" height="400"></canvas>
</div>
</td>
<td>
<iframe height="550px" class="preview-pane" type="application/pdf" width="100%" frameborder="0" style="position:relative;z-index:999"></iframe>
</td>
</tr>
<tr>
<td colspan="2" align="left">
<input type="button" onclick="genPDF();" value="Generate PDF"/>
</td>
</tr>
</table>
</body>
</html>
Ответ 4
Динамическая загрузка PDF размыто, тот же файл официальной демонстрации очень ясно. Я не могу найти проблему?
Используйте браузер Chrome. Версия 73.0.3683.86 (официальная версия) (64-разрядная версия) Вот мой код :
async process(buffer, index) {
// Processing the decrypted data stream
let uint8Array = new Uint8Array(buffer);
var word = await this.Uint8ToBase64(uint8Array);
var decryptedData = CryptoJS.AES.decrypt(word, this.authorKey, {
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.Pkcs7
});
// Then turn wordArray to uint8Array
let getUint8Array = await this.wordArrayToU8(decryptedData);
// decryption ends
this.loadingPdf(getUint8Array, index);
},
async loadingPdf(getUint8Array, index) {
// render canvas
let pdf = await pdfjsLib.getDocument({ data: getUint8Array, cMapUrl: cMapUrl, cMapPacked: cMapPacked });
let page = await pdf.getPage(1).then(page => {
return page;
});
let canvas = document.getElementById("the-canvas" + index);
const CSS_UNITS = 96.0 / 72.0;
const DEFAULT_SCALE = 1.7;
const UNKNOWN_SCALE = 0;
let viewport = page.getViewport( DEFAULT_SCALE * CSS_UNITS);
if (canvas.dataset.runed) return;
canvas.width = viewport.width*CSS_UNITS;
canvas.height = viewport.height*CSS_UNITS;
this.canvasW =
this.canvasW > (1000 / viewport.height) * viewport.width
? this.canvasW
: (1000 / viewport.height) * viewport.width;
canvas.style.width = (1000 / viewport.height) * viewport.width;
canvas.dataset.runed = true;
var context = canvas.getContext('2d');
// [Important] Turn off anti-aliasing
context.mozImageSmoothingEnabled = false;
context.webkitImageSmoothingEnabled = false;
context.msImageSmoothingEnabled = false;
context.imageSmoothingEnabled = false;
await page.render({
//enableWebGL: true,
// canvasContext: context,
transform: [CSS_UNITS, 0, 0, CSS_UNITS, 0, 0],
// transform: [1, 0, 0, 1, 0, 0],
canvasContext: canvas.getContext("2d"),
viewport: viewport
});
this.loadedPages.push(index)
},