html5canvas画图有什么用(Html5基于canvas实现电子签名并生成PDF文档)
html5canvas画图有什么用
Html5基于canvas实现电子签名并生成PDF文档前言
电子签名通俗来说就是通过技术手段实现在电子文档上加载电子形式的签名,其作用类似于纸质合同上的手写签名或加盖的公章。虽然电子签名多年来合法性一直遭到质疑,但其在企业工作流审批、请柬、单据保全等场景应用广泛,最近的项目中就有这样一个手写签名并生成PDF文件的需求。
实现思路
- 使用canvas来实现手写签名的功能,然后将canvas转化为图片,贴在签名的位置;
- 将整个需要生成文档的dom区域使用html2canvas插件转成一张大图;
- 使用JsPDF插件将上述图片生成PDF文档;
- 对于文件内容较多的情况,需要合理选择分页位置;
生成签名
1. 在tsx中定义canvas画布
<canvas className={styles.canvas} ref={canvasDom} width="350" height="150" />
注意
:Canvas的宽高必须要使用内联样式定义,这是因为Canvas标签有自己的默认宽高300px×150px。它内联样式定义的width和height是绘画区域(画布)实际宽度和高度,绘制的图形都是在这个上面。如果在style外链文件中定义其width和height,那么这个width和height是Canvas在浏览器中被渲染的高度和宽度。如果Canvas中没有直接定义width和height没或值不正确,就会被设置成默认值{width:300px,height:150px}。所以,如果你在style中外链文件中设置了canvas {width: 200px; height: 200px;},却没有直接在canvas上定义画布宽高,那么此时你输出canvas.height 值依旧为150,canvas.width值依旧为300。也就是一块150×300的画布在200×200的区域渲染,因而图片会出现拉伸、变形等现象。
2. 定义签名函数
const writing = ( beginX: number, beginY: number, stopX: number, stopY: number, ctx: any, ) => { ctx.beginPath(); // 开启一条新路径 ctx.globalAlpha = 1; // 设置图片的透明度 ctx.lineWidth = 3; // 设置线宽 ctx.strokeStyle = 'red'; // 设置路径颜色 ctx.moveTo(beginX, beginY); // 从(beginX, beginY)这个坐标点开始画图 ctx.lineTo(stopX, stopY); // 定义从(beginX, beginY)到(stopX, stopY)的线条(该方法不会创建线条) ctx.closePath(); // 创建该条路径 ctx.stroke(); // 实际地绘制出通过 moveTo() 和 lineTo() 方法定义的路径。默认颜色是黑色。 };
3. 注册监听事件
let beginX: number, beginY: number; const canvas: HTMLCanvasElement = canvasDom.current; const ctx = canvas.getContext('2d'); ctx.fillStyle = '#fff'; ctx.fillRect(0, 0, canvas.width, canvas.height); canvas.addEventListener('touchstart', function(event: any) { event.preventDefault(); // 阻止在canvas画布上签名的时候页面跟着滚动 beginX = event.touches[0].clientX - this.offsetLeft; beginY = event.touches[0].pageY - this.offsetTop; }); canvas.addEventListener('touchmove', (event: any) => { event.preventDefault(); // 阻止在canvas画布上签名的时候页面跟着滚动 event = event.touches[0]; let stopX = event.clientX - canvas.offsetLeft; let stopY = event.pageY - canvas.offsetTop; writing(beginX, beginY, stopX, stopY, ctx); beginX = stopX; // 这一步很关键,需要不断更新起点,否则画出来的是射线簇 beginY = stopY; });
注意
:
- 在注册“touchstart”和“touchmove”事件时,需要阻止默认事件,否则页面会跟着手势上下滑动。
- 移动端的每个触摸事件对象中都包括了touches这个属性,它用于描述位于屏幕上的所有手指的一个列表,获取当前事件对象我们习惯性的使用event = event.touches[0],而在PC端则不需要这么操作。
- offsetLeft值跟offsetTop值跟父级元素没关系,而是跟其上一级的定位元素(除position:static外的所有定位如fixed,relative,absolute元素)有关系。若上一级定位元素都没有除position:staice外的定位,则这个偏移量是相对于body而言的。
需要理清移动端事件对象的几个属性,⏬
clientX/clientY: 触摸位置距离当前body可视区域的x,y坐标;
pageX/pageY: 对于整个页面来说,触摸位置距离body左上角的x,y坐标,包括被scrollTop和scrollLeft的值;
screenX/screenY: 触摸位置距离显示器左边和顶部的x,y距离。
所以,在获取结束点坐标的时候,如果当前页面没有出现滚动条,使用clientY和pageY计算差别不大,如果页面比较长,出现了滚动条,那么就必须要使用pageY来计算。clientX同理,但是移动端通常横向滚动的场景不多,所以用clientX来计算即可。
在签名(touchmove)这个动作过程中,我们需要不断的更新起点位置,否则画出来是这样🔽
其实这个原理和微积分很相似,线段本质上就是由无穷多个小线段组成,宏观一点来看可以把线段当成一个个长度很小的小线段首尾相连构成。所以我一直觉得编程编到最后就是考验一个人的数学能力,交并集、逻辑思维、算法等都能看到数学的身影。最后生成签名如下:
生成PDF文档
html2canvas是一款将HTML代码转换成Canvas的插件,因此需要用一个li包裹住需要打印的内容区域,获得这个dom节点。
html2Canvas(dom, { allowTaint: true, width: dom.offsetWidth, //设置获取到的canvas宽度 height: dom.offsetHeight, //设置获取到的canvas高度 x: 0, //页面在水平方向滚动的距离 y: 0, //页面在垂直方向滚动的距离 })
注意
:此处需要设置width和height及x,y,否则当页面内容只有一页的时候没有问题,但是若页面内容有很多页的时候,就会出现生成的图片只有一小部分有内容的现象。问题就出现在这个配置参数上,若没有设置宽高,则默认只取当前视口的内容,丢弃掉其他超出当前视口的内容。
设置打印参数:
const print = () => { let dom: HTMLElement = pdfDom.current; html2Canvas(dom, { allowTaint: true, width: dom.offsetWidth, //设置获取到的canvas宽度 height: dom.offsetHeight, //设置获取到的canvas高度 x: 0, //页面在水平方向滚动的距离 y: 0, //页面在垂直方向滚动的距离 }).then((canvas: HTMLCanvasElement) => { let canvasWidth = canvas.width; let canvasHeight = canvas.height; let pageHeight = (canvasWidth / 592.28) * 841.89; // 一页A4 pdf能显示的canvas高度 let imgWidth = 595.28; // 设置图片宽度和A4纸宽度相等 let imgHeight = (592.28 / canvasWidth) * canvasHeight;//等比例换算成A4纸的高度 let totalHeight = imgHeight; // 需要打印的图片总高度,初始状态和图片高度相等 let pageData = canvas.toDataURL('image.jpg" alt="html5canvas画图有什么用(Html5基于canvas实现电子签名并生成PDF文档)" border="0" />
选择分页位置
按照上述步骤生成了一份PDF文档,但是当PDF页数有很多的时候,会有这样的问题⏬
可以看到,分页的时候从这段文字这里懒腰截断了。这显然不是我们想要看到的效果,如何解决这个问题呢?🤔
PDF文档页数较少的情况
可以在开发测试的时候预先在将要分页的地方插入一个padding,就是提前预留分页位置
PDF文档页数较多
对于这种情况,笔者尝试遍历要打印的dom节点的子节点,将每一页所能打印的dom节点高度累加,若超过了页面所能承载的最大高度,则将最后一个节点增加padding,打印完毕将样式还原。这种方法因为要计算每个dom节点的高度,非常耗性能,也要求页面dom元素的颗粒度较细,否则会出现一个页面有大块空白,完全无法模拟出word生成pdf的那种效果,所以就不展开讨论了。
到此这篇关于Html5基于canvas实现电子签名并生成PDF文档的文章就介绍到这了,更多相关canvas电子签名内容请搜索开心学习网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持开心学习网!
- canvas绘制动态线条(5分钟实现Canvas鼠标跟随动画背景)
- canvas如何调试(关于canvas.toDataURL 在iOS运行失败的问题解决)
- canvas怎么压缩图片(使用canvas压缩图片大小的方法示例)
- canvas指定区域生成图片(canvas实现图片镜像翻转的2种方式)
- canvas绘制分辨率(通过canvas转换颜色为RGBA格式及性能问题的解决)
- html5canvas功能介绍(Html5 Canvas实现图片标记、缩放、移动和保存历史状态功能 附转换公式)
- canvas心形水波(Canvas波浪花环的示例代码)
- 微信小程序canvas 动画(微信小程序使用canvas绘制钟表)
- canvas绘图画圆基本步骤(利用 Canvas实现绘画一个未闭合的带进度条的圆环)
- html5canvas案例(h5使用canvas画布实现手势解锁)
- js使用canvas(JavaScript canvas实现七彩时钟效果)
- canvas 绘图解决方案(高清屏下canvas重置尺寸引发的问题的解决)
- jscanvas背景色(JavaScript canvas实现代码雨效果)
- canvas 裁剪画布(Canvas图片分割效果的实现)
- html5+canvas动画(解析html5 canvas实现背景鼠标连线动态效果代码)
- canvas时钟代码(canvas实现烟花的示例代码)
- 终于来了,淘宝更改账户名测试中,快去看看你能不能修改(淘宝更改账户名测试中)
- 淘宝支持账号名修改,网友 终于可以 重新做人 了(淘宝支持账号名修改)
- 盘点那些年让人称奇的年终奖 最后一个赢辣条毫无悬念(盘点那些年让人称奇的年终奖)
- 你还没有升职吗 他竟因为几套激励理论,升职了(你还没有升职吗)
- 某知名企业绩效管理体系及薪酬分配体系操作手册(某知名企业绩效管理体系及薪酬分配体系操作手册)
- 职场人改不掉这4个习惯,只会越混越穷,一辈子也翻不了身(职场人改不掉这4个习惯)
热门推荐
- python程序开发过程(python调用外部程序的实操步骤)
- thinkphp5怎么设置当前的模块(thinkPHP5.1框架中Request类四种调用方式示例)
- laravel框架如何查询空的信息(Laravel中validation验证 返回中文提示 全局设置的方法)
- mysql char和varchar区别(MySQL CHAR和VARCHAR存储、读取时的差别)
- dede管理插件(dede编辑器换成kindEditor编辑器的方法图解)
- php换行乱码(php输出文字乱码的解决方法)
- cssdisplay覆盖规律(css解决display:inline-block;产生的缝隙间隙的方法)
- dede搜索模块下载(dede会员列表调用适用于企业、个人)
- laravel服务器设置(基于Laravel-admin 后台的自定义页面用法详解)
- javascript登录转注册界面(JavaScript实现登录窗体)
排行榜
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9