首頁>科技>

我曾經在一個文書互動相關的專案中遇到過這樣的一個需求,當用戶接收到管理員傳送的文書時,使用者需要在這個文書上簽字簽收,簽名需要跟原有的文書進行合併,做到模仿線下真實簽收的電子簽名。這簽收沒有呼叫APP特有的功能,而是直接使用H5的canvas畫布完成。

本文只介紹canvas實現你在手機上進行書寫(簽名),文書與簽名的合併是由Java後端完成。介面比較複雜這裡不進行介紹介面,我會在後面的文章中進入介紹,請關注文章的更新。

以下程式碼有做一些刪減,刪減的原因一來是涉及到業務不便公開,二來是跟簽名無關的程式碼留在裡面,容易誤導你們。

我在這裡簡單介紹一下,先定義一個canvas標籤,設定他的ID,初始寬度和高度,然後在增加canvas對應的JS初始化函式,這些函式基本可以直接複製到你們的工程裡,然後進行測試調整。主要的功能就是清除和儲存。當你的頁面初始化後,就會出現一個白然的畫布,如果你在Web頁面做測試 的話,你可以使用滑鼠進入繪畫(因為我這個功能是為某個公眾號裡的業務做的開發,因此我都是用微信開發者工具進行測試的),也可以放到手機上進入手寫測試(手機要支援觸控功能,不要拿老人機進入測試)。

大概透入一下儲存功能,當你點選儲存時,會向介面傳送一張圖片二進位制流,你只要做檔案讀寫,儲存到本地為圖片格式即可,圖片出來的就是你的簽名。至於我前面提到的文書籤名功能,是把文書Doc轉成圖片,然後把文書圖片跟籤MISTRA片進行合併成一張圖片。這樣就變成了文書電子簽名,因為文書是使用者上傳的,文書有大有小,你要圖片合成,就必須要定位座標,如何利用簡單的演算法進入簽名定位,這就涉及我下面刪除的一些前端邏輯和後端的介面了。有興趣的可以關注我後面的介紹。

雖然我這裡用的是vue寫法,但並不複雜,直接把div對應的靜態程式碼複製出去,把canvas對應的JS自定義宣告函式複製到JS中,把mounted函式裡的方法放在JS自動載入中即可。

老樣子,我先截圖(我部落格截圖的會看起來更清楚點),原始碼在圖後面,

原始碼

<template> <div> <div> <i aria-hidden="true" @click="back()"></i> <span >電子簽名</span> </div> <div> <canvas ref="canvas" width="300"//畫布初始大小 height="480">Canvas畫板</canvas> <div> <div @click="clear">清除</div> <div @click="save">儲存</div> </div> </div> </div></template><script> let draw; let preHandler = function(e){ e.preventDefault() } class Draw{//canvas對應的JS自定義宣告函式 constructor(el){ this.el = el this.canvas = document.getElementById(this.el);//獲取canvas this.cxt = this.canvas.getContext("2d");//canvas追加2d畫圖 this.stageInfo = canvas.getBoundingClientRect();//canvas元素的邊界框 this.path = { beginX: 0, beginY: 0, endX: 0, endY: 0 } this.isCanvas = false } init(btn){//初始化 this.canvas.addEventListener("touchstart",event =>{ document.addEventListener("touchstart",preHandler,false) this.drawBegin(event) }) this.canvas.addEventListener("touchend",event =>{ document.addEventListener("touchend",preHandler,false) this.drawEnd() }) this.clear(btn) } drawBegin(e){ window.getSelection() ? window.getSelection().removeAllRanges() : document.selection.empty() this.cxt.strokeStyle = "#000" //設定線條的顏色 this.cxt.beginPath();//回執開始路徑 this.cxt.moveTo( e.changedTouches[0].clientX - this.stageInfo.left, e.changedTouches[0].clientY - this.stageInfo.top )//通過moveTo和lineTo,我們來繪製一條線 this.path.beginX = e.changedTouches[0].clientX - this.stageInfo.left this.path.beginY = e.changedTouches[0].clientY - this.stageInfo.top canvas.addEventListener("touchmove",() => { this.drawing(event) }) } drawing(e){ //繪製已定義的路徑 this.cxt.lineTo( e.changedTouches[0].clientX - this.stageInfo.left, e.changedTouches[0].clientY - this.stageInfo.top ) //計算、描繪劃過的路徑 this.path.endX = e.changedTouches[0].clientX - this.stageInfo.left; this.path.endY = e.changedTouches[0].clientY - this.stageInfo.top; this.cxt.stroke() this.isCanvas = true } drawEnd(){ document.removeEventListener("touchstart",preHandler,false) document.removeEventListener("touchend",preHandler,false) document.removeEventListener("touchmove",preHandler,false) } clear(btn){ this.isCanvas = false this.cxt.clearRect(0,0,500,800) } save(){ return canvas.toDataURL("image/png") } getIsCanvas(){ return this.isCanvas } } export default{ data(){ return { msg: "welcome to your haiguan App", val: true, url: "", canvasUrl:'', isCanvas : false, xValue:0, yValue:0, pdfUrl:'' } }, created(){ }, activated() { }, mounted(){//載入 draw = new Draw("canvas") var width = document.body.clientWidth || document.documentElement.clientWidth var height = document.body.clientHeight || document.documentElement.clientHeight var canvasElement = document.getElementById('canvas') canvasElement.width = width - 2 canvasElement.height = height - 102 draw.init() }, methods:{ 。。。。。圖片合併邏輯介面,暫時刪除 clear: function(){//清除畫布,當用戶書寫完後,發現不好看,可以進入清除畫面,重新書寫簽名 draw.clear() this.isCanvas = false }, save: function(){//書寫完簽名後,進入儲存 this.isCanvas = draw.getIsCanvas() if(!this.isCanvas){ this.$message.error('請簽名') return }。。。。。。簽名完後面的邏輯,暫時刪除 } } }</script><style lang="stylus" scoped>@import '../../common/stylus/variable'.resisterSign height: 100% .container padding-top: 40px height: calc(100% - 40px) #canvas background: white cursor:default border:1px dashed #666 display:block // width: calc(100% - 2px) // height: calc(100% - 62px) .btns-bottom height: 40px padding: 10px 5px .but background: $color-btn1 border-radius: $cont-border-radius width: calc(50% - 10px) float: left margin: 0 5px .but-orange background: $color-btn4 #keyword-box margin:10px 0</style>

最新評論
  • 整治雙十一購物亂象,國家再次出手!該跟這些套路說再見了
  • NTT、英特爾和索尼共同創立新全球論壇 推動實現未來通訊