프런트엔드 HTML은 보고서를 동적으로 생성하고, 프런트엔드에는 날짜 범위 구성요소라는 기능이 있으므로 드래그하면 보고서가 백그라운드로 제출되지 않고 동적으로 변경됩니다.
따라서 보고서를 생성하려면 js를 사용해야 합니다.
사용된 구성 요소:
jquery.js jspdf.js canvg.js html2canvas.js jspdf.plugin.autotable.js
프론트에서 동적으로 생성되는 차트는 주로 HTML5 Canvas나 svg를 사용하는데, 아쉽게도 svg를 접한 적이 없습니다.
보고서는 원래 HTML 페이지의 모양을 유지해야 하지만 전체 HTML이 아니기 때문에 실제로 PDF 보고서로 변환해야 하는 것은 html svg입니다.
전제: jsPDF는 HTML을 지원하지만 지원이 그다지 좋지 않습니다. HTML을 사용하여 PDF를 직접 생성하면 실제로 HTML의 텍스트, 스타일 및 구조만 유지되고 손실됩니다.
예: 테이블이 손실되었습니다.
jsPDF는 svg 가져오기를 지원하지 않습니다.
아이디어: svg를 캔버스로 변환한 다음 html 캔버스를 캔버스로 변환하고 html2canvas를 사용하여 캔버스를 그림으로 변환하고 마지막으로 그림을 pdf로 작성합니다.
테이블의 경우 jspdf.plugin.autotable.js
firefox: html2canvas는 svg html을 캔버스로 직접 변환할 수 없습니다 --> 먼저 svg 요소를 캔버스로 변환 --> html 캔버스를 캔버스로 변환
크롬: html2canvas는 svg html을 캔버스로 직접 변환할 수 있습니다
//将指定节点下面的所有svg转换成canvas //这里需要:canvg.js function svg2canvas (targetElem) { var nodesToRecover = []; var nodesToRemove = []; var svgElem = targetElem.find('svg'); svgElem.each(function(index, node) { var parentNode = node.parentNode; var svg = node.outerHTML; var canvas = document.createElement('canvas'); canvg(canvas, svg); nodesToRecover.push({ parent: parentNode, child: node }); parentNode.removeChild(node); nodesToRemove.push({ parent: parentNode, child: canvas }); parentNode.appendChild(canvas); }); }
//这里是将html(文本)在一个iframe里面打开 //主要是排除其它元素的干扰导致不成功,之前是一直输出不成功,所示才使用iframe //这段代码是官网抠下来的。 //还有个问题就是:如果将页面的chart转换成canvas了,那web页面报表动态变化的功能将丢失。 function openWithIframe(html){ var iframe = document.createElement('iframe'); iframe.setAttribute("id", "myFrmame"); var $iframe = $(iframe); $iframe.css({ 'visibility': 'hidden', 'position':'static', 'z-index':'4' }).width($(window).width()).height($(window).height()); $('body').append(iframe); var ifDoc = iframe.contentWindow.document; //这里做是将报表使用到的css重新写入到iframe中,根据自身的需要 var style = "<link href='/javax.faces.resource/css/auth.css.jsf' rel='stylesheet' type='text/css'>"; style+="<link href='/javax.faces.resource/css/common.css.jsf' rel='stylesheet' type='text/css'>"; style+="<link href='/javax.faces.resource/css/dc.css.jsf' rel='stylesheet' type='text/css'>"; html = "<!DOCTYPE html><html><head>"+style+"</head><body>"+html+"</body></html>" ifDoc.open(); ifDoc.write(html); ifDoc.close(); /* //这里做一些微调,根据自身的需要 var fbody = $iframe.contents().find("body"); fbody.find("#chart-center").removeAttr("width"); fbody.find(".page-container").css("width", "370px"); fbody.find(".center-container").css("width", "600px"); fbody.find("#severity-chart svg").attr("width", "370"); fbody.find("#status-chart svg").attr("width", "300"); */ return fbody; }
//导出pdf function exportAsPDF(){ //得到要导出pdf的html根节点 var chartCenter = document.getElementById("chart-center").outerHTML; var fbody = openWithIframe(chartCenter); svg2canvas(fbody); //html2canvas官网的标准方法 html2canvas(fbody, { onrendered: function(canvas) { //var myImage = canvas.toDataURL("image/png"); //alert(myImage); //window.open(myImage); /* canvas.toBlob(function(blob) { saveAs(blob, "report.png"); }, "image/png"); */ //将图片转换成:base64编码的jpg图片。 var imgData = canvas.toDataURL('image/jpeg'); //alert(imgData); //l:横向, p:纵向 var doc = new jsPDF('l', 'pt', 'a3'); //var doc = new jsPDF('p', 'mm', [290, 210]); //var doc = new jsPDF();//默认是A4,由于我的报表比较大,所以专门设置了尺寸。 doc.setFontSize(22); doc.setFontType("bolditalic"); doc.text(500, 30, "Ticket Report"); //x:500, y:30 doc.addImage(imgData, 'jpeg', 10, 60); //写入位置:x:10, y:60 doc.addPage(); //新建一页 //这里就是把将table写入到pdf里面。 var res = doc.autoTableHtmlToJson(document.getElementById("tickets-summary-table"), true); doc.autoTable(res.columns, res.data); doc.save('ticket.report_'+new Date().getTime()+'.pdf'); $('#myFrmame').remove(); //最后将iframe删除 }, background:"#fff", //这里给生成的图片默认背景,不然的话,如果你的html根节点没有设置背景的话,会用黑色填充。 allowTaint: true //避免一些不识别的图片干扰,默认为false,遇到不识别的图片干扰则会停止处理html2canvas }); };
위 내용은 이 글의 전체 내용입니다. 모두 마음에 드셨으면 좋겠습니다.