本文主要实现画板基本功能和介绍canvas的具体的使用
<1> 实现鼠标绘制功能
首先是HTML代码:
直接在body中添加canvas标签
<canvas id="mycanvas"></canvas>
js代码:
$(function() {
var mycanvas = document.getElementById("mycanvas");
var ctx = mycanvas.getContext("2d");
var mX = 0;
var mY = 0;
var isDraw = false;
var width = document.documentElement.clientWidth;
var height = document.documentElement.clientHeight;
mycanvas.width = width;
mycanvas.height = height;
ctx.lineWidth = "2"; //设置画笔的大小
ctx.strokeStyle = "#FFA500"; //设置画笔的颜色
$("#mycanvas").on("mousedown", function(e) {
isDraw = true;
mX =e.pageX; //记录按下的位置X
mY = e.pageY; //记录按下的位置Y
});
$("#mycanvas").on("mousemove", function(e) {
if(isDraw) {
var tX = e.pageX;
var tY = e.pageY;
draw(mX,mY,tX,tY);
}
});
$("#mycanvas").on("mouseup", function(e) {
isDraw=false;
});
function draw(ox, oy, newX, newY) {
ctx.beginPath(); //开始
ctx.moveTo(ox, oy); //移动到...
ctx.lineTo(newX, newY); //To...
ctx.stroke(); //绘制
mX = newX;
mY = newY;
ctx.closePath(); //结束
}
});
其中需要注意的是,在CSS中给canvas设置的宽高和在标签中设置width和height是不一样的,建议在js中重新设置宽高
mycanvas.width=document.documentElement.clientWidth;
mycanvas.height=document.documentElement.clientHeight
到这个时候已经实现可以用鼠标在画布上绘制了。
<2>实现绘制图案功能
先从绘制直线开始
/**
*
* @param {Object} ox 起点X
* @param {Object} oy 起点Y
* @param {Object} newX 终点X
* @param {Object} newY 终点Y
*/
function drawLine(ox, oy, newX, newY) {
ctx.beginPath();
ctx.moveTo(ox, oy);
ctx.lineTo(newX, newY);
ctx.stroke();
ctx.closePath();
}
在mousemove事件中调用该方法,鼠标拖动绘制时会出现以下效果:
这显然不是想要的效果,原因是在拖动的时候会不停的绘制直线(问题1)
(问题1)解决办法:每次绘制之前,先清理画板
function drawLine(ox, oy, newX, newY) {
ctx.clearRect(0, 0, width, height); //清除整个画板,width和height都等于浏览器的大小
ctx.beginPath();
ctx.moveTo(ox, oy);
ctx.lineTo(newX, newY);
ctx.stroke();
ctx.closePath();
}
这样可以绘制出一条直线的效果了;
但当绘制第二条的时候,第一条直线却被清除了,原因在于每次绘制前都把画布给清理一遍了ctx.clearRect(0, 0, width, height),(问题2)
(问题2)解决办法:
我们应该在每次绘制后,先将画布上的内容保存一份出来,在下次绘制时先清理画布,然后把保存的内容重新绘制出来,再进行接下来的动作。
在这里使用到canvas的两个方法putImageData和getImageData,分别对应绘制数据和获取画布数据,
先创建一个数组用于保存画布数据:
var imageData = [];
在松开鼠标的时候便保存画布数据,所以在mouseup事件中:
imageData.push(ctx.getImageData(0, 0, width, height));
数据保存后,在清理画布之后要绘制出来:
function drawLine(ox, oy, newX, newY) {
ctx.clearRect(0, 0, width, height);
if(imageData.length > 0)
ctx.putImageData(imageData[imageData.length - 1], 0, 0, 0, 0, width, height); //将数据显示在画布上
ctx.beginPath();
ctx.moveTo(ox, oy);
ctx.lineTo(newX, newY);
ctx.stroke();
ctx.closePath();
}
至此,我们就完成绘制直线的功能了。
绘制矩形和圆形,思路都是一样的
function drawRect(startX, startY, endX, endY) {
ctx.clearRect(0, 0, width, height);
if(imageData.length > 0)
ctx.putImageData(imageData[imageData.length - 1], 0, 0, 0, 0, width, height);
ctx.beginPath();
ctx.rect(startX, startY, endX - startX, endY - startY); //创建矩形
ctx.stroke();
ctx.closePath();
}
function drawArc(startX, startY, endX, endY) {
ctx.clearRect(0, 0, width, height);
if(imageData.length > 0)
ctx.putImageData(imageData[imageData.length - 1], 0, 0, 0, 0, width, height);
ctx.beginPath();
var radius = Math.abs(Math.max((endX - startX), (endY - startY)));
//创建圆形,参数分别对应:圆心X,圆心Y,半径,起点(时钟3点方向为0度),终点 PI=180度,从0度开始
ctx.arc(startX, startY, radius, 0, 2 * Math.PI);
ctx.stroke();
ctx.closePath();
}
注:上述画圆效果可能和想象中不一样(请自行测试),现提供另一种效果(效果请自行测试):
//代码不是很复杂,就不多做解析了
function drawArc2(startX, startY, endX, endY) {
ctx.clearRect(0, 0, width, height);
if(imageData.length > 0)
ctx.putImageData(imageData[imageData.length - 1], 0, 0, 0, 0, width, height);
var offsetX = Math.abs(endX - startX);
var offsetY = Math.abs(endY - startY);
var radius = offsetX > offsetY ? offsetY / 2 : offsetX / 2;
ctx.beginPath();
if((endX - startX) < 0 && (endY - startY) < 0) {
ctx.arc(startX - radius, startY - radius, Math.abs(radius), 0, 2 * Math.PI);
} else if(endX - startX < 0) {
ctx.arc(startX - radius, startY + radius, Math.abs(radius), 0, 2 * Math.PI);
} else if(endY - startY < 0) {
ctx.arc(startX + radius, startY - radius, Math.abs(radius), 0, 2 * Math.PI);
} else {
ctx.arc(startX + radius, startY + radius, Math.abs(radius), 0, 2 * Math.PI);
}
ctx.stroke();
ctx.closePath();
}
到现在,基本的画板功能都已经实现了,最后,当然少不了橡皮擦:
function eraser(x, y) {
var o = 5; //擦除区域大小
ctx.clearRect(x - o, y - o, o * 2, o * 2);
}
很简单,和清除画布一样,只是把清除的区域限制好就行了。
最后,附上完整一点的代码:
$(function() {
var imageData = [];
var mycanvas = document.getElementById("mycanvas");
var ctx = mycanvas.getContext("2d");
var mX = 0;
var mY = 0;
var isDraw = false;
var width = document.documentElement.clientWidth;
var height = document.documentElement.clientHeight;
mycanvas.width = width;
mycanvas.height = height;
ctx.lineWidth = "2";
ctx.strokeStyle = "#FFA500";
$("#mycanvas").on("mousedown", function(e) {
isDraw = true;
mX = e.pageX;
mY = e.pageY;
//eraser(mX,mY);
});
$("#mycanvas").on("mousemove", function(e) {
if(isDraw) {
var tX = e.pageX;
var tY = e.pageY;
//draw(mX,mY,tX,tY);
//drawLine(mX, mY, tX, tY);
//drawRect(mX, mY, tX, tY);
//drawArc(mX, mY, tX, tY);
//drawArc2(mX, mY, tX, tY);
//eraser(tX,tY);
}
});
$("#mycanvas").on("mouseup", function(e) {
isDraw = false;
imageData.push(ctx.getImageData(0, 0, width, height));
});
function draw(ox, oy, newX, newY) {
ctx.beginPath();
ctx.moveTo(ox, oy);
ctx.lineTo(newX, newY);
ctx.stroke();
mX = newX;
mY = newY;
ctx.closePath();
}
/**
* 绘制直线
* @param {Object} ox 起点X
* @param {Object} oy 起点Y
* @param {Object} newX 终点X
* @param {Object} newY 终点Y
*/
function drawLine(ox, oy, newX, newY) {
ctx.clearRect(0, 0, width, height);
if(imageData.length > 0)
ctx.putImageData(imageData[imageData.length - 1], 0, 0, 0, 0, width, height);
ctx.beginPath();
ctx.setLineDash([5, 15]);
ctx.moveTo(ox, oy);
ctx.lineTo(newX, newY);
ctx.stroke();
ctx.closePath();
}
/**
* 绘制矩形
* @param {Object} startX
* @param {Object} startY
* @param {Object} endX
* @param {Object} endY
*/
function drawRect(startX, startY, endX, endY) {
ctx.clearRect(0, 0, width, height);
if(imageData.length > 0)
ctx.putImageData(imageData[imageData.length - 1], 0, 0, 0, 0, width, height);
ctx.beginPath();
ctx.rect(startX, startY, endX - startX, endY - startY);
ctx.stroke();
ctx.closePath();
}
function drawArc(startX, startY, endX, endY) {
ctx.clearRect(0, 0, width, height);
if(imageData.length > 0)
ctx.putImageData(imageData[imageData.length - 1], 0, 0, 0, 0, width, height);
ctx.beginPath();
var radius = Math.abs(Math.max((endX - startX), (endY - startY)));
ctx.arc(startX, startY, radius, 0, 2 * Math.PI);
ctx.stroke();
ctx.closePath();
}
function drawArc2(startX, startY, endX, endY) {
ctx.clearRect(0, 0, width, height);
if(imageData.length > 0)
ctx.putImageData(imageData[imageData.length - 1], 0, 0, 0, 0, width, height);
var offsetX = Math.abs(endX - startX);
var offsetY = Math.abs(endY - startY);
var radius = offsetX > offsetY ? offsetY / 2 : offsetX / 2;
ctx.beginPath();
if((endX - startX) < 0 && (endY - startY) < 0) {
ctx.arc(startX - radius, startY - radius, Math.abs(radius), 0, 2 * Math.PI);
} else if(endX - startX < 0) {
ctx.arc(startX - radius, startY + radius, Math.abs(radius), 0, 2 * Math.PI);
} else if(endY - startY < 0) {
ctx.arc(startX + radius, startY - radius, Math.abs(radius), 0, 2 * Math.PI);
} else {
ctx.arc(startX + radius, startY + radius, Math.abs(radius), 0, 2 * Math.PI);
}
ctx.stroke();
ctx.closePath();
}
function eraser(x, y) {
var o = 5;
ctx.clearRect(x - o, y - o, o * 2, o * 2);
}
});