基于 Taro 实现签字,轨迹回放 #98

简介: 基于 Taro 实现签字,轨迹回放 #98

前言


最近公司要在小程序上实现签字笔迹追踪,看了下网上关于Taro如何实现的文章,代码都很乱,很杂,所以,想记录下自己是如何实现的,并附上源码。


效果演示



源码


index.js

import Taro, { Component } from '@tarojs/taro';
import { View, Canvas } from '@tarojs/components';
import './index.less';
// 图片url(或filepath)转base64
const fileTobase64 = path => {
    return 'data:image/jpeg;base64,' + Taro.getFileSystemManager().readFileSync(path, 'base64');
};
// 签字轨迹
const historyTrajectory = {
    historyData:[
        {
            //操作时间
            time: 0,
            /**
            * 操作类型
            * 绘图:mapping
            */
            operation: 'mapping',//操作类型
            /**
            * 绘制路径
            * startX:开始x坐标
            * startY:开y纵坐标
            * currentX:目标位置的 x 坐标
            * currentY:目标位置的 y 坐标
            * z:1代表画线时鼠标处于move状态,0代表处于松开状态
            * colorStr:线的填充颜色
            * pen:笔迹大小
            */
            lineArr: {
                startX: 0,
                startY: 0,
                currentX: 0,
                currentY: 0,
                z: 0,
                colorStr: '#000',
                pen: 3
            }
        }
    ]
};
export default class Signature extends Component {
    constructor(props) {
        super(props);
        this.state = { };
        this.pen = 3;
        this.context = '';
        this.signPath = '';
        this.moveToX = 0;
        this.moveToY = 0;
        // 签字开始时间
        this.startDate = new Date().getTime();
        this.timer = '';
        this.colorStr = '#000';
    }
    componentDidMount() {
        const context = Taro.createCanvasContext('myCanvas', this.$scope);
        this.context = context;
        this.context.draw();
        this.context.lineWidth = this.pen;
    }
    // 手指触摸动作开始
    touchStart = (e) => {
        this.context.lineWidth = this.pen;
        this.context.moveTo(e.changedTouches[0].x, e.changedTouches[0].y);
        this.moveToX = Math.floor(e.changedTouches[0].x);
        this.moveToY = Math.floor(e.changedTouches[0].y);
        historyTrajectory.historyData.push({
            time: new Date().getTime() - this.startDate,
            operation: 'mapping',
            lineArr: {
                startX: this.moveToX,
                startY: this.moveToY,
                currentX: Math.floor(e.changedTouches[0].x),
                currentY: Math.floor(e.changedTouches[0].y),
                z: 1,
                colorStr: this.colorStr,
                pen: this.pen
            }
        });
    }
    // 手指触摸后移动
    touchMove = (e) => {
        const lineToX = Math.floor(e.changedTouches[0].x);
        const lineToY = Math.floor(e.changedTouches[0].y);
        this.context.lineWidth = this.pen;
        this.context.lineTo(lineToX, lineToY);
        this.context.stroke();
        this.context.draw(true);
        this.context.moveTo(lineToX, lineToY);
        historyTrajectory.historyData.push({
            time: new Date().getTime() - this.startDate,
            operation: 'mapping',
            lineArr: {
                startX: this.moveToX,
                startY: this.moveToY,
                currentX: lineToX,
                currentY: lineToY,
                z: 1,
                colorStr: this.colorStr,
                pen: this.pen
            }
        });
        this.moveToX = lineToX;
        this.moveToY = lineToY;
    }
    onTouchEnd = () => {
    }
    // 清空画布
    clearCanvas = () => {
        this.signPath = '';
        this.context.draw();
        historyTrajectory.historyData = [];
        historyTrajectory.historyData.push({
            time: 0,
            operation: 'mapping',
            lineArr: {
                startX: 0,
                startY: 0,
                currentX: 0,
                currentY: 0,
                z: 0,
                colorStr: this.colorStr,
                pen: this.pen
            }
        });
    }
    replay = () => {
        this.signPath = '';
        this.context.draw();
        clearInterval(this.timer);
        const startDate = new Date().getTime();
        let i = 0;
        let len = historyTrajectory.historyData.length;
        this.timer = setInterval(() => {
            const curTime = new Date().getTime() - startDate;
            if (curTime >= historyTrajectory.historyData[i].time) {
                switch (historyTrajectory.historyData[i].operation) {
                    case 'mapping':
                        this.context.setStrokeStyle(historyTrajectory.historyData[i].lineArr.colorStr);
                        this.context.lineWidth = historyTrajectory.historyData[i].lineArr.pen;
                        this.context.moveTo(historyTrajectory.historyData[i].lineArr.startX, historyTrajectory.historyData[i].lineArr.startY);
                        this.context.lineTo(historyTrajectory.historyData[i].lineArr.currentX, historyTrajectory.historyData[i].lineArr.currentY);
                        this.context.stroke();
                        this.context.draw(true);
                        break;
                }
                i++;
            }
            if(i >= len) {
                clearInterval(this.timer);
            }
        }, 1);
    }
    // 获取签字base64
    confirm() {
        Taro.canvasToTempFilePath({
            x: 0,
            y: 0,
            canvasId: 'myCanvas',
            success: (res) => {
                console.log('cofirm:', fileTobase64(res.tempFilePath));
            },
            fail: (error) => {
                console.error('btnConfirm:', error);
            }
        }, this.$scope);
    }
    render() {
        return (
            <View className="signature-container">
                <View className="canvas-area" style={{ height: (Taro.getSystemInfoSync().screenHeight - 150 + 'px') }}>
                    <Canvas
                        canvasId="myCanvas"
                        className="my-canvas"
                        disableScroll="false"
                        onTouchStart={this.touchStart}
                        onTouchMove={this.touchMove}
                        onTouchEnd={this.onTouchEnd}
                    />
                </View>
                <View className="canvas-btn">
                    <View className="btn" onClick={this.confirm}>确认</View>
                    <View className="btn" onClick={this.clearCanvas}>清除</View>
                    <View className="btn" onClick={this.replay}>回放</View>
                </View>
            </View>
        );
    }
}

index.less

.signature-container {
    padding: 24px;
    .canvas-area {
        overflow: hidden;
        width: 100%;
        border: 2px dashed #dcdcdc;
    }
    .my-canvas {
        width: 100%;
        height: 100%;
    }
    .canvas-btn {
        display: flex;
        justify-content: space-around;
        align-items: center;
        margin-top: 24px;
        .btn {
            display: flex;
            justify-content: center;
            align-items: center;
            font-size: 28px;
            border-radius: 5px;
            flex: 1;
            background-color: #359a64;
            color: #fff;
            height: 60px;
            margin: 0 24px;
        }
    }
}


目录
相关文章
|
移动开发 前端开发 CDN
移动端H5引入vconsole进行调试
移动端H5引入vconsole进行调试
892 0
|
存储 前端开发 JavaScript
ahooks 正式发布:值得拥抱的 React Hooks 工具库
ahook定位于一套基于 React Hooks 的工具库,核心围绕 React Hooks 的逻辑封装能力,降低代码复杂度和避免团队的重复建设为背景,共同建设和维护阿里经济体层面的 React Hooks 库。
23948 1
ahooks 正式发布:值得拥抱的 React Hooks 工具库
|
4月前
|
人工智能 数据可视化 前端开发
前后端联调安排工具全景解析:让接口联调有序推进,项目节奏不再脱节
在开发节奏加快的今天,联调失控常导致项目延期。前后端联调安排工具通过接口管理、进度同步、角色权限配置等功能,提升协作效率,保障项目按时交付。
|
机器学习/深度学习 自然语言处理 数据管理
GraphRAG核心组件解析:图结构与检索增强生成
【10月更文挑战第28天】在当今数据科学领域,自然语言处理(NLP)和图数据管理技术的发展日新月异。GraphRAG(Graph Retrieval-Augmented Generation)作为一种结合了图结构和检索增强生成的创新方法,已经在多个应用场景中展现出巨大的潜力。作为一名数据科学家,我对GraphRAG的核心组件进行了深入研究,并在此分享我的理解和实践经验。
562 0
|
开发框架 C语言 开发者
STM32寄存器操作、模板构建
【8月更文挑战第23天】本文档介绍STM32中的寄存器操作方法与模板构建技巧。寄存器是STM32控制内外设的核心,通过直接读写特定内存地址来进行操作。以配置GPIO为例,需定位寄存器地址并写入适当值。文档还提供了一个基本的代码模板,包括包含头文件、时钟配置、外设初始化及主函数流程,帮助开发者快速搭建开发框架,并强调了参考手册的重要性以确保正确使用。
450 1
|
SQL Oracle 关系型数据库
|
SQL 存储 安全
DDL、DML、DCL 的区别
【8月更文挑战第1天】
1268 0
DDL、DML、DCL 的区别
|
Java Spring 容器
@PostConstruct注解学习,最详细的分享教程
@PostConstruct注解学习,最详细的分享教程
421 0
|
JavaScript 前端开发 API
快速实现 iframe 嵌套页面
【6月更文挑战第22天】快速实现 iframe 嵌套页面
webpack——You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file.
webpack——You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file.
2331 0