前言
课件地址
课堂目标
- 掌握canvas 所提供的样式。
- 能够绘制丰富多彩的图形。
知识点
- 图形着色的区域
- 图形着色的方式
- 描边的样式
- 投影
图形的着色区域
图形的着色区域有两种:
- 描边区域: strokeStyle 代表了描边样式,描边区域的绘制方法有 stroke()、strokeRect() 、strokeText() 。
- 填充区域: fillStyle 代表了填充样式,填充区域的绘制方法有fill()、fillRect()、fillText()
图形的着色方式
图形的着色方式有3种:纯色、渐变、纹理。
1-纯色
1.书写方式(与css 一致):
- 颜色名称,如red
- 16位的颜色值,如 #000000
- rgb(r,g,b)
- rgba(r,g,b,a)
2.为图形着色
ctx.fillStyle= ‘red’
ctx.strokeStyle= ‘ rgb(r,g,b) ‘
2-渐变
1.建立渐变对象的方式:
- 线性渐变 gradient=ctx.createLinearGradient(x1, y1, x2, y2)
- 径向渐变 gradient=ctx.createRadialGradient(x1, y1, r1, x2, y2, r2)
2.定义渐变的颜色节点
gradient.addColorStop(position, color)
3.为图形着色
ctx.fillStyle= gradient
ctx.strokeStyle= gradient
4-线性渐变详解
const linerGradient=ctx.createLinearGradient(x1,y1,x2,y2);
linerGradient.addColorStop(0,'red');
linerGradient.addColorStop(.5,'yellow');
linerGradient.addColorStop(1,'green');
5-径向渐变详解
const radGradient=ctx.createRadialGradient(x1, y1, r1, x2, y2, r2);
radGradient.addColorStop(0,'red');
radGradient.addColorStop(.5,'yellow');
radGradient.addColorStop(1,'green');
3-纹理
纹理可以将一张图片作为图形的底色,如下图所示:
1.建立纹理对象:
pattern=context.createPattern(image,"repeat|repeat-x|repeat-y|no-repeat");
2.为图形着色
ctx.fillStyle= pattern
ctx.strokeStyle= pattern
影响描边样式的因素
- strokeStyle:描边的颜色
- lineWidth:描边宽
- lineCap:描边端点样式
- lineJoin:描边拐角类型
-
miterLimit:拐角最大厚度(只适用于lineJoin=‘miter’ 的情况)
当lineJoin 为miter 时,若拐角过小,拐角的厚度就会过大。
ctx.miterLimit 可避免此问题:
-
setLineDash(segments):将描边设置为虚线,可以通过getLineDash() 方法获取虚线样式。
例如:
- ctx.setLineDash([ 60, 90 ])
- ctx.setLineDash([ 60, 90, 120 ])
-
lineDashOffset:虚线偏移
案例-霓虹灯
霓虹灯图形使用两个三次贝塞尔曲线拼成:
代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>霓虹灯</title>
<style>
html{height: 100%;overflow: hidden;}
body{height: 100%;margin: 0;}
#canvas{
background: #000;
}
</style>
</head>
<body>
<canvas id="canvas"></canvas>
<script>
const canvas=document.getElementById('canvas');
//canvas充满窗口
canvas.width=window.innerWidth;
canvas.height=window.innerHeight;
//画笔
const ctx=canvas.getContext('2d');
//颜色数组
const colors=['red','yellow'];
function draw(){
//保存上下文对象的状态
ctx.save();
//偏移坐标系
ctx.translate(300,400);
//开始绘制路径
ctx.beginPath();
//向路径集合中添加子路径
//绘制心形子路径
//设置路径起点
ctx.moveTo(0,0);
//用两个三次贝塞尔曲线组成爱心
ctx.bezierCurveTo(-200,-50,-180,-300,0,-200);
ctx.bezierCurveTo(180,-300,200,-50,0,0);
ctx.closePath();
//设置描边宽度
ctx.lineWidth=10;
//虚线
ctx.setLineDash([30]);
/*------------虚线1--------------*/
//描边颜色
ctx.strokeStyle=colors[0];
//以描边的方式显示路径
ctx.stroke();
/*------------虚线2--------------*/
//描边颜色
ctx.strokeStyle=colors[1];
//虚线偏移
ctx.lineDashOffset=30;
//以描边的方式显示路径
ctx.stroke();
//将上下文对象的状态恢复到上一次保存时的状态
ctx.restore();
}
//连续渲染
let t1=0
!(function ani(t=0){
const t2=t%200
if(t1>t2){
colors.reverse();
draw();
}
t1=t2
requestAnimationFrame(ani)
})()
</script>
</body>
</html>
投影
投影是上下文对象的一种属性,在绘制图形时,无论执行的是描边方法,还是填充方法,只要设置了投影相关的属性,都会在其所绘图形的后面添加投影。
投影相关的属性:
-
偏移位置:
- shadowOffsetX = float
- shadowOffsetY = float
-
模糊度: shadowBlur = float
-
颜色:shadowColor = color
代码示例:
ctx.shadowColor='#000';
ctx.shadowOffsetY=30;
ctx.shadowOffsetX=30;
ctx.shadowBlur=30;
ctx.beginPath();
ctx.arc(300,200,100,0,Math.PI*2);
ctx.fillStyle='#93abff';
ctx.fill();
其实,投影不仅可以做投影,当投影比较亮的时候,还可以做光晕。
案例-发光的霓虹灯
案例代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>霓虹灯</title>
<style>
html{height: 100%;overflow: hidden;}
body{height: 100%;margin: 0;}
#canvas{
background: #000;
}
</style>
</head>
<body>
<canvas id="canvas"></canvas>
<script>
const canvas=document.getElementById('canvas');
//canvas充满窗口
canvas.width=window.innerWidth;
canvas.height=window.innerHeight;
//画笔
const ctx=canvas.getContext('2d');
//颜色数组
const colors=['red','yellow'];
function draw(){
//保存上下文对象的状态
ctx.save();
//偏移坐标系
ctx.translate(300,400);
//开始绘制路径
ctx.beginPath();
//向路径集合中添加子路径
//绘制心形子路径
//设置路径起点
ctx.moveTo(0,0);
//用两个三次贝塞尔曲线组成爱心
ctx.bezierCurveTo(-200,-50,-180,-300,0,-200);
ctx.bezierCurveTo(180,-300,200,-50,0,0);
ctx.closePath();
//设置描边宽度
ctx.lineWidth=10;
//虚线
ctx.setLineDash([30]);
/*------------虚线1--------------*/
//描边颜色
ctx.strokeStyle=colors[0];
//以描边的方式显示路径
ctx.stroke();
/*------------虚线2--------------*/
//投影颜色
ctx.shadowColor='orange';
//描边颜色
ctx.strokeStyle=colors[1];
//虚线偏移
ctx.lineDashOffset=30;
for(let i=50;i>5;i-=5){
//投影模糊
ctx.shadowBlur=i;
//以描边的方式显示路径
ctx.stroke();
}
//将上下文对象的状态恢复到上一次保存时的状态
ctx.restore();
}
//连续渲染
let t1=0
!(function ani(t){
const t2=t%200
if(t1>t2){
ctx.clearRect(0,0,canvas.width,canvas.height)
colors.reverse();
draw();
}
t1=t2
requestAnimationFrame(ani)
})()
</script>
</body>
</html>