gif图标网站,房产发布平台有哪些,上海市建设工程咨询行业协会官网,做网站小编怎么样一、前情提要
1. 需求 仿照e签宝#xff0c;实现pdf电子签章 拿到pdf链接#xff0c;移动章的位置#xff0c;获取章的坐标 技术 : 使用fabric pdfjs-dist vuedraggable 2. 借鉴 一位大佬的代码仓亏 : 地址 一位大佬写的文章 #xff1a;地址 3. 优化 在大佬的代码…
一、前情提要
1. 需求 仿照e签宝实现pdf电子签章 拿到pdf链接移动章的位置获取章的坐标 技术 : 使用fabric pdfjs-dist vuedraggable 2. 借鉴 一位大佬的代码仓亏 : 地址 一位大佬写的文章 地址 3. 优化 在大佬的代码基础上进行了些许优化变的更像e签宝 二、下载
ps : 怕版本不同导致无法运行请下载指定版本
1. fabric fabric : 是一个功能强大且操作简单的 Javascript HTML5 canvas 工具库 npm install fabric5.3.0
2. pdfjs-dist
npm install pdfjs-dist2.5.207
问题一
注意 : 最好配置一下babel因为打包的时候可能会报错
因为babel默认不会转化node_modules中的包但是pdfjs-dist用了es6的东东
// 安装包
npm install babel-loader babel/core babel/preset-env -D
在webpack.config.js中配置 {test: /\.js$/,loader: babel-loader,include: [resolve(src),// 转化pdfjs-dist之所以分开写是因为pdfjs-dist里面有很多es6的语法但是我们只需要转化pdfjs-dist里面的web文件夹下的js文件resolve(node_modules/pdfjs-dist/web/pdf_viewer.js),resolve(node_modules/pdfjs-dist/build/pdf.js),resolve(node_modules/pdfjs-dist/build/pdf.worker.js),resolve(node_modules/pdfjs-dist/build/pdf.worker.entry.js) ]
},
问题二
pdf.js文件过大可以给 .babelrc 加上属性compact: false 3. vuedraggable
npm install vuedraggable2.24.3
三、代码
1. 准备pdf文件 text.pdf 可放置在 src/static 文件夹中 ps : 线上最好让后端返回pdf链接因为存在pdf跨域问题 2. 大佬的代码 !-- //?模块说明 合同签章模块 --
templatediv idelesign classelesignel-rowel-col :span4 stylemargin-top: 1%div classleft-title我的印章/divdraggablev-modelmainImagelist:group{ name: itext, pull: clone }:sortfalseendendtransition-group typetransitionli v-foritem in mainImagelist :keyitem classitem styletext-align: centerimg :srcitem width100%; height100% classimgstyle //li/transition-group/draggable/el-colel-col :span16 styletext-align: center classpCenterdiv classpage!-- el-button classbtn-outline-dark clickzoomIn-/el-buttonspan stylecolor: red{{ (percentage * 100).toFixed(0) % }}/spanel-button classbtn-outline-dark clickzoomOut/el-button --el-button classbtn-outline-dark clickprevPage上一页/el-buttonel-button classbtn-outline-dark clicknextPage下一页/el-buttonel-button classbtn-outline-dark{{ pageNum }}/{{ numPages }}页/el-buttonel-input-numberstylemargin: 0 5px; border-radius: 5pxclassbtn-outline-darkv-modelpageNum:min1:maxnumPageslabel输入页码/el-input-numberel-button classbtn-outline-dark clickcutover跳转/el-button/divcanvas idthe-canvas /!-- 盖章部分 --canvas idele-canvas/canvasdiv classele-control stylemargin-bottom: 2%el-button classbtn-outline-dark clickremoveSignature删除签章/el-buttonel-button classbtn-outline-dark clickclearSignature清除所有签章/el-buttonel-button classbtn-outline-dark clicksubmitSignature提交所有签章信息/el-button/div/el-colel-col :span4 stylemargin-top: 1%div classleft-title任务信息/divdiv styletext-align: centerdivdiv classright-itemdiv classright-item-title文件主题/divdiv classdetail-item-desc{{ taskInfo.title }}/div/divdiv classright-itemdiv classright-item-title发起方/divdiv classdetail-item-desc{{ taskInfo.uname }}/div/divdiv classright-itemdiv classright-item-title截止时间/divdiv classdetail-item-desc{{ taskInfo.endtime }}/div/div/div/div/el-col/el-row/div
/template
script
import draggable from vuedraggable;
import { fabric } from fabric;
import workerSrc from pdfjs-dist/es5/build/pdf.worker.entry;
import * as pdfjsViewer from pdfjs-dist/web/pdf_viewer;
const pdfjsLib require(pdfjs-dist/es5/build/pdf.js);
pdfjsLib.GlobalWorkerOptions.workerSrc workerSrc;
export default {components: { draggable },data() {return {// pdf预览pdfUrl: ,pdfDoc: null,numPages: 1,pageNum: 1,scale: 2.2,pageRendering: false,pageNumPending: null,sealUrl: ,signUrl: ,canvas: null,ctx: null,canvasEle: null,whDatas: null,mainImagelist: [],taskInfo: {}// percentage: 1};},computed: {hasSigna() {if (this.canvasEle this.canvasEle.getObjects()[0]) {return true;} else {return false;}}},created() {var that this;that.mainImagelist [require(/assets/img/projectCenter/sign.png), require(/assets/img/projectCenter/seal.png)];that.taskInfo { title: 测试盖章, uname: 张三, endtime: 2021-09-01 17:59:59 };this.setPdfArea();},mounted() {// this.showpdf(this.pdfUrl);if (!pdfjsLib.getDocument || !pdfjsViewer.PDFViewer) {// eslint-disable-next-line no-alertalert(Please build the pdfjs-dist library using\n gulp dist-install);}},methods: {// pdf预览// zoomIn() {// console.log(缩小);// if (this.scale 0.5) {// this.$message.error(已经显示最小比例);// } else {// this.scale - 0.1;// this.percentage - 0.1;// this.renderPage(this.pageNum);// this.renderFabric();// }// },// zoomOut() {// console.log(放大);// if (this.scale 2.2) {// this.$message.error(已经显示最大比例);// } else {// this.scale 0.1;// this.percentage 0.1;// this.renderPage(this.pageNum);// this.renderFabric();// }// },renderPage(num) {let _this this;this.pageRendering true;return this.pdfDoc.getPage(num).then((page) {let viewport page.getViewport({ scale: _this.scale }); // 设置视口大小_this.canvas.height viewport.height;_this.canvas.width viewport.width;// Render PDF page into canvas contextlet renderContext {canvasContext: _this.ctx,viewport: viewport};let renderTask page.render(renderContext);// Wait for rendering to finishrenderTask.promise.then(() {_this.pageRendering false;if (_this.pageNumPending ! null) {// New page rendering is pendingthis.renderPage(_this.pageNumPending);_this.pageNumPending null;}});});},queueRenderPage(num) {if (this.pageRendering) {this.pageNumPending num;} else {this.renderPage(num);}},prevPage() {this.confirmSignature();if (this.pageNum 1) {return;}this.pageNum--;},nextPage() {this.confirmSignature();if (this.pageNum this.numPages) {return;}this.pageNum;},cutover() {this.confirmSignature();},// 渲染pdf到时还会盖章信息在渲染时同时显示出来不应该在切换页码时才显示印章信息showpdf(pdfUrl) {let caches JSON.parse(localStorage.getItem(signs)); // 获取缓存字符串后转换为对象// console.log(caches);if (caches ! null) {let datas caches[this.pageNum];if (datas ! null datas ! undefined) {for (let index in datas) {this.addSeal(datas[index].sealUrl,datas[index].left,datas[index].top,datas[index].index);}}}this.canvas document.getElementById(the-canvas);this.ctx this.canvas.getContext(2d);pdfjsLib.getDocument({ url: pdfUrl, rangeChunkSize: 65536, disableAutoFetch: false }).promise.then((pdfDoc_) {this.pdfDoc pdfDoc_;this.numPages this.pdfDoc.numPages;this.renderPage(this.pageNum).then(() {this.renderPdf({width: this.canvas.width,height: this.canvas.height});});this.commonSign(this.pageNum, true);});},/*** 盖章部分开始*/// 设置绘图区域宽高renderPdf(data) {this.whDatas data;// document.querySelector(#elesign).style.width data.width px;},// 生成绘图区域renderFabric() {let canvaEle document.querySelector(#ele-canvas);let pCenter document.querySelector(.pCenter);canvaEle.width pCenter.clientWidth;// canvaEle.height (this.whDatas.height)*(this.scale);canvaEle.height this.whDatas.height;this.canvasEle new fabric.Canvas(canvaEle);let container document.querySelector(.canvas-container);container.style.position absolute;container.style.top 50px;// container.style.left 30%;},// 相关事件操作哟canvasEvents() {// 拖拽边界 不能将图片拖拽到绘图区域外this.canvasEle.on(object:moving, function (e) {var obj e.target;// if object is too big ignoreif (obj.currentHeight obj.canvas.height || obj.currentWidth obj.canvas.width) {return;}obj.setCoords();// top-left cornerif (obj.getBoundingRect().top 0 || obj.getBoundingRect().left 0) {obj.top Math.max(obj.top, obj.top - obj.getBoundingRect().top);obj.left Math.max(obj.left, obj.left - obj.getBoundingRect().left);}// bot-right cornerif (obj.getBoundingRect().top obj.getBoundingRect().height obj.canvas.height ||obj.getBoundingRect().left obj.getBoundingRect().width obj.canvas.width) {obj.top Math.min(obj.top,obj.canvas.height - obj.getBoundingRect().height obj.top - obj.getBoundingRect().top);obj.left Math.min(obj.left,obj.canvas.width - obj.getBoundingRect().width obj.left - obj.getBoundingRect().left);}});},// 添加公章addSeal(sealUrl, left, top, index) {fabric.Image.fromURL(sealUrl, (oImg) {oImg.set({left: left,top: top,// angle: 10,scaleX: 0.8,scaleY: 0.8,index: index});// oImg.scale(0.5); //图片缩小一this.canvasEle.add(oImg);});},// 删除签章removeSignature() {this.canvasEle.remove(this.canvasEle.getActiveObject());},// 翻页展示盖章信息commonSign(pageNum, isFirst false) {if (isFirst false) this.canvasEle.remove(this.canvasEle.clear()); // 清空页面所有签章let caches JSON.parse(localStorage.getItem(signs)); // 获取缓存字符串后转换为对象// console.log(caches);if (caches null) return false;let datas caches[this.pageNum];if (datas ! null datas ! undefined) {for (let index in datas) {this.addSeal(datas[index].sealUrl,datas[index].left,datas[index].top,datas[index].index);}}},// 确认签章位置并保存到缓存confirmSignature() {let data this.canvasEle.getObjects(); // 获取当前页面内的所有签章信息let caches JSON.parse(localStorage.getItem(signs)); // 获取缓存字符串后转换为对象let signDatas {}; // 存储当前页的所有签章信息let i 0;// let sealUrl ;for (var val of data) {signDatas[i] {width: val.width,height: val.height,top: val.top,left: val.left,angle: val.angle,translateX: val.translateX,translateY: val.translateY,scaleX: val.scaleX,scaleY: val.scaleY,pageNum: this.pageNum,sealUrl: this.mainImagelist[val.index],index: val.index};i;}if (caches null) {caches {};caches[this.pageNum] signDatas;} else {caches[this.pageNum] signDatas;}localStorage.setItem(signs, JSON.stringify(caches)); // 对象转字符串后存储到缓存},// 提交数据submitSignature() {this.confirmSignature();// let caches localStorage.getItem(signs);// console.log(JSON.parse(caches));return false;},// 清空数据clearSignature() {this.canvasEle.remove(this.canvasEle.clear()); // 清空页面所有签章localStorage.removeItem(signs); // 清除缓存},end(e) {this.addSeal(this.mainImagelist[e.newDraggableIndex],e.originalEvent.layerX,e.originalEvent.layerY,e.newDraggableIndex);},// 设置PDF预览区域高度setPdfArea() {this.pdfUrl ./static/text.pdf;// this.pdfurl res.data.data.pdfurl;this.$nextTick(() {this.showpdf(this.pdfUrl); // 接口返回的应该还有盖章信息不只是pdf});}},watch: {whDatas: {handler() {const loading this.$loading({lock: true,text: Loading,spinner: el-icon-loading,background: rgba(0, 0, 0, 0.7)});if (this.whDatas) {// console.log(this.whDatas);loading.close();this.renderFabric();this.canvasEvents();let eleCanvas document.querySelector(#ele-canvas);eleCanvas.style border:1px solid #5ea6ef;margin-top: 10px;;}}},pageNum: function () {this.commonSign(this.pageNum);this.queueRenderPage(this.pageNum);}}
};
/script
style langscss scoped
/*pdf部分*/
#the-canvas {margin-top: 10px;
}html:fullscreen {background: white;
}
.elesign {display: flex;flex: 1;flex-direction: column;position: relative;/* padding-left: 180px; */margin: auto;/* width:600px; */
}
.page {text-align: center;margin: 0 auto;margin-top: 1%;
}
#ele-canvas {/* border: 1px solid #5ea6ef; */overflow: hidden;
}
.ele-control {text-align: center;margin-top: 3%;
}
#page-input {width: 7%;
}keyframes ani-demo-spin {from {transform: rotate(0deg);}50% {transform: rotate(180deg);}to {transform: rotate(360deg);}
}
/* .loadingclass{position: absolute;top:30%;left:49%;z-index: 99;
} */
.left {position: absolute;top: 42px;left: -5px;padding: 5px 5px;/*border: 1px solid #eee;*//*border-radius: 4px;*/
}
.left-title {text-align: center;padding-bottom: 10px;border-bottom: 1px solid #eee;
}
li {list-style-type: none;padding: 10px;
}
.imgstyle {vertical-align: middle;width: 130px;border: solid 1px #e8eef2;background-image: url(~/assets/img/projectCenter/tuo.png);background-repeat: no-repeat;
}
.right {position: absolute;top: 7px;right: -177px;margin-top: 34px;padding-top: 10px;padding-bottom: 20px;width: 152px;/*border: 1px solid #eee;*//*border-radius: 4px;*/
}
.right-item {margin-bottom: 15px;margin-left: 10px;
}
.right-item-title {color: #777;height: 20px;line-height: 20px;font-size: 12px;font-weight: 400;text-align: left !important;
}
.detail-item-desc {color: #333;line-height: 20px;width: 100%;font-size: 12px;display: inline-block;text-align: left;
}
.btn-outline-dark {color: #0f1531;background-color: transparent;background-image: none;border: 1px solid #3e4b5b;
}.btn-outline-dark:hover {color: #fff;background-color: #3e4b5b;border-color: #3e4b5b;
}
/style
3. 优化后的代码 !-- //?模块说明 合同签章模块 addToTab--
templatediv classcontract-signature-viewdiv classtitle-operationh2 classtitle合同签章/h2div classoperationel-button typedanger clickremoveSignature删除签章/el-buttonel-button typedanger clickclearSignature清空签章/el-buttonel-button typeprimary clicksubmitSignature提交签章/el-button/div/divdiv classsection-box!-- 签章图片 --aside classsignature-imgdiv classinfoh3 classname印章/h3p classtext将示例印章标识拖到文件相应区域即可获取签章位置/p/div!-- 拖拽 --draggablev-modelmainImagelist:group{ name: itext, pull: clone }:sortfalseendendtransition-group typetransitionliv-foritem in mainImagelist:keyitem.imgclassitemstyletext-align: centerimg :srcitem.img width100%; height100% classimg //li/transition-group/draggable/aside!-- 主体区域 --section classmain-layout :class{ is-first: isFirst }!-- 操作 --div classoperate-boxdiv classslider-boxel-sliderclasssliderv-modelscale:min0.5:max2:step0.1:show-tooltipfalsechangesliderChange/span classscale-value{{ (scale * 100).toFixed(0) % }}/span/divdiv classpage-changei classicon el-icon-arrow-left clickprevPage /!-- :min1 --el-inputclassinput-boxv-model.numberpageNum:maxdefaultNumPageschangecutover/span classdefault-text/{{ defaultNumPages }}/spani classicon el-icon-arrow-right clicknextPage //div/div!-- 画图 --div classout-view :class{ is-show: isShowPdf }div classcanvas-layout v-foritem in numPages :keyitem!-- pdf部分 --canvas classthe-canvas /!-- 盖章部分 --canvas classele-canvas/canvas/div/divi classloading v-loading!isShowPdf //section!-- 位置信息 --div classposition-infoh3 classtitle位置信息/h3ul classnavli classitem v-for(item, index) in coordinateList :keyindexspan{{ item.name }}/spanspan{{ item.page }}/spanspan{{ item.left }}/spanspan{{ item.top }}/span/li/ul/div/div/div
/template
script
// 拖拽插件
import draggable from vuedraggable;
// pdf插件
import { fabric } from fabric;
import workerSrc from pdfjs-dist/es5/build/pdf.worker.entry;
const pdfjsLib require(pdfjs-dist/es5/build/pdf.js);
pdfjsLib.GlobalWorkerOptions.workerSrc workerSrc;export default {components: { draggable },data() {return {// pdf地址pdfUrl: ,// 左侧签章列表mainImagelist: [],// 右侧坐标数据coordinateList: [{ name: 名称, page: 所在页面, left: x坐标, top: Y坐标 }],// 总页数numPages: 1,defaultNumPages: 1,// 当前页pageNum: 1,// 缩放比例scale: 1,// pdf是否显示isFirst: true,isShowPdf: false,// pdf最外层的out-viewoutViewDom: null,// 各页pdf的canvas-layoutcanvasLayoutTopList: [],// 用来签章的canvas数组canvasEle: [],// 绘图区域的宽高whDatas: null,// pdf渲染的canvas数组canvas: [],// pdf渲染的canvas的ctx数组ctx: [],// pdf渲染的canvas的宽高pdfDoc: null,// 隐藏的input用来提交数据shadowInputValue: };},created() {this.mainImagelist [{ name: 印章, img: require(/assets/img/projectCenter/contract-sign-img.png) }// { name: 印章, img: require(./sign.png) },// { name: 红章, img: require(/assets/img/projectCenter/seal.png) }];this.setPdfArea();},mounted() {},methods: {/*** pdf相关部分*/// 设置PDF地址setPdfArea() {// // 1. 获取地址栏// const urlString window.location.href;// // 2. 截取地址栏// const pdfStr urlString.split(?)[1];// // 3. 截取pdf地址并解码// this.pdfUrl decodeURIComponent(pdfStr.split()[1]);this.pdfUrl ./static/text.pdf;this.$nextTick(() {this.showpdf(this.pdfUrl); // 接口返回的应该还有盖章信息不只是pdf});},// 解析pdfshowpdf(pdfUrl) {pdfjsLib.getDocument({ url: pdfUrl, rangeChunkSize: 65536, disableAutoFetch: false }).promise.then((pdfDoc_) {this.pdfDoc pdfDoc_;this.numPages this.pdfDoc.numPages;this.defaultNumPages this.pdfDoc.numPages;this.$nextTick(() {this.canvas document.querySelectorAll(.the-canvas);this.canvas.forEach((item) {this.ctx.push(item.getContext(2d));});// 循环渲染pdffor (let i 1; i this.numPages; i) {this.renderPage(i).then(() {this.renderPdf({width: this.canvas[i - 1].width,height: this.canvas[i - 1].height});});}setTimeout(() {this.renderFabric();this.canvasEvents();}, 1000);});});},// 设置pdf宽高缩放比例渲染pdfrenderPage(num) {// console.log(this.canvas, this.canvas[num], num);return this.pdfDoc.getPage(num).then((page) {const viewport page.getViewport({ scale: this.scale }); // 设置视口大小this.canvas[num - 1].height viewport.height;this.canvas[num - 1].width viewport.width;// Render PDF page into canvas contextconst renderContext {canvasContext: this.ctx[num - 1],viewport: viewport};page.render(renderContext);});},// 设置绘图区域宽高renderPdf(data) {this.whDatas data;},// 生成绘图区域renderFabric() {// 1. 拿到全部的canvas-layoutconst canvasLayoutDom document.querySelectorAll(.canvas-layout);// 2. 循环遍历canvasLayoutDom.forEach((item) {this.canvasLayoutTopList.push({ obj: item, top: item.offsetTop });// 3. 设置宽高和居中item.style.width this.whDatas.width px;item.style.height this.whDatas.height px;item.style.margin 0 auto 18px;item.style.boxShadow 4px 4px 4px #e9e9e9;// 4. 拿到盖章canvasconst canvasEle item.querySelector(.ele-canvas);// 5. 拿到pdf的canvasconst pCenter item.querySelector(.the-canvas);// 6. 设置盖章canvas的宽高canvasEle.width pCenter.clientWidth;canvasEle.height this.whDatas.height;// 7. 创建fabric对象并存储this.canvasEle.push(new fabric.Canvas(canvasEle));// 8. 设置盖章canvas的样式const container item.querySelector(.canvas-container);container.style.position absolute;container.style.left 50%;container.style.transform translateX(-50%);container.style.top 0px;});// 现形this.isFirst false;this.isShowPdf true;this.outViewDom document.querySelector(.out-view);// 开启监听窗口滚动this.outViewScroll();},// 开启监听窗口滚动outViewScroll() {this.outViewDom.addEventListener(scroll, this.outViewRun);},// 关闭监听窗口滚动outViewScrollClose() {this.outViewDom.removeEventListener(scroll, this.outViewRun);},// 窗口滚动outViewRun() {const scrollTop this.outViewDom.scrollTop;const topList this.canvasLayoutTopList.map((item) item.top);// 增加一个最大值topList.push(Number.MAX_SAFE_INTEGER);for (let index 0; index topList.length; index) {const element topList[index];if (element scrollTop scrollTop topList[index 1]) {this.pageNum index 1;break;}}},// scale滑块,重新渲染整个pdfsliderChange() {this.pageNum 1;this.numPages 0;this.canvasLayoutTopList [];this.canvasEle [];this.ctx [];this.canvas [];this.isShowPdf false;// this.outViewScrollClose();this.whDatas null;this.coordinateList [{ name: 名称, page: 所在页面, left: x坐标, top: Y坐标 }];this.getSignatureJson();setTimeout(() {this.numPages this.pdfDoc.numPages;this.$nextTick(() {this.canvas document.querySelectorAll(.the-canvas);this.canvas.forEach((item) {this.ctx.push(item.getContext(2d));});// 循环渲染pdffor (let i 1; i this.numPages; i) {this.renderPage(i).then(() {this.renderPdf({width: this.canvas[i - 1].width,height: this.canvas[i - 1].height});});}setTimeout(() {this.renderFabric();this.canvasEvents();}, 1000);});}, 1000);},/*** 签章相关部分*/// 签章拖拽边界处理不能将图片拖拽到绘图区域外canvasEvents() {this.canvasEle.forEach((item) {item.on(object:moving, (e) {const obj e.target;// if object is too big ignoreif (obj.currentHeight obj.canvas.height || obj.currentWidth obj.canvas.width) {return;}obj.setCoords();// top-left cornerif (obj.getBoundingRect().top 0 || obj.getBoundingRect().left 0) {obj.top Math.max(obj.top, obj.top - obj.getBoundingRect().top);obj.left Math.max(obj.left, obj.left - obj.getBoundingRect().left);}// bot-right cornerif (obj.getBoundingRect().top obj.getBoundingRect().height obj.canvas.height ||obj.getBoundingRect().left obj.getBoundingRect().width obj.canvas.width) {obj.top Math.min(obj.top,obj.canvas.height - obj.getBoundingRect().height obj.top - obj.getBoundingRect().top);obj.left Math.min(obj.left,obj.canvas.width - obj.getBoundingRect().width obj.left - obj.getBoundingRect().left);}// console.log(obj.cacheKey,obj.cacheKey);const findIndex this.coordinateList.slice(1).findIndex((coord) coord.cacheKey obj.cacheKey);const keys [width, height, top, left, angle, scaleX, scaleY];keys.forEach((item) {this.coordinateList[findIndex 1][item] Math.ceil(obj[item] / this.scale);});this.getSignatureJson();});});},// 拖拽结束end(e) {// 找到当前拖拽到哪一个canvas-layout上const currentCanvasLayout e.originalEvent.target.parentElement.parentElement;const findIndex this.canvasLayoutTopList.findIndex((item) item.obj currentCanvasLayout);if (findIndex -1) return false;// 取整const left e.originalEvent.layerX 0 ? 0 : Math.ceil(e.originalEvent.layerX / this.scale);const top e.originalEvent.layerY 0 ? 0 : Math.ceil(e.originalEvent.layerY / this.scale);// console.log(e, e, findIndex);this.addSeal({sealUrl: this.mainImagelist[e.newDraggableIndex].img,left,top,index: e.newDraggableIndex,pageNum: findIndex});},// 添加公章addSeal({ sealUrl, left, top, index, pageNum }) {fabric.Image.fromURL(sealUrl, (oImg) {oImg.set({// 距离左边的距离left: left,// 距离顶部的距离top: top,// 角度// angle: 10,// 缩放比例需要乘以scalescaleX: 0.8 * this.scale,scaleY: 0.8 * this.scale,index,// 禁止缩放lockScalingX: true,lockScalingY: true,// 禁止旋转lockRotation: true});this.canvasEle[pageNum].add(oImg);// 保存签章信息this.saveSignature({ pageNum, index, sealUrl });});// this.removeActive();},// 保存签章saveSignature({ pageNum, index, sealUrl }) {// 1. 拿到当前签章的信息let length 0;let pageConfig this.coordinateList.filter((item) item.page - 1 pageNum);if (pageConfig) length pageConfig.length;const currentSignInfo this.canvasEle[pageNum].getObjects()[length];// 2. 拼接数据const keys [width, height, top, left, angle, scaleX, scaleY];const obj {};keys.forEach((item) {obj[item] Math.ceil(currentSignInfo[item] / this.scale);});obj.cacheKey currentSignInfo.cacheKey;obj.sealUrl sealUrl;obj.index index;obj.name ${this.mainImagelist[index].name}${this.coordinateList.length};obj.page pageNum 1;this.coordinateList.push(obj);this.getSignatureJson();},// 签章生成json字符串getSignatureJson() {// 1. 判断是否有签章if (this.coordinateList.length 1) return (this.shadowInputValue );// 2. 拿到签章的信息去除第一条const signatureList this.coordinateList.slice(1);// 3. 拼接数据只要left和top和pageconst keys [page, left, top];const arr [];signatureList.forEach((item) {const obj {};keys.forEach((key) {obj[key] item[key];});arr.push(obj);});// 4. 转成json字符串this.shadowInputValue JSON.stringify(arr);},/*** 操作相关部分*/// 上一页prevPage() {if (this.pageNum 1) return;this.pageNum--;// 滚动到指定位置this.outViewDom.scrollTop this.canvasLayoutTopList[this.pageNum - 1].top;},// 下一页nextPage() {if (this.pageNum this.numPages) return;this.pageNum;// 滚动到指定位置this.outViewDom.scrollTop this.canvasLayoutTopList[this.pageNum - 1].top;},// 切换页码cutover() {this.outViewScrollClose();if (this.pageNum 1) {this.pageNum 1;} else if (this.pageNum this.numPages) {this.pageNum this.numPages;}// 滚动到指定位置this.outViewDom.scrollTop this.canvasLayoutTopList[this.pageNum - 1].top;setTimeout(() {this.outViewScroll();}, 500);},// 删除所有的签章选中状态removeActive() {this.canvasEle.forEach((item) {item.discardActiveObject().renderAll();});},// 删除签章removeSignature() {// 1. 判断是否有选中的签章const findItem this.canvasEle.filter((item) item.getActiveObject());// 2. 判断选中签章的个数if (findItem.length 0) return this.$message.error(请选择要删除的签章);// 3. 判断选中签章的个数是否大于1if (findItem.length 1) {this.removeActive();return this.$message.error(只能选择删除一个签章,请重新选择);}// 4. 拿到选中的签章的cacheKeyconst activeObj findItem[0].getActiveObject();const findIndex this.coordinateList.findIndex((item) item.cacheKey activeObj.cacheKey);// 5. 删除选中的签章findItem[0].remove(activeObj);// 6. 删除选中的签章的信息this.coordinateList.splice(findIndex, 1);this.getSignatureJson();},// 清空签章clearSignature() {this.canvasEle.forEach((item) {item.clear();});this.coordinateList [{ name: 名称, page: 所在页面, left: x坐标, top: Y坐标 }];this.getSignatureJson();},// 提交数据submitSignature() {console.log(this.coordinateList, this.coordinateList);}}
};
/script
style langscss scoped
.contract-signature-view {/*pdf部分*/.ele-canvas {overflow: hidden;}.title-operation {height: 80px;padding: 20px 40px;display: flex;align-items: center;justify-content: space-between;.title {font-size: 20px;font-weight: 600;}border-bottom: 1px solid #e4e4e4;}.section-box {position: relative;display: flex;height: calc(100vh - 60px);.signature-img {width: 240px;min-width: 240px;background-color: #fff;padding: 40px 15px;border-right: 1px solid #e4e4e4;.info {margin-bottom: 38px;.name {font-size: 18px;font-weight: 600;color: #000000;line-height: 25px;margin-bottom: 20px;}.text {font-size: 14px;color: #000000;line-height: 20px;}}.item {padding: 10px;border: 1px dashed rgba(0, 0, 0, 0.3);:not(:last-child) {margin-bottom: 10px;}.img {vertical-align: middle;width: 120px;background-repeat: no-repeat;}}}.main-layout {flex: 1;background-color: #f7f8fa;position: relative;.is-first {.operate-box {opacity: 0;}}.operate-box {opacity: 1;position: absolute;top: 0;left: 0;width: 100%;height: 40px;background-color: #fff;border-bottom: 1px solid #e4e4e4;display: flex;justify-content: center;align-items: center;.slider-box {width: 230px;display: flex;justify-content: center;align-items: center;border-left: 1px solid #e4e4e4;border-right: 1px solid #e4e4e4;.slider {width: 120px;}.scale-value {margin-left: 24px;font-size: 16px;color: #000000;line-height: 22px;}}.page-change {display: flex;align-items: center;margin-left: 30px;.icon {cursor: pointer;padding: 0 5px;color: #c1c1c1;}.input-box {border: none;/deep/ .el-input__inner {width: 34px;height: 20px;border: none;padding: 0;text-align: center;border-bottom: 1px solid #e4e4e4;}}.default-text {display: flex;line-height: 22px;margin-right: 5px;}}}.out-view {height: calc(100vh - 100px);margin: 40px auto;overflow-x: auto;overflow-y: auto;padding-top: 20px;text-align: center;opacity: 0;transition: all 0.5s;.is-show {opacity: 1;}.canvas-layout {position: relative;text-align: center;margin: 0 auto 18px;}}.loading {width: 20px;height: 20px;position: absolute;top: 50%;left: 50%;transform: translate(-50%, -50%);z-index: 999;/deep/ .el-loading-mask {background-color: transparent;}}}.position-info {width: 355px;min-width: 355px;border-left: 1px solid #e4e4e4;background-color: #fff;padding: 14px 15px;.title {font-size: 14px;font-weight: 400;color: #000000;line-height: 20px;padding-bottom: 18px;}.nav {display: flex;flex-direction: column;.item {display: flex;justify-content: space-between;padding: 10px 0;border-bottom: 1px solid #eee;:first-child {background-color: #f7f8fa;}span {flex: 1;text-align: center;font-size: 12px;color: #000000;line-height: 20px;}}}}}
}
/style
文章转载自: http://www.morning.lbxhy.cn.gov.cn.lbxhy.cn http://www.morning.tlpgp.cn.gov.cn.tlpgp.cn http://www.morning.dgmjm.cn.gov.cn.dgmjm.cn http://www.morning.nbybb.cn.gov.cn.nbybb.cn http://www.morning.fchkc.cn.gov.cn.fchkc.cn http://www.morning.cbpkr.cn.gov.cn.cbpkr.cn http://www.morning.pltbd.cn.gov.cn.pltbd.cn http://www.morning.hcwlq.cn.gov.cn.hcwlq.cn http://www.morning.kqlrl.cn.gov.cn.kqlrl.cn http://www.morning.jrplk.cn.gov.cn.jrplk.cn http://www.morning.mkkcr.cn.gov.cn.mkkcr.cn http://www.morning.nqpy.cn.gov.cn.nqpy.cn http://www.morning.frqtc.cn.gov.cn.frqtc.cn http://www.morning.pbxkk.cn.gov.cn.pbxkk.cn http://www.morning.lwzpp.cn.gov.cn.lwzpp.cn http://www.morning.rqknq.cn.gov.cn.rqknq.cn http://www.morning.wnpps.cn.gov.cn.wnpps.cn http://www.morning.qbdsx.cn.gov.cn.qbdsx.cn http://www.morning.jtjmz.cn.gov.cn.jtjmz.cn http://www.morning.pgxjl.cn.gov.cn.pgxjl.cn http://www.morning.sxcwc.cn.gov.cn.sxcwc.cn http://www.morning.jxcwn.cn.gov.cn.jxcwn.cn http://www.morning.kyctc.cn.gov.cn.kyctc.cn http://www.morning.clfct.cn.gov.cn.clfct.cn http://www.morning.bmtyn.cn.gov.cn.bmtyn.cn http://www.morning.qbzdj.cn.gov.cn.qbzdj.cn http://www.morning.gmmyn.cn.gov.cn.gmmyn.cn http://www.morning.rjrh.cn.gov.cn.rjrh.cn http://www.morning.sfzwm.cn.gov.cn.sfzwm.cn http://www.morning.hxcuvg.cn.gov.cn.hxcuvg.cn http://www.morning.dnpft.cn.gov.cn.dnpft.cn http://www.morning.qllcp.cn.gov.cn.qllcp.cn http://www.morning.hrnrx.cn.gov.cn.hrnrx.cn http://www.morning.ttdbr.cn.gov.cn.ttdbr.cn http://www.morning.jghty.cn.gov.cn.jghty.cn http://www.morning.kabaifu.com.gov.cn.kabaifu.com http://www.morning.pgfkl.cn.gov.cn.pgfkl.cn http://www.morning.ncfky.cn.gov.cn.ncfky.cn http://www.morning.ypjjh.cn.gov.cn.ypjjh.cn http://www.morning.zgpgl.cn.gov.cn.zgpgl.cn http://www.morning.gjws.cn.gov.cn.gjws.cn http://www.morning.fcwb.cn.gov.cn.fcwb.cn http://www.morning.yllym.cn.gov.cn.yllym.cn http://www.morning.gktds.cn.gov.cn.gktds.cn http://www.morning.yrmpr.cn.gov.cn.yrmpr.cn http://www.morning.gfznl.cn.gov.cn.gfznl.cn http://www.morning.kzyr.cn.gov.cn.kzyr.cn http://www.morning.mlpch.cn.gov.cn.mlpch.cn http://www.morning.zcrjq.cn.gov.cn.zcrjq.cn http://www.morning.qtkdn.cn.gov.cn.qtkdn.cn http://www.morning.yknsr.cn.gov.cn.yknsr.cn http://www.morning.rykmz.cn.gov.cn.rykmz.cn http://www.morning.fstdf.cn.gov.cn.fstdf.cn http://www.morning.msfqt.cn.gov.cn.msfqt.cn http://www.morning.ctlbf.cn.gov.cn.ctlbf.cn http://www.morning.myhpj.cn.gov.cn.myhpj.cn http://www.morning.nzhzt.cn.gov.cn.nzhzt.cn http://www.morning.crkhd.cn.gov.cn.crkhd.cn http://www.morning.lpmjr.cn.gov.cn.lpmjr.cn http://www.morning.kmkpm.cn.gov.cn.kmkpm.cn http://www.morning.kmqjx.cn.gov.cn.kmqjx.cn http://www.morning.yjmns.cn.gov.cn.yjmns.cn http://www.morning.jpwkn.cn.gov.cn.jpwkn.cn http://www.morning.kyctc.cn.gov.cn.kyctc.cn http://www.morning.wynnb.cn.gov.cn.wynnb.cn http://www.morning.rcklc.cn.gov.cn.rcklc.cn http://www.morning.xqxlb.cn.gov.cn.xqxlb.cn http://www.morning.bswxt.cn.gov.cn.bswxt.cn http://www.morning.mwnch.cn.gov.cn.mwnch.cn http://www.morning.nbwyk.cn.gov.cn.nbwyk.cn http://www.morning.dbfp.cn.gov.cn.dbfp.cn http://www.morning.kxnjg.cn.gov.cn.kxnjg.cn http://www.morning.cmcjp.cn.gov.cn.cmcjp.cn http://www.morning.sfwfk.cn.gov.cn.sfwfk.cn http://www.morning.chmcq.cn.gov.cn.chmcq.cn http://www.morning.xkyst.cn.gov.cn.xkyst.cn http://www.morning.jncxr.cn.gov.cn.jncxr.cn http://www.morning.pprxs.cn.gov.cn.pprxs.cn http://www.morning.syfty.cn.gov.cn.syfty.cn http://www.morning.rgxcd.cn.gov.cn.rgxcd.cn