表格技术七十二变丨手把手教你用Canvas电子表格做电子签名
myzbx 2025-05-05 17:36 32 浏览
日常生活工作学习中,大家对电子表格必定不陌生。从工作数据汇总分析到出门收据各种电子发票,这些都是由电子表格制作出来的。
不过大家对电子表格的印象可能停留在这里:
标准行列数据统计的表格样式。但其实,表格也可以是这样的:
工作中遇到需要实现的表格情况往往比大家想象的要更加复杂,最近我们在做客户支持的工作过程中遇到了一个客户,他需要借助电子表格表格实现合同中的电子签名。
电子签名通俗来说就是通过技术手段实现在电子文档上加载电子形式的签名,其作用类似于纸质合同上的手写签名或加盖的公章。在企业工作流审批、请柬、单据保全等场景应用广泛。
在经济活跃跨区域化现象越来越多的今天,作为电子表格的一个重要使用场景,电子合同可以实现异地签约,签署的时间第点更加自由;面对大批量的合同签署也可以轻松解决;同时传统纸质合同的管理更加方便,避免了纸质合同因保存管理问题而出现损坏。
而今天,客户在实际项目中需要实现的内容长这样:
看到这里,有些小伙伴可能会说这有什么难的,虽然这个东西长相酷似word,
但不就是电子表格去掉边框线吗?
如果只是简单的表格框内容,下段代码就可以简单的实现表格的绘制。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>02Canvas案例-绘制表格</title>
</head>
<body>
<div id="container">
<canvas id="cavsElem">
</canvas>
</div>
<script>
(function(){
var canvas=document.querySelector('#cavsElem');
var ctx=canvas.getContext('2d');
canvas.width=600;
canvas.height=600;
canvas.style.border='1px solid green';
var rectH=10;
var rectW=20;
ctx.lineWidth=.5;
//绘制表格
// 第一步: 绘制横线
for(var i=0;i<canvas.width;i++){
ctx.moveTo(rectW*i,0);
//如果不设置moveTo,当前画笔没有位置
ctx.lineTo(rectW*i,canvas.height);
}
//第二步:绘制竖线:如果绘制的格子的宽高相等,可以将for循环放到一个里面;
for(var i=0;i<canvas.height;i++){
ctx.moveTo(0,rectH*i);
ctx.lineTo(canvas.width,rectH*i);
}
ctx.stroke();
}())
</script>
</body>
</html>
但是放大仔细看看,就会发现情况并不如我们所想的这么简单。
在这个合同中,我们除了要隐藏边框线,还要考虑边缘留白、图片跨越、页面滚动后截图不全等问题。 而借助电子表格在数据处理和分析方面天生具备的优势,可以很容易的实现电子签名功能。
我们今天就一起来尝试通过基于Canvas的电子表格来实现电子签名并导出PDF的项目开发需求。
环境准备
- 环境准备:安装SpreadJS 前端表格插件,并通过插件绘制canvas画布。
2. 初始化Spread工作簿,并导入合同模板
3. 创建Canvas画布并引用esign.js画法实现手写签名区域
4. 通过自定义超链接跳转命令,签名区域呼出
5. 将签名区域转化为图片设置为背景图片
6. 使用SpreadJS提供的导出PDF接口将签署的文件导出
电子签名的实现
初始化Spread工作簿
1、引入以下文件
<link rel="stylesheet" type="text/css" href="node_modules/@grapecity/spread-sheets/styles/gc.spread.sheets.excel2013white.css">
<script src="node_modules/@grapecity/spread-sheets/dist/gc.spread.sheets.all.min.js" type="text/javascript"></script>
<script src="new2.ssjson" type="text/javascript"></script>
2、创建用于承载SpreadJS的DOM
<div id="ss" class="sample-spreadsheets" style="height: 900px;">
3、用JS获取DOM对象并进行初始化
var spread = new GC.Spread.Sheets.Workbook(document.getElementById("ss"));
4、导入合同模板
spread.fromJSON(str);
到这里,我们Spread工作簿已经初始化完成了。当然,你也可以添加对应的CSS调整表单的大小。
关于模板的制作,你可以在在线表格编辑器中根据需求进行绘制,并导出为ssjson文件并通过fromJSON导入到我们的表单中。
接下来,用Canvas画布来实现手写签名区域。
手写签名区域
1、首先,我们先创建签名区域的DOM元素,并定义一个Canvas画布,默认情况下不显示。
<div class="containter" id="box" style="display: none;">
<div class="canvasDiv">
<div id="editing_area">
<canvas id="canvasEdit"></canvas>
</div>
</div>
<div class="btnDiv">
<a id="sign_clear" class="clearBtn">清空</a>
<a id="sign_clear2" class="clearBtn">签署</a>
</div>
</div>
2、引用esign.js和jQuery。Esign.js是一种用鼠标在canvas上绘制的画法。
<script type="text/javascript" src="js/esign.js"></script>
<script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>
3、初始化
$(document).esign("canvasEdit", "sign_show", "sign_clear", "sign_ok");
$(document).on('click', '#sign_clear2', takeScreenshot);
Canvas画布中利用自定义单元格,理论上也是能开发出能够直接签名的单元格。
用户可以直接在单元格进行签名,有兴趣的小伙伴可以尝试用自定义单元格实现。
自定义超链接命令
1、创建超链接
sheet.setValue(32, 10, "审核人签名:")
sheet.setHyperlink(32, 10, { command: "popup" });
2、为超链接设置命令,点击弹出画布
spread.commandManager().register("popup",{
canUndo: true,
execute: function (context, options, isUndo) {
var Commands = GC.Spread.Sheets.Commands;
// 在此加cmd
options.cmd = "popup";
if (isUndo) {
Commands.undoTransaction(context, options);
return true;
} else {
Commands.startTransaction(context, options);
document.getElementById("box").style.display = "block";
Commands.endTransaction(context, options);
return true;
}
}
});
指定DOM转为图片并设置为单元格背景
1、利用canvas的接口,将画布转为base64,调用接口设置背景
function convertCanvasToImage(canvas) {
return canvas.toDataURL("image/png");
};
function takeScreenshot() {
var canvas = document.getElementById("canvasEdit");
var imgUrl = convertCanvasToImage(canvas); //截取图片路径,该路径为服务器参数
var sheet = spread.getSheet(0);
sheet.getCell(32,13).backgroundImage(imgUrl);
sheet.getCell(35,13).backgroundImage(imgUrl);
sheet.getCell(38,13).backgroundImage(imgUrl);
}
2、关闭签名画布
function tishi(){
document.getElementById("box").style.display = "none";
}
setTimeout(tishi,100)
将电子签名导出PDF
上面已经实现了电子签名内容,但是我们都知道合同需要有打印输出功能,接下来我们继续介绍如何使用pdf打印输出电子签名。
1、引用PDF拓展文件以及filesaver
<script src="node_modules/@grapecity/spread-sheets-pdf/dist/gc.spread.sheets.pdf.min.js" type="text/javascript"></script>
<script src="node_modules/file-saver/dist/FileSaver.min.js" type="text/javascript"></script>
2、调用接口导出PDF
spread.savePDF(function (blob) {
var fileName = 'download';
saveAs(blob, fileName + '.pdf');
}, function (error) {
console.log(error);
}, {
title: 'Test Title',
});
注意:导出中文字符需要注册对应的字体。
总结
以上,我们实现了基于Canvas电子表格实现电子签名并使用PDF导出打印的完整功能,由于Canvas完全取代了页面的dom结构,因此打印时不需要遍历要打印的dom节点的子节点,也不必将每一页所能打印的dom节点高度累加,这样做可以不用再计算dom节点的高度,大幅节省了系统性能,同时实现了较细的页面颗粒度,不会造成大块空白的情况,完全模拟出了word生成pdf的那种效果。同时,也解决了我们在文章开头中提到缘留白、图片跨越、页面滚动后截图不全三个问题。
关注我们的账号,接下来还会为大家带来更多在工作项目中遇到的有趣内容。
来都来了,点个赞再走吧吧~
相关推荐
- 零基础入门AI智能体:详细了解什么是变量类型、JSON结构、Markdown格式
-
当品牌跳出固有框架,以跨界联动、场景创新叩击年轻群体的兴趣点,一场关于如何在迭代中保持鲜活的探索正在展开,既藏着破圈的巧思,也映照着与新一代对话的密码。在创建AI智能体时,我们会调用插件或大模型,而在...
- C# 13模式匹配:递归模式与属性模式在真实代码中的性能影响分析
-
C#13对模式匹配的增强让复杂数据处理代码更简洁,但递归模式与属性模式的性能差异一直是开发者关注的焦点。在实际项目中,选择合适的模式不仅影响代码可读性,还可能导致执行效率的显著差异。本文结合真实测试...
- 零基础快速入门 VBA 系列 6 —— 常用对象(工作簿、工作表和区域)
-
上一节,我介绍了VBA内置函数以及如何自动打字和自动保存文件。这一节,我们来了解一下Excel常用对象。Excel常用对象Excel有很多对象,其中最常用也最重要的包括以下3个:1.Workbo...
- 不同生命数字的生肖龙!准到雷普!
-
属龙的人总在自信爆棚和自讨苦吃之间反复横跳?看完这届龙宝宝的日常我悟了。属龙的人好像天生自带矛盾体:领导力超强可人缘时好时坏,工作雷厉风行却总在爱情里翻车。关键年份的龙性格差异更大——76年龙靠谱但不...
- 仓颉编程语言基础-面向对象编程-属性(Properties)
-
属性是仓颉颉中一种强大的机制,它允许你封装对类(或接口interface、结构体struct、枚举enum、扩展extend)内部状态的访问。它看起来像一个普通的成员变量(字段),但在其背后,它通过...
- Python中class对象/属性/方法/继承/多态/魔法方法详解
-
一、基础入门:认识类和对象1.类和对象的概念在Python中,类(class)是一种抽象的概念,用于定义对象的属性和行为,而对象(也称为实例)则是类的具体表现。比如,“汽车”可以是一个类,它有...
- VBA基础入门:搞清楚对象、属性和方法就成功了一半
-
如果你刚接触VBA(VisualBasicforApplications),可能会被“对象”“属性”“方法”这些术语搞得一头雾水。但事实上,这三个概念是VBA编程的基石。只要理解它们之间的关系,...
- P.O类型文推荐|年度编推合集(一百九十五篇)
-
点击左上方关注获取更多精彩推文目录2019年度编推35篇(1V1)《悖论》作者:流苏.txt(1V1)《桂花蒸》作者:大姑娘浪.txt(1V1)《豪门浪女》作者:奚行.txt...
- Python参数传递内存大揭秘:可变对象 vs 不可变对象
-
90%的Python程序员不知道,函数参数传递中可变对象的修改竟会导致意想不到的副作用!一、参数传递的本质:对象引用传递在Python中,所有参数传递都是对象引用的传递。这意味着函数调用时传递的不是对...
- JS 开发者必看!TC39 2025 最新动向,这些新语法要火?
-
大家好,很高兴又见面了,我是"高级前端进阶",由我带着大家一起关注前端前沿、深入前端底层技术,大家一起进步,也欢迎大家关注、点赞、收藏、转发,您的支持是我不断创作的动力。TC39第...
- 2025 年值得尝试的 5 个被低估的 JavaScript 库
-
这些JavaScript库可能不会在社交媒体或HackerNews上流行起来,但它们会显著提高您的工作效率和代码质量。JavaScript不再只是框架。虽然React、Vue和Sv...
- Python自动化办公应用学习笔记30—函数的参数
-
一、函数的参数1.形参:o定义:在函数定义时,声明在函数名后面括号中的变量。o作用:它们是函数内部的占位符变量,用于接收函数被调用时传入的实际值。o生命周期:在函数被调用时创建,在函数执...
- 16种MBTI人格全解析|测完我沉默了三秒:原来我是这样的人?
-
MBTI性格测试火了这么久,你还不知道自己是哪一型?有人拿它当社交话题,有人拿它分析老板性格,还有人干脆当成择偶参考表。不废话,今天我一次性给你整理全部16种MBTI人格类型!看完你不仅能知道自己是谁...
- JS基础与高级应用: 性能优化
-
在现代Web开发中,性能优化已成为前端工程师必须掌握的核心技能之一。本文从URL输入到页面加载完成的全过程出发,深入分析了HTTP协议的演进、域名解析、代码层面性能优化以及编译与渲染的最佳实践。通过节...
- 爱思创CSP-J/S初赛模拟赛线上开赛!助力冲入2024年CSP-J/S复赛!
-
CSP-J/S组初赛模拟赛爱思创,专注信奥教育19年,2022年CSP-J/S组赛事指定考点,特邀NOIP教练,开启全真实CSP-J/S组线上初赛模拟大赛!一、比赛对象:2024年备考CSP-J/S初...
- 一周热门
- 最近发表
-
- 零基础入门AI智能体:详细了解什么是变量类型、JSON结构、Markdown格式
- C# 13模式匹配:递归模式与属性模式在真实代码中的性能影响分析
- 零基础快速入门 VBA 系列 6 —— 常用对象(工作簿、工作表和区域)
- 不同生命数字的生肖龙!准到雷普!
- 仓颉编程语言基础-面向对象编程-属性(Properties)
- Python中class对象/属性/方法/继承/多态/魔法方法详解
- VBA基础入门:搞清楚对象、属性和方法就成功了一半
- P.O类型文推荐|年度编推合集(一百九十五篇)
- Python参数传递内存大揭秘:可变对象 vs 不可变对象
- JS 开发者必看!TC39 2025 最新动向,这些新语法要火?
- 标签列表
-
- HTML 简介 (30)
- HTML 响应式设计 (31)
- HTML URL 编码 (32)
- HTML Web 服务器 (31)
- HTML 表单属性 (32)
- HTML 音频 (31)
- HTML5 支持 (33)
- HTML API (36)
- HTML 总结 (32)
- HTML 全局属性 (32)
- HTML 事件 (31)
- HTML 画布 (32)
- HTTP 方法 (30)
- 键盘快捷键 (30)
- CSS 语法 (35)
- CSS 轮廓宽度 (31)
- CSS 谷歌字体 (33)
- CSS 链接 (31)
- CSS 定位 (31)
- CSS 图片库 (32)
- CSS 图像精灵 (31)
- SVG 文本 (32)
- 时钟启动 (33)
- HTML 游戏 (34)
- JS Loop For (32)