使用jspdf生成pdf报表

前端技术 2023/09/04 JavaScript

由于前台html已经动态生成报表,而且,前台有一个功能,一个date range组件,当你拖动的时候,报表会在不提交到后台的情况下动态变化。
因此需要用到js生成生报表:

用到的组件:

jquery.js
jspdf.js
canvg.js
html2canvas.js
jspdf.plugin.autotable.js

前台动态生成的chart现在一般是用的html5的canvas或者是svg,很不幸运,我遇到的是svg, 如果是flash没研究过。

由于报表还需要保持原html页面的外观,但是又不是整个html,真正需要转换成pdf报表的是:html+svg

前提:jsPDF 支持html,但支持不是很好,当你用一个html直接生成pdf的时候,其实他只保留了html里面文本,样式,结构都丢失了。
比如:table就丢失了。
jsPDF不支持svg导入。

思路:将svg转换成canvas,再将html+canvas转换成canvas,再使用html2canvas将canvas转换成图片,最后将图片写入pdf.
table的话就使用:jspdf.plugin.autotable.js

firefox:   html2canvas不能直接将svg+html转换成canvas  --> 先将svg元素转换成canvas --> html+canvas转换成canvas
chrome:  html2canvas可以直接将svg+html转换成canvas

//将指定节点下面的所有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
  });
  
};

以上所述就是本文的全部内容了,希望大家能够喜欢。

本文地址:https://www.stayed.cn/item/9112

转载请注明出处。

本站部分内容来源于网络,如侵犯到您的权益,请 联系我

我的博客

人生若只如初见,何事秋风悲画扇。