使用Canvas构建签名控件

分享于 

13分钟阅读

Web开发

  繁體

介绍

最近,我为客户开发 Windows 8 Metro ( 概念证明)。 POC中的一个需求是捕获使用触摸事件编写的客户的签名。 在本文中,我将向你展示如何使用 HTML5 Canvas 元素和鼠标事件编写这样的签名控件。 同样的功能也可以用在触摸平台中,使用小。

画布元素基础

画布元素是一个可以放置在网页内的绘图面。 它是 HTML5规范的一部分,并且在大多数主流浏览器中实现了。 画布公开了一组 JavaScript api,使开发人员能够绘制基于像素的图形。 为了使用画布,首先需要创建 inside 网页。 下面是声明画布元素的方法:


<canvas id="myCanvas" width="300px" height="300px"></canvas>



现在网页上有了一个画布,你可以使用它的JavaScript来绘制图形。 为了绘制,你必须获取画布上下文。 下面是一个演示如何从canvas元素中获取上下文的代码示例:


var canvas = document.getElementById("signatureCanvas"),


 ctx = canvas.getContext("2d"); 



在代码中,声明了两个变量- 画布和 ctx。 将画布元素( 主要是使用它的id属性) 设置为,然后使用 getContext 函数检索绘图上下文。 函数获取一个上下文id参数,如果浏览器支持 web webgl,那么它可以拥有 2d 值或者实验值 experimental。 如果你想了解更多关于使用webgl创建 3d 图形的内容,你可以从这里开始

获取绘图上下文后,可以使用 canvas api启动绘图。 有很多功能,如 fillRect ( 使用填充颜色绘制 rectangle的步骤) 和 clearRect ( 清除画布中的rectangle 区域)。 本文主要介绍创建一个包装画布的控件,我鼓励你在继续之前阅读以下文章中的画布:

动态创建控制元素

现在你已经了解了关于画布的一点知识,让我们开始开发签名控制。 首先,你需要创建HTML外观和感觉。 为此,可以在动态创建元素和生成控件的表示形式的情况下,使用 document.createElement 函数。 下面是我在建议解决方案中使用的代码:


function createControlElements() { 


 var signatureArea = document.createElement("div"),


 labelDiv = document.createElement("div"),


 canvasDiv = document.createElement("div"),


 canvasElement = document.createElement("canvas"),


 buttonsContainer = document.createElement("div"),


 buttonClear = document.createElement("button"),


 buttonAccept = document.createElement("button");



 labelDiv.className = "signatureLabel";


 labelDiv.textContent = label;



 canvasElement.id = "signatureCanvas";


 canvasElement.clientWidth = cWidth;


 canvasElement.clientHeight = cHeight;


 canvasElement.style.border = "solid 2px black";



 buttonClear.id = "btnClear";


 buttonClear.textContent = "Clear";



 buttonAccept.id = "btnAccept";


 buttonAccept.textContent = "Accept";



 canvasDiv.appendChild(canvasElement);


 buttonsContainer.appendChild(buttonClear);


 buttonsContainer.appendChild(buttonAccept);



 signatureArea.className = "signatureArea";


 signatureArea.appendChild(labelDiv);


 signatureArea.appendChild(canvasDiv);


 signatureArea.appendChild(buttonsContainer);



 document.getElementById(containerId).appendChild(signatureArea);


}



可以看到,我创建了一些内存元素,然后在它们上面设置一些属性。 之后,我将创建的元素添加到彼此,创建 HTML fragment 并将 fragment 连接到带有 containerId的容器元素。

在画布中实现图形

现在已经有了元素,接下来的任务是在画布中实现图形。 为此,你需要向画布中添加鼠标事件监听器。 最合适的事件是 mousedown mousedown 和 mouseup。 下面是用于连接事件的代码:





canvas.addEventListener("mousedown", pointerDown, false);


canvas.addEventListener("mouseup", pointerUp, false);



下面是 pointerDown pointerUp和paint的代码,包括:


function pointerDown(evt) {


 ctx.beginPath();


 ctx.moveTo(evt.offsetX, evt.offsetY);


 canvas.addEventListener("mousemove", paint, false);


}



function pointerUp(evt) {


 canvas.removeEventListener("mousemove", paint);


 paint(evt);


}



function paint(evt) {


 ctx.lineTo(evt.offsetX, evt.offsetY);


 ctx.stroke();


}



在 pointerDown函数中,使用 beginPath 函数启动图形路径。 然后,上下文移动到鼠标点使用事件 offsetX event和 properties属性的点。 然后,将事件监听器连接到 mousemove事件。 如果在移动鼠标时被调用,则将上下文移动到新点,然后使用笔划函数在前一点和当前点之间绘制线条。 当释放鼠标按钮时,将调用 pointerUp 函数。 在 pointerUp函数中,将最后一行绘制到终点,并将事件侦听器移到mousemove事件监听器 to。 如果你在画布元素上悬停,则删除 mousemove事件侦听器将阻止绘图的继续。

将签名图像数据作为字节 array 获取

在画布上绘制签名之后,你可能想要提取它。 这可以使用上下文 getImageData 来完成,后者返回在画布中绘制的数据。 函数调用的返回类型有一个数据属性,它保存一个表示画布'的字节 array。 以下函数可以帮助检索签名:





function getSignatureImage() {


 return ctx.getImageData(0, 0, canvas.width, canvas.height).data;


}



整个控制实现

让我们把前面所有的函数打包到一个JavaScript控件中。 下面是控件的实现:


(function (ns) {


 "use strict";



 ns.SignatureControl = function (options) {


 var containerId = options && options.canvasId || "container",


 callback = options && options.callback || {},


 label = options && options.label || "Signature",


 cWidth = options && options.width || "300px",


 cHeight = options && options.height || "300px",


 btnClearId,


 btnAcceptId,


 canvas,


 ctx;



 function initCotnrol() {


 createControlElements();


 wireButtonEvents();


 canvas = document.getElementById("signatureCanvas");


 canvas.addEventListener("mousedown", pointerDown, false);


 canvas.addEventListener("mouseup", pointerUp, false);


 ctx = canvas.getContext("2d"); 


 }



 function createControlElements() { 


 var signatureArea = document.createElement("div"),


 labelDiv = document.createElement("div"),


 canvasDiv = document.createElement("div"),


 canvasElement = document.createElement("canvas"),


 buttonsContainer = document.createElement("div"),


 buttonClear = document.createElement("button"),


 buttonAccept = document.createElement("button");



 labelDiv.className = "signatureLabel";


 labelDiv.textContent = label;



 canvasElement.id = "signatureCanvas";


 canvasElement.clientWidth = cWidth;


 canvasElement.clientHeight = cHeight;


 canvasElement.style.border = "solid 2px black";



 buttonClear.id = "btnClear";


 buttonClear.textContent = "Clear";



 buttonAccept.id = "btnAccept";


 buttonAccept.textContent = "Accept";



 canvasDiv.appendChild(canvasElement);


 buttonsContainer.appendChild(buttonClear);


 buttonsContainer.appendChild(buttonAccept);



 signatureArea.className = "signatureArea";


 signatureArea.appendChild(labelDiv);


 signatureArea.appendChild(canvasDiv);


 signatureArea.appendChild(buttonsContainer);



 document.getElementById(containerId).appendChild(signatureArea);


 }



 function pointerDown(evt) {


 ctx.beginPath();


 ctx.moveTo(evt.offsetX, evt.offsetY);


 canvas.addEventListener("mousemove", paint, false);


 }



 function pointerUp(evt) {


 canvas.removeEventListener("mousemove", paint);


 paint(evt);


 }



 function paint(evt) {


 ctx.lineTo(evt.offsetX, evt.offsetY);


 ctx.stroke();


 }



 function wireButtonEvents() {


 var btnClear = document.getElementById("btnClear"),


 btnAccept = document.getElementById("btnAccept");


 btnClear.addEventListener("click", function () {


 ctx.clearRect(0, 0, canvas.width, canvas.height);


 }, false);


 btnAccept.addEventListener("click", function () {


 callback();


 }, false);


 }



 function getSignatureImage() {


 return ctx.getImageData(0, 0, canvas.width, canvas.height).data;


 }



 return {


 init: initCotnrol,


 getSignatureImage: getSignatureImage


 };


 }


})(this.ns = this.ns || {});



首先,使用JavaScript名称空间 创建控件的作用域。 在命名空间中,你为 SignatureControl 声明一个构造函数。 控件可以获取选项列表,这些选项可以帮助配置它的外观和行为。 例如当单击接受按钮时,将调用回调选项。 控件将公开两个函数- init init和 getSignatureImage。 init函数负责初始化所有元素,将事件监听器连接到控件按钮,并将事件监听器连接到鼠标事件。 getSignatureImage 函数将负责检索签名字节 array。

在HTML页中使用控件

在你拥有控件之后,让我们看看如何使用它 inside 网页。 下面的网页演示如何使用该控件:


<!doctype html>


<html>


<head>


 <title>Signature</title>


 <link href="signature.css" rel="stylesheet" type="text/css" />


 <script type="text/javascript" src="signature.js"></script> 


 <script type="text/javascript">


 function loaded() {


 var signature = new ns.SignatureControl({ containerId: 'container', callback: function () {


 alert('hello');


 } 


 });


 signature.init();


 }



 window.addEventListener('DOMContentLoaded', loaded, false);


 </script> 


</head>


<body>


 <div id="container"> 


 </div>


</body>


</html>



DOM内容完成加载时,使用它的构造函数函数和一些选项创建一个签名对象。 然后,你只需调用 init函数来创建该控件并启用它的功能。 如果要检索签名,可以使用下面的代码:


var signatureByteArray = signature.getSignatureImage();



下面是该控件的屏幕截图:

The Signature Control

摘要

本文向你展示了如何创建一个控件来捕获签名。 为了使用 Windows 8触摸事件的功能,你只需要将鼠标事件的调用替换为相应的触摸事件( 例如 mouseup 将变成 MSPointerUp )。


相关文章