表格技术七十二变丨手把手教你用Canvas电子表格做电子签名

日常生活工作学习中,大家对电子表格必定不陌生。从工作数据汇总分析到出门收据各种电子发票,这些都是由电子表格制作出来的。

不过大家对电子表格的印象可能停留在这里:

标准行列数据统计的表格样式。但其实,表格也可以是这样的:

工作中遇到需要实现的表格情况往往比大家想象的要更加复杂,最近我们在做客户支持的工作过程中遇到了一个客户,他需要借助电子表格表格实现合同中的电子签名。

电子签名通俗来说就是通过技术手段实现在电子文档上加载电子形式的签名,其作用类似于纸质合同上的手写签名或加盖的公章。在企业工作流审批、请柬、单据保全等场景应用广泛。

在经济活跃跨区域化现象越来越多的今天,作为电子表格的一个重要使用场景,电子合同可以实现异地签约,签署的时间第点更加自由;面对大批量的合同签署也可以轻松解决;同时传统纸质合同的管理更加方便,避免了纸质合同因保存管理问题而出现损坏。

而今天,客户在实际项目中需要实现的内容长这样:

看到这里,有些小伙伴可能会说这有什么难的,虽然这个东西长相酷似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的项目开发需求。

环境准备

  1. 环境准备:安装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的那种效果。同时,也解决了我们在文章开头中提到缘留白、图片跨越、页面滚动后截图不全三个问题。

关注我们的账号,接下来还会为大家带来更多在工作项目中遇到的有趣内容。

来都来了,点个赞再走吧吧~

相关文章

HTML+JS 实现手机号码归属地查询功能

手机号码归属地 API 是一种提供号码归属地信息的接口,它通过与运营商和电信数据库交互,根据手机号码查询相关归属地信息并返回结果。通过使用手机号码归属地API,开发者可以轻松地集成号码归属地查询功能到...

172号卡分销系统推荐人手机号操作步骤_号卡分销平台登录_

内容最后可以获取一级名额172号卡分销系统推荐人手机号操作步骤详解172号卡分销系统是一款高效便捷的分销管理工具。本文将详细介绍如何在该系统中操作推荐人的手机号,为您的分销业务提供精准的指导。无论您是...

前端入门——html 表单(炫酷的前端表单和表格)

前言前面已经学习相关html大部分知识,基本上可以制作出简单的页面,但是这些页面都是静态的,一个网站如果要实现用户的互动交流,这时表单就起到关键的作用,表单的用途很多,它主要用来收集用户的相关信息,是...

AI驱动的表单自动填写(ai表格插件)

我们都同意,填写表格是一项枯燥且耗时的任务。如果我们可以创建一个可以为我们填写表格的 AI 助手,让我们将时间投入到更有建设性的任务中,那会怎样?AI 助手将能够通过调用以表单字段为参数的函数来填写表...

HTML表单search、tel和color高级元素的使用

search类型元素search类型的input元素是一种专门用来输入搜索关键词的文本框。其代码格式如下。<input type="search" name="user_...

如何使用java.net.URLConnection发起和处理HTTP请求

技术背景在Java开发中,经常需要与网络进行交互,发送HTTP请求并处理响应。java.net.URLConnection 是Java提供的一个用于处理URL连接的抽象类,通过它可以方便地发起和处理H...