uniapp,使用canvas制作一个签名版

news2024/12/25 9:34:50

先看效果图

 我把这个做成了页面,没有做成组件,因为之前我是配合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。

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/913487.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Docker(二) Docker容器

在docker中的容器都是由镜像所创建的&#xff0c;一个镜像可以创建多个容器。 一、调试Docker 启动Docker systemctl start docker 查看Docker中有哪些镜像 docker images 下载镜像 docker pull hello-world 运行镜像 docker run hello-world 出现 Hello from Docker! 这…

【方法】分卷压缩文件的密码忘记了怎么办?

压缩分卷压缩文件&#xff0c;和压缩成单个压缩文件一样&#xff0c;都是可以设置密码&#xff0c;保护文件不能被随意打开。 解压带有密码的分卷压缩文件&#xff0c;只需要解压第一个分卷文件&#xff0c;并输入原本设置的密码就可以解压全部分卷。但要是密码忘记了&#xf…

家装小程序制作丨家装行业必备媒介

在当今互联网时代&#xff0c;小程序已经成为许多企业和个人的首选&#xff0c;用于推广和销售产品或服务。对于家装行业来说&#xff0c;自有一款专属的家装小程序能够带来诸多好处。本文将探讨家装小程序制作的优点&#xff0c;并简要介绍相关的流程。 优点 提升用户体验&am…

Windows系统下安装Nginx以及相关端口问题的解决方法详解

系列文章目录 安装Tomac服务器——安装步骤以及易出现问题的解决方法 文章目录 系列文章目录 一 背景 二 安装 2.1 下载Nginx 2.2 选择Nginx版本 2.3 解压Nginx 三 Nginx的使用 3.1 Nginx基本目录 3.2查看80端口是否被占用 3.3 Nginx启动方式 第一种&#xff1a;双…

win10家庭版远程桌面补丁_rdp wrapper

RDP Wrapper Library 就是可以帮你在 Windows 7、Windows 8、Windows 10 家庭版中打开远程桌面的工具。 1、把电脑上打开的安全软件与杀毒软件都关掉&#xff0c;因为这个远程桌面补丁会修改系统文件&#xff0c;所以安全软件可能会拦截。 2、下载RDP Wrapper Library补丁压缩…

RISC-V(1)——RISC-V是什么,有什么用

目录 1. RISC-V是什么 2. RISC-V指令集 3. RISC-V特权架构 4. RiscV的寄存器描述 5. 指令 5.1 算数运算—add/sub/addi/mul/div/rem 5.2 逻辑运算—and/andi/or/ori/xor/xori 5.3 位移运算—sll/slli/srl/srli/sra/srai 5.4 数据传输—lb/lh/lw/lbu/lhu/lwu/sb/sh/sw …

MPLS与SD-WAN哪个更适合企业组网?

MPLS专线和SD-WAN是最为人熟知的两种组网方式&#xff0c;而且二者一个是传统组网方式&#xff0c;一个是新兴产品&#xff0c;所以难免会被放在一起比较。有人会问&#xff0c;MPLS专线和SD-WAN哪个更适合企业组网&#xff1f;其实&#xff0c;MPLS专线和SD-WAN都是企业实现高…

言语理解-中心理解之递进关系及转折关系

例题 例题 例题 记叙&#xff0c;议论多还是 例题 不仅仅依赖程度词&#xff0c;联系下文 例题 例题 例题 例题

​建材商城小程序制作:建材采购更便捷!

建材商城小程序主要用于建材产品的展示、销售和交易。用户可以在小程序中浏览各类建材产品&#xff0c;包括地板、瓷砖、卫浴、灯具等&#xff0c;并获取详细的产品信息、规格参数、价格以及用户评价等。 建材商城小程序优点&#xff1a; 便利的购物体验&#xff1a;建材商城小…

【洛谷】P1163 银行贷款

原题链接&#xff1a;https://www.luogu.com.cn/problem/P1163 目录 1. 题目描述 2. 思路分析 3. 代码实现 1. 题目描述 2. 思路分析 这题需要注意的是利率按月累计这句话&#xff0c;也就是相当于“利滚利”。 我们定义sum变量表示贷款原值&#xff0c;money表示每月支付…

Java调用高德地图API根据详细地址获取经纬度

开发指南&#xff1a;地理/逆地理编码-API文档-开发指南-Web服务 API | 高德地图API 一、首先需要注册成为开发者&#xff0c;注册成功后就可以使用此开放平台。 高德开放平台网址&#xff1a;高德开放平台 | 高德地图API 点击注册&#xff1a; 选择注册方式&#xff0c;注册…

马斯克遭冷遇,Twitter更名近一个月,许多品牌仍未删除蓝鸟标志

根据报道&#xff0c;Twitter更名为X已经近一个月了&#xff0c;但许多主要品牌仍然没有完全删除其营销中的蓝鸟标志。只有宝洁这一家美国广告支出最高的公司在其网站的社交媒体联系信息中将蓝鸟换成了新的X标志。 另外&#xff0c;Expedia和IBM这两家公司在其网站上甚至没有显…

SSM整合-配置类版

目录 一、导入依赖二、SSM整合1.1 WebInit配置类1.2 SpringMvcConfig配置类1.3 SpringConfig配置类1.4 JdbcConfig配置类1.5 MybatisConfig配置类1.6 mybatis-config.xml配置1.7 log4j.xml配置1.8 目录结构 一、导入依赖 <properties><spring.version>5.3.1</sp…

mall :sa-token项目源码解析

文章目录 一、mall开源项目1.1 来源1.2 项目转移1.3 项目克隆 二、Sa-Toekn框架2.1 Sa-Token 简介2.2 分布式后端项目的使用流程2.3 分布式后端项目的使用场景 三、源码解析3.1 集成与配置3.1.1 导入依赖3.1.2 添加配置3.1.3 异常处理3.1.4 存储用户信息 3.2 登录认证3.2.1 配置…

智慧健康杂志智慧健康杂志社智慧健康编辑部2023年第15期目录

智慧医疗 医疗信息化 提高病案首页填写质量&#xff0c;体现病案信息利用价值 张明芳; 1-4 经支气管镜检查联合针吸活检术在肺癌诊断中的临床应用价值 邱洪亮; 5-8 高频超声对距腓前韧带损伤的诊断价值 梁劲松;叶绮婷;曹肖维; 9-12《智慧健康》投稿邮箱&#xff1a…

clickhouse(十四、分布式DDL阻塞及同步阻塞问题)

文章目录 一、分布式ddl 阻塞、超时现象验证方法解决方案 二、副本同步阻塞现象验证解决方案 一、分布式ddl 阻塞、超时 现象 在clickhouse 集群的操作中&#xff0c;如果同时执行一些重量级变更语句&#xff0c;往往会引起阻塞。 一般是由于节点堆积过多耗时的ddl。然后抛出…

第9章:聚类

聚类任务 性能度量 距离度量 非度量距离 原型聚类 有很好的统计学上的意义&#xff0c;但是只能找到椭球形的聚类。 密度聚类 层次聚类

vue插入重复的html内容

vue添加重复的html内容是通过绑定一个数组来v-for循环实现的。 效果展示&#xff1a; 首先创建数组&#xff0c;里面为重复内容的数量&#xff0c;里面默认存在一个初始值。 然后通过v-for来绑定这个数组&#xff0c;循环数据。 通过添加点击事件&#xff0c;来增加或删除数组…

非常好用的Python单行代码详解

概要 有用的 Python 单行代码片段&#xff0c;只需一行代码即可解决特定编码问题&#xff01;在本文中&#xff0c;将分享20 个 Python 一行代码&#xff0c;你可以在 30 秒或更短的时间内轻松学习它们。这种单行代码将节省你的时间&#xff0c;并使你的代码看起来更干净且易于…

docker之Consul环境的部署

目录 一、Docker consul的介绍 1.1 template模板(更新) 1.2 registrator&#xff08;自动发现&#xff09; 1.3 agent(代理) 二.consul的工作原理 三.Consul的特性 四.Consul的使用场景 五.搭建Consul的集群 5.1 需求 5.2 部署consul 5.3 主服务器部署[192.168.19.10…