uniapp,使用canvas制作一个签名板,写字板

先看效果图

 我把这个做成了页面,没有做成组件,因为之前我是配合uview-plus的popup弹出层使用的,这种组件好像是没有生命周期的,第一次打开弹出层可以正常写字,但是关闭之后再打开就不会显示绘制的线条了,还需要重新加载组件的父页面才可以重新写字,所以我又做成了页面,功能就正常了。

代码实现:

<template>
    <view class="page">
        <canvas class="mycanvas" canvas-id="mycanvas" @touchstart="touchstart" @touchmove="touchmove" @touchend="touchend"></canvas>
        <view class="button-group">
            <button class="one" @click="clear">清空</button>
            <button class="two" @click="finish">确定</button>
        </view>
    </view>
</template>
 
<script setup>
import { reactive,onMounted } from "vue";
import {
		onReachBottom,
		onShow,onLoad,onReady,onHide
	 } from '@dcloudio/uni-app';
     import http from '@/common/http.js'
     import store from '@/store/index.js'
     import { pathToBase64, base64ToPath } from 'image-tools'

     let state = store()
     let props=defineProps({
     })
     let emits = defineEmits()
        let data=reactive({
            ctx:null, //绘图图像
            points:[],//路径点集合
            path:'',
            flag:false,
        })
        onShow(()=>{
            data.ctx = uni.createCanvasContext("mycanvas",this);   //创建绘图对象
            //设置画笔样式
            data.ctx.lineWidth = 4;
            data.ctx.lineCap = "round"
            data.ctx.lineJoin = "round"
			data.flag=false

        }) 
            //触摸开始,获取到起点
            function touchstart(e){
                let startX = e.changedTouches[0].x;
                let startY = e.changedTouches[0].y;
                let startPoint = {X:startX,Y:startY};
                 
                /* **************************************************
                    #由于uni对canvas的实现有所不同,这里需要把起点存起来
                 * **************************************************/
                data.points.push(startPoint);
                 
                //每次触摸开始,开启新的路径
                data.ctx.beginPath();
            }
             
            //触摸移动,获取到路径点
            function touchmove(e){
                let moveX = e.changedTouches[0].x;
                let moveY = e.changedTouches[0].y;
                let movePoint = {X:moveX,Y:moveY};
                data.points.push(movePoint);//存点
                let len = data.points.length;
                if(len>=2){
                    draw();//绘制路径
                }
                 
            }
             
            // 触摸结束,将未绘制的点清空防止对后续路径产生干扰
            function touchend(){    
                data.points=[];
            }
             
            /* ***********************************************
            #   绘制笔迹
            #   1.为保证笔迹实时显示,必须在移动的同时绘制笔迹
            #   2.为保证笔迹连续,每次从路径集合中区两个点作为起点(moveTo)和终点(lineTo)
            #   3.将上一次的终点作为下一次绘制的起点(即清除第一个点)
            ************************************************ */
             function draw() {
                let point1 = data.points[0]
                let point2 = data.points[1]
                data.points.shift()
                data.ctx.moveTo(point1.X, point1.Y)
                data.ctx.lineTo(point2.X, point2.Y)
                data.ctx.stroke()
                data.ctx.draw(true)
				data.flag=true
            }
            //清空画布
            function clear(){
                uni.getSystemInfo({
                    success: function(res) {
                        let canvasw = res.windowWidth;
                        let canvash = res.windowHeight;
                        data.ctx.clearRect(0, 0, canvasw, canvash);
                        data.ctx.draw(false);
						data.flag=false
                    }
                })
            }
             
            //完成绘画并保存到本地
           function finish(){
				if(!data.flag){
                    http.hint('请签名!')
					return
				}
                // 此API,H5中返回的是base64,APP中返回的是png图片,一个临时路径
                uni.canvasToTempFilePath({
                  canvasId: 'mycanvas',
                  success: function(res) {
                    let path = res.tempFilePath;
                    // 因为我是在APP在,所以需要base64,在这里用image-tools插件把png转为base64
                    pathToBase64(path).then(res=>{
                        // 因为之前后端要svg字符串,但是png直接转svg转不了,所以先转为base64,然后在转svg
//                         let svg=`<?xml version="1.0" standalone="no"?>
// <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
// <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="body_1" width="100%" height="500">

// <g transform="matrix(1.3333334 0 0 1.3333334 0 0)">
//     <image  x="0" y="0" xlink:href="${res}" preserveAspectRatio="none" width="100%" height="500" /></g>
// </svg>`              
                        state.svgPath=res
                        // emits('confirm',true)
                        uni.navigateBack({
                            delta:1
                        })
                    }).catch(err=>{
                        console.log('err :>> ', err);
                    })
                  }
                })
            }
</script>
 
<style scoped lang="less">
.page{
    overflow: hidden;
}
    .button-group{
        position: fixed;
        left: 50rpx;
        bottom: 10rpx;
        display: flex;
        align-items: center;
        // justify-content: space-between;
        // height: 200rpx;
        .one{
            width: 200rpx;
            margin-right: 50rpx;
            border: 1px solid #123454;
        }
        .two{
            width: 400rpx;
            background-color: #123454;
            color: #fff;
        }
    }
    .title{
        height:50upx;
        line-height: 50upx;
        font-size: 16px;
    }
    .mycanvas{
        width: 100%;
        height: calc(100vh - 200upx);
        background-color: #ECECEC;
    }
    .footer{
        font-size: 16px;
        height: 150upx;
        display: flex;
        justify-content: space-around;
        align-items: center;
    }
    .left,.right{
        line-height: 100upx;
        height: 100upx;
        width: 250upx;
        text-align: center;
        font-weight: bold;
        color: white;
        border-radius: 5upx;
    }
    .left{
        background: #007AFF;
    }
    .right{
        background:orange;
    }
</style>

 在H5中,点击确定后输出为base64,在APP中输出为临时路径的png图片,我是在APP中使用,所以还需要把png图片转为base64,格式按后端要求,如果只需要传图片就不需要转base64了,也可以转svg,转svg的我注释掉了,用到的图片转换插件为image-tools

如果大家在使用过程中发现了什么问题,欢迎在评论区指正,谢谢观看!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值