需求流程:
实操
1:首先是新建签名,出现可缩放,拖拽的框,我是借鉴uniapp插件
插件地址: https://ext.dcloud.net.cn/plugin?id=2059
2: 按照插件步骤执行完毕,下一步就是获取拖拽,缩放之后的 宽高和坐标
x, y, w, h
在下载的插件里面,有个end方法,在end方法里面,获取当前框的大小的位置
<canvas
canvas-id="canvas-drag"
disable-scroll="true"
@touchstart="start"
@touchmove="move"
@touchend="end"
:style="'width: ' + width + 'rpx; height: ' + height + 'rpx;'"
></canvas>
end(e) {
uni.setStorageSync("storage_x", parseInt(pdfX));
uni.setStorageSync("storage_y", parseInt(pdfY));
uni.setStorageSync("storage_w", parseInt(pdfW));
uni.setStorageSync("storage_h", parseInt(pdfH));
this.tempGraphArr = [];
if (isMove) {
isMove = false; // 重置移动标识
// 用户操作结束时记录历史
this.recordHistory();
}
},
记录之后,画框,旋转,缩放,这一快就结束了。之后就是
写签名
将签名放在指定位置
将签名导出本地
<template>
<!-- <div v-show="showCanvas"> -->
<div class="contain">
<canvas
canvas-id="mycanvas"
class="mycanvas"
disable-scroll="true"
@touchstart="ontouchstart"
@touchmove="touchmove"
@touchend="touchend"
></canvas>
<view class="footer">
<view class="footer-wrap">
<pdf-button
text="清除"
mode="clear"
@pdfButton="clear"
class="btn"
></pdf-button>
<pdf-button
v-if="show"
text="完成"
mode="pdfGary"
left="31rpx"
class="btn"
>
</pdf-button>
<pdf-button
v-else
text="完成"
mode="pdfFinssh"
@pdfButton="close"
left="31rpx"
class="btn"
>
</pdf-button>
</view>
</view>
</div>
</template>
<script>
import pdfButton from "../../components/pdfButton";
export default {
components: {
pdfButton,
},
data() {
return {
headerStyleHeight: 0,
headerStyleTop: 0,
oc: "",
points: [], //路径点集合
showCanvas: false, //
show: true,
};
},
mounted() {
this.clear();
},
onShow() {
this.initCanvas();
// console.log('参数',+uni.getStorageSync("storage_w"));
},
methods: {
close() {
uni.canvasToTempFilePath({
canvasId: "mycanvas",
success: (res) => {
console.log("res", res.tempFilePath);
const canvas = res.tempFilePath;
uni.navigateTo({
url: `/pages/previewFinally/index?hasSingle=${1}&canvas=${canvas}`,
});
},
});
},
initCanvas() {
this.showCanvas = true;
this.oc = uni.createCanvasContext("mycanvas");
//设置画笔样式
this.oc.lineWidth = 4;
this.oc.lineCap = "round";
this.oc.lineJoin = "round";
this.oc.strokeStyle = "black";
this.oc.fillStyle = "#fff";
this.oc.lineWidth = 5;
this.oc.fillRect(0, 0, 400, 700);
this.oc.fill();
this.oc.draw();
},
ontouchend(e) {
console.log("结束啊啊啊啊");
oc.ontouchmove = null;
this.show = false;
},
ontouchmove(e) {
const { clientX, clientY } = e.changedTouches[0];
oc.lineTo(clientX - oc.offsetLeft, clientY - oc.offsetTop);
oc.stroke();
},
//触摸开始,获取到起点
ontouchstart(e) {
// debugger
// ctx.beginPath();
const startX = e.changedTouches[0].x;
const startY = e.changedTouches[0].y;
let startPoint = {
X: startX,
Y: startY,
};
this.points.push(startPoint);
//每次触摸开始,开启新的路径
this.oc.beginPath();
},
//触摸移动,获取到路径点
touchmove(e) {
let moveX = e.changedTouches[0].x;
let moveY = e.changedTouches[0].y;
let movePoint = {
X: moveX,
Y: moveY,
};
this.points.push(movePoint); //存点
let len = this.points.length;
if (len >= 2) {
this.draw(); //绘制路径
}
},
// 触摸结束,将未绘制的点清空防止对后续路径产生干扰
touchend() {
this.points = [];
this.show = false;
},
/* ***********************************************
# 绘制笔迹
# 1.为保证笔迹实时显示,必须在移动的同时绘制笔迹
# 2.为保证笔迹连续,每次从路径集合中区两个点作为起点(moveTo)和终点(lineTo)
# 3.将上一次的终点作为下一次绘制的起点(即清除第一个点)
************************************************ */
draw() {
let point1 = this.points[0];
let point2 = this.points[1];
this.points.shift();
this.oc.moveTo(point1.X, point1.Y);
this.oc.lineTo(point2.X, point2.Y);
this.oc.stroke();
this.oc.draw(true);
},
//清空画布
clear() {
this.show = true;
let that = this;
uni.getSystemInfo({
success: (res) => {
let canvasw = res.windowWidth;
let canvash = res.windowHeight;
that.oc.clearRect(0, 0, canvasw, canvash);
that.oc.draw(true);
// that.initCanvas();
},
});
},
},
};
</script>
<style lang="scss">
.contain {
height: 100vh;
position: relative;
.button {
width: 100%;
height: 50px;
line-height: 50px;
text-align: center;
font-size: 20px;
border: 1px solid #bbbbbb;
}
.header-box {
width: 100%;
background-color: #ffffff;
padding-bottom: 20rpx;
color: red;
}
.content-box {
width: 100%;
height: 500px;
// background-color: aliceblue;
padding: 20rpx;
box-sizing: border-box;
}
.signature {
position: fixed;
top: 10px;
left: 2%;
z-index: 999;
width: 96%;
}
.mycanvas {
width: 100%;
height: 330rpx;
}
.footer {
font-size: 14px;
height: 100%;
display: flex;
justify-content: space-around;
align-items: center;
background: #f2f3f5;
.footer-wrap {
height: 100%;
padding: 57rpx 37rpx 17rpx 37rpx;
box-sizing: border-box;
display: flex;
align-items: center;
}
}
.sty-single {
position: absolute;
top: 70rpx;
left: 0rpx;
width: 569rpx;
height: 200rpx;
z-index: 111;
}
}
.btn {
height: 100%;
}
</style>
// 接收传来的canvas
onLoad(options) {
this.hasSingle = options.hasSingle;
this.canvas = options.canvas;
this.px();
},
// 渲染canvas,注意宽高,坐标。用之前保存的坐标
data() {
return {
pdfDataList: uni.getStorageSync("filePath"),
hasSingle: 0,
canvas: "",
rpx: "",
finillyX: uni.getStorageSync("storage_x"),
finillyY: uni.getStorageSync("storage_y"),
finillyW: uni.getStorageSync("storage_w"),
finillyH: uni.getStorageSync("storage_h"),
};
},
// 渲染
<image
v-if="pdfDataList != '' && hasSingle == 1"
:src="canvas"
class="sty-single transfo"
:style="{
width: finillyW + 'px',
height: finillyH + 'px',
top: finillyY + 'px',
left: finillyX + 'px',
}"
></image>
<view class="footer-wrap">
<pdf-button
v-if="canvas"
text="保存合同"
mode="finishBig"
@pdfButton="finishSave"
class="btn"
>
</pdf-button>
finishSave() {
// 提示用户正在合成,否则用户可能有不当操作或者以为手机卡死
wx.showLoading({
title: "合成中",
mask: true,
});
// 创建画布对象
const ctx = uni.createCanvasContext("myCanvas");
console.log("ctx", ctx);
// 获取图片信息,要按照原图来绘制,否则图片会变形
uni.getImageInfo({
src: this.pdfDataList, // 底图
success: (res) => {
// 根据 图片的大小 绘制底图 的大小
console.log(" 底图", res);
let imgPath = res.path;
ctx.drawImage(
imgPath,
0,
0,
(750 / 2) * this.rpx,
(1061 / 2) * this.rpx
);
wx.getImageInfo({
src: this.canvas,
success: (res) => {
console.log(" 签名", res);
ctx.drawImage(
res.path,
this.finillyX,
this.finillyY,
this.finillyW,
this.finillyH
);
ctx.draw();
setTimeout(() => {
console.log("111");
uni.canvasToTempFilePath({
canvasId: "myCanvas",
success: (res) => {
uni.hideLoading();
console.log("合成图片", res);
const tempFilePath = res.tempFilePath;
// 保存到相册
wx.saveImageToPhotosAlbum({
filePath: tempFilePath,
success: (res) => {
// 修改下载状态
wx.showModal({
title: "温馨提示",
content: "已保存到本地相册",
confirmText: "我知道了",
showCancel: false,
success: (res) => {
console.log("res图片保存成功", res);
if (res.confirm) {
uni.reLaunch({
url: "/pages/contract/index",
});
}
uni.setStorageSync("sing", "");
uni.setStorageSync("File", "");
uni.setStorageSync("filePath", "");
},
});
},
});
},
});
}, 2000);
},
});
},
});
},
由于canvas画出来的坐标都是px,所以在保存的时候。为了不同机型,需要做适配,按比例就好
px() {
const { windowWidth } = wx.getSystemInfoSync();
this.rpx = windowWidth / 375;
//获取屏幕宽度,获取自适应单位
console.log("rpx", this.rpx);
},