要求:
最近在维护一个老项目(后端是ssm,前端是jsp),要求导出一个报表页,导出为pdf文档。表头需要增加 ‘内部资料,不宜公开‘,同时页面增加文字水印。
导出效果:
如下图(仅展示一部分):
整体思路:
本来想着java代码(jasperReport)完成,但是一是发现jasperReport好像不太支持水印,二是itext会比较繁琐,看着这些生成的echarts图,后端做的话会非常耗费精力,耗费时间。生成的图片还可能不一样样式。于是考虑前端直接导出为pdf,未使用任何后端代码
警示语和水印我采用了导出时显示,导出后隐藏的方式。
直接上代码:
1.导入相关插件:html2canvas.js(0.4.1) 和 jspdf.debug.js(1.0.272), 版本太新的,我用着有问题。大家可以按需下载。
js库地址:https://cdnjs.com/libraries/moment.js
<script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/0.4.1/html2canvas.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/1.0.272/jspdf.debug.js"></script>
2.添加水印,以及移除水印。
<script>
// 添加水印方法
// CON:水印文字内容;H:水印行高;W:水印宽度;R:旋转度数(可为负值);C:水印字体颜色;S:水印字体的大小; O:水印透明度(0~1之间取值)
function TpWatermark(CON,H,W,R,C,S,O) {
// 判断水印是否存在,如果存在,那么不执行
if (document.getElementById('tp-watermark') != null) {
return
}
var TpLine = parseInt(document.getElementById("echartContent").clientWidth/W) * 2; // 一行显示几列
var StrLine = '';
for(var i = 0; i < TpLine; i++){
StrLine += '<span style="display: inline-block; line-height:' + H + 'px; width:' + W + 'px; text-align: center; transform:rotate(' + R + 'deg); color:' + C + '; font-size:'+ S + 'px; opacity:' + O + ';">'+ CON +'</span>'
}
var DivLine = document.createElement("div");
DivLine.innerHTML = StrLine;
var TpColumn = parseInt(document.getElementById("echartContent").clientHeight/H) * 2; // 一列显示几行
var StrColumn = '';
for(var i = 0; i < TpColumn; i++){
StrColumn += '<div style="white-space: nowrap;">' + DivLine.innerHTML + '</div>';
}
var DivLayer = document.createElement("div");
DivLayer.innerHTML = StrColumn;
DivLayer.id = "tp-watermark"; // 给水印盒子添加类名
DivLayer.style.position = "fixed";
DivLayer.style.top = "10px"; // 整体水印距离顶部距离
DivLayer.style.left = "-100px"; // 改变整体水印的left值
DivLayer.style.zIndex = "99999"; // 水印页面层级
DivLayer.style.pointerEvents = "none";
document.getElementById("echartContent").appendChild(DivLayer); // 到页面中
}
// 移除水印方法
function RemoveTpWatermark(){
// 判断水印是否存在,如果存在,那么执行
if (document.getElementById('tp-watermark') == null) {
return
}
document.getElementById("echartContent").removeChild(document.getElementById('tp-watermark'));
}
</script>
3.导出pdf
3.1.此种方法适合导出数据比较少,在一页之内的,数据超过一页,只打印第一页。
//本方法屏幕分辨率低的,可能会分页,第二页数据显示不出来
function exportPDF() {
var userName = "${user.userName} ${user.loginName}";
var wmName = userName+" <%=newTime%>" ;
var pdf = new jsPDF();
var print_content = document.getElementById('echartContent');
// 修改背景色
print_content.style.cssText="background: #fff";
//添加警示语:pdftitle:内部资料,不宜公开
var pdfTitle = document.getElementById('pdfTitle');
var filename = '可视化数据报表.pdf';
TpWatermark(wmName,'500','700','-30','grey','50','0.1');
pdfTitle.style.display = "block";
// html --> pdf
pdf.addHTML(document.getElementById('echartContent'), function(){
pdf.output("save", filename)
})
setTimeout(()=>{ pdfTitle.style.display = 'none',RemoveTpWatermark()},0)
}
</script>
3.2这种导出方式比较理想。可以实现html页面长截图效果。
<script>
function downPdf () { // 下载pdf
var userName = "${user.userName} ${user.loginName}";
var wmName = userName+" <%=newTime%>" ;
var pdfTitle = document.getElementById('pdfTitle');
pdfTitle.style.display = "block";
TpWatermark(wmName,'500','700','-30','grey','50','0.1');
// 获取dom高度、宽度
var shareContent = document.getElementById('echartContent')
//修改背景色,否则会有黑边,不太美观
shareContent.style.cssText="background: #fff";
var width = shareContent.offsetWidth / 4
var height = shareContent.offsetHeight / 4
let _this = this
// eslint-disable-next-line
html2canvas(document.getElementById('echartContent'), {
onrendered: function (canvas) {
var context = canvas.getContext('2d')
context.mozImageSmoothingEnabled = false
context.webkitImageSmoothingEnabled = false
context.msImageSmoothingEnabled = false
context.imageSmoothingEnabled = false
var pageData = canvas.toDataURL('image/jpeg', 1.0)
var img = new Image()
img.src = pageData
img.onload = function () {
var filename = '可视化数据报表.pdf';
// 获取dom高度、宽度
img.width = img.width / 2
img.height = img.height / 2
img.style.transform = 'scale(0.5)'
if (width > height) {
// 此可以根据打印的大小进行自动调节
// eslint-disable-next-line
var pdf = new jsPDF('l', 'mm', [
width * 0.505,
height * 0.545
])
} else {
// eslint-disable-next-line
var pdf = new jsPDF('p', 'mm', [
width * 0.505,
height * 0.545
])
}
pdf.addImage(
pageData,
'jpeg',
0,
0,
width * 0.505,
height * 0.545
)
pdf.save(filename)
}
},
// background: '#fff'
})
setTimeout(()=>{ pdfTitle.style.display = 'none',RemoveTpWatermark()},0)
}
</script>