实测,开发者工具中滚动条位置会影响书写,显示会有些问题,手机上测试正常
index.js
const App = getApp();
Page({
/**
* 页面的初始数据
*/
data: {
curScrollTop : 0
},
/**
* 生命周期函数--监听页面加载
*/
onLoad(options) {
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady() {
},
/**
* 生命周期函数--监听页面显示
*/
onShow() {
if(this.data.showBigResImgPop){
this.setData({
showBigResImgPop : false
})
}else{
// this.init();
}
},
/**
* 写入签名生成图片
*/
onPageScroll:function(e){ // 获取滚动条当前位置
this.setData({
curScrollTop : e.scrollTop
})
// console.log(this.data.curScrollTop)
},
writeSignatureDo(){
this.setData({
showWriteSignature : true,
})
// 写入签名生成图片
this.writeSignature();
},
writeSignature(){
if(!this.data._left && !this.data._top){
const query1 = wx.createSelectorQuery();
query1.select('#writeSignatureCanvasBox').boundingClientRect((res)=>{
// console.log(res)
this.setData({
_left : res.left,
_top : res.top,
})
}).exec()
}
const query = wx.createSelectorQuery();
query.select('#writeSignatureCanvas')
.fields({
node: true,
size: true
})
.exec((res) => {
// console.log(res);
// const canvas = res[0].node;
// console.log('canvas初始宽高', canvas.width, canvas.height);
this.setData({
canvas : res[0].node,
screenWidth : wx.getSystemInfoSync().screenWidth,
screenWidthHalf : wx.getSystemInfoSync().screenWidth / 2,
})
// console.log('canvas初始宽高', this.data.canvas.width, this.data.canvas.height);
// /* START 不设置 CANVAS宽高时,canvas.width=300,canvas.height=150,ctx.lineWidth可以对应设置 细 一些 */
// // setNameMouseX : (e.touches[0].pageX - this.data._left + ((this.data.screenWidth - this.data.canvas.width) / 2)) * (this.data.canvas.width / this.data.screenWidth),
// // setNameMouseY : (e.touches[0].pageY - this.data._top + ((this.data.screenWidthHalf - this.data.canvas.height) / 2)) * (this.data.canvas.height / this.data.screenWidthHalf),
// /* END */
// /* START 设置 CANVAS宽高时,触摸画线根据CANVAS宽高计算标准必须是 300 | 150,ctx.lineWidth可以对应设置 稍粗 一些 */
// this.data.canvas.width = this.data.screenWidth;
// this.data.canvas.height = this.data.screenWidthHalf;
// // setNameMouseX : e.touches[0].pageX - this.data._left + ((this.data.screenWidth - 300) / 2),
// // setNameMouseY : e.touches[0].pageY - this.data._top + ((this.data.screenWidthHalf - 150) / 2),
// /* END */
/* START 设置 CANVAS宽高 * dpr 时,触摸画线根据CANVAS宽高计算标准必须是 300 * dpr | 150 * dpr,ctx.lineWidth可以对应设置 粗 一些 */
this.setData({
dpr : wx.getSystemInfoSync().pixelRatio
})
this.data.canvas.width = this.data.screenWidth * this.data.dpr;
this.data.canvas.height = this.data.screenWidthHalf * this.data.dpr;
// setNameMouseX : e.touches[0].pageX * this.data.dpr - this.data._left * this.data.dpr + ((this.data.screenWidth * this.data.dpr - 300 * this.data.dpr) / 2),
// setNameMouseY : e.touches[0].pageY * this.data.dpr - this.data._top * this.data.dpr + ((this.data.screenWidthHalf * this.data.dpr - 150 * this.data.dpr) / 2),
// y轴滚动条影响手写内容处理
// - this.data.curScrollTop * this.data.dpr
/* END */
this.setData({
writeSignatureCanvasW : this.data.screenWidth,
writeSignatureCanvasH : this.data.screenWidthHalf,
})
// const ctx = canvas.getContext('2d');
this.setData({
ctx : this.data.canvas.getContext('2d')
})
this.data.ctx.strokeStyle = "#4FADF8";
this.data.ctx.lineWidth = 14;
this.data.ctx.clearRect(0, 0, this.data.canvas.width, this.data.canvas.height);
})
},
writeSignatureCanvasTouchStartEvent(e){
// console.log(e)
this.setData({
// setNameMouseX : (e.touches[0].pageX - this.data._left + ((this.data.screenWidth - this.data.canvas.width) / 2)) * (this.data.canvas.width / this.data.screenWidth),
// setNameMouseY : (e.touches[0].pageY - this.data._top + ((this.data.screenWidthHalf - this.data.canvas.height) / 2)) * (this.data.canvas.height / this.data.screenWidthHalf),
// setNameMouseX : e.touches[0].pageX - this.data._left + ((this.data.screenWidth - 300) / 2),
// setNameMouseY : e.touches[0].pageY - this.data._top + ((this.data.screenWidthHalf - 150) / 2),
setNameMouseX : e.touches[0].pageX * this.data.dpr - this.data._left * this.data.dpr + ((this.data.screenWidth * this.data.dpr - 300 * this.data.dpr) / 2),
setNameMouseY : e.touches[0].pageY * this.data.dpr - this.data._top * this.data.dpr + ((this.data.screenWidthHalf * this.data.dpr - 150 * this.data.dpr) / 2) - this.data.curScrollTop * this.data.dpr,
})
this.data.ctx.beginPath();
this.data.ctx.moveTo(this.data.setNameMouseX,this.data.setNameMouseY);
},
writeSignatureCanvasTouchEndEvent(e){
// console.log(e)
this.setData({
setNameMouseX : null,
setNameMouseY : null,
})
this.setData({
showResButton : true
})
},
writeSignatureCanvasTouchMoveEvent(e){
this.setData({
// setNameMouseX : (e.touches[0].pageX - this.data._left + ((this.data.screenWidth - this.data.canvas.width) / 2)) * (this.data.canvas.width / this.data.screenWidth),
// setNameMouseY : (e.touches[0].pageY - this.data._top + ((this.data.screenWidthHalf - this.data.canvas.height) / 2)) * (this.data.canvas.height / this.data.screenWidthHalf),
// setNameMouseX : e.touches[0].pageX - this.data._left + ((this.data.screenWidth - 300) / 2),
// setNameMouseY : e.touches[0].pageY - this.data._top + ((this.data.screenWidthHalf - 150) / 2),
setNameMouseX : e.touches[0].pageX * this.data.dpr - this.data._left * this.data.dpr + ((this.data.screenWidth * this.data.dpr - 300 * this.data.dpr) / 2),
setNameMouseY : e.touches[0].pageY * this.data.dpr - this.data._top * this.data.dpr + ((this.data.screenWidthHalf * this.data.dpr - 150 * this.data.dpr) / 2) - this.data.curScrollTop * this.data.dpr,
})
this.data.ctx.lineTo(this.data.setNameMouseX,this.data.setNameMouseY);
this.data.ctx.stroke();
},
// 重写
reSetWriteSignatureCanvas(){
this.setData({
showResButton : false
})
this.data.ctx.clearRect(0, 0, this.data.canvas.width, this.data.canvas.height);
},
// 确定
setWriteSignatureCanvas(){
this.setData({
showWriteSignature : false,
writeSignatureImg : this.data.canvas.toDataURL('image/png'),
})
// 写入海报,生成最终图片
this.makeResImg();
},
/**
* 写入海报,生成最终图片
*/
makeResImg() {
const query = wx.createSelectorQuery();
query.select('#makeResCanvas')
.fields({
node: true,
size: true
})
.exec((res) => {
// console.log(res);
const canvas = res[0].node;
// console.log('canvas初始宽高', canvas.width, canvas.height);
const ctx = canvas.getContext('2d');
// const dpr = wx.getSystemInfoSync().pixelRatio;
// console.log(dpr);
// canvas.width = res[0].width * dpr;
// canvas.height = res[0].height * dpr;
// console.log(canvas.width , canvas.height)
// ctx.scale(dpr, dpr);
// 写入 生成图片 背景图片
const posterBgImg = canvas.createImage();
posterBgImg.src = '../../images/form-img.png';
posterBgImg.onload = () => {
// console.log('背景图实际宽高', posterBgImg.width, posterBgImg.height);
canvas.width = posterBgImg.width;
canvas.height = posterBgImg.height;
this.setData({
// makeResCanvasW: posterBgImg.width,
// makeResCanvasH: posterBgImg.height,
// makeResCanvasW:750,
// makeResCanvasH:750 / posterBgImg.width * posterBgImg.height,
makeResCanvasW:0,
makeResCanvasH:0,
})
// console.log('canvas宽高设置与背景图一致', canvas.width, canvas.height);
ctx.drawImage(posterBgImg, 0, 0, posterBgImg.width, posterBgImg.height);
// 写入勾选项图片
const checkImg = canvas.createImage();
checkImg.src = '../../images/check.png';
checkImg.onload = () => {
// 画入签名图片
const reSetWriteSignatureImg = canvas.createImage();
reSetWriteSignatureImg.src = this.data.writeSignatureImg;
reSetWriteSignatureImg.onload = () => {
ctx.drawImage(reSetWriteSignatureImg, 1892, 2848, 350, 175);
// 设置勾选项
ctx.drawImage(checkImg, 558, 1895, 32, 24);
ctx.drawImage(checkImg, 1443, 1895, 32, 24);
ctx.drawImage(checkImg, 1443, 2047, 32, 24);
// 写入文本
ctx.fillStyle = '#4FADF8';
ctx.textAlign = 'left';
ctx.textBaseline = 'top';
ctx.font = '46px "PingFangSC-Regular","STHeitiSC-Light","微软雅黑","Microsoft YaHei","sans-serif"';
ctx.fillText('客户姓名',545,384);
// 写入多行文本
// this.writeTextOnCanvas(ctx, 42, 40, '写入多行文本写入多行文本写入多行文本写入多行文本写入多行文本写入多行文本' ,562, 1350);
let add = '北京市北京市东城区东华门街道';
add = '北京市北京市东城区东华门街道多四个字';
if(add.length > 14){
this.writeTextOnCanvas(ctx, 52, 30, add ,1716, 869);
}else{
ctx.fillText(add,1716,895);
}
ctx.fillText('企业详细地址',545,1064);
let date = new Date()
ctx.fillText(date.getFullYear() + '-' + (date.getMonth() + 1) + '-' + date.getDate(),1892,3035);
// 生成最终图片
this.setData({
posterUrl: canvas.toDataURL('image/png'),
})
}
}
}
})
},
// 查看大图
showBigResImg(){
this.setData({
showBigResImgPop : true
})
wx.previewImage({
current: this.data.posterUrl,
urls: [this.data.posterUrl]
});
},
// 写入多行文本
//ctx_2d getContext("2d") 对象
//lineheight 段落文本行高
//bytelength 设置单字节文字一行内的数量
//text 写入画面的段落文本
//startleft 开始绘制文本的 x 坐标位置(相对于画布)
//starttop 开始绘制文本的 y 坐标位置(相对于画布)
writeTextOnCanvas(ctx_2d, lineheight, bytelength, text ,startleft, starttop){
function getTrueLength(str){//获取字符串的真实长度(字节长度)
var len = str.length, truelen = 0;
for(var x = 0; x < len; x++){
if(str.charCodeAt(x) > 128){
truelen += 2;
}else{
truelen += 1;
}
}
return truelen;
}
function cutString(str, leng){//按字节长度截取字符串,返回substr截取位置
var len = str.length, tlen = len, nlen = 0;
for(var x = 0; x < len; x++){
if(str.charCodeAt(x) > 128){
if(nlen + 2 < leng){
nlen += 2;
}else{
tlen = x;
break;
}
}else{
if(nlen + 1 < leng){
nlen += 1;
}else{
tlen = x;
break;
}
}
}
return tlen;
}
for(var i = 1; getTrueLength(text) > 0; i++){
var tl = cutString(text, bytelength);
ctx_2d.fillText(text.substr(0, tl).replace(/^\s+|\s+$/, ""), startleft, (i-1) * lineheight + starttop);
text = text.substr(tl);
}
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide() {
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload() {
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh() {
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom() {
},
/**
* 用户点击右上角分享
*/
onShareAppMessage() {
}
})
index.wxml
<button bindtap="writeSignatureDo" style="background-color: #0FC393;">我要签名</button>
<view wx:for="{{5}}">
<view>1111</view>
<view>2222</view>
<view>3333</view>
<view>5555</view>
<view>6666</view>
<view>7777</view>
<view>8888</view>
<view>9999</view>
</view>
<button bindtap="writeSignatureDo" style="background-color: #0FC393;">我要签名</button>
<image wx:if="{{writeSignatureImg}}" src="{{writeSignatureImg}}" mode="widthFix"></image>
<!-- -->
<view>
<canvas type="2d" id="makeResCanvas" style="width: {{makeResCanvasW}}rpx;height: {{makeResCanvasH}}rpx;"></canvas>
<image bindtap="showBigResImg" wx:if="{{posterUrl}}" src="{{posterUrl}}" mode="widthFix" style="width: 100%;"></image>
</view>
<view wx:if="{{showWriteSignature}}" class="dis-flex flex-dir-column flex-x-center flex-y-center" style="width: 100%; height: 100%; background-color: rgba(0,0,0,.5); position: fixed; left: 0; top: 0;">
<view style="text-align: center; color: #fff; margin-bottom: 30rpx;">请写入签名</view>
<view id="writeSignatureCanvasBox">
<canvas type="2d" id="writeSignatureCanvas" catch:touchstart="writeSignatureCanvasTouchStartEvent" catch:touchend="writeSignatureCanvasTouchEndEvent" catch:touchmove="writeSignatureCanvasTouchMoveEvent" style="width: {{writeSignatureCanvasW}}px;height: {{writeSignatureCanvasH}}px; background-color: #fff;"></canvas>
</view>
<view class="dis-flex flex-x-center flex-y-center" style="width: 50%; margin-top: 30rpx;">
<button catchtap="reSetWriteSignatureCanvas" type="default">重写</button>
<button catchtap="setWriteSignatureCanvas" wx:if="{{showResButton}}" type="default">确定</button>
</view>
</view>
素材图片: