canvas合成

555 阅读2分钟

前言

课件地址

github.com/buglas/canv…

课堂目标

1.理解合成的原理。

2.可以灵活熟练的合成图像。

知识点

1.透明度合成 globalAlpha

2.路径裁剪 clip()

3.全局合成 globalCompositeOperation

1-透明度合成 globalAlpha

globalAlpha 就是全局对象的透明度,全局对象就是canvas 的上下文对象。 使用方法:ctx.globalAlpha=0.6;

image-20220428225539073

代码示例:

ctx.save();
ctx.globalAlpha=0.5;
ctx.fillRect(50,50,400,200);
ctx.fillRect(150,150,400,200);
ctx.restore();
ctx.fillRect(250,250,400,200);

注意:globalAlpha 要和颜色里的rgba 区别一下。

rgba 控制的是某种颜色的透明度;

globalAlpha 相当于是让整个画布变透明了。

2-路径裁剪 clip

路径裁剪就是在画布上设置一个路径,让我们之后绘制的图像只显示在这个路径之中。

路径裁剪的步骤:

  1. 定义路径
  2. ctx.clip()
  3. 绘制其它图形

代码示例:

ctx.beginPath();
ctx.arc(300,300,100,0,Math.PI*2);
ctx.stroke();
ctx.clip();
ctx.fillRect(300,300,100,100);

3-全局合成 globalCompositeOperation

全局合成是canvas 画布中的已绘图像和将绘图像的融合方式。

我们可以从形状和色彩两方面解读全局合成。

以下图为例,说一下全局合成的步骤。

image-20220428230554161

更多……

全局合成步骤:

  1. 先画一个黄色的正方形
  2. 设置全局合成的属性
  3. 再绘制一个绿色的圆

合成示例-刮刮乐

刮刮乐的绘制步骤:

1.用css 在canvas 中添加一个背景。

image-20220428231114302

2.在canvas 中绘制一张遮罩图。

image-20220428231225367

3.在canvas 画布中实现手绘效果。

image-20220428231635512

4.将手绘效果与遮罩做destination-out 合成。

image-20220428231705622

整体代码:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width,user-scalable=no">
    <title>刮刮乐</title>
    <style>
        body{margin: 0;overflow: hidden}
        #canvas{
            margin: 100px;
            background-image: url("./images/ggl-back.png");
        }
    </style>
</head>
<body>
<canvas id="canvas"></canvas>
<script>
    const canvas=document.getElementById('canvas');
    const ctx=canvas.getContext('2d');

    /*图像尺寸,遮罩图和背景图尺寸一样*/
    const [width,height]=[395,188];
    canvas.width=385;
    canvas.height=188;

    /*建立图像源*/
    const img=new Image();
    img.src='./images/ggl-mask.png';
    img.onload=function(){
        /*绘制遮罩层*/
        ctx.drawImage(img,0,0);
    };

    /*
    * 线对象 Line
    *   ctx 上下文对象
    *   drawing 是否正在绘图
    *
    *   鼠标按下 moveTo(x,y)
    *       记录正在绘图的状态 drawing
    *       保存状态
    *       设置全局合成属性globalCompositeOperation 为destination-out
    *       线宽lineWidth为30
    *       moveTo()设置路径起点
    *   鼠标移动 lineTo(x,y)
    *       lineTo()绘制下一个点
    *       stroke()描边
    *   鼠标抬起 restore()
    *       状态还原
    *       取消正在绘图的状态
    * */
    class Line{
        constructor(ctx){
            this.ctx=ctx;
            this.drawing=false;
        }
        moveTo(x,y){
           const {ctx}=this;
           this.drawing=true;
           ctx.save();
           ctx.lineWidth=30;
           ctx.globalCompositeOperation='destination-out';
           ctx.moveTo(x,y);
        }
        lineTo(x,y){
            const {ctx}=this;
            ctx.lineTo(x,y);
            ctx.stroke();
        }
        restore(){
            this.ctx.restore();
            this.drawing=false;
        }
    }

    /*实例化线对象 Line*/
    const line=new Line(ctx);

    /*==========鼠标事件===========*/
    /*鼠标按下*/
    canvas.addEventListener('mousedown',function(event){
        //鼠标左键按下
        if(event.buttons===1) {
            //获取鼠标位置
            const {x, y} = getMousePos(event);
            //绘制起点
            line.moveTo(x,y);
        }
    });
    /*鼠标移动*/
    canvas.addEventListener('mousemove',function(event){
        //鼠标左键按下且处于绘图状态
        if(event.buttons===1&&line.drawing) {
            //获取鼠标位置
            const {x, y} = getMousePos(event);
            //绘制下一个点
            line.lineTo(x,y);
        }
    });
    /*鼠标抬起*/
    canvas.addEventListener('mouseup',function(event){
        //鼠标左键按下
        if(event.buttons===1) {
            //状态还原
            line.restore();
        }
    });


    //获取鼠标在canvas中的位置
    function getMousePos(event){
        //获取鼠标位置
        const {clientX,clientY}=event;
        //获取canvas 边界位置
        const {top,left}=canvas.getBoundingClientRect();
        //计算鼠标在canvas 中的位置
        const x=clientX-left;
        const y=clientY-top;
        return {x,y};
    }
</script>
</body>
</html>

总结

已绘制到canvas 上的图像不可被修改,只能被覆盖或擦除。

路径裁剪是基于路径的一种合成方式,它只能使用路径设置裁剪区域,如果是文字的话,就无效。

透明度合成和全局合成都是基于像素的操作。