canvas 样式

1,462 阅读2分钟

前言

课件地址

github.com/buglas/canv…

课堂目标

  1. 掌握canvas 所提供的样式。
  2. 能够绘制丰富多彩的图形。

知识点

  1. 图形着色的区域
  2. 图形着色的方式
  3. 描边的样式
  4. 投影

图形的着色区域

图形的着色区域有两种:

  • 描边区域: strokeStyle 代表了描边样式,描边区域的绘制方法有 stroke()、strokeRect() 、strokeText() 。
  • 填充区域: fillStyle 代表了填充样式,填充区域的绘制方法有fill()、fillRect()、fillText()

image-20220326171226471

图形的着色方式

图形的着色方式有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-线性渐变详解

image-20220326172615397

const linerGradient=ctx.createLinearGradient(x1,y1,x2,y2);
linerGradient.addColorStop(0,'red');
linerGradient.addColorStop(.5,'yellow');
linerGradient.addColorStop(1,'green');

5-径向渐变详解

image-20220326172759169

const radGradient=ctx.createRadialGradient(x1, y1, r1, x2, y2, r2);
radGradient.addColorStop(0,'red');
radGradient.addColorStop(.5,'yellow');
radGradient.addColorStop(1,'green');

3-纹理

纹理可以将一张图片作为图形的底色,如下图所示:

image-20220326173348412

1.建立纹理对象:

pattern=context.createPattern(image,"repeat|repeat-x|repeat-y|no-repeat");

2.为图形着色

ctx.fillStyle= pattern
ctx.strokeStyle= pattern

影响描边样式的因素

  • strokeStyle:描边的颜色
  • lineWidth:描边宽

image-20220326174019808

  • lineCap:描边端点样式

image-20220326174033975

  • lineJoin:描边拐角类型

image-20220326174105179

  • miterLimit:拐角最大厚度(只适用于lineJoin=‘miter’ 的情况)

    当lineJoin 为miter 时,若拐角过小,拐角的厚度就会过大。

image-20220326174135902

​ ctx.miterLimit 可避免此问题:

image-20220326174208563

  • setLineDash(segments):将描边设置为虚线,可以通过getLineDash() 方法获取虚线样式。

    例如:

    • ctx.setLineDash([ 60, 90 ])

    image-20220326174323737

    • ctx.setLineDash([ 60, 90, 120 ])

    image-20220326174449674

  • lineDashOffset:虚线偏移

image-20220326174557437

案例-霓虹灯

1

霓虹灯图形使用两个三次贝塞尔曲线拼成:

image-20220326180948506

代码如下:

<!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>

投影

投影是上下文对象的一种属性,在绘制图形时,无论执行的是描边方法,还是填充方法,只要设置了投影相关的属性,都会在其所绘图形的后面添加投影。

image-20220326182924385

投影相关的属性:

  • 偏移位置:

    • 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();

其实,投影不仅可以做投影,当投影比较亮的时候,还可以做光晕。

案例-发光的霓虹灯

1

案例代码:

<!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>