您的位置:首页 > Web前端 > HTML5

【初识HTML5】(3) : 画布常用的API (2)

2015-02-13 16:18 399 查看
5.路径、描边、填充

到目前为止,我们讨论过所见即所得的方法只有两个strokeRect() 和fillRect()。但是在实际的设计中,我们不可能都是一笔到底的,比如AI ,我们都是运用路径在作画,因此,在HTML5中,我们同样也是有基于路径的方法。还是先看一段代码吧;

....................................................
context.font = '48pt Helvetica';
context.strokeStyle = 'blue';
context.fillStyle = 'red';
context.lineWidth = '2'; // Line width set to 2 for text
// adText...............................................................
context.strokeText('Stroke', 60, 110);
context.fillText('Fill', 440, 110);
context.strokeText('Stroke & Fill', 650, 110);
context.fillText('Stroke & Fill', 650, 110);
// Rectangles.........................................................
context.lineWidth = '5'; // Line width set to 5 for shapes context.beginPath();
context.rect(80, 150, 150, 100);
context.stroke();
context.beginPath();
context.rect(400, 150, 150, 100);
context.fill();
context.beginPath();
context.rect(750, 150, 150, 100);
context.stroke();
context.fill();
// Open arcs..........................................................
context.beginPath();
context.arc(150, 370, 60, 0, Math.PI*3/2);
context.stroke();
context.beginPath();
context.arc(475, 370, 60, 0, Math.PI*3/2);
context.fill();
context.beginPath();
context.arc(820, 370, 60, 0, Math.PI*3/2);
context.stroke();
context.fill();
// Closed arcs........................................................
context.beginPath();
context.arc(150, 550, 60, 0, Math.PI*3/2);
context.closePath();
context.stroke();
context.beginPath();
context.arc(475, 550, 60, 0, Math.PI*3/2);
context.closePath();
context.fill();
context.beginPath();
context.arc(820, 550, 60, 0, Math.PI*3/2);
context.closePath();
context.stroke();
context.fill();




先介绍下这里用到的API:

arc(x,y,r,sAngle,eAngle,counterclockwise);

x 圆的中心的 x 坐标。

y 圆的中心的 y 坐标。

r 圆的半径。

sAngle 起始角,以弧度计。(弧的圆形的三点钟位置是 0 度)。

eAngle 结束角,以弧度计。

counterclockwise 可选。规定应该逆时针还是顺时针绘图。False = 顺时针,true = 逆时针。

beginPath()

开始一条路径,或重置当前的路径。

closePath()

创建从当前点到开始点的路径。

fill()

填充当前的图像(路径)。默认颜色是黑色。

rect(double x, double y, double width, double height)

x 矩形左上角的 x 坐标

y 矩形左上角的 y 坐标

width 矩形的宽度,以像素计

height 矩形的高度,以像素计

stroke()

会实际地绘制出通过 moveTo() 和 lineTo() 方法定义的路径。默认颜色是黑色。

总结几点:

1.左边第一排第二、第三个图像一个是开放曲线,一个是闭合曲线,区别就是一句代码:closePath();

2.当我们在填充路径时,无论你是开发的还是闭合的,都可以填充。如第二排的图所示;

接下来我们重点研究一下beginPath();

var canvas = document.getElementById('canvas'),
context = canvas.getContext('2d');
context.beginPath();
context.rect(10, 10, 100, 100);
context.beginPath(); //有和没有次语句是完全不一样的
context.rect(50, 50, 100, 100);
context.stroke();




大家理解了吧~ beginpath 清除了之前所有的子路径,从当前的位置开始绘制。

OK 还没结束,我们再来看一种情况:

var canvas = document.getElementById('canvas'),
context = canvas.getContext('2d');
context.beginPath();
context.rect(10, 10, 100, 100);
context.stroke();
context.beginPath(); //有这句代码和没有这句代码区别在哪里?
context.rect(50, 50, 100, 100);
context.stroke();




不难发现,如果没有beginPath(), 第一个矩形又被描了一遍,对吧?

相信到这为止,大家应该对beginpath()有了进一步的了解了吧~

6.填充的原理

很多编程牛人的之所以是牛人,因为他们知道更多底层的东西,不但知其然,还知其所以然。这是每个大牛的必经之路。同样道理,HTML5的填充原理可能很多人不一定知道,但是知道原理之后我们可以做很多事情。

浏览器在填充时,遵循着一个规则非零环绕数规则 (Nonzero Winding Rule)。下面我们详细讲述此规则的原理



大家看到图上的交叉区域了吗?图中的角度表示了曲线的走向是顺时针还是逆时针。

浏览器的工作原理如下:

**第一步:首先,从交叉区域画一条线一直到外面;

第二布:与箭头交叉的曲线如果是顺时针方向,则加1,逆时针则减1(当然,初始化的时候计数为0);

第三步:对计算结果不为0的位置进行填充。很明显,图中空白的地方,有两条互为反方向的曲线经过直线,结果为0,所以不填充。**

既然知道原理了,我们就好办事儿啦,比如说做出一些镂空的效果,我们来实际应用一下:

var canvas = document.getElementById('canvas'),
context = canvas.getContext('2d');

context.arc(300, 190, 150, 0, Math.PI*2, false); // 顺时针
context.arc(300, 190, 100, 0, Math.PI*2, true); // 逆时针
context.fill();




我们通过这个fill()的原理,轻松做出了上面的效果。

7.线条

Sam在自学HTML5的时候感觉,线条其实是有点小烦的,还涉及到角度,三角函数等等,要画的好并不是件容易的事情。Anyway, 我们还是应该花点时间去啃下这块骨头。大家有什么好的建议和想法都可以一起交流,Sam虽然不是程序猿,但是大家都知道程序猿是需要耐心的,并且通过交流,大家可以少走很多弯路,get到新的技能。right? OK, Let’s start~

先看一段代码:

var context = document.getElementById('canvas').getContext('2d');
context.lineWidth = 1;
context.beginPath();
context.moveTo(50, 10);
context.lineTo(450, 10);
context.stroke();
context.beginPath();
context.moveTo(50.5, 50.5);
context.lineTo(450.5, 50.5);
context.stroke();




这里主要用到两个方法:

moveTo(x, y)

x 路径的目标位置的 x 坐标

y 路径的目标位置的 y 坐标

lineTo(x, y)

x 路径的目标位置的 x 坐标

y 路径的目标位置的 x 坐标

1像素线条的问题:

有时候大家在画图的时候发现,1像素的线条有时候模糊不清,为什么呢?

我们向来看两个图:

var context = document.getElementById('canvas').getContext('2d');
context.lineWidth = 1;
context.beginPath();
context.moveTo(50, 10);
context.lineTo(450, 10);
context.stroke();
context.beginPath();
context.strokeStyle='red';
context.moveTo(50, 11.5);
context.lineTo(450, 11.5);
context.stroke();




问题来了:我们通过放大浏览器发现一个问题。两条线居然重合了。按理说不应该呀。线条宽度才1像素,我们算上线的宽度,再多加0.5,在Y轴下移1.5,怎么线还是重合的呢? 真想只有一个,我们不了解浏览器。。。



1.浏览器在画画的时候是不是以线条和像素边界对齐来画画的,而是用线条的中间线(图中的红色箭头)来对齐像素点,然后左右平均延伸开来画画的,按理说就是左右各画0.5像素。但是计算机木画不了0.5像素的线呀。所以只能延伸到左右两边都给画了。所以1像素最后成了2像素。这样就解释了为什么我们看到图上是重合的。

2.根据这个原理,其实大家可以自己测试一下,在放大的情况下,但凡是单数宽度的线条,两边都是有点白色模糊的,而双数的基本是很清晰的。因为单数的情况下,一定会跨在某个像两边,造成“虚化”的想象。

3.当然,没有人去计较这个问题,在正常比例浏览的情况下,肉眼辨别的都是清晰的。毕竟才0.5像素的误差,当线条大于1的时候基本就忽略不计了,所以不要去追求这个问题,我们在这里讨论主要目的是知道一些底层的东西罢了。

在讨论线条的时候,我们说过,HTML5是没有画虚线的API的,所以我们要自己动手,下面是一个简单的小例子,大家可以参考一下:

var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');
var lineWidth = 10;
var lineGap = 10;

context.lineWidth = 10;

for (var i = 100; i <= canvas.width; i+=lineGap+lineWidth) {
context.beginPath();
context.moveTo(i, 100);
context.moveTo(i, 100);
context.lineTo(i+lineWidth, 100);
context.stroke();
}




相信大家到目前为止,自己动手画一个网格背景应该已经不是什么大问题了。



接下来我们看看和线条有关的的4个属性吧:

lineWidth:设置或返回当前线条的宽度,以像素计。

lineCap:设置或返回线条末端线帽的样式。

butt 默认。向线条的每个末端添加平直的边缘。

round 向线条的每个末端添加圆形线帽。

square 向线条的每个末端添加正方形线帽。

lineJoin:设置或返回所创建边角的类型,当两条线交汇时。

bevel 创建斜角。

round 创建圆角。

miter 默认。创建尖角。

miterLimit:设置或返回最大斜接长度。

斜接长度指的是在两条线交汇处内角和外角之间的距离。

只有当 lineJoin 属性为 “miter” 时,miterLimit 才有效。

边角的角度越小,斜接长度就会越大。

为了避免斜接长度过长,我们可以使用 miterLimit 属性。

如果斜接长度超过 miterLimit 的值,边角会以 lineJoin 的 “bevel” 类型来显示

比较简单,我们就对lineJoin和miterLimit做个演示吧:

var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');
context.beginPath();
context.lineWidth = 10;
context.lineJoin = "round";
context.moveTo(20, 20);
context.lineTo(100, 50);
context.lineTo(20, 100);
context.stroke();




我们再来看看miterLimit的使用

var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');
context.lineWidth = 10;
context.lineJoin = "miter";
context.miterLimit = 30;
context.moveTo(20, 20);
context.lineTo(50, 27);
context.lineTo(20, 34);
context.stroke();




大家尝试把miterLimit改为1试试?边角会以 lineJoin 的 “bevel” 类型来显示。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  html5 sam走起