项目说明:
最终实现效果
需求:
凡pfd文件支持拖拽盖章最后生成文件流在重新上传上去
技术栈:vue
, element-ui
, jquery
步骤:
<script type="text/javascript" src="js/jquery.js"></script>
<script type="text/javascript" src="js/jqui.js"></script>
<script type="text/javascript" src="js/pdf.js"></script>
<script type="text/javascript" src="js/pdf.worker.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/css/bulma.min.css">
<template>
<div>
<section class="theinput">
<span class="sealTitle">我的印章</span>
<el-divider></el-divider>
<div class="imageBox" v-for="item in imgList" :key="item.id" @click="imgClick(item)">
<img class="image" :src="item.src" alt="" draggable="true">
</div>
</section>
<section id="print">
<div id="imgDiv">
</div>
<div v-if="imgArray.length > 0">
<div v-for="(item, index) in imgArray" :key="index">
<div class="signarea" :id="'signarea' + index">
<img :class="'img' + index" :src="item" alt="" />
<div v-if="isShow" class="zoom" @click="fangda(index)">+</div>
<div v-if="isShow" class="tview" @click="opacity(index)">▨</div>
<div v-if="isShow" class="tdeg" @click="revolve(index)">↺</div>
<div v-if="isShow" class="contraction" @click="contraction(index)">-</div>
</div>
</div>
</div>
</section>
<section class="rgh">
<el-button @click="handleSave" type="primary" size="medium " icon="el-icon-picture-outline-round">保存模板</el-button>
</section>
</div>
</template>
<script>
import html2Canvas from 'html2canvas' //相当于截图操作
import JsPDF from 'jspdf' // 用于生成pdf
// a,b 为两个图片自行寻找
import a from '../../assets/1.png'
import b from '../../assets/2.png'
export default {
data() {
return {
drag: false,
imgList: [
{
id: 1,
src: a
},
{
id: 2,
src: b
}
],
imgArray: [],
deg: 0,
signarea: "",
isShow: true
}
},
mounted() {
this.init()
},
methods: {
// 签章放大
fangda(index) {
let signarea = document.querySelector(`#signarea${index}`)
if (signarea.scale <= 2.5) {
signarea.scale = signarea.scale / 1 + 0.1
} else {
signarea.scale = 1
}
signarea.style.transform = `scale(${signarea.scale})`
},
// 签章缩小
contraction(index) {
let signarea = document.querySelector(`#signarea${index}`)
if (signarea.scale <= 1) {
signarea.scale = signarea.scale / 1 - 0.1
} else {
signarea.scale = 1
}
signarea.style.transform = `scale(${signarea.scale})`
},
// 签章透明度
opacity(index) {
let imgInd = document.querySelector(`.img${index}`)
if (imgInd.opacity >= 0.1) {
imgInd.opacity = imgInd.opacity / 1 - 0.15
} else {
imgInd.opacity = 1
}
imgInd.style.opacity = `${imgInd.opacity}`
},
revolve(index) {
this.deg += 15;
let imgInd = document.querySelector(`.img${index}`)
imgInd.style.transform = `rotate(${this.deg}deg)`
},
//开始拖拽事件
onStart() {
this.drag = true;
},
//拖拽结束事件
onEnd() {
this.drag = false;
},
init() {
this.signarea = $('.signarea')
$("#imgDiv").empty(); //清空上一PDF文件展示图
PDFJS.cMapUrl = 'https://cdn.jsdelivr.net/npm/[email protected]/cmaps/';
PDFJS.cMapPacked = true;
// url 地址
PDFJS.getDocument({ url: 'http://dy-oss-bucket-prod.oss-cn-zhangjiakou.aliyuncs.com/ding3304434c3a141e3335c2f4657eb6378f-file/fileb903b3e2321649afa7fc2d4033b066a3_4a0b0b64a4be4e9094e1c3c2ce7e22e6.pdf?Expires=1675840126&OSSAccessKeyId=LTAI5t5pnuyi3iQHwB2wzNZs&Signature=tEp2%2BqG%2FJWFEZ%2FhpEM%2FEz525cNw%3D' }).then(function (pdf) { //PDF转换为canvas
$("#imgDiv").css("border", "0"); //清除文本、边框
if (pdf) {
window.pageNum = pdf.numPages;
$("#pagesText").text(`共 ${pageNum} 页`);
for (let i = 1; i <= pageNum; i++) {
let canvas = document.createElement('canvas');
canvas.id = "pageNum" + i;
$("#imgDiv").append(canvas);
let context = canvas.getContext('2d');
openPage(pdf, i, context);
}
}
});
function openPage(pdfFile, pageNumber, context) {
let scale = 2;
pdfFile.getPage(pageNumber).then(function (page) {
let viewport = page.getViewport(scale); // reference canvas via context
let canvas = context.canvas;
canvas.width = viewport.width;
// $("#print").attr("style", "width:"+canvas.width+"px")
canvas.height = viewport.height;
// 记录当前canvas的width,height
window.wi = canvas.width;
window.he = canvas.height;
canvas.style.width = "100%";
canvas.style.height = "100%";
let renderContext = {
canvasContext: context,
viewport: viewport
};
page.render(renderContext);
});
return
};
},
// 左侧印章点击事件
imgClick(item) {
this.isShow = true
this.imgArray.push(item.src)
$(function () {
$(".signarea").draggable();
})
},
handleSave() {
this.isShow = false
this.conversionPdfFlow('234')
},
conversionPdfFlow(reportName = '文件名称') {
return new Promise(() => {
var title = reportName;
html2Canvas(document.querySelector('#print'), {
allowTaint: true,
scale: 1.5,
}).then((canvas) => {
let contentWidth = canvas.width
let contentHeight = canvas.height
//一页pdf显示html页面生成的canvas高度;
let pageHeight = contentWidth / 592.28 * 841.89
//未生成pdf的html页面高度
let leftHeight = contentHeight
//页面偏移
let position = 0
//a4纸的尺寸[595.28,841.89],html页面生成的canvas在pdf中图片的宽高
let imgWidth = 595.28
let imgHeight = 592.28 / contentWidth * contentHeight
let pageData = canvas.toDataURL('image/jpeg', 1.0)
let PDF = new JsPDF('', 'pt', 'a4')
//有两个高度需要区分,一个是html页面的实际高度,和生成pdf的页面高度(841.89)
//当内容未超过pdf一页显示的范围,无需分页
if (leftHeight < pageHeight) {
PDF.addImage(pageData, 'JPEG', 0, 0, imgWidth, imgHeight)
} else {
while (leftHeight > 0) {
PDF.addImage(pageData, 'JPEG', 0, position, imgWidth, imgHeight)
leftHeight -= pageHeight
position -= 841.89
//避免添加空白页
if (leftHeight > 0) {
PDF.addPage()
}
}
}
let pdfData = PDF.output('datauristring')//获取base64Pdf
console.log(pdfData,"获取base64Pdf")
}
)
})
},
}
}
</script>
<style>
html {
background: #f2f6fc;
}
.sealTitle {
display: block;
text-align: center;
}
.imageBox {
width: 120px;
border: 1px solid #eee;
margin: 0 auto;
}
.theinput {
position: fixed;
z-index: 101;
}
#print {
position: relative;
margin: 0 auto;
z-index: 1;
width: 794px;
}
.signarea {
position: absolute;
z-index: 100;
top: 0;
left: 300px;
}
.signarea img {
width: 43mm;
}
canvas {
margin: 0;
padding: 0;
margin-bottom: -6px;
}
.zoom,
.tdeg,
.tview,
.lessen,
.contraction {
position: absolute;
cursor: pointer;
background-color: #fff;
padding: 3px 10px;
border-radius: 4px;
}
.contraction {
bottom: 0;
right: -30px;
}
.zoom {
top: 0;
left: -30px;
}
.tdeg {
top: 0;
right: -30px;
}
.tview {
left: -30px;
bottom: 0;
}
.lessen {
right: -30px;
bottom: 0;
}
.theinput {
width: 300px;
margin: 10px;
}
image {
width: 20px;
}
.rgh {
position: fixed;
right: 100px;
top: 20px;
}
</style>