V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
GrapeCityChina
V2EX  ›  分享发现

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

  •  
  •   GrapeCityChina · 2021-08-11 13:40:46 +08:00 · 661 次点击
    这是一个创建于 990 天前的主题,其中的信息可能已经有所发展或是发生改变。

    转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具、解决方案和服务,赋能开发者。

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

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

    图片 1.png

    标准行列数据统计的表格样式。

    但其实,表格也可以是这样的:

    3.png

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

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

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

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

    6.png

    看到这里,有些小伙伴可能会说这有什么难的,虽然这个东西长相酷似 word,

    但不就是电子表格去掉边框线吗?

    1.jpg

    如果只是简单的表格框内容,下段代码就可以简单的实现表格的绘制。

    <!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>
    

    但是放大仔细看看,就会发现情况并不如我们所想的这么简单。

    2.jpg

    3.jpg

    4.jpg

    在这个合同中,我们除了要隐藏边框线,还要考虑边缘留白、图片跨越、页面滚动后截图不全等问题。 而借助电子表格在数据处理和分析方面天生具备的优势,可以很容易的实现电子签名功能。

    我们今天就一起来尝试通过基于 Canvas 的电子表格来实现电子签名并导出 PDF 的项目开发需求。

    实现思路

    环境准备

    1. 环境准备:安装 SpreadJS 前端表格插件,并通过插件绘制 canvas 画布。

    1. 初始化 Spread 工作簿,并导入合同模板

    2. 创建 Canvas 画布并引用 esign.js 画法实现手写签名区域

    3. 通过自定义超链接跳转命令,签名区域呼出

    4. 将签名区域转化为图片设置为背景图片

    5. 使用 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>
    

    1 、创建用于承载 SpreadJS 的 DOM

    <div id="ss" class="sample-spreadsheets" style="height: 900px;">

    2 、用 JS 获取 DOM 对象并进行初始化

    var spread = new GC.Spread.Sheets.Workbook(document.getElementById("ss"));

    3 、导入合同模板

    spread.fromJSON(str);

    到这里,我们 Spread 工作簿已经初始化完成了。当然,你也可以添加对应的 CSS 调整表单的大小。

    关于模板的制作,你可以在在线表格编辑器中根据需求进行绘制,并导出为 ssjson 文件并通过 fromJSON 导入到我们的表单中。

    接下来,用 Canvas 画布来实现手写签名区域。

    手写签名区域

    1 、首先,我们先创建签名区域的 DOM 元素,并定义一个 Canvas 画布,默认情况下不显示。

    4.png

    <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>
    
    

    1 、调用接口导出 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 的那种效果。同时,也解决了我们在文章开头中提到缘留白、图片跨越、页面滚动后截图不全三个问题。

    5.jpg

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

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

    目前尚无回复
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   4069 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 05:21 · PVG 13:21 · LAX 22:21 · JFK 01:21
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.