C#結(jié)合JavaScript實(shí)現(xiàn)手寫板簽名效果
應(yīng)用場(chǎng)景
我們最近開發(fā)了一款筆跡測(cè)試功能的程序(測(cè)試版),用戶在手寫板上手寫簽名,提交后即可測(cè)試出被測(cè)試者的心理素質(zhì)評(píng)價(jià)分析。類似功能的場(chǎng)景還比如,在銀行柜臺(tái) 辦理業(yè)務(wù),期間可能需要您使用手寫設(shè)備進(jìn)行簽名并確認(rèn);保險(xiǎn)續(xù)期小程序,到期后需要你在確認(rèn)續(xù)期條款后,在手機(jī)上提供的簽名區(qū)域進(jìn)行簽名并提交確認(rèn)。
實(shí)現(xiàn)效果
筆跡測(cè)試顯示界面如下:
可選擇畫筆顏色(默認(rèn)為黑色筆) ,在虛線框內(nèi)可隨便寫一段文字,點(diǎn)擊提交即可。當(dāng)然程序還提供拍照上傳功能,這里不再詳述。下面我們開始介紹,C#如何結(jié)合JavaScript實(shí)現(xiàn)手寫板寫字并上傳到服務(wù)器進(jìn)行處理。
開發(fā)運(yùn)行環(huán)境
操作系統(tǒng): Windows Server 2019 DataCenter
手寫觸屏設(shè)備:Microsoft Surface Pro 9
.net版本: .netFramework4.0 或以上
開發(fā)工具:VS2019 C#
設(shè)計(jì)實(shí)現(xiàn)
手寫功能
設(shè)計(jì)采用了 iframe 嵌入式的方式實(shí)現(xiàn) JavaScript 前端,假設(shè)頁面為 hw.aspx ,該頁面實(shí)現(xiàn)了手寫功能、重寫功能、畫筆選擇功能和提交功能,其完整示例代碼如下:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=yes"/> <title>手寫板</title> <style type="text/css"> html,body{ margin: 0; padding: 0; } .saveimg{ text-align: center; } .saveimgs span{ display: inline-block; margin-top:5px; } </style> </head> <body> <script src="jquery-3.3.1.min.js"></script> <div align="center"> <canvas id="myCanvas" width="500" height="300" style="border:1px dotted #6699cc"></canvas> <div class="control-ops control"> <button type="button" class="btn btn-primary" onclick="javascript:clearArea();return false;">重寫</button> <select style="display:none" id="selWidth" onchange="aaa()"> <option value="1">1</option> <option value="3" selected="selected">3</option> <option value="5">5</option> <option value="7">7</option> <option value="9">9</option> <option value="11">11</option> </select> <select id="selColor" onchange="aaa2()"> <option value="black" selected="selected">黑色筆</option> <option value="blue">藍(lán)色筆</option> <option value="red">紅色筆</option> <option value="green">綠色筆</option> <option value="yellow">黃色筆</option> <option value="gray">深灰筆</option> </select> <button type="button" class="saveimg" onclick="javascript:saveImageInfo();return false;">提交</button> </div> <div class="saveimgs"></div> </div> </body> <script type="text/javascript"> var mousePressed = false; var lastX, lastY; var ctx = document.getElementById('myCanvas').getContext("2d"); var c = document.getElementById("myCanvas"); var control = document.getElementsByClassName("control")[0]; var saveimgs = document.getElementsByClassName("saveimgs")[0]; window.onload = function () { document.getElementById('myCanvas').setAttribute("width", $(window).width()-5); InitThis(); } function saveImageInfo(){ var image = c.toDataURL("image/png"); window.parent.document.getElementById('pbase64').value = image; window.parent.document.getElementById('phw').click(); return; var ctximg = document.createElement("span"); ctximg.innerHTML = "<img src='"+image+"' alt='from canvas'/>"; if(saveimgs.getElementsByTagName('span').length >= 1){ var span_old = saveimgs.getElementsByTagName("span")[0]; saveimgs.replaceChild(ctximg,span_old) } else{ saveimgs.appendChild(ctximg); } } var selected1,selected2; function aaa(){ var sel = document.getElementById('selWidth'); var value = sel.selectedIndex; return selected1 = sel[value].value; } function aaa2(){ var sel2 = document.getElementById('selColor'); var value = sel2.selectedIndex; return selected2 = sel2[value].value; } function InitThis() { // 觸摸屏 c.addEventListener('touchstart', function (event) { console.log(1) if (event.targetTouches.length == 1) { event.preventDefault();// 阻止瀏覽器默認(rèn)事件,重要 var touch = event.targetTouches[0]; mousePressed = true; Draw(touch.pageX - this.offsetLeft, touch.pageY - this.offsetTop, false); } },false); c.addEventListener('touchmove', function (event) { console.log(2) if (event.targetTouches.length == 1) { event.preventDefault();// 阻止瀏覽器默認(rèn)事件,重要 var touch = event.targetTouches[0]; if (mousePressed) { Draw(touch.pageX - this.offsetLeft, touch.pageY - this.offsetTop, true); } } },false); c.addEventListener('touchend', function (event) { console.log(3) if (event.targetTouches.length == 1) { event.preventDefault();// 阻止瀏覽器默認(rèn)事件,防止手寫的時(shí)候拖動(dòng)屏幕,重要 mousePressed = false; } },false); /*c.addEventListener('touchcancel', function (event) { console.log(4) mousePressed = false; },false);*/ // 鼠標(biāo) c.onmousedown = function (event) { mousePressed = true; Draw(event.pageX - this.offsetLeft, event.pageY - this.offsetTop, false); }; c.onmousemove = function (event) { if (mousePressed) { Draw(event.pageX - this.offsetLeft, event.pageY - this.offsetTop, true); } }; c.onmouseup = function (event) { mousePressed = false; }; } function Draw(x, y, isDown) { if (isDown) { ctx.beginPath(); ctx.strokeStyle = selected2; ctx.lineWidth = selected1; ctx.lineJoin = "round"; ctx.moveTo(lastX, lastY); ctx.lineTo(x, y); ctx.closePath(); ctx.stroke(); } lastX = x; lastY = y; } function clearArea() { ctx.setTransform(1, 0, 0, 1, 0, 0); ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height); // 清除簽名圖片 if(saveimgs.getElementsByTagName('span').length >= 1){ var clearImg = saveimgs.getElementsByTagName('span')[0]; saveimgs.removeChild(clearImg); } } </script> </html>
該頁面需要引用 jquery-3.3.1.min.js
前端引用
前端頁面除嵌入手寫功能頁面外,iframe的父窗口需要放置兩個(gè)元素,一個(gè)用于存儲(chǔ)手寫提交后的Base64數(shù)據(jù)的 Asp.net 服務(wù)器按鈕文本框元素,另一個(gè)是用于模擬調(diào)用服務(wù)器事件的 Asp.net 服務(wù)器按鈕元素。
引用代碼如下:
<div style=" text-align:center"> <iframe width="520" height="350" id="hw" runat="server" scrolling="no" frameborder="0" src="/cc/module/hw/hw.aspx" ></iframe> <asp:TextBox ID="pbase64" TextMode="MultiLine" style="display:none" runat="server" ></asp:TextBox> <asp:button ID="phw" OnClientClick="waittip()" text="后臺(tái)處理" runat="server" style="display:none" onclick="phw_Click" /> </div>
后端處理
手寫功能中的提交執(zhí)行代碼將調(diào)用如下:
window.parent.document.getElementById('pbase64').value = image; window.parent.document.getElementById('phw').click();
其中 pbase64 和 phw 控件為服務(wù)器控件,可直接模擬調(diào)用 phw 按鈕的服務(wù)器 click,在這之前其還可以自動(dòng)處理 OnClientClick事件以顯示等待界面。請(qǐng)注意 waittip() 執(zhí)行了一段 javascript 腳本,如下:
function waittip() { layer.open({ type: 2, shadeClose: false, content: '正在分析,請(qǐng)稍候...' }); }
這其中引入了 Layer 彈出層技術(shù),關(guān)于 Layer 彈層組件請(qǐng)參照我的文章《改造 layer 彈層移動(dòng)版組件》
這是調(diào)用服務(wù)器Click的事件處理代碼,將上傳的Base64圖片轉(zhuǎn)為兩種格式的圖片文件(PNG和JPEG)。代碼如下:
protected void phw_Click(object sender, EventArgs e) { string mtfilename = "d:\\hw_" + System.Guid.NewGuid().ToString() + ".png"; string mtfilename2 = "d:\\hw_" + System.Guid.NewGuid().ToString() + ".jpg"; string dummyData = pbase64.Text.Trim().Replace("data:image/png;base64,", ""); Base64StringToImage(dummyData, mtfilename); if (File.Exists(mtfilename)==false) { base64.ImageUrl = dummyData; layer.open("保存手寫圖片失敗,請(qǐng)重試并提交。" , "'確定'", "error"); return; } System.Drawing.Image img = System.Drawing.Image.FromFile(mtfilename); using (var b = new System.Drawing.Bitmap(img.Width, img.Height)) { b.SetResolution(img.HorizontalResolution, img.VerticalResolution); using (var g = System.Drawing.Graphics.FromImage(b)) { g.Clear(System.Drawing.Color.White); g.DrawImageUnscaled(img, 0, 0); } b.Save(mtfilename2, System.Drawing.Imaging.ImageFormat.Jpeg); } }
小結(jié)
本示例中的前后端代碼僅為展示參考,手寫功能在支持觸屏的設(shè)備可以支持手寫,也可以用鼠標(biāo)進(jìn)行模擬。
服務(wù)器調(diào)用示例中需要使用 Base64StringToImage(dummyData, mtfilename); 方法由Base64數(shù)據(jù)轉(zhuǎn)化為圖片文件,代碼如下:
public bool Base64StringToImage(string strbase64, string outputFilename) { byte[] arr = Convert.FromBase64String(strbase64); MemoryStream ms = new MemoryStream(arr); System.Drawing.Image img = System.Drawing.Image.FromStream(ms); img.Save(outputFilename); img.Dispose(); if (File.Exists(outputFilename)) { return true; } return false; }
到此這篇關(guān)于C#結(jié)合JavaScript實(shí)現(xiàn)手寫板簽名效果的文章就介紹到這了,更多相關(guān)C# JavaScript手寫簽名內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
在WCF數(shù)據(jù)訪問中使用緩存提高Winform字段中文顯示速度的方法
這篇文章主要介紹了在WCF數(shù)據(jù)訪問中使用緩存提高Winform字段中文顯示速度的方法,是非常實(shí)用的功能,需要的朋友可以參考下2014-09-09C#實(shí)現(xiàn)撲克游戲(21點(diǎn))的示例代碼
21點(diǎn)又名黑杰克,該游戲由2到6個(gè)人玩,使用除大小王之外的52張牌,游戲者的目標(biāo)是使手中的牌的點(diǎn)數(shù)之和不超過21點(diǎn)且盡量大。本文將用C#實(shí)現(xiàn)這一經(jīng)典游戲,需要的可以參考一下2022-08-08c#讀取圖像保存到數(shù)據(jù)庫中(數(shù)據(jù)庫保存圖片)
這篇文章主要介紹了使用c#讀取圖像保存到數(shù)據(jù)庫中的方法,大家參考使用吧2014-01-01c# richtextbox更新大量數(shù)據(jù)不卡死的實(shí)現(xiàn)方式
這篇文章主要介紹了c# richtextbox更新大量數(shù)據(jù)不卡死的實(shí)現(xiàn)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-04-04