uniapp+canvas实现逐字手写效果

在移动端使用 UniApp 进行逐字手写的功能。用户可以在一个 inputCanvas 上书写单个字,然后在特定时间后将这个字添加到 outputCanvas 上,形成一个逐字的手写效果。用户还可以保存整幅图像或者撤销上一个添加的字。

 

  1. 初始化 Canvas

    • 使用 uni.createCanvasContext 创建画布上下文,设置笔触样式和线条属性。
  2. 触摸事件处理

    • handleTouchStart:捕获触摸开始事件,初始化绘图状态。
    • handleTouchMove:捕获触摸移动事件,实时绘制路径。
    • handleTouchEnd:捕获触摸结束事件,启动定时器准备添加字。
  3. 添加字符

    • addChar 方法将 inputCanvas 的内容绘制到 outputCanvas 上,同时保存字符的路径。
  4. 撤销功能

    • undoChar 方法删除上一个字符,并重新绘制 outputCanvas
  5. 保存和上传图像

    • saveImage 方法将 outputCanvas 的内容保存为图片,并调用 upload 方法上传。

完整代码:

<template><view class="container"><view class="tip"><view class="">请您在区域内逐字手写以下文字,全部写完后点击保存!</view><u-alert style="margin-bottom: 20upx;" :description="ruleForm.sqcn" type = "primary" ></u-alert></view><view class="canvas-container"><canvas canvas-id="inputCanvas" class="input-canvas" @touchstart="handleTouchStart"@touchmove="handleTouchMove" @touchend="handleTouchEnd"></canvas></view><view class="buttons"><u-button text="撤销上一个字" size="normal" type="error" @click="undoChar"></u-button><u-button text="保存" size="normal" type="primary" @click="saveImage"></u-button></view><canvas :style="{ height: outputHeight }" canvas-id="outputCanvas" class="output-canvas"></canvas></view>
</template><script>import fileService from "@/api/file/fileService.js";import knsService from "@/api/kns/knsService"export default {data() {return {isDrawing: false,startX: 0,startY: 0,strokes: [],canvasWidth: 300,canvasHeight: 300,charObjects: [],timer: null,delay: 1000, // 1秒延迟fj: '',outputHeight: '50px',label: '',ruleForm: {}};},mounted() {this.getData()this.initCanvas('inputCanvas');this.initCanvas('outputCanvas');},onLoad(option) {this.label = option.label;},methods: {// 获取承诺async getData() {const res = await knsService.getSettingData();this.ruleForm = res[0];},initCanvas(canvasId) {const context = uni.createCanvasContext(canvasId, this);context.setStrokeStyle('#000');context.setLineWidth(4);context.setLineCap('round');context.setLineJoin('round');context.draw();},handleTouchStart(e) {e.preventDefault(); // 阻止默认滚动行为if (this.timer) {clearTimeout(this.timer);this.timer = null;}const touch = e.touches[0];this.isDrawing = true;this.startX = touch.x;this.startY = touch.y;this.strokes.push({x: touch.x,y: touch.y});},handleTouchMove(e) {e.preventDefault(); // 阻止默认滚动行为if (!this.isDrawing) return;const touch = e.touches[0];const context = uni.createCanvasContext('inputCanvas', this);context.moveTo(this.startX, this.startY);context.lineTo(touch.x, touch.y);context.stroke();context.draw(true);this.startX = touch.x;this.startY = touch.y;this.strokes.push({x: touch.x,y: touch.y});},handleTouchEnd(e) {e.preventDefault(); // 阻止默认滚动行为this.isDrawing = false;this.timer = setTimeout(this.addChar, this.delay);},addChar() {const inputContext = uni.createCanvasContext('inputCanvas', this);uni.canvasToTempFilePath({canvasId: 'inputCanvas',success: (res) => {// 保存这个字符的路径this.charObjects.push(res.tempFilePath);// 清空 inputCanvas 上的内容inputContext.clearRect(0, 0, this.canvasWidth, this.canvasHeight);inputContext.draw();this.redrawOutputCanvas()},});},undoChar() {if (this.charObjects.length > 0) {this.charObjects.pop();this.redrawOutputCanvas();if (this.charObjects.length === 0) {this.outputHeight = 50; // 如果字符对象为空,则将输出画布高度设置为 50}}},redrawOutputCanvas() {const context = uni.createCanvasContext('outputCanvas', this);const charSize = 50; // 调整字符大小const charSpacing = 48; // 调整字符间距const maxCharsPerRow = Math.floor(this.canvasWidth / charSpacing); // 每行最大字符数// 动态设置高度const numRows = Math.ceil(this.charObjects.length / maxCharsPerRow); // 计算行数this.outputHeight = `${numRows * charSize}px`; // 动态计算输出画布的高度console.log(this.outputHeight, this.charObjects.length, 'outputHeight');// 清除画布并设置高度context.clearRect(0, 0, this.canvasWidth, this.outputHeight);// 绘制字符this.charObjects.forEach((charPath, index) => {const rowIndex = Math.floor(index / maxCharsPerRow); // 当前字符的行索引const colIndex = index % maxCharsPerRow; // 当前字符的列索引context.drawImage(charPath, 10 + colIndex * charSpacing, 10 + rowIndex * charSpacing, charSize,charSize);});this.$nextTick(() => {// 一次性绘制所有字符context.draw();})},saveImage() {if (this.charObjects.length === 0) {uni.showToast({icon: "error",title: '请手写文字!'})return false;}uni.canvasToTempFilePath({canvasId: 'outputCanvas',success: (res) => {// 保存图片console.log(res.tempFilePath, 'res.tempFilePath');this.upload(res.tempFilePath);},});},upload(img) {fileService.upload(img).then((res) => {let pages = getCurrentPages()let currPage = pages[pages.length - 1]; //当前页面let prevPage = pages[pages.length - 2]; //上一个页面//修改前一页数据if (prevPage.inputForm) {prevPage.inputForm[this.label] = res} console.log(res, 'res');//返回上一页uni.navigateBack({delta: 1,})});},},};
</script><style scoped lang="scss">.container {display: flex;flex-direction: column;align-items: center;margin-top: 40upx;.canvas-container {position: relative;width: 600upx;height: 600upx;.input-canvas {position: absolute;top: 0;left: 0;width: 100%;height: 100%;border-radius: 10upx;border: 4upx dashed #dddee1;touch-action: none;/* 禁止默认触摸动作 */}}.output-canvas {width: 600upx;/* 设置高度为原来的一半 */border: 2upx solid #dddee1;margin-top: 40upx;}.buttons {display: flex;justify-content: space-around;width: 100%;padding: 0upx 50upx;}button {margin: 20upx;}.tip {view:nth-child(1){color: #FF6F77;font-size: 24upx;margin-bottom: 20upx;}}}
</style>

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

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

相关文章

Top3专业课150满分,怎么考的?

这个系列会邀请上岸学长学姐进行经验分享~ 今天经验分享的同学是小马哥上海交大819的全程班学员&#xff0c;专业课150分满分&#xff0c;这位同学也是819期末考试的第一名&#xff0c;非常厉害&#xff01;大家吸吸欧气&#xff01; 初试成绩单 前言 先介绍下自己&#xff0…

新火种AI|复旦团队在“冷冻人脑”领域获得重大进展!人工智能是否会对此形成助力?

​在低温医学领域&#xff0c;“冷冻人脑”技术的研究和突破既是重点&#xff0c;也是难点。因为这项技术关乎着人类是否可以取得一个令人瞩目的突破——人类的生命是否能够得到延续。 早几年&#xff0c;诸如“利用人体冷冻技术将身患绝症的病人保存十几年&#xff0c;几十年…

C# 文件清理

/// <summary>/// 定期清除文件/// </summary>/// <param name"fileDirect">文件夹</param>/// <param name"postFix">文件后缀</param>/// <param name"saveDay">保存天数</param>private voi…

IntelliJ IDEA集成Baidu Comate,商城系统支付交易功能开发实战

文章目录 Baidu Comate介绍安装配置体验安装插件配置体验注释生成代码技术问答 实战设计表生成代码导入数据 总结 Baidu Comate介绍 在科技互联网飞速发展的今天&#xff0c;百度凭借其深厚的技术积累和创新能力&#xff0c;推出了一款名为Baidu Comate智能代码助手的产品。该…

文章解读与仿真程序复现思路——电力系统保护与控制EI\CSCD\北大核心《基于改进粒子滤波的锂离子电池剩余寿命预测 》

本专栏栏目提供文章与程序复现思路&#xff0c;具体已有的论文与论文源程序可翻阅本博主免费的专栏栏目《论文与完整程序》 论文与完整源程序_电网论文源程序的博客-CSDN博客https://blog.csdn.net/liang674027206/category_12531414.html 电网论文源程序-CSDN博客电网论文源…

Windows 10x64 IoT Enterprise LTSC 2021

打KB5036892补丁&#xff0c;升级版本19044.4291&#xff0c;打简体中文补丁包&#xff0c;系统后续升级需要升级英文补丁&#xff0c;需要重新打中文补丁包&#xff0c;系统禁用升级。禁用打印机服务&#xff0c;需要安装打印机的自行打开服务Print Spooler。 链接&#xff1a…

【SqL】数据库脚本编写规范和指南

编写本文档的目的是保证在开发过程中产出高效、格式统一、易阅读、易维护的SQL代码。 1 编写目的 2 SQL书写规范 3 SQL编写原则 软件全套资料获取进主页或者本文末个人名片直接获取。

Spring AOP的实操 + 原理(动态代理)

1 什么是Spring AOP 要想知道Spring AOP那必然是是要先知道什么是AOP了: AOP&#xff0c;全称为 Aspect-Oriented Programming&#xff08;面向切面编程&#xff09;&#xff0c;是一种编程范式&#xff0c;用于提高代码的模块化&#xff0c;特别是横切关注点&#xff08;cros…

钡铼BL205分布式IO在精密机械加工自动化中的精准控制OPC UA

随着工业自动化技术的不断发展&#xff0c;精密机械加工领域对于高效、精准的控制需求日益增加。在这一背景下&#xff0c;钡铼BL205分布式IO的出现为精密机械加工自动化注入了新的活力和可能性。本文将探讨钡铼BL205分布式IO在精密机械加工自动化中的应用&#xff0c;尤其是其…

使用Python探究OpenAI API

谁没听说过OpenAI?这家人工智能研究实验室因其著名的产品ChatGPT而改变了世界。它改变了AI实施领域&#xff0c;许多公司现在急于成为下一大热点。 尽管竞争激烈&#xff0c;OpenAI仍然是任何生成式AI业务需求的首选公司&#xff0c;因为它拥有最好的模型和持续的支持。该公司…

在使用LabVIEW控制多个串口设备进行数据读取时,读取时间过长

在使用LabVIEW控制多个串口设备进行数据读取时&#xff0c;如果发现数据更新时间超过5秒&#xff0c;可以从以下几个方面进行分析和解决&#xff1a; 1. 串口配置与通信参数 确保每个串口的通信参数&#xff08;波特率、数据位、停止位、校验位等&#xff09;配置正确&#x…

【Spring Security系列】权限之旅:SpringSecurity小程序登录深度探索

作者&#xff1a;后端小肥肠 创作不易&#xff0c;未经允许严禁转载。 姊妹篇&#xff1a; 【Spring Security系列】Spring SecurityJWTRedis实现用户认证登录及登出_spring security jwt 退出登录-CSDN博客 1. 前言 欢迎来到【Spring Security系列】&#xff01;在当今数字化…

识别剪贴板的内容并且添加磁力头

有时候复制的磁力链接并没有磁力头&#xff0c;而只有后面的内容&#xff0c;这个时候就必须给磁力链接添加开头magnet:xturn:btih:下载软件才能识别&#xff0c;如果经常需要这么做比较麻烦&#xff0c;于是我写了一个自动添加磁力头的小软件&#xff0c;运行即可自动添加&…

记录一个写SpringBoot中Hive数据可以正常提取但无法存到MySQL的bug

【背景】 我正在用SpringBoot框架写一个数据治理项目&#xff0c;目前所处阶段是将hive和hdfs中的元数据提取出来&#xff0c;存储到MySQL中&#xff0c;我的hive和hdfs上的数据存储在三台Linux服务器上&#xff08;hadoop102-104&#xff09;&#xff0c;MySQL在我本地Window…

JAVA 转 Golang——速通 Golang 基础

文章目录 1. 前言&#xff1a;2. go的下载与配置3. Golang 目录结构4. Golang 的基础语法4.1. 变量声明4.2. 输入输出4.3. 条件控制4.4. 数组和切片4.5. 映射表 1. 前言&#xff1a; 根据鼠鼠的实习投递经历&#xff0c;由于越来越多中大型公司都使用 Golang&#xff0c;在现在…

vue + SpringBoot + flowable 实现工作流审批功能 (流程图部署)

目录 搭建前端vue项目 vue init webpack project_name 初始化项目 导入 element-ui 框架 npm install element-ui -s 设置 element-ui 全局配置 编辑 main.js 文件 import ElementUI from "element-ui"; // ui框架导入 import element-ui/lib/theme-chal…

文心大模型4.0创建智能体:资深研发专家一对一辅导

目录 前言 一、什么是文心智能体平台&#xff1f; 1、通过平台能做什么 2、平台的优势 3、智能体类型 二、如何访问和使用这个智能体&#xff1f; 1、零代码开发&#xff1a;一句话创建智能体 2、资深研发专家一对一辅导智能体介绍 总结 前言 在当今快节奏和高度竞争的…

Sping源码(八)—registerBeanPostProcessors

序言 之前我们用大量的篇幅介绍过invokeBeanFactoryPostProcessors()方法的执行流程。 而invokeBeanFactoryPostProcessors的主要逻辑就是遍历执行实现了BeanDefinitionRegistryPostProcesso类(主要是针对BeanDefinition的操作)和BeanFactoryPostProcessor(主要针对BeanFacrot…

干货 | 什么是单相感应电机控制器?一文带你看感应交流电机解决方案KP86202

单相感应电机控制器是一种用于控制单相感应电机运行的电子设备。单相感应电机是一种常见的电动机类型&#xff0c;广泛应用于家用电器、商业设备以及轻工制造等领域。 单相感应电机控制器通常包括电源模块、控制逻辑模块和功率输出模块。其主要功能是对单相感应电机进行启停、…

如何生成Github Badge徽章图标

如何生成徽章Badge 什么是徽章(Badge)生成小徽章shields网站开源项目的徽章lib版本徽章代码测试覆盖度开源协议Github workflow的徽章 开源代码实践效果py-enumjs-enumerate 什么是徽章(Badge) 在开源项目的README中&#xff0c;经常会见到一些徽章(Badge)小图标&#xff0c;如…