微信小程序> 微信小程序canvas实现小程序手写板用户签名附代码测试有效-微信电子签名小程序-小程序电子签名

微信小程序canvas实现小程序手写板用户签名附代码测试有效-微信电子签名小程序-小程序电子签名

浏览量:1888 时间: 来源:qq_41211900
1.

工作中公司业务需要的微信小程序用户签字功能

2.

先看效果图:

3.

color_black.png

4.

color_black_selected.png

5.

color_red.png

6.

color_red_selected.png

7.

js:放在page里面

data:{canvasName:'handWriting',ctx:'',canvasWidth:0,canvasHeight:0,transparent:1,//透明度selectColor:'black',lineColor:'#1A1A1A',//颜色lineSize:1.5,//笔记倍数lineMin:0.5,//最小笔画半径lineMax:4,//最大笔画半径pressure:1,//默认压力smoothness:60,//顺滑度,用60的距离来计算速度currentPoint:{},currentLine:[],//当前线条firstTouch:true,//第一次触发radius:1,//画圆的半径cutArea:{top:0,right:0,bottom:0,left:0},//裁剪区域bethelPoint:[],//保存所有线条生成的贝塞尔点;lastPoint:0,chirography:[],//笔迹currentChirography:{},//当前笔迹linePrack:[]//划线轨迹,生成线条的实际点},8.

初始化:

onLoad(){letcanvasNamethis.data.canvasNameletctxwx.createCanvasContext(canvasName)this.setData({ctx:ctx})varquerywx.createSelectorQuery();query.select('.handCenter').boundingClientRect(rect{this.setData({canvasWidth:rect.width,canvasHeight:rect.height})}).exec();},9.

事件函数

//笔迹开始uploadScaleStart(e){if(e.type!'touchstart')returnfalse;letctxthis.data.ctx;ctx.setFillStyle(this.data.lineColor);//初始线条设置颜色ctx.setGlobalAlpha(this.data.transparent);//设置半透明letcurrentPoint{x:e.touches[0].x,y:e.touches[0].y}letcurrentLinethis.data.currentLine;currentLine.unshift({time:newDate().getTime(),dis:0,x:currentPoint.x,y:currentPoint.y})this.setData({currentPoint,//currentLine})if(this.data.firstTouch){this.setData({cutArea:{top:currentPoint.y,right:currentPoint.x,bottom:currentPoint.y,left:currentPoint.x},firstTouch:false})}this.pointToLine(currentLine);},//笔迹移动uploadScaleMove(e){if(e.type!'touchmove')returnfalse;if(e.cancelable){//判断默认行为是否已经被禁用if(!e.defaultPrevented){e.preventDefault();}}letpoint{x:e.touches[0].x,y:e.touches[0].y}//测试裁剪if(point.ythis.data.cutArea.top){this.data.cutArea.toppoint.y;}if(point.y0)this.data.cutArea.top0;if(point.xthis.data.cutArea.right){this.data.cutArea.rightpoint.x;}if(this.data.canvasWidth-point.x0){this.data.cutArea.rightthis.data.canvasWidth;}if(point.ythis.data.cutArea.bottom){this.data.cutArea.bottompoint.y;}if(this.data.canvasHeight-point.y0){this.data.cutArea.bottomthis.data.canvasHeight;}if(point.xthis.data.cutArea.left){this.data.cutArea.leftpoint.x;}if(point.x0)this.data.cutArea.left0;this.setData({lastPoint:this.data.currentPoint,currentPoint:point})letcurrentLinethis.data.currentLinecurrentLine.unshift({time:newDate().getTime(),dis:this.distance(this.data.currentPoint,this.data.lastPoint),x:point.x,y:point.y})//this.setData({//currentLine//})this.pointToLine(currentLine);},//笔迹结束uploadScaleEnd(e){if(e.type!'touchend')return0;letpoint{x:e.changedTouches[0].x,y:e.changedTouches[0].y}this.setData({lastPoint:this.data.currentPoint,currentPoint:point})letcurrentLinethis.data.currentLinecurrentLine.unshift({time:newDate().getTime(),dis:this.distance(this.data.currentPoint,this.data.lastPoint),x:point.x,y:point.y})//this.setData({//currentLine//})if(currentLine.length2){varinfo(currentLine[0].time-currentLine[currentLine.length-1].time)/currentLine.length;//$("#info").text(info.toFixed(2));}//一笔结束,保存笔迹的坐标点,清空,当前笔迹//增加判断是否在手写区域;this.pointToLine(currentLine);varcurrentChirography{lineSize:this.data.lineSize,lineColor:this.data.lineColor};varchirographythis.data.chirographychirography.unshift(currentChirography);this.setData({chirography})varlinePrackthis.data.linePracklinePrack.unshift(this.data.currentLine);this.setData({linePrack,currentLine:[]})},10.

其他函数:

retDraw(){this.data.ctx.clearRect(0,0,700,730)this.data.ctx.draw()},//画两点之间的线条;参数为:line,会绘制最近的开始的两个点;pointToLine(line){this.calcBethelLine(line);return;},//计算插值的方式;calcBethelLine(line){if(line.length1){line[0].rthis.data.radius;return;}letx0,x1,x2,y0,y1,y2,r0,r1,r2,len,lastRadius,dis0,time0,curveValue0.5;if(line.length2){x0line[1].xy0line[1].yx2line[1].x+(line[0].x-line[1].x)*curveValue;y2line[1].y+(line[0].y-line[1].y)*curveValue;//x2line[1].x;//y2line[1].y;x1x0+(x2-x0)*curveValue;y1y0+(y2-y0)*curveValue;;}else{x0line[2].x+(line[1].x-line[2].x)*curveValue;y0line[2].y+(line[1].y-line[2].y)*curveValue;x1line[1].x;y1line[1].y;x2x1+(line[0].x-x1)*curveValue;y2y1+(line[0].y-y1)*curveValue;}//从计算公式看,三个点分别是(x0,y0),(x1,y1),(x2,y2);(x1,y1)这个是控制点,控制点不会落在曲线上;实际上,这个点还会手写获取的实际点,却落在曲线上lenthis.distance({x:x2,y:y2},{x:x0,y:y0});lastRadiusthis.data.radius;for(letn0;nline.length-1;n++){dis+line[n].dis;time+line[n].time-line[n+1].time;if(disthis.data.smoothness)break;}this.setData({radius:Math.min(time/len*this.data.pressure+this.data.lineMin,this.data.lineMax)*this.data.lineSize});line[0].rthis.data.radius;//计算笔迹半径;if(line.length2){r0(lastRadius+this.data.radius)/2;r1r0;r2r1;//return;}else{r0(line[2].r+line[1].r)/2;r1line[1].r;r2(line[1].r+line[0].r)/2;}letn5;letpoint[];for(leti0;in;i++){letti/(n-1);letx(1-t)*(1-t)*x0+2*t*(1-t)*x1+t*t*x2;lety(1-t)*(1-t)*y0+2*t*(1-t)*y1+t*t*y2;letrlastRadius+(this.data.radius-lastRadius)/n*i;point.push({x:x,y:y,r:r});if(point.length3){letathis.ctaCalc(point[0].x,point[0].y,point[0].r,point[1].x,point[1].y,point[1].r,point[2].x,point[2].y,point[2].r);a[0].colorthis.data.lineColor;//letbethelPointthis.data.bethelPoint;//console.log(a)//console.log(this.data.bethelPoint)//bethelPointbethelPoint.push(a);this.bethelDraw(a,1);point[{x:x,y:y,r:r}];}}this.setData({currentLine:line})},//求两点之间距离distance(a,b){letxb.x-a.x;letyb.y-a.y;returnMath.sqrt(x*x+y*y);},ctaCalc(x0,y0,r0,x1,y1,r1,x2,y2,r2){leta[],vx01,vy01,norm,n_x0,n_y0,vx21,vy21,n_x2,n_y2;vx01x1-x0;vy01y1-y0;normMath.sqrt(vx01*vx01+vy01*vy01+0.0001)*2;vx01vx01/norm*r0;vy01vy01/norm*r0;n_x0vy01;n_y0-vx01;vx21x1-x2;vy21y1-y2;normMath.sqrt(vx21*vx21+vy21*vy21+0.0001)*2;vx21vx21/norm*r2;vy21vy21/norm*r2;n_x2-vy21;n_y2vx21;a.push({mx:x0+n_x0,my:y0+n_y0,color:"#1A1A1A"});a.push({c1x:x1+n_x0,c1y:y1+n_y0,c2x:x1+n_x2,c2y:y1+n_y2,ex:x2+n_x2,ey:y2+n_y2});a.push({c1x:x2+n_x2-vx21,c1y:y2+n_y2-vy21,c2x:x2-n_x2-vx21,c2y:y2-n_y2-vy21,ex:x2-n_x2,ey:y2-n_y2});a.push({c1x:x1-n_x2,c1y:y1-n_y2,c2x:x1-n_x0,c2y:y1-n_y0,ex:x0-n_x0,ey:y0-n_y0});a.push({c1x:x0-n_x0-vx01,c1y:y0-n_y0-vy01,c2x:x0+n_x0-vx01,c2y:y0+n_y0-vy01,ex:x0+n_x0,ey:y0+n_y0});a[0].mxa[0].mx.toFixed(1);a[0].mxparseFloat(a[0].mx);a[0].mya[0].my.toFixed(1);a[0].myparseFloat(a[0].my);for(leti1;ia.length;i++){a[i].c1xa[i].c1x.toFixed(1);a[i].c1xparseFloat(a[i].c1x);a[i].c1ya[i].c1y.toFixed(1);a[i].c1yparseFloat(a[i].c1y);a[i].c2xa[i].c2x.toFixed(1);a[i].c2xparseFloat(a[i].c2x);a[i].c2ya[i].c2y.toFixed(1);a[i].c2yparseFloat(a[i].c2y);a[i].exa[i].ex.toFixed(1);a[i].exparseFloat(a[i].ex);a[i].eya[i].ey.toFixed(1);a[i].eyparseFloat(a[i].ey);}returna;},bethelDraw(point,is_fill,color){letctxthis.data.ctx;ctx.beginPath();ctx.moveTo(point[0].mx,point[0].my);if(undefined!color){ctx.setFillStyle(color);ctx.setStrokeStyle(color);}else{ctx.setFillStyle(point[0].color);ctx.setStrokeStyle(point[0].color);}for(leti1;ipoint.length;i++){ctx.bezierCurveTo(point[i].c1x,point[i].c1y,point[i].c2x,point[i].c2y,point[i].ex,point[i].ey);}ctx.stroke();if(undefined!is_fill){ctx.fill();//填充图形(后绘制的图形会覆盖前面的图形,绘制时注意先后顺序)}ctx.draw(true)},selectColorEvent(event){console.log(event)varcolorevent.currentTarget.dataset.colorValue;varcolorSelectedevent.currentTarget.dataset.color;this.setData({selectColor:colorSelected,lineColor:color})},11.

设置背景函数:

//设置canvas背景色不设置导出的canvas的背景为透明//@params:字符串colorsetCanvasBg(color){console.log(999);/*将canvas背景设置为白底,不设置导出的canvas的背景为透明*///rect()参数说明矩形路径左上角的横坐标,左上角的纵坐标,矩形路径的宽度,矩形路径的高度//这里是canvasHeight-4是因为下边盖住边框了,所以手动减了写this.data.ctx.rect(0,0,this.data.canvasWidth,this.data.canvasHeight-4);//ctx.setFillStyle('red')this.data.ctx.setFillStyle(color)this.data.ctx.fill()//设置填充this.data.ctx.draw()//开画},12.

修改上面其他函数中的:

13.

retDraw函数为(给canvas设置个白色的背景,不然导出的是透明的,根据自己的情况选择是否用):

retDraw(){this.data.ctx.clearRect(0,0,700,730)this.data.ctx.draw();//设置canvas背景this.setCanvasBg("#fff");},14.

初始化onload钩子函数中也,给canvas添加白色背景:

onLoad:function(options){letcanvasNamethis.data.canvasNameletctxwx.createCanvasContext(canvasName)this.setData({ctx:ctx})varquerywx.createSelectorQuery();query.select('.handCenter').boundingClientRect(rect{this.setData({canvasWidth:rect.width,canvasHeight:rect.height})/*将canvas背景设置为白底,不设置导出的canvas的背景为透明*///console.log(this,'hahah');this.setCanvasBg('#fff');}).exec();},15.

在原代码中增加保存、预览、上传等功能:

16.

保存到相册:

//保存到相册saveCanvasAsImg(){wx.canvasToTempFilePath({canvasId:'handWriting',fileType:'png',quality:1,//图片质量success(res){//console.log(res.tempFilePath,'canvas生成图片地址');wx.saveImageToPhotosAlbum({filePath:res.tempFilePath,success(res){wx.showToast({title:'已保存到相册',duration:2000});}})}})},17.

预览:

//预览previewCanvasImg(){wx.canvasToTempFilePath({canvasId:'handWriting',fileType:'jpg',quality:1,//图片质量success(res){//console.log(res.tempFilePath,'canvas生成图片地址');wx.previewImage({urls:[res.tempFilePath],//预览图片数组})}})},18.

上传:

//上传uploadCanvasImg(){wx.canvasToTempFilePath({canvasId:'handWriting',fileType:'png',quality:1,//图片质量success(res){//console.log(res.tempFilePath,'canvas生成图片地址');//上传wx.uploadFile({url:'https://example.weixin.qq.com/upload',//仅为示例,非真实的接口地址filePath:res.tempFilePath,name:'file_signature',formData:{user:'test'},success(res){constdatares.data//dosomething}})}})},19.

wxss:

page{background:#fbfbfb;height:auto;overflow:hidden;}.wrapper{width:100%;height:95vh;margin:30rpx0;overflow:hidden;display:flex;align-content:center;flex-direction:row;justify-content:center;font-size:28rpx;}.handWriting{background:#fff;width:100%;height:95vh;}.handRight{display:inline-flex;align-items:center;}.handCenter{border:4rpxdashed#e9e9e9;flex:5;overflow:hidden;box-sizing:border-box;}.handTitle{transform:rotate(90deg);flex:1;color:#666;}.handBtnbutton{font-size:28rpx;}.handBtn{height:95vh;display:inline-flex;flex-direction:column;justify-content:space-between;align-content:space-between;flex:1;}.delBtn{position:absolute;top:250rpx;left:0rpx;transform:rotate(90deg);color:#666;}.delBtnimage{position:absolute;top:13rpx;left:25rpx;}.subBtn{position:absolute;bottom:52rpx;left:-3rpx;display:inline-flex;transform:rotate(90deg);background:#008ef6;color:#fff;margin-bottom:30rpx;text-align:center;justify-content:center;}.black-select{width:60rpx;height:60rpx;position:absolute;top:30rpx;left:25rpx;}.black-select.color_select{width:90rpx;height:90rpx;top:30rpx;left:10rpx;}.red-select{width:60rpx;height:60rpx;position:absolute;top:140rpx;left:25rpx;}.red-select.color_select{width:90rpx;height:90rpx;top:120rpx;left:10rpx;}20.

实现微信小程序手写板用户签名(附代码)预览、保存、上传均有,三种手写板方法_下载https://download.csdn.net/download/qq_41211900/11166644

版权声明

即速应用倡导尊重与保护知识产权。如发现本站文章存在版权问题,烦请提供版权疑问、身份证明、版权证明、联系方式等发邮件至197452366@qq.com ,我们将及时处理。本站文章仅作分享交流用途,作者观点不等同于即速应用观点。用户与作者的任何交易与本站无关,请知悉。

  • 头条
  • 搜狐
  • 微博
  • 百家
  • 一点资讯
  • 知乎