canvas画图--流畅没有齿痕的线,图像画线
画图,首先要获取鼠标位置,当鼠标在画图板上移动时,随之画线。
1.画图板canvas,监听鼠标事件
2.获取鼠标事件,得到鼠标位置。
var mouse = {x: 0, y: 0}; //起始鼠标位置,也就是mousedown
var last_mouse = {x: 0, y: 0};
/* Mouse Capturing Work */
canvas.addEventListener('mousemove', function(e) {
last_mouse.x = mouse.x;
last_mouse.y = mouse.y;
mouse.x = e.pageX - this.offsetLeft;
mouse.y = e.pageY - this.offsetTop;
}, false);
以上,通过canvas.addEventListener使画图板canvas监听到鼠标事件。
3. 画线
var onPaint = function() {
ctx.beginPath();
ctx.moveTo(last_mouse.x, last_mouse.y); //[code]moveTo 从一个点移动到另一个点。
ctx.lineTo(mouse.x, mouse.y); //lineTo方法画直线; 方法接受终点的坐标(x,y)作为参数
ctx.closePath();
ctx.stroke();
};[/code]
第一步是用 beginPath 创建一个路径。在内存里,路径是以一组子路径(直线,弧线等)的形式储存的,它们共同构成一个图形。每次调用 beginPath,子路径组都会被重置,然后可以绘制新的图形。
第二步就是实际绘制路径的部分,moveTo和lineTo。
第三步是调用 closePath 方法,它会尝试用直线连接当前端点与起始端点来关闭路径,但如果图形已经关闭或者只有一个点,它会什么都不做。这一步不是必须的。
最后一步是调用 stroke 或 fill 方法,这时,图形才是实际的绘制到 canvas 上去。stroke 是绘制图形的边框,fill 会用填充出一个实心图形。
基础知识,请参考https://developer.mozilla.org/zh-CN/docs/Canvas_tutorial/Drawing_shapes
以下是完整的代码。
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type" />
<meta http-equiv="Content-Script-Type" content="text/javascript" />
<meta http-equiv="Content-Style-Type" content="text/css" />
<meta content=" initial-scale=0.80,user-scalable=no" />
<link href="http://code.jquery.com/ui/1.9.1/themes/base/jquery-ui.css" />
<script src="http://code.jquery.com/jquery-1.8.2.js"></script>
<script src="http://code.jquery.com/ui/1.9.1/jquery-ui.js"></script>
<title>Pencil</title>
<style type="text/css">
html, body {
width: 100%;
height: 100%;
}
#sketch {
border: 10px solid gray;
height: 100%;
position: relative;
}
#tmp_canvas {
position: absolute;
left: 0px; right: 0;
bottom: 0; top: 0;
cursor: crosshair;
}
</style>
<script type="text/javascript">
$(document).ready(function(){
var canvas = document.querySelector('#paint');
var ctx = canvas.getContext('2d');
var sketch = document.querySelector('#sketch');
var sketch_style = getComputedStyle(sketch);
canvas.width = parseInt(sketch_style.getPropertyValue('width'));
canvas.height = parseInt(sketch_style.getPropertyValue('height'));
var mouse = {x: 0, y: 0};
var last_mouse = {x: 0, y: 0};
/* Mouse Capturing Work */
canvas.addEventListener('mousemove', function(e) {
last_mouse.x = mouse.x;
last_mouse.y = mouse.y;
mouse.x = e.pageX - this.offsetLeft;
mouse.y = e.pageY - this.offsetTop;
}, false);
/* Drawing on Paint App */
ctx.lineWidth = 5;
ctx.lineJoin = 'round';
ctx.lineCap = 'round';
ctx.strokeStyle = 'blue';
canvas.addEventListener('mousedown', function(e) {
canvas.addEventListener('mousemove', onPaint, false);
}, false);
canvas.addEventListener('mouseup', function() {
canvas.removeEventListener('mousemove', onPaint, false);
}, false);
var onPaint = function() {
ctx.beginPath();
ctx.moveTo(last_mouse.x, last_mouse.y);
ctx.lineTo(mouse.x, mouse.y);
ctx.closePath();
ctx.stroke();
};
});
</script>
</head>
<body>
<div>
<canvas></canvas>
</div>
</body>
</html>
这个代码很容易实现,但是它有个问题,就是画线不流畅,出现折断痕迹。
4.画流畅的线
可以根据二次贝塞尔曲线,连接2点画弧得到没有折痕的流畅曲线。
可以参照:
tmp_ctx.beginPath();
tmp_ctx.moveTo(ppts[0].x, ppts[0].y); //使用 beginPath() 和 moveTo() 方法来定义开始点
for (var i = 1; i < ppts.length - 2; i++) {
var c = (ppts[i].x + ppts[i + 1].x) / 2;
var d = (ppts[i].y + ppts[i + 1].y) / 2;
tmp_ctx.quadraticCurveTo(ppts[i].x, ppts[i].y, c, d); //二次贝塞曲线函数
}
// For the last 2 points
tmp_ctx.quadraticCurveTo(
ppts[i].x,
ppts[i].y,
ppts[i + 1].x,
ppts[i + 1].y
);
tmp_ctx.stroke(); //[code]这时,图形才是实际的绘制到 canvas 上去,stroke 是绘制图形的边框[/code]
quadraticCurveTo(cpx, cpy, x, y);方法通过使用表示二次贝塞尔曲线的指定控制点,向当前路径添加一个点。第一个点是用于二次贝塞尔计算中的控制点,第二个点是曲线的结束点。曲线的开始点是当前路径中最后一个点。
虽然这样子可以画出贝塞尔曲线,但是你可以发现,它还是有锯齿边缘的。但是在画图之前加一个clearRect()函数,则锯齿消失!我不晓得这是为什么。。。
5.画没有齿痕的流畅曲线
tmp_ctx.beginPath();
tmp_ctx.moveTo(ppts[0].x, ppts[0].y);
tmp_ctx.clearRect(0, 0, 2000, 2000);//它可以消除齿痕!
for (var i = 1; i < ppts.length - 2; i++) {
var c = (ppts[i].x + ppts[i + 1].x) / 2;
var d = (ppts[i].y + ppts[i + 1].y) / 2;
tmp_ctx.quadraticCurveTo(ppts[i].x, ppts[i].y, c, d);
}
// For the last 2 points
tmp_ctx.quadraticCurveTo(
ppts[i].x,
ppts[i].y,
ppts[i + 1].x,
ppts[i + 1].y
);
tmp_ctx.stroke();
6.接下来是橡皮的问题,虽然可以用相同背景色来代替,但是如果背景不单一,那就不管用了。所以,我们需要一个完完全全的橡皮,而不是相同背景,或者消除一块区域的痕迹。
那么,我们可以简单的引用globalCompositeOperation()函数,这个函数是用来在画布上组合颜色,我们可以利用这个原理,叠加(数学上的"或"原理)来制作橡皮。
同画笔一样,获得鼠标位置,叠加画板上已有的颜色,则为取消。
globalCompositeOperation()函数,请参考
画笔画图时: context.globalCompositeOperation = 'source-over'; //新的颜色覆盖之前的
橡皮擦除时: context.globalCompositeOperation = 'destination-out'; //新的颜色与之前颜色,重叠的部分消失
7. 画具有透明度的线
<!--
Internet Explorer 9、Firefox、Opera、Chrome 以及 Safari 支持。
From:?postid=2841967 -->
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type" />
<meta http-equiv="Content-Script-Type" content="text/javascript" />
<meta http-equiv="Content-Style-Type" content="text/css" />
<meta content=" initial-scale=0.80,user-scalable=no" />
<link href="http://code.jquery.com/ui/1.9.1/themes/base/jquery-ui.css" />
<script src="http://code.jquery.com/jquery-1.8.2.js"></script>
<script src="http://code.jquery.com/ui/1.9.1/jquery-ui.js"></script>
<title>Pencil</title>
<style type="text/css">
ul, li{
clear:both;
list-style:none;
margin:0 auto;
display: inline;
}
html, body {
width: 100%;
height: 100%;
}
#sketch {
border: 10px solid gray;
height: 100%;
position: relative;
}
#tmp_canvas {
position: absolute;
left: 0px; right: 0;
bottom: 0; top: 0;
cursor: crosshair;
}
</style>
<script type="text/javascript">
$(document).ready(function(){
var canvas = document.querySelector('#paint');
var ctx = canvas.getContext('2d');
var sketch = document.querySelector('#sketch');
var sketch_style = getComputedStyle(sketch);
canvas.width = parseInt(sketch_style.getPropertyValue('width'));
canvas.height = parseInt(sketch_style.getPropertyValue('height'));
// Creating a tmp canvas
var tmp_canvas = document.createElement('canvas');
var tmp_ctx = tmp_canvas.getContext('2d');
tmp_canvas.id = 'tmp_canvas';
tmp_canvas.width = canvas.width;
tmp_canvas.height = canvas.height;
sketch.appendChild(tmp_canvas);
var mouse = {x: 0, y: 0};
var last_mouse = {x: 0, y: 0};
var paint = {
init:function(canvasID_, canvas, context, brushImage){
this.canvasID_ = canvasID_;
this.canvasID = $("#"+canvasID_);
this.canvas = canvas;
this.context = context;
/** Drawing on Line Paint App */
this.context.lineWidth = 5;
this.context.lineJoin = 'round';
this.context.lineCap = 'round';
this.context.strokeStyle = 'red';
this.context.fillStyle = 'red';
this.color=["#000000","#9E9E9E","#FFFFFF","#8B5742","#FF0000","#FFC125","#00688B","#CDB38B","#CD8C95"];
this.lock = false;
this.line = false;
ppts = [];
// Pencil Points
this.brush = brushImage;
this.context.globalAlpha = 1;
/** mouse event */
if (this.touchSupported) {
this.mouseDownEvent = "touchstart";
this.mouseMoveEvent = "touchmove";
this.mouseUpEvent = "touchend";
}
else {
this.mouseDownEvent = "mousedown";
this.mouseMoveEvent = "mousemove";
this.mouseUpEvent = "mouseup";
}
this.bind();
},
bind:function(){
var t = this; //paint Instance
this.canvasID.live({
mousedown: function(e){
mouse.x = typeof e.offsetX !== 'undefined' ? e.offsetX : e.layerX;
mouse.y = typeof e.offsetY !== 'undefined' ? e.offsetY : e.layerY;
ppts.push({x: mouse.x , y: mouse.y});
t.lock=true;
},
mousemove: function(e){
if(t.lock){
mouse.x = typeof e.offsetX !== 'undefined' ? e.offsetX : e.layerX;
mouse.y = typeof e.offsetY !== 'undefined' ? e.offsetY : e.layerY;
ppts.push({x: mouse.x , y: mouse.y });
//tmp_ctx.clearRect(0, 0, 2000, 2000);
//if(t.line == true){ //draw line
t.onPaint();
//}
//if(t.line ==false){
//t.drawPoint(); //draw image
//}
}
},
mouseleave:function(e){
t.lock = false;
//ctx.drawImage(tmp_canvas, 0, 0);
//tmp_ctx.clearRect(0, 0, 2000, 2000);
ppts = [];
},
mouseup: function(e){
t.lock = false;
//ctx.drawImage(tmp_canvas, 0, 0);
//tmp_ctx.clearRect(0, 0, 2000, 2000);
//tmp_ctx.drawImage(canvas, 0, 0);
ppts = [];
}
});
},
onPaint:function()
{
var tmp_ctx = this.context;
// Tmp canvas is always cleared up before drawing.
tmp_ctx.clearRect(0, 0, 2000, 2000);
//取消齿痕; 如果想用橡皮,则注释这句,因为绘图痕迹绘在两个图层中。
if (ppts.length < 3) {
var b = ppts[0];
tmp_ctx.beginPath();
tmp_ctx.arc(b.x, b.y, tmp_ctx.lineWidth / 2, 0, Math.PI * 2, !0);
tmp_ctx.fill();
tmp_ctx.closePath();
return;
}
tmp_ctx.beginPath();
tmp_ctx.moveTo(ppts[0].x, ppts[0].y);
for (var i = 1; i < ppts.length - 2; i++) {
var c = (ppts[i].x + ppts[i + 1].x) / 2;
var d = (ppts[i].y + ppts[i + 1].y) / 2;
tmp_ctx.quadraticCurveTo(ppts[i].x, ppts[i].y, c, d);
}
// For the last 2 points
tmp_ctx.quadraticCurveTo(
ppts[i].x,
ppts[i].y,
ppts[i + 1].x,
ppts[i + 1].y
);
tmp_ctx.stroke();
},
changeColor:function(style,color)
{
var t=this;
var styleNum = style;
var colorNum = color;
console.debug("pen ="+style+", color="+color);
t.context.strokeStyle = t.color[colorNum];
t.context.fillStyle = t.color[colorNum];
if(styleNum == 0){ //mark pen
t.line = true;
t.context.lineWidth = 30;
t.context.globalAlpha = 0.5;
t.context.globalCompositeOperation = 'source-over';
console.debug("mark");
}
if(styleNum == 1){ //peicnl
t.line = true;
t.context.lineWidth = 5;
t.context.globalAlpha = 1;
t.context.globalCompositeOperation = 'source-over';
console.debug("pencil");
}
if(styleNum == 2){ //resetEraser
t.line = true;
//t.context = ctx;
t.resetEraser();
}
},
resetEraser:function()
{
var t=this;
//t.context = ctx;
t.context.lineWidth = 30;
t.context.globalAlpha = 1;
t.context.globalCompositeOperation = 'destination-out';
console.debug("resetEraser");
},
clear:function()
{
ppts = [];
this.context.globalAlpha = 0;
this.context.clearRect(0, 0, this.w, this.h);
}
};
<!-- drawing -->
var brush = new Image();
brush.src = "images/color_01.png";
//defalut red
brush.onload = function(){
paint.init('tmp_canvas',tmp_canvas,tmp_ctx, brush);
};
var style = 1;
var color = 1;
$('.tool> li > a').click(function() {
var idx = $('.tool> li > a').index(this);
style = idx;
paint.changeColor(style, color);
if(idx == 2){
//paint.init('paint',paint,ctx, brush);
}
});
$('.brush > li > a').click(function() {
var idx = $('.brush > li > a').index(this);
var i = idx + 1;
//brush.src = "images/color_0"+i+".png";
color = idx;
paint.changeColor(style, color);
});
});
</script>
</head>
<body>
<div>
<ul>
<li><a href="javascript:void(0)"><img src="images/crayon-outline.png" alt=""></a></li>
<li><a href="javascript:void(0)"><img src="images/marker-outline.png" alt=""></a></li>
<li><a href="javascript:void(0)"><img src="images/eraser-outline.png" alt=""></a></li>
<li><a href="javascript:void(0)"><img src="images/image-outline.png" alt=""></a></li>
</ul>
<ul>
<li><a href="javascript: void(0);"><img src="images/color_01.png" /></a></li>
<li><a href="javascript: void(0);"><img src="images/color_02.png" /></a></li>
<li><a href="javascript: void(0);"><img src="images/color_03.png" /></a></li>
<li><a href="javascript: void(0);"><img src="images/color_04.png" /></a></li>
<li><a href="javascript: void(0);"><img src="images/color_05.png" /></a></li>
<li><a href="javascript: void(0);"><img src="images/color_06.png" /></a></li>
<li><a href="javascript: void(0);"><img src="images/color_07.png" /></a></li>
<li><a href="javascript: void(0);"><img src="images/color_08.png" /></a></li>
<li><a href="javascript: void(0);"><img src="images/color_09.png" /></a></li>
</ul>
</div>
<div>
<canvas></canvas>
</div>
</body>
</html>
引用请注明出处~
猜你在找