前端之canvas实现电子签约完成线上签署功能

news/2025/1/8 18:28:52/文章来源:https://www.cnblogs.com/ypSharing/p/18660336

最近发现现在租房还是签合同,越来越多采用电子签约的方式进行,好处不用多说节约成本,节约时间。抱着好奇的心理,尝试自己动手实现一个电子签。原来并不复杂主要通过了canvas绘画能力进行实现的。
主要功能

  1. 创建合同模板:使用HTML和CSS创建一个合同模板。
  2. 添加签名区域:在合同模板中添加一个区域用于签名。
  3. 实现签名功能:使用元素实现签名功能。
  4. 将签名保存到合同模板:将签名绘制到合同模板中。
  5. 提供下载功能:允许用户下载带有签名的合同png/pdf格式。
    展示效果如下

实现

主要三个重要点:实现签名,签名放到指定位置,保存pdf/png

1. 实现签名

const canvas = $('#signatureCanvas')[0]// document.getElementById('signatureCanvas');const ctx = canvas.getContext('2d');let drawing = false;$('#signatureCanvas').on('mousedown touchstart', (e) => {drawing = true;draw(e);});$('#signatureCanvas').on('mousemove touchmove', (e) => {if (drawing) {draw(e);}});$('#signatureCanvas').on('mouseup mouseout touchend', () => {drawing = false;ctx.beginPath();});function draw(e) {const rect = canvas.getBoundingClientRect();const x = e.clientX - rect.left;const y = e.clientY - rect.top;ctx.lineWidth = 4;ctx.lineCap = 'round';ctx.strokeStyle = '#000000';ctx.lineTo(x, y);ctx.stroke();ctx.beginPath();ctx.moveTo(x, y);}

2. 签名放到指定位置

//取消签名document.getElementById('clearButton').addEventListener('click', () => {ctx.clearRect(0, 0, canvas.width, canvas.height);});// 保存签名document.getElementById('saveButton').addEventListener('click', () => {const dataURL = canvas.toDataURL();let name = '.' + signNameif (name) {const signTexts = document.querySelectorAll(name);signTexts.forEach(signText => {signText.style.backgroundImage = `url(${dataURL})`;signText.style.backgroundSize = 'cover';signText.textContent = ''; // 清空文本内容});$('.pop').hide();}});

3. 保存pdf/png

这里用到了html2canvas保存图片格式,html2pdf保存pdf格式

  // 下载签名与输入完成后的后合同$('#downloadAgree').click(function () {// 你可以指定要转换为PDF的元素const element = document.body;/*html2pdf().from(element).save('page.pdf');*/// 将当前页面保存为png格式html2canvas(element).then(canvas => {// 创建一个a标签来下载PNG文件const link = document.createElement('a');link.href = canvas.toDataURL('image/png');link.download = 'page.png';element.appendChild(link);link.click();element.removeChild(link);});});

完成代码

<!DOCTYPE html>
<html lang="en"><head><meta name="author" content="cypking"></meta><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script><script src="https://html2canvas.hertzen.com/dist/html2canvas.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/html2pdf.js/0.10.1/html2pdf.bundle.min.js"></script>
</head>
<style>html,body {height: 100%;width: 100%;padding: 20px;}.pop {height: 100vh;width: 100vw;position: fixed;top: 0;left: 0;background: rgba(0, 0, 0, .5);display: flex;align-items: center;justify-content: center;}.mark {display: flex;flex-direction: column;align-items: center;justify-content: center;}h1 {text-align: center;margin: auto;}.sign {width: 100%;display: flex;align-items: center;justify-content: space-around;}input {display: inline-block;margin-left: 10px;margin-top: 10px;height: 24px;line-height: 24px;}dl {display: flex;flex-direction: column;align-items: flex-end;}dt,dd {display: flex;align-items: center;}.sign-text,.sign-date,.sign-text1,.sign-date1 {margin-top: 10px;height: 40px;width: 80px;border: 1px dashed #ccc;display: flex;align-items: center;text-align: center;justify-content: center;border-radius: 4px;cursor: pointer;}#signatureCanvas {background-color: white;}#downloadAgree {display: inline-block;margin: 20px auto 40px;}.controlPanel {position: fixed;bottom: 20px;right: 20px;}.party {width: 50px;height: 50px;border-radius: 100%;border: 1px dashed black;position: relative;margin-bottom: 20px;}.partya::after {content: '甲';width: 16px;height: 16px;border-radius: 100%;font-size: 12px;line-height: 16px;position: absolute;left: 0;right: 0;top: 0;bottom: 0;margin: auto;}.partyb::after {content: '乙';width: 16px;height: 16px;border-radius: 100%;font-size: 12px;line-height: 16px;position: absolute;left: 0;right: 0;top: 0;bottom: 0;margin: auto;}
</style><body><span>✏️</span><!-- 合同 --><div class="agreement"><h1> 居住房屋租赁合同</h1><br /><br>出租人 (甲方): <input type="text" placeholder="请输入" /><br>证件类型及编号:<input type="text" placeholder="请输入" /><br><br>承租人 (乙方):<input type="text" placeholder="请输入" /><br>证件类型及编号:<input type="text" placeholder="请输入" /><br><br>根据《中华人民共和国民法典》等有关法律、法规的规定,甲、乙双方在平等、自愿、公平和诚实信用的基础上,经协商一致,就乙方承租甲方可依法出租的房屋事宜,订立本合同。<br><br>租金及支付方式<br>租赁起止日期: 2025-02-01 至 2026-02-01<br>租赁期限:1年<br><br>方式①<br>租金付款方式:年付****12元人民币<br>押金:***元人民币<br>总金额:***元人民币<br>(大写):***<br>期数:1次<br><br>租客身份信息<br>姓名:<input type="text" placeholder="请输入" /><br>性别:<input type="text" placeholder="请输入" /><br>联系电话:<input type="text" placeholder="请输入" /><br>证件类型:<input type="text" placeholder="请输入" /><br>证件号码:<input type="text" placeholder="请输入" /><br>工作:<input type="text" placeholder="请输入" /><br><br>条款内容<br>第一条出租房屋情况和租赁用途<br>1-1.甲方将*** 房屋出租给乙方。该房屋建筑面积为 *** 平方米。<br>1-2.乙方向甲方承诺,承租该房屋仅用作居住使用。<br><br>第二条交付日期和租赁期限<br>2-1.甲、乙双方约定,该房屋租赁期起止时间 2025-02-01 至 2026-02-01<br>2-2.双方同意,甲方于 *** 前将该房屋交付给乙方,由乙方进行验收。<br><br>第三条 租金及支付方式<br>3-1.乙方使用 年付,即在租赁期限内一次性付清支付房租。<br>3-2.甲乙双方约定,在租赁期间内,该房屋采用方式①进行支付,房屋押金为 ***元,月租金 *** 元,一次性缴纳费用*** 元,。(注:双方约定的租金为甲方净得租金)最后一期租期不足期的,以实际居住天数计算该期租金。在租赁期间内,未经双方协商一致,任何一方不得擅自调整租金标准。<br>3-3.该房屋租赁期满后,甲乙双方协商一致续租的,乙方须支付甲方一个月租金作为甲方服务费,则户屋押金自动转为该房屋续租押金,不足部分(若有)由乙方补足。租赁期满后甲、乙双方确认不续租或本合同解除后,房屋押金除用以抵扣应由乙方承担但尚未交纳的费用(包括但不限于租金、违约金等本合同约定由乙方承担的费用)外,剩余部分 (若有) 应无息退还乙方。<br><br>第四条其他相关费用<br>4-1.租赁期限内,该房屋所发生的:水费、电费、煤气费、有线电视费、网络宽带费、物业管理费、室内设施维修费 (人为使用不当的应由乙方承担的除外)、保洁费、暖气费中,甲方承担的费用为:物业管理费、暖气费。<br>除甲方承担的费用外,其他费用均由乙方承担;<br>4-2.甲方应依法收取本条项下费用(费用标准以国家电网、当地燃气集团、自来水公司等服务提供商制定的为准)。<br><br>第五条提供材料<br>(一)本人及同住人员,真实有效身份证件正反面照片或纸质版复印件一份<br>(二)本人及同住人员联系方式<br>(三)宠物种类及数量<br><br>第六条 房屋使用要求和维修责任<br>5-1.甲方应确保该房屋交付时符合规定的安全条件。乙方入住 30 天内附属设施、设备非乙方使用不当或不合理使用有损坏或故障时,甲方负责维修;乙方入住超过 30天后,附属设施、设备有损坏或故障时由乙方自行维修解决,甲方不负责维修。<br>5-2.乙方应对该房屋的使用安全负责。租赁期间,乙方应合理使用并爱护该房屋及其附属设施、设备因乙方使用不当或不合理使用,致使该房屋及其附属设施、设备损坏或发生故障的,乙方应负责修复,乙方不维修的,甲方可代为维修,费用由乙方承担。<br>5-3.租赁期间,甲方应定期对该房屋进行检查、养护,保证该房屋及其附属设施、设备处于正常的可使用和安全的状态。甲方应在检查养护前 3 日通知乙方。检查养护时,乙方应予以配合。甲方应减少对乙方使用该房屋的影响。<br>5-4.租赁期间,乙方须全力配合甲方因该房屋注册公司 (含:工商、税务、资质审批部门)所需要的实地核查,每年实地核查次数不超过 3次。若乙方以各种理由拒不配合视乙方违约,赔偿甲方壹个月房租做为违约金。<br><br>第七条 转租、承租权转让和交换<br>6-1.租赁期间,乙方无转租权。<br>6-2.租赁期间,乙方不得将该房屋转让给他人承租或与他人承租的居住房屋进行交换<br><br>第八条 续租<br>7-1. 该房屋租赁期限届满、乙方需继续承租的,乙方应于租赁期限届满前三十日内向甲方提出续租,经甲、乙双方协商一致后,重新签订合同。乙方支付续租账单 (包括但不限于支付租金或补足续租押金)即视为乙方已完全了解续租租期、续租租金等重要信息并确认该续租合同,与甲方建立房屋租赁关系。乙方不续租的,甲方有权在租赁期限届满前三十日内带人看房,乙方需给予配合。<br><br>第九条 房屋返还<br>8-1.除甲方同意乙方续租外,乙方应在本合同的租期届满后 1日内返还该房屋<br>8-2.乙方未经甲方书面同意逾期返还该房屋的,每逾期一日,乙方应按该房屋日租金的 三倍向甲方支付房屋占用费。<br>8-3.除本合同附件另有约定外,乙方返还该房屋时,该房屋及其装修、附属设施和设备应当符合正常使用后的状态。经甲方书面验收认可后,相互结清各自应当承担的费用<br><br>第十条 解除本合同的条件<br>10-1.甲、乙双方同意在租赁期内,有下列情形之一的,本合同解除,双方互不担责:<br>(一) 该房屋占用范围内的土地使用权依法提前收回的;<br>(二) 该房屋因公共利益需要被依法征收的;<br>(三) 该房屋因城市建设需要被依法列入房屋拆迁许可范围的;<br>(四) 该房屋因不可抗力原因毁损、灭失,致使乙方不能正常使用的:<br>(五) 签订本合同时,甲方已告知乙方该房屋已设定抵押,租赁期间被处分的;<br>(六) 甲乙双方协商一致解除本合同的。<br>10-2.甲、乙双方同意,甲方有下列情形之一的,乙方可书面通知甲方解除本合同,并有权要求甲方赔偿损失。<br>(一) 甲方未按合同约定按时交付该房屋,经乙方书面催告后 7日内仍未交付的;<br>(二) 甲方交付的该房屋不符合本合同约定或存在重大质量缺陷,致使乙方不能正常使用的;<br><br>10-3.甲、乙双方同意,乙方有下列情形之一的,甲方可书面通知乙方解除本合同,并有权要求乙方赔偿损失。<br>(一) 乙方擅自改变房屋居住用途的;<br>(二) 因乙方原因造成房屋结构损坏的:<br>(三) 乙方擅自转租该房屋、转让该房屋承租权或与他人交换各自承租的房屋的;<br>(四) 乙方擅自增加承租同住人,或人均承租建筑面积、使用面积低于规定标准的<br>(五) 乙方利用承租的居住房屋从事违法违规活动的:<br>(六) 乙方逾期不支付本合同项下约定由乙方承担的费用的(包括但不限于房屋押金、租金、水电煤费用等);<br>(七)乙方擅自将该房屋钥匙交付或配给非居住人员的;<br>(八)乙方隐瞒、漏报、谎报自身传染性疾病或隐性疾病的;<br>(九) 乙方在未承租的房间堆放私人物品的。<br>(十) 欠缴各项费用达月租金额 15%的。<br><br>第十一条违约责任<br>11-2.甲方未在本合同中告知乙方,该房屋出租前已抵押,造成乙方损失的,甲方应负责赔偿。<br>11-3.乙方未征得甲方书面同意或者超出甲方书面同意的范围擅自装修房屋或者增设附属设施的,甲方可以要求乙方恢复房屋原状并赔偿损失。<br>11-4.租赁期间,非本合同约定的情况,甲方提前解除合同,甲方应向乙方支付壹个月房屋租金作为违约金。若违约金不足抵付乙方损失的,甲方还应负责赔偿。<br>11-5.租赁期间,非本合同约定的情况,乙方中途擅自退租的,乙方应向甲方支付壹个月房屋租金作为违约金。若违约金不足抵付甲方损失的,乙方还应负责赔偿。<br>11-6.租赁期间,甲方有本合同第 10-2条约定情形之一的,应向乙方支付贰个月房屋租金作为违约金,若违约金不足抵付乙方损失的,甲方还应负责赔偿。<br>11-7.租赁期间,乙方有本合同第 10-3 条约定情形之一的,应向甲方支付贰个月房屋租金作为违约金,若违约金不足抵付甲方损失的,乙方还应负责赔偿。<br>11-8租赁期间,乙方承诺租赁期内不使用煤气罐,不给电动车电池充电,若乙方私自违反承诺,造成意外事故与甲方无关,所有责任由乙方自行承担。合同期内甲方不定期实地检查屋内安全隐患,一经发现乙方使用煤气罐或给电动车电池充电行为,视乙方严重违约,甲方有权收回房屋且押金不退。<br><br>第十二条 其他条款<br>12.1租赁期间内,承租人是房屋的实际管理人,承租人需时刻注意防火、防盗、防触电,不做危及自身人身安全的活动,房屋内发生的一切安全事故都由承租人来承担,与出租人无关,包括但不限于高空抛物,水电煤气使用不当,在房屋内摔倒等,如果承租人利用此房进行不正当的经营或者违法活动,出租方有权无条件的立刻收回房屋,给出租方造成损失的,要按照实际损失进行赔偿。<br>12.2.本合同未尽事宜,经甲、乙双方协商一致,可订立补充条款。本合同补充条款及附件,为本合同不可分割的一部分。<br>12.3.本合同为电子合同,经乙方在本系统点击”确认签署“或支付本合同项下账单 (该房屋租金及/或押金账单) 后生效。<br>12.4.本合同生效后,甲、乙双方对合同内容的变更或补充应另行订立合同,作为本合同的附件。本合同附件与本合同具有同等法律效力。<br><br>第十三条 解决争议的方式<br>11-1.本合同由中华人民共和国法律、法规管辖。<br>11-2.双方在履行本合同过程中若发生争议的,甲、乙双方可协商解决或者向人民调解委员会申请调解,也可选择下列第二种方式解决:<br>(一) 提交当地仲裁委员会仲裁,(二) 依法向人民法院提起诉讼。<br><br>其它内容<br>房间家具清单:<br>床2。床垫2。衣柜1。茶几1。沙发1。电视柜 1。椅子4。窗帘3。冰箱1。洗衣机1。钥匙 1。电卡 1。户门禁 1。油烟机 1。洗碗机 1。茶几1。餐桌1。<br>公共家具清单:<br><br><br><br><br><div class="sign"><dl><dt>甲方(出租人)签字:<div class="sign-text">签字</div></dt><dd>日期:<div class="sign-date">签字</div></dd></dl><dl><dt>乙方(承租人)签字:<div class="sign-text1">签字</div></dt><dd>日期:<div class="sign-date1">签字</div></dd></dl></div></div><div class="controlPanel"><div class="party partya"></div><div class="party partyb"></div><button id="downloadAgree">下载合同</button></div><div class="pop"><div class="mark"><canvas id="signatureCanvas" width="700" height="400" style="border:1px solid #000000;"></canvas><div><button id="clearButton">清除签名</button><button id="saveButton">保存签名</button></div></div></div>
</body>
<script>$('.pop').hide();let signName = ''$(' .sign-text,.sign-date ,  .sign-text1,.sign-date1').click(function (e) {console.log(111, e.target.className);signName = e.target.className$('.pop').show();});const canvas = $('#signatureCanvas')[0]// document.getElementById('signatureCanvas');const ctx = canvas.getContext('2d');let drawing = false;$('#signatureCanvas').on('mousedown touchstart', (e) => {drawing = true;draw(e);});$('#signatureCanvas').on('mousemove touchmove', (e) => {if (drawing) {draw(e);}});$('#signatureCanvas').on('mouseup mouseout touchend', () => {drawing = false;ctx.beginPath();});function draw(e) {const rect = canvas.getBoundingClientRect();const x = e.clientX - rect.left;const y = e.clientY - rect.top;ctx.lineWidth = 4;ctx.lineCap = 'round';ctx.strokeStyle = '#000000';ctx.lineTo(x, y);ctx.stroke();ctx.beginPath();ctx.moveTo(x, y);}//取消签名document.getElementById('clearButton').addEventListener('click', () => {ctx.clearRect(0, 0, canvas.width, canvas.height);});// 保存签名document.getElementById('saveButton').addEventListener('click', () => {const dataURL = canvas.toDataURL();let name = '.' + signNameif (name) {const signTexts = document.querySelectorAll(name);signTexts.forEach(signText => {signText.style.backgroundImage = `url(${dataURL})`;signText.style.backgroundSize = 'cover';signText.textContent = ''; // 清空文本内容});$('.pop').hide();}});
</script>
<script>// 下载签名与输入完成后的后合同$('#downloadAgree').click(function () {// 你可以指定要转换为PDF的元素const element = document.body;/*html2pdf().from(element).save('page.pdf');*/// 将当前页面保存为png格式html2canvas(element).then(canvas => {// 创建一个a标签来下载PNG文件const link = document.createElement('a');link.href = canvas.toDataURL('image/png');link.download = 'page.png';element.appendChild(link);link.click();element.removeChild(link);});});
</script></html>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/865996.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

git怎么玩

首先如果是windos下个git bash 1.自己用git,用于本地和github的交互!

电流传感器HLSR50-P KX022-1020加速度计 LM27761DSGR稳压器 MAX14752EUE SAF7755HV音频 DSP规格、产品特征、及应用

分享电流传感器HLSR50-P KX022-1020加速度计 LM27761DSGR稳压器 MAX14752EUE SAF7755HV音频 DSP规格、产品特征、及应用1、HLSR50-P是一款开环霍尔效应电流传感器,主要用于电子测量直流、交流和脉冲电流,同时确保初级和次级电路之间的电隔离。HLSR50-P 电流传感器规格用于测量…

招行面试: 分布式调度 设计,要考虑 哪些问题?

本文原文链接 文章很长,且持续更新,建议收藏起来,慢慢读!疯狂创客圈总目录 博客园版 为您奉上珍贵的学习资源 : 免费赠送 :《尼恩Java面试宝典》 持续更新+ 史上最全 + 面试必备 2000页+ 面试必备 + 大厂必备 +涨薪必备 免费赠送 :《尼恩技术圣经+高并发系列PDF》 ,帮你 …

Idea中集成SceneBuilder以及使用讲解

目录1 Idea中集成SceneBuilder1.1 Idea中集成SceneBuilder1.2 SceneBuilder1.2.1 添加组件ControlsFX1.2.1.1页面展示1.2.2 hierarchy displays1.3 简单使用1.3.1 搭建项目1.3.2 fxml文件1.3.3 生成exe文件2 SceneBuilder页面讲解2.1 Properties窗口预览2.2 Text面板2.2.1 Text…

JavaFX基础之环境配置,架构,FXML

目录1 JavaFX1.1 简介1.2 环境准备1.2.1 手动管理依赖1.2.2 maven或Gradle管理1.3 JavaFX 架构1.3.1 JavaFX 架构图1.3.2 JavaFX组件1.3.2.1 舞台1.3.2.2 场景1.3.2.3 控件1.3.2.4 布局1.3.2.5 图表1.3.2.6 2D图形1.3.2.7 3D图形1.3.2.8 声音1.3.2.9 视频1.4 简单使用1.5 FXML1…

编译原理-期末

第一章编译原理的基础问答设 A机器 上有 语言L 的编译程序,可以用它来编制B机器上的语言的编译程序,试用 T形图 进行表示。 通过自展完成C语言的编写,试描述这个过程。 画出编译程序的总体结构图,简要说明每个模块的功能 如何理解“单词是程序设计语言中具有独立意义的最小…

ESP8266及继电器电路图解析

ESP8266及继电器介绍 ESP8266概述:ESP8266 是一款低成本、低功耗的 Wi-Fi 芯片,由乐鑫信息科技(Espressif Systems)开发。它集成了 TCP/IP 协议栈,能够实现串口与 Wi-Fi 之间的转换,广泛应用于物联网(IoT)领域,如智能家居、智能穿戴、工业控制等。 特点:低功耗:在睡…

docker-compose部署下Fastapi中使用sqlalchemy和Alembic

本篇介绍使用Fastapi + sqlalchemy + alembic 来完成后端服务的数据库管理,并且通过docker-compose来部署后端服务和数据库Mysql。包括:1. 数据库创建,数据库用户创建 2. 数据库服务发现 3. Fastapi 连接数据库 4. Alembic 连接数据库 5. 服务健康检查本篇介绍使用Fastapi +…

误删除了表?PolarDB MySQL帮你恢复!完成就送2025蛇年春联!

由于DDL语句无法回滚,如果误删除了表(例如DROP TABLE),可能会导致数据丢失。PolarDB MySQL提供表回收站的功能,删除的表会被临时转移到表回收站。 通过本次操作,带您体验如何使用PolarDB MySQL提供表回收站的功能,从表回收站恢复误删的表。 完成任务赢奖励,活动火热进行…

《墨香古韵:传统与现代的完美融合》——传世经典的美,划破时空的风格和型

《墨香古韵:传统与现代的完美融合》 由“解锁AI超能”的邦林AIGC出品 一直叹服古人用那样少的笔墨,就可以塑造一个让人无限联想、余味无穷的作品。 而上帝造人,诸多完美,唯独留下一个大大的Bug, 那就是人想象不出自己没见闻过的东西,而有大师也曾说过,人的想象力总是先于…

学习 - Linux - Centos安装jdk8

Centos安装jdk8 安装包下载地址: 通过网盘分享的文件:jdk 链接: https://pan.baidu.com/s/1dQTMZk7foPZhOcw55QM_lQ?pwd=sky1 提取码: sky1 二、上传至Centos系统解压文件并移动到usr/local目录下 解压 tar zxvf jdk-8u181-linux-x64.tar.gz 移动 mv jdk1.8.0_181 /usr/loca…

CICD Day7、Jenkins Pipeline 常用指令及Pipeline快捷生成方式(片段生成器)

1、常用指令 在编写Pipeline脚本时,会涉及各种指令,这些指令用于实现构建过程中的不同功能。熟悉这些指令后,编写一个完整的Pipeline脚本将变得十分简单 1.1 shsh指令用于执行shell命令,配置示例如下stage(Build) {stage {sh hostname} }在上述配置中,在构建的过程中,执行…