您的位置:首页 > 移动开发

html5 canvas实现的手机端签字板

2015-10-28 00:00 411 查看
摘要: 可以实现手机端手指的签字,撤销,保存为图片以及重写等操作

功能展示:

这里显示不了图片,就算了吧。。。。

功能具体实现:

参数配置:

var DEFAULT_BRUSH_SIZE = 3;//设置画笔的粗细
var DEFAULT_BRUSH_COLOR = "#000000";//设置画笔的颜色
var BACKGROUND_COLOR = "#FFFFFF";//设置画布的背景颜色
var cut = 0;//设置断点
var point = {};//记录画笔的位置
var next_point = {};//记录下一个画笔的位置
var context;//context上下文
其中说明下context上下文的作用:html5中canvas本身是不具有绘画功能的,就是一个画布,类似于Java中的一个panel,而context可以提供在画布中绘画的方法和属性,通过canvas.getContext()得到

补充一点:因为是实现签字功能,其实就是实现两点之间画直线,需要一个起始点和一个终点,也就是上面参数设置的:point和next_point

这里我们需要不断的监控point和next_point的变化:

首先设置x和y的坐标:

function setPoint(x, y) {
//不断执行
var n_point = {};
n_point.x = x;
n_point.y = y;
return n_point;
}


function upDate(up_point) {
//不断执行
if (!next_point) {
next_point = setPoint(0, 0);
} else {
next_point = setPoint(up_point.x, up_point.y);
}
}


因为要不断的监控坐标的变化,这里我另外封装了一个方法,一遍调用它(其实后来我在想,为什么要另外封装一个方法,不能直接调用呢?\(^o^)/)

调用如下:

function loop(e) {
upDate(point);
}


下面是初始化画布和画笔的操作:

function init() {
var canvas = document.getElementById("canvas");
var canvasWidth = canvas.width = window.innerWidth;//获取画布的宽度
var canvasHeight = canvas.height = window.innerHeight;//获取画布的高度
context = canvas.getContext('2d');//获取画布上下文

context.fillStyle = BACKGROUND_COLOR;//设置背景填充颜色
context.fillRect(0, 0, canvasWidth, canvasHeight);//设置画布背景

point.x = 0;
point.y = 0;

canvas.addEventListener('touchmove', touchMove, false);
canvas.addEventListener('touchstart', touchStart, false);
canvas.addEventListener('touchend', touchEnd, false);
document.getElementById("chonghua").addEventListener('click', chonghua, false);
document.getElementById('backButton').addEventListener('click', backAction, false);
setInterval(loop, 1);
}


默认的第一个点为(0,0)其中需要说明的就是setInterval()方法,这个就是实现了不断地调用,一旦启动,就会不停的调用

clearInterval(setInterval(function,time))这个方法

因为是手机端,所以在上面注册touchmove、touchstart、touchend方法

下面是绘图的方法:

function draw(context) {
if (cut > 1) {
//context.save;//保存当前绘画状态
context.fillStyle = DEFAULT_BRUSH_COLOR;//设置填充的背景颜色
context.lineWidth = DEFAULT_BRUSH_SIZE;//设置画笔的大小
context.lineCap = "tound";//设置线条,让线条更加的圆润
context.beginPath();

context.moveTo(point.x, point.y);
context.lineTo(next_point.x, next_point.y);
console.log("画笔" + cut);
context.stroke();
context.restore();//回复绘画状态
}
}


下面是对应的touchmove,touchstart,touchend方法

//触摸滑动事件
function touchMove() {
var e = event.touches[0];
console.log("touchMove");
point = setPoint(e.clientX, e.clientY);
$pos_display.innerHTML = '你上一点鼠标的位置为(' + point.x + ',' + point.x + ').<br/>你当前鼠标的位置为(' + next_point.x + ',' + next_point.x + ')';//更新当前鼠标点击的位置
draw(context);
cut++;
}


//触摸开始事件
function touchStart() {
console.log("touchStart");
var canvas = document.createElement('canvas');
var content = document.getElementById('canvasContent');
content.appendChild(canvas);
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
canvas.addEventListener('touchmove', touchMove, false);
canvas.addEventListener('touchstart', touchStart, false);
canvas.addEventListener('touchend', touchEnd, false);
context = canvas.getContext('2d');
draw(context);
cut = 1;
}


//触摸结束时间
function touchEnd() {
console.log("touchEnd");
document.getElementById("canvas").getContext('2d').save();
}


其中需要注意点是断点连续的问题:

这一笔画完,和下一笔开始时,首尾链接到一起去了

所以这里我的处理方法是:】

设置一个cut断点,开始触发时,把断点设为1;在draw方法中判断断点,如果断点为1则不执行任何操作,touchmove方法中让断点累加

这样就实现了基本的签字功能

撤销功能:

Canvas中有一个restore方法,可以返回到save操作的那个状态,然而我使用的时候并没有什么卵用 (*  ̄︿ ̄)

解决方案:

因为canvas是透明的!!!这就联想到ps中图层的效果,最终展现的时候是每个图层的叠加,

每touchstart的时候就新建一个图层(<canvas>)

实现:

//撤销上一次操作
function backAction() {
console.log(document.getElementsByTagName("canvas").length);
if (document.getElementsByTagName("canvas").length == 1) {
chonghua();
}else{
document.getElementById('canvasContent').removeChild(document.getElementsByTagName("canvas")[document.getElementsByTagName("canvas").length - 1]);
}
}


注意新建的<canvas>,html中是以堆栈管理的,所以删除应该是删除最上面的一个图层

所以重画 也就非常简单了:不断地调用撤销操作:

//重画
function chonghua() {
var max = document.getElementsByTagName("canvas").length-1;
for(var i = max;i>0;i--){
document.getElementById('canvasContent').removeChild(document.getElementsByTagName("canvas")[document.getElementsByTagName("canvas").length - 1]);
}
if(document.getElementsByTagName("canvas").length == 1){
var context = document.getElementById('canvas').getContext('2d');
context.fillStyle = "#ffffff";
context.fillRect(0,0,window.innerWidth,window.innerHeight);
};
}


这里貌似我写的有些复杂,让撤销调用了重画的方法,其实代码可以简化下的o(一︿一+)o

保存的时候有些麻烦:需要将每一个图层(下面就用图层来代替canvas)合并为一个图层,又类似ps中的图层合并

思想就是调用context中的drawImage方法,图层绘画图层,但是后来发现绘画玩,底层的图层和上面的图层就有很多的重合,撤销和重画功能都不灵了,具体的解决步骤如下:

function drawImg(img){
var canvas = document.getElementById("canvas");
return canvas.getContext('2d').drawImage(img,0,0);
}


$scope.saveImg = function () {
var canvas = document.getElementById("canvas");
var canvasLength = document.getElementsByTagName("canvas").length-1;
for(var i = canvasLength;i>0;i--){
drawImg(document.getElementsByTagName("canvas")[i]);
document.getElementById("canvasContent").removeChild(document.getElementsByTagName("canvas")[i])
}
var dataUrl = canvas.toDataURL();
$scope.globalNavigator.pushPage('main/crm/img.html', {
animation: "fade",
src: dataUrl
})
}


其中需要说明下的就是context中的toDataURL();默认转成png格式的,当然也可以自己指定,在toDataURL中加上参数即可

网上都有说要base64.js和canvas2image.js,才能转成图片保存,当然我也下载了,当时后来我把两个引入注释掉,貌似功能并没有收到影响 O(∩_∩)O哈哈~
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: