html5 canvas实现的手机端签字板

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

功能展示:

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

 

功能具体实现:

参数配置:

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 + ').
你当前鼠标的位置为(' + 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的时候就新建一个图层()

 

实现:

//撤销上一次操作
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]);
   
}
}

 

注意新建的,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哈哈~

 


转载于:https://my.oschina.net/Nealyang/blog/523188

你可能感兴趣的:(php,python,java)