渐变
线性渐变
在一条直线上进行渐变
var gnt = cxt.createLinearGradient(x1, y1, x2, y2);
gnt.addColorStop(value1,color1);
gnt.addColorStop(value2,color2);
第2和第3步可以反复多次添加多个渐变,每次渐变都以上一个渐变的结束位置为开始位置
cxt.fillStyle = gnt;
cxt.fill();
fill()可以改为fillRect()或fillText()。其中fillRect()表示矩形渐变,fillText()表示文字渐变。
var gnt = cxt.createLinearGradient(0,150, 200, 150);
gnt.addColorStop(0, "HotPink");
gnt.addColorStop(1, "white");
cxt.fillStyle = gnt;
cxt.fillRect(0, 0, 200, 150);
var text = "绿叶学习网";
cxt.font = "bold 50px 微软雅黑";
var gnt = cxt.createLinearGradient(0, 75, 200, 75);
gnt.addColorStop(0, "HotPink");
gnt.addColorStop(1, "LightSkyBlue");
cxt.fillStyle = gnt;
cxt.fillText(text, 10, 90);
径向渐变(用得少)
径向渐变,是一种从起点到终点、颜色从内到外进行的圆形渐变(从中间向外拉,像圆一样)。径向渐变是圆形渐变或椭圆形渐变,颜色不再沿着一条直线渐变,而是从一个起点向所有方向渐变。
var gnt = cxt.createRadialGradient(x1,y1,r1,x2,y2,r2);
gnt.addColorStop(value1,color1);
gnt.addColorStop(value2,color2);
第2和第3步可以反复多次添加多个渐变,每次渐变都以上一个渐变的结束位置为开始位置
cxt.fillStyle = gnt;
cxt.fill();
fill()可以改为fillRect()或fillText()。其中fillRect()表示矩形渐变,fillText()表示文字渐变。
//画圆
cxt.beginPath();
cxt.arc(80, 80, 50, 0, Math.PI * 2, true);
cxt.closePath();
//渐变
var gnt = cxt.createRadialGradient(100, 60, 10, 80, 80, 50);
gnt.addColorStop(0, "white");
gnt.addColorStop(0.9, "orange");
gnt.addColorStop(1, "rgba(0,0,0,0)");
//填充
cxt.fillStyle = gnt;
cxt.fill();
gradient = cxt.createRadialGradient(60, 60, 0, 60, 60, 60);
gradient.addColorStop("0", "magenta");
gradient.addColorStop("0.25", "blue");
gradient.addColorStop("0.50", "green");
gradient.addColorStop("0.75", "yellow");
gradient.addColorStop("1.0", "HotPink");
cxt.fillStyle = gradient;
cxt.fillRect(0, 0, 120, 120);
var i = 0;
setInterval(function () {
gradient = cxt.createRadialGradient(60, 60, 0, 60, 60, 60);
gradient.addColorStop(i * 0, "magenta");
gradient.addColorStop(i * 0.25, "blue");
gradient.addColorStop(i * 0.50, "green");
gradient.addColorStop(i * 0.75, "yellow");
gradient.addColorStop(i * 1.0, "HotPink");
cxt.fillStyle = gradient;
i = i + 0.1;
if (i >= 1) { //超过颜色点值后,自动归0
i = 0;
}
cxt.fillRect(0, 0, 120, 120);
}, 50);
阴影
属性 |
说明 |
---|---|
shadowOffsetX |
阴影与图形的水平距离,默认值为0。大于0时向右偏移,小于0时向左偏移 |
shadowOffsetY |
阴影与图形的垂直距离,默认值为0。大于0时向下偏移,小于0时向上偏移 |
shadowColor |
阴影的颜色,默认值为黑色 |
shadowBlur |
阴影的模糊值,默认值为0。该值越大,模糊度越强;该值越小,模糊度越弱 |
//设置左上方向的阴影
cxt.shadowOffsetX = -5;
cxt.shadowOffsetY = -5;
cxt.shadowColor = "LightSkyBlue ";
cxt.shadowBlur = 1;
cxt.fillStyle = "HotPink";
cxt.fillRect(30, 30, 50, 50);
//设置右下方向的阴影
cxt.shadowOffsetX = 5;
cxt.shadowOffsetY = 5;
cxt.shadowColor = "LightSkyBlue ";
cxt.shadowBlur = 10;
cxt.fillStyle = "HotPink";
cxt.fillRect(100, 30, 50, 50);
//定义文字
var text = "绿叶学习网";
cxt.font = "bold 60px 微软雅黑";
//定义阴影
cxt.shadowOffsetX = 5;
cxt.shadowOffsetY = 5;
cxt.shadowColor = "LightSkyBlue ";
cxt.shadowBlur = 10;
//填充文字
cxt.fillStyle = "HotPink";
cxt.fillText(text, 10, 90);
//创建image对象
var image = new Image();
image.src = "images/princess.png";
image.onload = function () {
//定义阴影
cxt.shadowOffsetX = 5;
cxt.shadowOffsetY = 5;
cxt.shadowColor = "HotPink";
cxt.shadowBlur = 10;
cxt.fillRect(40, 15, 120, 120);
cxt.drawImage(image, 40, 15);
}
四个方向的阴影效果,只需要shadowOffsetX和shadowOffsetY这两个属性的值都定义为0就可以了。
//创建image对象
var image = new Image();
image.src = "images/princess.png";
image.onload = function () {
//定义阴影
cxt.shadowOffsetX = 0;
cxt.shadowOffsetY = 0;
cxt.shadowColor = "HotPink";
cxt.shadowBlur = 10;
cxt.fillRect(40, 15, 120, 120);
cxt.drawImage(image, 40, 15);
}
路径
方法 |
说明 |
---|---|
beginPath() |
开始一条新的路径 |
closePath() |
关闭当前路径 |
isPointInPath() |
判断某一个点是否存在于当前路径内 |
beginPath()
cxt.beginPath();
用于开始一个新路径(同时也是结束上一个路径),刚开始绘图时,其实都默认执行了一次 beginPath() 开始了一个新路径,直到再次遇到 beginPath() 才会结束默认创建的路径,而开始一段新路径。
Canvas基于“状态”绘制图形。每一次绘制(stroke()或fill()),Canvas会检测整个程序定义的所有状态,这些状态包括strokeStyle、fillStyle、lineWidth等。当一个状态值没有被改变时,Canvas就一直使用最初的值,当一个状态值被改变时,需要分两种情况考虑。
(1)如果使用beginPath()开始一个新的路径,则不同路径使用不同的值。
(2)如果没有使用beginPath()开始一个新的路径,则后面的值会覆盖前面的值(后来者居上原则)。
cxt.lineWidth = 5;
//第1条直线
cxt.moveTo(50, 40);
cxt.lineTo(150, 40);
cxt.strokeStyle = "red";
cxt.stroke();
//第2条直线
cxt.moveTo(50, 80);
cxt.lineTo(150, 80);
cxt.strokeStyle = "green";
cxt.stroke();
//第3条直线
cxt.moveTo(50, 120);
cxt.lineTo(150, 120);
cxt.strokeStyle = "blue";
cxt.stroke();
三条直线都属于同一个路径,所以cxt.strokeStyle=‘green’;会覆盖cxt.strokeStyle=‘red’;,然后cxt.strokeStyle=‘blue’;会覆盖cxt.strokeStyle=‘green’;。因此strokeStyle属性最终取值为blue,即三条直线都是blue。
cxt.lineWidth = 5;
//第1条直线
cxt.beginPath();
cxt.moveTo(50, 40);
cxt.lineTo(150, 40);
cxt.strokeStyle = "red";
cxt.stroke();
//第2条直线
cxt.beginPath();
cxt.moveTo(50, 80);
cxt.lineTo(150, 80);
cxt.strokeStyle = "green";
cxt.stroke();
//第3条直线
cxt.beginPath();
cxt.moveTo(50, 120);
cxt.lineTo(150, 120);
cxt.strokeStyle = "blue";
cxt.stroke();
使用beginPath()后,三条直线将位于不同的路径中。因此,不同路径中定义的状态不会像上一个例子那样发生覆盖。
判断是否属于同一路径的标准是:是否使用了beginPath(),而不是视觉上是否有首尾连线。
Canvas中的绘制方法如stroke()、fill()等,都是以“之前最近的beginPath()”后面所有定义的状态为基础进行绘制的。
closePath()
cxt.closePath();
用于关闭路径,即将同一个路径的起点与终点连接起来,使其成为一个封闭的图形。
常用于绘制多边形的最后一步。
如果Canvas只有一条线段的话,那么closePath()方法就什么都不做。
cxt.arc(70, 70, 50, 0, -90 * Math.PI / 180, true);
cxt.stroke();
cxt.closePath();
cxt.lineWidth = 10;
cxt.strokeStyle = "HotPink";
cxt.moveTo(40, 60);
cxt.lineTo(100, 60);
cxt.lineTo(100, 30);
cxt.lineTo(150, 75);
cxt.lineTo(100, 120);
cxt.lineTo(100, 90);
cxt.lineTo(40, 90);
cxt.lineTo(40, 60);
cxt.stroke();
将lineWidth定义得足够大(10px)时,如果使用lineTo()方法来关闭图形,会有一个如图所示的“缺口”小问题。有两种方法可以解决:
isPointInPath()
cxt.isPointInPath(x , y);
用于判断点 x,y 是否在当前路径中,若在返回true,否则返回false,仅对 rect()方法有效,对 strokeRect() 和 fillRect() 无效。
cxt.strokeStyle = "HotPink";
cxt.rect(50, 50, 80, 80);
cxt.stroke();
if (cxt.isPointInPath(100, 50)) {
alert("点(100,100)存在于当前路径中");
}
cxt.moveTo(50, 50);
cxt.lineTo(150, 50);
cxt.stroke();
if (cxt.isPointInPath(100, 50)) {
alert("点(50,100)存在于当前路径中");
}
上面代码只在IE浏览器中运行中有效果,但是在Google浏览器和Firefox中不会弹出对话框。实际上,当我们想要使用isPointInPath()方法判断某个点是否位于一条直线上时,在Goole和Firefox浏览器中都是无法实现的。不过可以使用isPointInPath()方法判断某个点是否位于一个图形(如矩形、圆形等)上面。
状态
Canvas基于“状态”来绘制图形。每一次绘制(stroke()或fill()),Canvas会检测整个程序定义的所有状态,这些状态包括strokeStyle、fillStyle、lineWidth等。当一个状态值没有被改变时,Canvas就会一直使用最初的值。当一个状态值被改变时,分两种情况考虑:
(1)如果使用beginPath()开始一个新的路径,则不同路径使用不同的值。
(2)如果没有使用beginPath()开始一个新的路径,则后面的值会覆盖前面的值(后来者居上原则)。
状态的保存和恢复
Canvas提供了两个操作状态的方法:
save()和restore()一般情况下都是成对配合使用,使用场景如下:
(1)图形或图片裁切。
(2)图形或图片变换。
(3)以下属性改变的时候:fillStyle、font、globalAlpha、globalCompositeOperation、lineCap、lineJoin、lineWidth、miterLimit、shadowBlur、shadowColor、shadowOffsetX、shadowOffsetY、strokeStyle、textAlign、textBaseline。
应用一:清除剪切区域
创建剪切区域 clip()
创建剪切区域后,绘制的图形都只限于这个剪切区域之内,超出剪切区域的部分不会显示(被剪切掉了)。
把整个画布(Canvas)看成一个房子,clip()方法的剪切区域则可以看成一扇窗户。即使房子再大,最终透过窗户所能看到的空间也就只有窗户这么大。
cxt.clip();
clip()方法也不支持Canvas自带的两个方法:strokeRect()、fillRect()。如果要使用strokeRect()和fillRect(),请使用rect()方法来代替。
//绘制一个"描边圆",圆心为(50,50),半径为40
cxt.beginPath();
cxt.arc(50, 50, 40, 0, 360 * Math.PI / 180, true);
cxt.closePath();
cxt.strokeStyle = "HotPink";
cxt.stroke();
//使用clip(),使得"描边圆"成为一个剪切区域
cxt.clip();
//绘制一个"填充矩形"
cxt.beginPath();
cxt.fillStyle = "#66CCFF";
cxt.fillRect(50, 50, 100, 80);
清除剪切区域
在图形或者图片剪切(clip())之前使用save()方法来保持当前状态,然后在剪切(clip())之后使用restore()方法恢复之前保存的状态。
如果不使用save()和restore(),即便使用clearRect()方法清空画布,后面绘制的所有图形或图片也都会限制在这个剪切区域内。
//save()保存状态
cxt.save();
//使用clip()方法指定一个圆形的剪切区域
cxt.beginPath();
cxt.arc(70, 70, 50, 0, 360 * Math.PI / 180, true);
cxt.closePath();
cxt.stroke();
cxt.clip();
//绘制一张图片
var image = new Image();
image.src = "images/princess.png";
image.onload = function () {
cxt.drawImage(image, 10, 20);
}
$$("btn").onclick = function () {
//restore()恢复状态
cxt.restore();
//清空画布
cxt.clearRect(0, 0, cnv.width, cnv.height);
//绘制一张新图片
var image = new Image();
image.src = "images/Judy.png";
image.onload = function () {
cxt.drawImage(image, 10, 20);
}
}
删除 cxt.save()和cxt.restore() 后效果为:
应用二:图片/图形的变换
cxt.fillStyle = "HotPink";
cxt.translate(30, 30);
cxt.fillRect(0, 0, 100, 50);
cxt.fillStyle = "LightSkyBlue ";
cxt.translate(60, 60);
cxt.fillRect(0, 0, 100, 50);
蓝色矩形预期坐标为 (60,60),最终效果却是 (90,90),因为之前 translate(30, 30),整个坐标系的原点已经发生了位移变化 !
解决方案是使用 save()和restore()来实现
cxt.save();
cxt.fillStyle = "HotPink";
cxt.translate(30, 30);
cxt.fillRect(0, 0, 100, 50);
cxt.restore();
cxt.fillStyle = "LightSkyBlue ";
cxt.translate(60, 60);
cxt.fillRect(0, 0, 100, 50);
在变换操作(平移、缩放、旋转)中,一般都是在操作之前使用save()方法保存当前状态,其中当前状态包括参考坐标、图形大小等。然后再使用restore()方法来恢复之前保存的状态。
Canvas对象
属性
常用于文字水平居中对齐和清空画布
cxt.clearRect(0, 0, cnv.width, cnv.height);
方法
cnv.toDataURL(type);
直接在Canvas画布上点击鼠标右键,在弹出的快捷菜单中也能“另存为”图片为本地图片,为什么还要那么麻烦地使用toDataURL()呢?
事实上,很多旧版本的浏览器并不具备这个功能。因此为了兼容性,建议使用toDataURL()方法进行处理。
图形的重叠模式
默认情况下,后绘制的图形会覆盖之前绘制的图形。
通过 globalCompositeOperation 可以修改重叠模式
cxt.globalCompositeOperation = 属性值;
属性值 |
说明 |
---|---|
source-over |
默认值,新图形覆盖旧图形 |
copy |
只显示新图形,旧图形作透明处理 |
darker |
两种图形都显示,在重叠部分,颜色由两个图形的颜色值相减后形成 |
destination-atop |
只显示新图形与旧图形重叠部分以及新图形的其余部分,其他部分作透明处理 |
destination-in |
只显示旧图形中与新图形重叠部分,其他部分作透明处理 |
destination-out |
只显示旧图形中与新图形不重叠部分,其他部分作透明处理 |
destination-over |
与source-over属性相反,旧图形覆盖新图形 |
lighter |
两种图形都显示,在图形重叠部分,颜色由两个图形的颜色值相加后形成 |
source-atop |
只显示旧与新图形重叠部分及旧图形的其余部分,其他部分作透明处理 |
source-in |
只显示新图形中与旧图形重叠部分,其他部分作透明处理 |
source-out |
只显示新图形中与旧图形不重叠部分,其余部分作透明处理 |
xor |
两种图形都绘制,其中重叠部分透明处理 |
cxt.globalCompositeOperation = "xor";
//绘制矩形
cxt.fillStyle = "HotPink";
cxt.fillRect(30, 30, 60, 60);
//绘制圆形
cxt.beginPath();
cxt.arc(100, 100, 40, 0, Math.PI * 2, true);
cxt.closePath();
cxt.fillStyle = "LightSkyBlue";
cxt.fill();
cxt.globalCompositeOperation = "xor";
//绘制第1个矩形
cxt.fillStyle = "HotPink";
cxt.fillRect(30, 30, 60, 60);
//绘制圆形
cxt.beginPath();
cxt.arc(100, 100, 40, 0, Math.PI * 2, true);
cxt.closePath();
cxt.fillStyle = "LightSkyBlue";
cxt.fill();
//绘制第2个矩形
cxt.fillStyle = "HotPink";
cxt.fillRect(110, 30, 60, 60);