首页 > 其他分享 >如何通过canvas实现粗细不同的电子签名

如何通过canvas实现粗细不同的电子签名

时间:2023-04-24 17:44:34浏览次数:47  
标签:粗细 canvas 鼠标 ctx multi coord 电子签名 绘制

想要实现一个电子签名,可以支持鼠标签名,还能类似书法效果线条有粗有细,同时可以导出成图片.

一、实现连贯的划线

  1)首先需要注册鼠标下压、鼠标放开、鼠标移出和鼠标移动事件,通过鼠标下压赋值downFlag标记开始绘制

  2)  鼠标移动时,将当前坐标位置传入绘制方法,通过lineTo方法实现绘制

/**
     * 按下鼠标启动绘制标记
     **/
    canvas.addEventListener('mousedown', e => {
      preCoord = [e.offsetX, e.offsetY, new Date().getTime()];
      downFlag = true;
    })

    /**
     * 鼠标松开结束绘制
     **/
    canvas.addEventListener('mouseup', e => {
      downFlag = false;
    })
    canvas.addEventListener('mouseout', () => {
      downFlag = false;
    })

    /**
     * 鼠标移动时绘制文字
     **/
    canvas.addEventListener('mousemove', e => {
      if (downFlag) {
        const coord = [e.offsetX, e.offsetY];
        drawSign(coord);
        preCoord = [...coord, new Date().getTime()];
      }
    })

  3) 启动线的绘制,其中注释的线段

function drawSign(coord) {
      // 为了实现阶段性线的不同粗细程度,所以每次绘制必须重新开始一段路径
      ctx.beginPath();
      getColor(coord);

      ctx.lineTo(...preCoord);
      ctx.lineTo(...coord);

      ctx.stroke();
      ctx.closePath();
    }

 

二、为了美观,实现书法类似的效果,需要设每个线段设置不同的宽度才可以

  1)根据每两个事件点的时间差计算一个倍数关系,然后乘以一个基础宽度就可以得到不同的宽度,本文实现的效果是绘制越慢线条越宽,越快线条越窄

  2) 设置线的连接方式和线端点效果,使整个线条看起来更加圆滑

/**
     * 根据绘制时间差设置绘制线宽
     **/
    function getColor(coord) {
      if (preCoord.length === 0) {
        return;
      }
      // 当前是计算的每两个点的时间差是五毫秒的倍数
      const tempMulti = (new Date().getTime() - preCoord[2]) / 5;
      if (tempMulti > multi) {
        multi = multi * 1.4;
      } else {
        multi = multi * 0.9;
      }
      if (multi > 5) {
        multi = 5;
      }
      if (multi < 1) {
        multi = 1;
      }
      ctx.lineWidth = 2 * multi;
      
      // 通过设置连线效果和线端点效果可以使线条看起来更圆滑
      ctx.lineCap = 'round';
      ctx.lineJoin = 'round';
      ctx.strokeStyle = 'rgba(153, 153, 153, 1)';
    }

三、下面奉上完整的代码和效果图

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>signature</title>
</head>
<body style="text-align: center;">
  <div>
    <button id="output" style="margin: 10px;">导出</button>
  </div>
  
  <canvas id="canvas" width="800" height="800" style="width: 800px;height: 800px;border: 1px solid gray;"></canvas>
</body>
</html>
<script type="module">
  window.onload = (() => {
    const canvas = document.getElementById('canvas');
    const ctx = canvas.getContext('2d');

    // 上一个绘制点的坐标
    let preCoord = [];
    // 绘制启动标志
    let downFlag = false;
    // 初始线宽
    let multi = 5;
    
    /**
     * 按下鼠标启动绘制标记
     **/
    canvas.addEventListener('mousedown', e => {
      preCoord = [e.offsetX, e.offsetY, new Date().getTime()];
      downFlag = true;
    })

    /**
     * 鼠标松开结束绘制
     **/
    canvas.addEventListener('mouseup', e => {
      downFlag = false;
    })
    canvas.addEventListener('mouseout', () => {
      downFlag = false;
    })

    /**
     * 鼠标移动时绘制文字
     **/
    canvas.addEventListener('mousemove', e => {
      if (downFlag) {
        const coord = [e.offsetX, e.offsetY];
        drawSign(coord);
        preCoord = [...coord, new Date().getTime()];
      }
    })

    document.getElementById('output').addEventListener('click', e => {
      const a = document.createElement('a');
      a.href = canvas.toDataURL('image/png');
      a.download = 'signature.png';
      a.click();
    })
    
    /**
     * 根据绘制时间差设置绘制线宽
     **/
    function getColor(coord) {
      if (preCoord.length === 0) {
        return;
      }
      // 当前是计算的每两个点的时间差是五毫秒的倍数
      const tempMulti = (new Date().getTime() - preCoord[2]) / 5;
      if (tempMulti > multi) {
        multi = multi * 1.4;
      } else {
        multi = multi * 0.9;
      }
      if (multi > 5) {
        multi = 5;
      }
      if (multi < 1) {
        multi = 1;
      }
      ctx.lineWidth = 2 * multi;
      
      // 通过设置连线效果和线端点效果可以使线条看起来更圆滑
      ctx.lineCap = 'round';
      ctx.lineJoin = 'round';
      ctx.strokeStyle = 'rgba(153, 153, 153, 1)';
    }

    function drawSign(coord) {
      // 为了实现阶段性线的不同粗细程度,所以每次绘制必须重新开始一段路径
      ctx.beginPath();
      getColor(coord);

      ctx.lineTo(...preCoord);
      ctx.lineTo(...coord);

      ctx.stroke();
      ctx.closePath();
    }
  })
</script>
完整代码

 

标签:粗细,canvas,鼠标,ctx,multi,coord,电子签名,绘制
From: https://www.cnblogs.com/codeOnMar/p/17349988.html

相关文章

  • 浅谈两种前端截图方式:Canvas截图 vs SVG截图
    背景如今很多网站都引入截图功能,可用于问题反馈、内容分享等实用需求,而前端截图也不知不觉成为了首选。今天为大家推荐两种前端截图方式,虽然有些局限,但是也能应付大部分项目需求。Canvas截图:html2canvasSVG截图:rasterizehtml原理首先来谈下两种前端截图方式的原理,虽然实现方式不......
  • 微信小程序使用canvas2d实现拼图游戏
    根据周文洁微信小程序开发实战编写,但是微信更新了canvas接口,按照书上写的已经不能使用了。目录 改进后如下:app.wxss:1.container{2height:100vh;3color:#E64340;4font-weight:bold;5display:flex;6flex-direction:column;7align-i......
  • Failed to execute 'toDataURL' on 'HTMLCanvasElement': Tainted canvases may not b
    最近在使用图片导出base64的时候遇到下面的报错我的代码如下letmyImage=newImage();myImage.src=imgSrcData;myImage.crossOrigin='Anonymous';网上查阅资料,都说给图片设置 crossOrigin值为 Anonymous就可以了,我这么设置,但是依然不行,后来才发现,设置这个crossO......
  • 手动下载canvas、地图的当前画面(下载为图片)
    functionDownloadImg(){//使用前需要npm下载html2canvas并引入组件中才能使用html2canvas(document.querySelector("#map"),{//参数为容器的dom//转换为图片backgroundColor:"#ffffff",//设置截图的背景色......
  • canvas绘制多边形
    1、获取ctx,id为canvasId的canvas标签document.getElementById("canvasId")。getXO你text("2d");2、确定尺寸3、添加点击画布的监听ctx.addEventListener("click",(e)=>that.addLis(e),false);//单击添加多边形顶点addEventListener("dblclick",(e)=>that.......
  • canvas和svg区别
    Canvas描述:通过Javascript来绘制2D图形。是逐像素进行渲染的。其位置发生改变,会重新进行绘制。SVG描述:一种使用XML描述的2D图形的语言SVG基于XML意味着,SVGDOM中的每个元素都是可用的,可以为某个元素附加Javascript事件处理器。在SVG中,每个被绘制的图形均被视为对象。如果SVG......
  • html2canvas插件使用小结
    简介html2canvas能够实现在用户浏览器端直接对整个或部分页面进行截屏。这个html2canvas脚本将当页面渲染成一个canvas图片,通过读取DOM并将不同的样式应用到这些元素上实现。它不需要来自服务器任何渲染,整张图片都是在客户端浏览器创建。当浏览器不支持Canvas时,将采用Flashcanv......
  • Mapboxgl Chrome75版本下发现问题:中文标签无法加载,由Canvas的measureText()方法导致
    很刁钻的问题,排查了好久。我自己开发测试用的浏览器(版本为112)运行正常,在老版本(75)谷歌浏览器报错如下:mapbox-gl.js:32UncaughtTypeError:Failedtoexecute'getImageData'on'CanvasRenderingContext2D':Valueisnotoftype'long'.atMp.TinySDF.draw(mapbox-gl.j......
  • vue pc使用htmlCanvas Jspdf 实现点击将页面生成图片并转成pdf下载
    <template><divid="main"ref="workbench"v-loading="loading"class="echartsPdf">需要的内容</div></template><script>importhtml2canvasfrom'html2canvas'importJspdf......
  • HTML5 Canvas和SVG的区别
    Canvas主要是用笔刷来绘制2D图形的。SVG主要是用标签来绘制不规则矢量图的。相同点:都是主要用来画2D图形的。区别:SVG画的是矢量图,Canvas画的是位图;SVG节点过多时渲染慢,Canvas性能更好一点,但写起来更复杂;SVG支持分层和事件,Canvas不支持,但是可以用库实现。......