canvas涂鸦板
功能说明
此画板兼容PC端和移动端,是使用HTML5开发的一款画图软件,用户可以在画板中随意涂鸦,然后保存成图片
技术说明:
- 利用canvas的画图功能
- html5在pc端和移动端浏览器中的事件差异
开发步骤
html代码
<!DOCTYPE html>
<html><head>
<title>涂鸦板</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- <script type="text/javascript"
src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML">
</script>-->
<style type="text/css">
#myCanvas {border: 1px solid black;
}
</style>
</head><body>
<!--注意,设置canvas宽、高时不要加上单位,如px-->
<canvas id="myCanvas" width="300" height="300"></canvas>
<div><button onclick="clean();">清 空</button><button onclick="save();">生成图片</button>
</div>
<img id='img' />
</body>
<script type="text/javascript" src="js/canvas.js"></script></html>
代码说明:
- 一个canvas元素,用于画图,通过css设置其边框
- 两个按钮,一个用户生成图片,一个用于清空涂鸦板
- 一个img元素,用来显示生成的涂鸦图片
下面我们来说js代码
相关知识
首先我们要实现在pc端和移动端都能够绘制图形,这意味着我们既要响应鼠标的事件,又要响应触摸事件
不用怀疑,在手机端浏览器中,onmousedown无法对你按下手指的动作做出响应,我们必须使用与之相对应的触摸事件才可以
下面介绍一下我们用到的事件
事件名称 | 何时触发 | 事件名称 | 何时触发 |
---|---|---|---|
onmousedown | 鼠标按下时 | touchstart | 手指触摸屏幕时 |
onmousemove | 鼠标移动时 | touchmove | 手指在屏幕上滑动时 |
onmouseup | 鼠标松开时 | touchend | 手指从屏幕离开时 |
onmousedown与touchstart对应
onmousemove与touchmove对应
onmouseup与touchend对应
前者为PC端事件,后者为移动端(如手机)事件
下面我们开始编码
获取元素、声明变量
var canvas, board, img;//获取canvascanvas = document.getElementById('myCanvas');//获取img,当用户点击“生成图片”时,会将用户的涂鸦生成图片并显示到这个img中img = document.getElementById('img');//获取绘图上下文,将来就是用这个上下文在画板上绘制图形board = canvas.getContext('2d');//声明变量,表示鼠标的按下状态,false表示未按下,true表示按下var mousePress = false;var last = null;
注册事件
//为鼠标按下事件指定要执行的函数canvas.onmousedown = beginDraw;//为鼠标移动事件指定要执行的函数canvas.onmousemove = drawing;//为鼠标松开事件指定要执行的函数canvas.onmouseup = endDraw;//为canvas添加touchstart事件,当手指在触摸屏设备(如手机)中按下时触发canvas.addEventListener('touchstart', beginDraw, false);//为canvas添加touchmove事件,当手指在触摸屏设备(如手机)中按下并移动时触发canvas.addEventListener('touchmove', drawing, false);//为canvas添加touchend事件,当手指在触摸屏设备(如手机)中离开时触发canvas.addEventListener('touchend', endDraw, false);
beginDraw函数
function beginDraw(event) { mousePress = true;}
代码说明:
onmousedown和touchstart事件都会执行这个函数,此函数将变量mousePress的值设置为true,表示用户已经按下了鼠标或者用户按下了手指,这个变量我们后面使用
drawing函数
function drawing(event) {event.preventDefault();if (!mousePress) return;var xy = pos(event);if (last != null) {board.beginPath();board.moveTo(last.x, last.y);board.lineTo(xy.x, xy.y);board.stroke();}last = xy;}function pos(event) {var x, y;if (isTouch(event)) {x = event.touches[0].pageX;y = event.touches[0].pageY;} else {x = event.offsetX + event.target.offsetLeft;y = event.offsetY + event.target.offsetTop;}// log('x='+x+' y='+y);return {x: x,y: y};}
代码说明:
onmouseover和touchmove事件都会执行这个函数,也就说用户用鼠标在canvas上滑动和用手指在屏幕上滑动时都会触发这个事件。
event.preventDefault():的作用是禁用浏览器的默认事件,而只执行我们自己编写的代码,因为有的浏览器当你在上面滑动时可能会执行浏览器自己的事件,比如刷新页面等。
if (!mousePress) return:如果此变量的值为false,则不执行后面的代码,即如果用户没有按下鼠标或者触摸屏幕就不会执行画图的操作
var xy = pos(event):调用pos函数,此函数的作用是返回鼠标当前的坐标,或者手指当前的坐标,返回值的格式为{x:x,y:y},我们使用canvas画图需要用到坐标。关于pos函数,我们稍后详细解释
if (last != null):如果last的值不为null,就开始执行画图代码
{board.beginPath();board.moveTo(last.x, last.y);board.lineTo(xy.x, xy.y);board.stroke();}
因为last的初始值为null,所以第一次的判断不会成立,就不会执行上面的画图代码,而是执行下面的last = xy;但是mousemove和touchmove事件在你移动的过程中会一直执行,所以下次的判断就成立了,进而执行画图代码。代码的具体含义请自己学习canvas的使用,非常简单
pos函数
function pos(event) {var x, y;if (isTouch(event)) {x = event.touches[0].pageX;y = event.touches[0].pageY;} else {x = event.offsetX + event.target.offsetLeft;y = event.offsetY + event.target.offsetTop;}// log('x='+x+' y='+y);return {x: x,y: y};
}
代码说明
此函数的作用是获取鼠标点击或者手指触摸的坐标位置
isTouch(event):因为在移动端和PC端获取操作位置的方法不一样,所以使用此方法判断触发当前操作的是鼠标事件还是触摸事件,注意其参数是pos函数的参数,而pos函数的参数event又是其调用者drawing函数传递的,isTouch函数我们稍后会做讲解
理解了这个方法,后面的代码就简单了:根据不同的触发者,分别使用不同的方法获取当前的坐标位置,然后拼接成json格式数据{x:x,y:y}并返回给pos函数的调用者drawing函数
isTouch函数
function isTouch(event) {
var type = event.type;
if (type.indexOf('touch') >= 0) {return true;
} else {return false;
}
}
代码说明
var type = event.type:event.type属性返回的是触发当前操作的是鼠标事件(onmousemove)还是触屏事件(touchmove),我们可以将其输出看一下结果
PC端
移动端
后面的代码就简单了,我们已经看到了event.type的值了,为mousemove或者touchmove,下面的代码就是判断如果type值中包含touch关键字,就返回true,否则返回false。然后pos函数再根据这个返回值执行不同的代码获取鼠标或者手指当前的位置
endDraw函数
function endDraw(event) {
mousePress = false;
event.preventDefault();
last = null;
}
代码解释
当执行onmouseup或者touchend事件时执行这些代码,也就是说当用户松开鼠标或者手指离开触摸屏的时候会执行这些代码
此函数将mousePress变量设置为false,这样再次执行drawing函数时,因为条件不满足(if (!mousePress) return;),就不会执行画图代码了,直到下次用户按下鼠标或者按下手指才会执行
last = null的作用是清空当前存储的坐标值
OK,到这里其实就已经实现画图了,下面的函数用于将用户的涂鸦生成图片
save函数
function save() {
var dataUrl = canvas.toDataURL();
img.src = dataUrl;
}
代码解释
canvas.toDataURL():返回一张使用canvas绘制的图片
img.src = dataUrl:将生成的图片显示到页面上
clean函数
function clean() {
board.clearRect(0, 0, canvas.width, canvas.height);
}
代码解释
这行代码的作用是清除canvas画布上的内容
完整代码
html代码
<!DOCTYPE html>
<html><head>
<title>涂鸦板</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- <script type="text/javascript"
src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML">
</script>-->
<style type="text/css">
#myCanvas {border: 1px solid black;
}
</style>
</head><body>
<!--注意,设置canvas宽、高时不要加上单位,如px-->
<canvas id="myCanvas" width="300" height="300"></canvas>
<div><button onclick="clean();">清 空</button><button onclick="save();">生成图片</button>
</div>
<img id='img' />
</body>
<script type="text/javascript" src="js/canvas.js"></script></html>
js代码
var canvas, board, img;
//获取canvas
canvas = document.getElementById('myCanvas');
//获取img,当用户点击“生成图片”时,会将用户的涂鸦生成图片并显示到这个img中
img = document.getElementById('img');
//获取绘图上下文,将来就是用这个上下文在画板上绘制图形
board = canvas.getContext('2d');
//设置画笔宽度和颜色
board.lineWidth = 1;
board.strokeStyle = "#0000ff";
//声明变量,表示鼠标的按下状态,false表示未按下,true表示按下
var mousePress = false;
var last = null;function beginDraw(event) {mousePress = true;
}function drawing(event) {
event.preventDefault();
if (!mousePress) return;
var xy = pos(event);
if (last != null) {board.beginPath();board.moveTo(last.x, last.y);board.lineTo(xy.x, xy.y);board.stroke();
}
last = xy;}function endDraw(event) {mousePress = false;event.preventDefault();last = null;
}function pos(event) {var x, y;if (isTouch(event)) {x = event.touches[0].pageX;y = event.touches[0].pageY;} else {x = event.offsetX + event.target.offsetLeft;y = event.offsetY + event.target.offsetTop;
}
return {x: x,y: y
};
}function log(msg) {var log = document.getElementById('log');var val = log.value;log.value = msg + 'n' + val;
}function isTouch(event) {var type = event.type;//alert(type);if (type.indexOf('touch') >= 0) {return true;} else {return false;}
}function save() { //返回一张使用canvas绘制的图片 var dataUrl = canvas.toDataURL(); img.src = dataUrl;
}function clean() {board.clearRect(0, 0, canvas.width, canvas.height);
}//为鼠标按下事件指定要执行的函数
canvas.onmousedown = beginDraw;
//为鼠标移动事件指定要执行的函数
canvas.onmousemove = drawing;
//为鼠标松开事件指定要执行的函数
canvas.onmouseup = endDraw;
//为canvas添加touchstart事件,当手指在触摸屏设备(如手机)中按下时触发
canvas.addEventListener('touchstart', beginDraw, false);
//为canvas添加touchmove事件,当手指在触摸屏设备(如手机)中按下并移动时触发
canvas.addEventListener('touchmove', drawing, false);
//为canvas添加touchend事件,当手指在触摸屏设备(如手机)中离开时触发
canvas.addEventListener('touchend', endDraw, false);