Canvas和fabric电子签章盖章

<template>
	<div class="app-container signatures">
		<div>
			<div class="opt_btn" style="margin-bottom: 10px;">
				<el-button class="btn-outline-dark" @click="prevPage">上一页</el-button>
				<el-button class="btn-outline-dark" @click="nextPage">下一页</el-button>
				<el-button class="btn-outline-dark">{{ pageNum }}/{{ numPages }}页</el-button>
				<el-input-number style="margin:0 5px;border-radius:5px;" class="btn-outline-dark" v-model="npageNum"
					@change="page_change" :min="1" :max="numPages" label="输入页码"></el-input-number>
				<el-button class="btn-outline-dark" @click="cutover">跳转</el-button>
			</div>
			<!-- 展示pdf -->
			<canvas id="pdf-canvas" />
			<!-- 盖章 -->
			<canvas id="Canvas"></canvas>
			<i class="el-icon-error" id="deleteBtn" @click="deleteCanvas"></i>
		</div>

		<div>
			<div class="sign_stamp">
				<div class="add_sign">添加</div>
				<div class="sign_type">
					<div :class="sign_type==1?'active_type':''" @click="change_signTyp(1)">手动</div>
					<div :class="sign_type==2?'active_type':''" @click="change_signTyp(2)">自动</div>
				</div>
				<div class="sign_tip" v-if="sign_type==1">请拖动样例章到附件盖章位置,如需盖多次章,拖动多次</div>
				<el-input v-if="sign_type==2" v-model="keywords" placeholder="请输入关键字" clearable></el-input>
				<div class="sign_part">
					<div v-if="sign_type==1">
						<draggable :group="{ name: 'itext', pull: 'clone' }" :sort="false" @end="end">
							<transition-group type="transition">
								<img id="sign_img" :src="mainImagelist" key="sign" width="160px" height="160px"
									class="imgstyle" />
							</transition-group>
						</draggable>
					</div>
					<img id="sign_img" v-if="sign_type==2" :src="mainImagelist" key="sign" width="160px" height="160px"
						class="imgstyle" />
					<div class="sign_title">样例章</div>
				</div>

				<div class="sign_btn">
					<div @click="submit_sign">签章预览</div>
					<div class="btn2" @click="clear_sign">重新盖章</div>
					<div class="btn3" @click="submit_sign">下载盖章版</div>
					<div class="btn4" @click="down_pdf">下载原版</div>
				</div>

				<!-- <FileUpload></FileUpload> -->
			</div>
		</div>
	</div>
</template>

<script>
	import {
		fabric
	} from 'fabric';
	let pdfjsLib = require("pdfjs-dist/build/pdf.js");
	import workerSrc from "pdfjs-dist/build/pdf.worker.entry";
	pdfjsLib.GlobalWorkerOptions.workerSrc = workerSrc;
	import draggable from "vuedraggable";
	export default {
		components: {
			draggable
		},
		data() {
			return {
				mainImagelist: require('./sign.png'), //电子签章图片
				canvas: '', //pdf-canvas
				canvasEle: '', //盖章-canvas
				pdfUrl: 'http://192.168.5.25:9200/dev-api/profile/changeFile/%E8%A1%A8%E5%8D%95%E5%BB%BA%E8%AE%BE.pdf', //pdf路径
				numPages: 1, //pdf总页数
				pageNum: 1, //pdf当前页
				npageNum: 1, //跳转的页数
				sign_type: 1, //	1:手动 2:自动
				keywords: '', //关键字

				pdfDoc: null,
				ctx: null,
				pageRendering: false,
				whDatas: null,
			}
		},
		mounted() {
			localStorage.removeItem('signs'); //清空数据
			this.setPdfArea(); //展示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) {
						loading.close();
						this.renderFabric(); //生成绘图区域
						// let eleCanvas = document.querySelector("#Canvas");
						// eleCanvas.style = "border:1px solid #5ea6ef";
					}
				}
			},
			pageNum: function() {
				this.commonSign(this.pageNum);
				this.queueRenderPage(this.pageNum);
			}
		},
		methods: {
			/* 设置pdf区域 */
			setPdfArea() {
				this.$nextTick(() => {
					this.showpdf(this.pdfUrl);
				});
			},
			/* 渲染pdf,到时还会盖章信息,在渲染时,同时显示出来,不应该在切换页码时才显示印章信息 */
			showpdf(pdfUrl) {
				this.canvas = document.getElementById("pdf-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,
						});
					});
				});
			},
			renderPage(num) {
				let _this = this;
				this.pageRendering = true;
				return this.pdfDoc.getPage(num).then((page) => {
					var scale = 1;
					// 获取pdf尺寸
					var viewport = page.getViewport(scale);
					_this.canvas.height = viewport.height;
					_this.canvas.width = viewport.width;
					// Render PDF page into canvas context
					let renderContext = {
						canvasContext: _this.ctx,
						viewport: viewport,
					};
					let renderTask = page.render(renderContext);
					// Wait for rendering to finish
					renderTask.promise.then(() => {
						_this.pageRendering = false;
						if (_this.pageNumPending !== null) {
							// New page rendering is pending
							this.renderPage(_this.pageNumPending);
							_this.pageNumPending = null;
						}
					});
				});
			},
			/* 翻页 */
			queueRenderPage(num) {
				this.renderPage(num);
			},
			/* 翻页展示盖章信息 */
			commonSign(pageNum, isFirst = false) {
				if (isFirst == false) this.canvasEle.remove(this.canvasEle.clear()); //清空页面所有签章
				let caches = JSON.parse(localStorage.getItem('signs')); //获取缓存字符串后转换为对象
				if (caches == null) return false;
				let datas = caches[this.pageNum];
				if (datas != null && datas != undefined) {
					for (let index in datas) {
						this.addSign(datas[index].x, datas[index].y, datas[index].index);
					}
				}
			},
			/* 设置绘图区域宽高 */
			renderPdf(data) {
				this.whDatas = data;
			},
			/* 生成绘图区域 */
			renderFabric() {
				let canvaEle = document.querySelector("#Canvas");
				canvaEle.width = this.whDatas.width;
				canvaEle.height = this.whDatas.height;
				this.canvasEle = new fabric.Canvas('Canvas');
				this.canvasEvents();
				let container = document.querySelector(".canvas-container");
				container.style.position = "absolute";
				container.style.top = "65px";
			},
			/* 上一页 */
			prevPage() {
				this.confirmSignature();
				if (this.pageNum <= 1) {
					return;
				}
				this.pageNum--;
				this.npageNum = this.pageNum;
			},
			/* 下一页 */
			nextPage() {
				this.confirmSignature();
				if (this.pageNum >= this.numPages) {
					return;
				}
				this.pageNum++;
				this.npageNum = this.pageNum;
			},
			/* 跳转 */
			cutover() {
				this.confirmSignature();
			},
			/*  */
			page_change(value) {
				this.confirmSignature();
				this.pageNum = this.npageNum
			},
			/* 拖拽结束 */
			end(e) {
				this.addSign(e.originalEvent.layerX - 83, e.originalEvent.layerY - 80, e
					.newDraggableIndex)
			},
			/* 生成电子签章 */
			addSign(x, y, index) {
				var imgElement = document.getElementById('sign_img');
				var imgInstance = new fabric.Image(imgElement, {
					left: x,
					top: y,
					scaleX: 0.5,
					scaleY: 0.5,
					index: index,
				});
				imgInstance.set({
					borderColor: '#8ABBFF',
					cornerSize: 0,
					padding: 15,
					borderDashArray: [5, 5],
					hasRotatingPoint: false,
				});
				this.canvasEle.add(imgInstance);
			},
			/* 确认签章位置 */
			confirmSignature() {
				this.displayBtn(); //隐藏关闭按钮
				let data = this.canvasEle.getObjects(); //获取当前页面内的所有签章信息
				let result = JSON.parse(localStorage.getItem('signs')); //获取缓存字符串后转换为对象
				let signDatas = {}; //存储当前页的所有签章信息
				data && data.map((val, index) => {
					signDatas[index] = {
						x: val.left,
						y: val.top,
						index: val.index
					}
				})
				if (result == null) {
					result = {}
					result[this.pageNum] = signDatas;
				} else {
					result[this.pageNum] = signDatas;
				}
				console.log(result, '最终结果')
				localStorage.setItem('signs', JSON.stringify(result)); //对象转字符串后存储到缓存
			},
			/* 签章预览 */
			submit_sign() {
				this.confirmSignature(); //确认签章位置
			},
			/* 重新盖章 */
			clear_sign() {
				this.canvasEle.remove(this.canvasEle.clear()); //清空页面所有签章
				localStorage.removeItem('signs'); //清除缓存
			},
			/* 下载原版 */
			down_pdf() {
				console.log('下载原版')
			},
			/* 电子签章相关事件 */
			canvasEvents() {
				var that = this;
				var deleteBtn = document.getElementById('deleteBtn');
				this.canvasEle.on('selection:created', function(e) {
					that.addDeleteBtn(e.selected[0].lineCoords.tr.x, e.selected[0].lineCoords.tr.y);
				});
				this.canvasEle.on('selection:updated', function(e) {
					that.addDeleteBtn(e.selected[0].lineCoords.tr.x, e.selected[0].lineCoords.tr.y);
				});
				this.canvasEle.on('mouse:down', function(e) {
					if (!that.canvasEle.getActiveObject()) {
						deleteBtn.style.display = 'none';
					}
				});
				this.canvasEle.on('object:modified', function(e) {
					that.addDeleteBtn(e.target.lineCoords.tr.x, e.target.lineCoords.tr.y);
				});
				this.canvasEle.on('object:scaling', function(e) {
					deleteBtn.style.display = 'none';
				});
				this.canvasEle.on('object:moving', function(e) {
					deleteBtn.style.display = 'none';
				});
				this.canvasEle.on('object:rotating', function(e) {
					deleteBtn.style.display = 'none';
				});
				this.canvasEle.on('mouse:wheel', function(e) {
					deleteBtn.style.display = 'none';
				})
			},
			/* 隐藏关闭按钮 */
			displayBtn() {
				var deleteBtn = document.getElementById('deleteBtn');
				deleteBtn.style.display = 'none';
			},
			/* 电子签章添加删除图标 */
			addDeleteBtn(x, y) {
				var left = document.getElementsByClassName('opt_btn')[0].offsetLeft;
				left = left ? left - 10 : 0
				var deleteBtn = document.getElementById('deleteBtn');
				deleteBtn.style.display = 'none';
				deleteBtn.style.left = x + left + 'px';
				deleteBtn.style.top = y + 50 + 'px';
				deleteBtn.style.display = 'block';
			},
			/* 删除签章 */
			deleteCanvas() {
				var deleteBtn = document.getElementById('deleteBtn');
				if (this.canvasEle.getActiveObject()) {
					this.canvasEle.remove(this.canvasEle.getActiveObject());
					deleteBtn.style.display = 'none';
				}
			},
			/* 签章类型切换 */
			change_signTyp(type) {
				this.clear_sign()
				this.sign_type = type;
				this.pageNum = 1;
			}
		}
	}
</script>


<style lang="scss" scoped="scoped">
	.signatures {
		background-color: #F6F7FA;
		display: flex;
		justify-content: center;

		#Canvas {
			border: 1px solid #e6ebf5;
			box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
		}

		#deleteBtn {
			position: absolute;
			top: 0px;
			left: 0px;
			cursor: pointer;
			display: none;
			font-size: 30px;
			color: #1677FF;
		}

		/* 签章部分 */
		.sign_stamp {
			width: 265px;
			margin-left: 50px;

			.add_sign {
				font-size: 21px;
				font-family: PingFangSC-Regular, PingFang SC;
				font-weight: 400;
				color: #000000;
				line-height: 29px;
			}

			.sign_type {
				display: flex;
				justify-content: center;
				align-items: center;
				width: 114px;
				height: 34px;
				background: #DDE2F0;
				border-radius: 6px;
				border: 0px solid rgba(0, 0, 0, 0.65);
				margin: 19px 0 14px;

				font-size: 15px;
				font-family: PingFangSC-Regular, PingFang SC;
				font-weight: 400;
				color: rgba(0, 0, 0, 0.65);
				line-height: 30px;

				div {
					width: 55px;
					text-align: center;
					cursor: pointer;
				}

				.active_type {
					width: 55px;
					height: 30px;
					background: #FFFFFF;
					box-shadow: 0px 1px 2px 0px rgba(0, 0, 0, 0.03), 0px 1px 6px -1px rgba(0, 0, 0, 0.02), 0px 2px 5px 0px rgba(0, 0, 0, 0.02);
					border-radius: 4px;
					border: 0px solid rgba(0, 0, 0, 0.88);
				}
			}

			.sign_tip {
				font-size: 15px;
				font-family: PingFangSC-Regular, PingFang SC;
				font-weight: 400;
				color: rgba(0, 0, 0, 0.5);
				line-height: 21px;
			}

			.sign_part {
				width: 215px;
				height: 215px;
				background: #FFFFFF;
				display: flex;
				align-items: center;
				flex-direction: column;
				margin: 30px 0 40px;

				img {
					width: 164px;
					height: 164px;
					margin: 13px auto 0;
				}

				.sign_title {
					font-size: 15px;
					font-family: PingFangSC-Regular, PingFang SC;
					font-weight: 400;
					color: #000000;
					line-height: 21px;
					padding: 5px 0 7px;
				}
			}

			.sign_btn {
				display: flex;
				flex-wrap: wrap;

				div {
					width: 122px;
					height: 42px;
					background: #22B35E;
					border-radius: 6px;
					font-size: 17px;
					font-family: PingFangSC-Regular, PingFang SC;
					font-weight: 400;
					color: #FFFFFF;
					line-height: 42px;
					text-align: center;
					margin: 0 20px 20px 0;
					cursor: pointer;
				}

				div:nth-child(2n) {
					margin-right: 0;
				}

				.btn2 {
					background: #FF9F18;
				}

				.btn3 {
					background: #1677FF;
				}

				.btn4 {
					background: #FFFFFF;
					border: 2px solid #1677FF;
					color: #1677FF;
					line-height: 38px;
				}
			}
		}

		.sortable-ghost {
			background: transparent !important;
		}

		::v-deep .sign_stamp .el-input--medium .el-input__inner {
			width: 264px;
			height: 33px !important;
			line-height: 33px !important;
		}

		/* 签章部分 */
	}
</style>

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值