目 录 | |
---|---|
1 | 色彩 Color |
2 | 透明度 Transparency |
3 | 线型 Line styles |
4 | 渐变 Gradients |
1. 色彩 Color
如果想要给图形上色,有两个重要的属性可以做到:fillStyle 和 strokeStyle。
-
fillStyle = color
设置图形的填充颜色。
-
strokeStyle = color
设置图形轮廓的颜色。
color 可以是表示 CSS 颜色值的字符串,渐变对象或者图案对象。默认情况下,线条和填充颜色都是黑色(CSS 颜色值 #000000)。
一旦设置了 strokeStyle 或者 fillStyle 的值,那么这个新值就会成为新绘制的图形的默认值。如果要给每个图形上不同的颜色,需要重新设置 fillStyle 或 strokeStyle 的值。
canvas接受所有符合 CSS3 颜色值标准 的有效字符串。
// 以下 fillStyle 的值均为 '橙色'
ctx.fillStyle = "orange";
ctx.fillStyle = "#FFA500";
ctx.fillStyle = "rgb(255,165,0)";
ctx.fillStyle = "rgba(255,165,0,1)";
下面来看一个fillStyle的例子。
function draw() {
var ctx = document.getElementById('canvas').getContext('2d');
for (var i=0;i<6;i++){
for (var j=0;j<6;j++){
ctx.fillStyle = 'rgb(' + Math.floor(255-42.5*i) + ',' +
Math.floor(255-42.5*j) + ',0)';
ctx.fillRect(j*25,i*25,25,25);
}
}
}
在本示例里使用了两层 for 循环来绘制方格阵列,每个方格不同的颜色,结果如下图所示。
代码中使用了两个变量 i 和 j 来为每一个方格产生唯一的 RGB 色彩值,其中仅修改红色和绿色通道的值,而保持蓝色通道的值不变。
了解了fillStyle后,下面来看看strokeStyle。
function draw2() {
var ctx = document.getElementById('cvs2').getContext('2d');
for (var i=0;i<6;i++){
for (var j=0;j<6;j++){
ctx.strokeStyle = 'rgb(0,' + Math.floor(255-42.5*i) + ',' +
Math.floor(255-42.5*j) + ')';
ctx.beginPath();
ctx.arc(12.5+j*25,12.5+i*25,10,0,Math.PI*2,true);
ctx.stroke();
}
}
}
与上一个例子类似,只不过本例中使用的是 strokeStyle 属性,保持不变的是红色通道值,画的不是方格,而是用 arc 方法来画圆。
2. 透明度 Transparency
除了可以绘制实色图形,还可以用 canvas 来绘制半透明的图形。通过设置 globalAlpha 属性或者使用一个半透明颜色作为轮廓或填充的样式。
- globalAlpha = transparencyValue
这个属性影响到 canvas 里所有图形的透明度,有效的值范围是 0.0 (完全透明)到 1.0(完全不透明),默认是 1.0。
globalAlpha 属性在需要绘制大量拥有相同透明度的图形时候相当高效。在绘制透明度比较多变的图形时,下面的方法可操作性更强一点。
因为 strokeStyle 和 fillStyle 属性接受符合 CSS 3 规范的颜色值,那我们可以用下面的写法来设置具有透明度的颜色。
// 指定透明颜色,用于描边和填充样式
ctx.strokeStyle = "rgba(255,0,0,0.5)";
ctx.fillStyle = "rgba(255,0,0,0.5)";
rgba() 方法与 rgb() 方法类似,就多了一个用于设置色彩透明度的参数。它的有效范围是从 0.0(完全透明)到 1.0(完全不透明)。
下面来分别看看两种方式的示例。
function draw3() {
var ctx = document.getElementById('cvs3').getContext('2d');
ctx.fillStyle = '#FD0';
ctx.fillRect(0,0,75,75);
ctx.fillStyle = '#6C0';
ctx.fillRect(75,0,75,75);
ctx.fillStyle = '#09F';
ctx.fillRect(0,75,75,75);
ctx.fillStyle = '#F30';
ctx.fillRect(75,75,75,75);
ctx.fillStyle = '#FFF';
// 设置透明度值
ctx.globalAlpha = 0.2;
// 画半透明圆
for (var i=0;i<7;i++){
ctx.beginPath();
ctx.arc(75,75,10+10*i,0,Math.PI*2,true);
ctx.fill();
}
}
先来看看globalAlpha。
在本例中,将用四色格作为背景,设置 globalAlpha 为 0.2 后,在上面画一系列半径递增的半透明圆。最终结果是一个径向渐变效果。圆叠加得越更多,原先所画的圆的透明度会越低。通过增加循环次数,画更多的圆,背景图的中心部分会完全消失。
下面是rgba()的示例。
function draw4() {
var ctx = document.getElementById('cvs4').getContext('2d');
ctx.fillStyle = 'rgb(255,221,0)';
ctx.fillRect(0,0,150,37.5);
ctx.fillStyle = 'rgb(102,204,0)';
ctx.fillRect(0,37.5,150,37.5);
ctx.fillStyle = 'rgb(0,153,255)';
ctx.fillRect(0,75,150,37.5);
ctx.fillStyle = 'rgb(255,51,0)';
ctx.fillRect(0,112.5,150,37.5);
// 画半透明矩形
for (var i=0;i<10;i++){
ctx.fillStyle = 'rgba(255,255,255,'+(i+1)/10+')';
for (var j=0;j<4;j++){
ctx.fillRect(5+i*14,5+j*37.5,14,27.5)
}
}
}
与前一个例子类似,不过不是画圆,而是画矩形。这里还可以看出,rgba() 可以分别设置轮廓和填充样式,因而具有更好的可操作性和使用灵活性。
3. 线型 Line styles
上一篇博文中的线条十分单调,这里将介绍一系列属性用于修饰线条的样式。
-
lineWidth = value
设置线条宽度。
-
lineCap = type
设置线条末端样式。
-
lineJoin = type
设定线条与线条间接合处的样式。
-
getLineDash() 返回一个包含当前虚线样式,长度为非负偶数的数组。
-
setLineDash(segments)
设置当前虚线样式。
-
lineDashOffset = value
设置虚线样式的起始偏移量。
下面来分别看看各属性的例子,首先是lineWidth。
function draw5() {
var ctx = document.getElementById('cvs5').getContext('2d');
for (var i = 0; i < 10; i++){
ctx.lineWidth = 1+i;
ctx.beginPath();
ctx.moveTo(5+i*14,5);
ctx.lineTo(5+i*14,140);
ctx.stroke();
}
}
lineWidth属性设置当前绘线的粗细。属性值必须为正数。默认值是1.0。
lineWidth是指给定路径的中心到两边的粗细。换句话说就是在路径的两边各绘制线宽的一半。因为画布的坐标并不和像素直接对应,当需要获得精确的水平或垂直线的时候要特别注意。
本例中使用递增的宽度绘制了10条直线。最左边的线宽1.0单位。
最左边的以及所有宽度为奇数的线颜色出现偏差,这就是因为路径的定位问题导致。
想要获得精确的线条,就得知道线条是如何描绘出来。
下图用网格来代表 canvas 的坐标格,每一格对应屏幕上一个像素点。在第一个图中,填充了 (2,1) 至 (5,5) 的矩形,整个区域的边界刚好落在像素边缘上,这样就可以得到的矩形有着清晰的边缘。
如果想要绘制一条从 (3,1) 到 (3,5),宽度是 1.0 的线条,结果将会是第二幅图。
实际填充区域(深蓝色部分)仅仅延伸至路径两旁各一半像素。而另外半个像素会以笔触颜色一半的色调进行渲染,于是线条颜色被渲染为浅蓝和深蓝两个部分。这就是上例中为何宽度为 1.0 的线并不准确的原因。
要解决这个问题,必须对路径施以更加精确的控制。已知粗 1.0 的线条会在路径两边各延伸半像素,那么像第三幅图那样绘制从 (3.5,1) 到 (3.5,5) 的线条,其边缘正好落在像素边界,填充出来就是准确的宽为 1.0 的线条。
以上是lineWidth,下面来看看lineCap属性。
function draw6() {
var ctx = document.getElementById('cvs6').getContext('2d');
var lineCap = ['butt','round','square'];
ctx.strokeStyle = '#09f';
ctx.beginPath();
ctx.moveTo(10,10);
ctx.lineTo(140,10);
ctx.moveTo(10,140);
ctx.lineTo(140,140);
ctx.stroke();
// 画线条
ctx.strokeStyle = 'black';
for (var i=0;i<lineCap.length;i++){
ctx.lineWidth = 15;
ctx.lineCap = lineCap[i];
ctx.beginPath();
ctx.moveTo(25+i*50,10);
ctx.lineTo(25+i*50,140);
ctx.stroke();
}
}
lineCap属性决定了线条端点显示的样子。可选值为:butt,round 和 square。默认是 butt。
本例中绘制了三条直线,分别赋予不同的 lineCap 值。还有两条辅助线是为了看清它们之间的区别,三条线的起点终点都落在辅助线上。
最左边的线用了默认的 butt 。可以注意到它是与辅助线齐平的。中间的是 round 的效果,端点处加上了半径为一半线宽的半圆。右边的是 square 的效果,端点处加上了等宽且高度为一半线宽的方块。
接下来是lineJoin属性。
function draw7() {
var ctx = document.getElementById('cvs7').getContext('2d');
var lineJoin = ['round','bevel','miter'];
ctx.lineWidth = 10;
for (var i=0;i<lineJoin.length;i++){
ctx.lineJoin = lineJoin[i];
ctx.beginPath();
ctx.moveTo(-5,5+i*40);
ctx.lineTo(35,45+i*40);
ctx.lineTo(75,5+i*40);
ctx.lineTo(115,45+i*40);
ctx.lineTo(155,5+i*40);
ctx.stroke();
}
}
lineJoin的属性决定了图形中两线段连接处所显示的样子。可选值为:round, bevel 和 miter。默认是 miter。
同样用三条折线来做例子,分别设置不同的 lineJoin 值。最上面一条是 round 的效果,边角处被磨圆了,圆的半径等于线宽。中间和最下面一条分别是 bevel 和 miter 的效果。当值是 miter 的时候,线段会在连接处外侧延伸直至交于一点。
最后介绍虚线的使用。
var canvas8 = document.getElementById('cvs8');
var ctx8 = document.getElementById('cvs8').getContext('2d');
var offset = 0;
function draw8() {
ctx8.clearRect(0,0, canvas8.width, canvas8.height);
ctx8.setLineDash([4, 2]);
ctx8.lineDashOffset = -offset;
ctx8.strokeRect(10,10, 100, 100);
}
function march() {
offset++;
if (offset > 16) {
offset = 0;
}
draw8();
setTimeout(march, 20);
}
march();
用 setLineDash 方法和 lineDashOffset 属性来制定虚线样式。
setLineDash 方法接受一个数组,来指定线段与间隙的交替,数组第一个值表示虚线的长度,第二个值表示虚线之前的空隙。
lineDashOffset 属性设置起始偏移量。
4. 渐变 Gradients
与CSS3和SVG一样,canvas也有自己的渐变功能,同样分为 线性渐变 和 径向渐变。
使用下面的方法可以新建一个 canvasGradient 对象,并且赋给图形的 fillStyle 或 strokeStyle 属性,从而实现渐变效果。
-
createLinearGradient(x1, y1, x2, y2)
createLinearGradient 线性渐变方法接受 4 个参数,表示渐变的起点 (x1,y1) 与终点 (x2,y2)。
-
createRadialGradient(x1, y1, r1, x2, y2, r2)
createRadialGradient 径向渐变方法接受 6 个参数,前三个定义一个以 (x1,y1) 为原点,半径为 r1 的圆,后三个参数则定义另一个以 (x2,y2) 为原点,半径为 r2 的圆。
var lineargradient = ctx.createLinearGradient(0,0,150,150);
var radialgradient = ctx.createRadialGradient(75,75,0,75,75,100);
创建出 canvasGradient 对象后,可以用 addColorStop 方法上色。
-
gradient.addColorStop(position, color)
addColorStop 方法接受 2 个参数,position 参数必须是一个 0.0 与 1.0 之间的数值,表示渐变中颜色所在的相对位置。例如,0.5 表示颜色会出现在正中间。color 参数必须是一个有效的 CSS 颜色值(如 #FFF, rgba(0,0,0,1),等等)。
可以根据需要添加任意多个色标(color stops)。下面是最简单的线性黑白渐变的例子。
function draw9() {
var ctx = document.getElementById('cvs9').getContext('2d');
var lineargradient = ctx.createLinearGradient(0,0,130,130);
lineargradient.addColorStop(0,'white');
lineargradient.addColorStop(0.5,'grey');
lineargradient.addColorStop(1,'black');
ctx.fillStyle = lineargradient;
// draw shapes
ctx.fillRect(10,10,130,130);
}
然后来看看径向渐变。
function draw10() {
var ctx = document.getElementById('cvs10').getContext('2d');
var radgrad = ctx.createRadialGradient(45,45,10,52,50,30);
radgrad.addColorStop(0, '#A7D30C');
radgrad.addColorStop(0.9, '#019F62');
radgrad.addColorStop(1, 'rgba(1,159,98,0)');
var radgrad2 = ctx.createRadialGradient(105,105,20,112,120,50);
radgrad2.addColorStop(0, '#FF5F98');
radgrad2.addColorStop(0.75, '#FF0188');
radgrad2.addColorStop(1, 'rgba(255,1,136,0)');
var radgrad3 = ctx.createRadialGradient(95,15,15,102,20,40);
radgrad3.addColorStop(0, '#00C9FF');
radgrad3.addColorStop(0.8, '#00B5E2');
radgrad3.addColorStop(1, 'rgba(0,201,255,0)');
var radgrad4 = ctx.createRadialGradient(0,150,50,0,140,90);
radgrad4.addColorStop(0, '#F4F201');
radgrad4.addColorStop(0.8, '#E4C700');
radgrad4.addColorStop(1, 'rgba(228,199,0,0)');
// 画图形
ctx.fillStyle = radgrad4;
ctx.fillRect(0,0,150,150);
ctx.fillStyle = radgrad3;
ctx.fillRect(0,0,150,150);
ctx.fillStyle = radgrad2;
ctx.fillRect(0,0,150,150);
ctx.fillStyle = radgrad;
ctx.fillRect(0,0,150,150);
}
本例定义了4个不同的径向渐变。由于可以控制渐变的起始与结束点,所以可以实现稍微复杂的效果。
比如这里让起点稍微偏离终点,这样达到了一种球状3D效果,但最好不要让里圆与外圆部分交叠。
样式的介绍就到这里,下一篇博文将介绍文本的绘制和图片的使用。