马黑黑 发表于 2022-8-15 16:17

canvas画布裁剪方法的遮罩用途

本帖最后由 马黑黑 于 2022-8-15 16:20 编辑

演示和解释帖子标题的命题,我们需要准备好CSS和HTML,很简单:

<style>
      #papa { margin: auto; display: grid; place-items: center; width: 1024px; height: 640px; background: url('https://638183.freep.cn/638183/Pic/38/333.png') no-repeat center/cover; position: relative; }
      #canv { position: absolute; }
</style>

<div id="papa"><canvas id="canv"></canvas></div>


画布置于一个父窗口之内。父框令子元素绝对居中。为了便于观察,CSS给画布设置了红色边框。

接下来就是通过JS操作画布,思路是在画布创建一个圆形裁剪区域、并在该区域上画一幅图片;圆形裁剪区域的半径循环变大变小,从而达到图片的开启、遮罩效果。

画布的 clip 方法,将上文建立的图形定义为画布的裁剪区,把裁剪区以外的范围“剪掉”、不可访问,随后在画布上绘制的内容只能在裁剪区上可见。

画布画图片,这里指将一张图片“绘制”到画布上,使用 drawImage 方法,该方法我们过去有过介绍。

下面是具体实现代码:

<script type="text/javascript">
let r = 10, speed = 0.5, idx = 0; //裁剪半径、速度
let w = canv.width = 500, h = canv.height = 500; //画布宽高
let ctx = canv.getContext('2d'); //画笔

let image = new Image(); //声明图像对象
image.src = 'https://638183.freep.cn/638183/t22/51/s3.jpg'; //指定图像RUL

image.onload = () =>ctx.drawImage(image, 0, 0, w, h); //图片加载事件 : 将图片画在画布上(本例可以不要这句,演示用)

(function draw() {
      ctx.clearRect(0, 0, w, h); //清空画布
      ctx.save(); //保存画布状态
      ctx.beginPath(); //开启路径
      ctx.arc(w / 2, h / 2, r, 0, Math.PI*2);
      ctx.clip(); //裁剪上面设定的圆
      ctx.drawImage(image, 0, 0, w, h); //在裁剪的区域上作图 : 图片仅能在当前裁剪区域显示
      ctx.restore(); //恢复画布之前的保存状态
      r += speed; //裁剪区域半径加上变化速度
      if (r > w/2 || r <= 0) speed = -speed; // 半径大于画布的一半或小于等于0时(半径不能小于0)速度正负互反
      requestAnimationFrame(draw); //定时器运行本函数
})();
</script>


函数 draw 的 if 语句所用到的条件还有其他用途,例如换图片等。整个脚本还可以深加工,做更多的事情。

马黑黑 发表于 2022-8-15 16:26

<style>
        #papa { margin: auto; display: grid; place-items: center; width: 700px; height: 640px; position: relative; }
        #canv { position: absolute; border: 1px solid red; }
</style>

<div id="papa"><canvas id="canv"></canvas></div>

<script type="text/javascript">
let r = 10, speed = 0.5, idx = 0; //裁剪半径、速度
let w = canv.width = 500, h = canv.height = 500; //画布宽高
let ctx = canv.getContext('2d'); //画笔

let image = new Image(); //声明图像对象
image.src = 'https://638183.freep.cn/638183/t22/51/s3.jpg'; //指定图像RUL

image.onload = () =>ctx.drawImage(image, 0, 0, w, h);

(function draw() {
        ctx.clearRect(0, 0, w, h); //清空画布
        ctx.save(); //保存画布状态
        ctx.beginPath(); //开启路径
        ctx.arc(w / 2, h / 2, r, 0, Math.PI*2);
        ctx.clip(); //裁剪上面设定的圆
        ctx.drawImage(image, 0, 0, w, h); //在裁剪的区域上作图 : 图片仅能在当前裁剪区域显示
        ctx.restore(); //恢复画布之前的保存状态
        r += speed; //裁剪区域半径加上变化速度
        if (r > w/2 || r <= 0) speed = -speed; // 半径大于画布的一半或小于等于0时(半径不能小于0)速度正负互反
        requestAnimationFrame(draw); //定时器运行本函数
})();
</script>

小辣椒 发表于 2022-8-15 16:36

有点难的,小白感觉一下子学不会

马黑黑 发表于 2022-8-15 17:28

小辣椒 发表于 2022-8-15 16:36
有点难的,小白感觉一下子学不会

这个需要有JS积累

红影 发表于 2022-8-15 19:24

画布宽度的一半,正好是圆的半径。所以能从0到半径的变化。

红影 发表于 2022-8-15 19:25

ctx.arc(w / 2, h / 2, r, 0, Math.PI*2);
ctx.clip(); //裁剪上面设定的圆

原来这俩一起作用的,我还以为直接ctx.clip(); 就能裁出圆来呢{:4_173:}

马黑黑 发表于 2022-8-15 21:07

红影 发表于 2022-8-15 19:25
ctx.arc(w / 2, h / 2, r, 0, Math.PI*2);
ctx.clip(); //裁剪上面设定的圆



它不接受任何参数,是寄生裁剪的

红影 发表于 2022-8-16 22:01

马黑黑 发表于 2022-8-15 21:07
它不接受任何参数,是寄生裁剪的

嗯,只要设定好了,它就只管裁。

马黑黑 发表于 2022-8-16 22:37

红影 发表于 2022-8-16 22:01
嗯,只要设定好了,它就只管裁。

是的
页: [1]
查看完整版本: canvas画布裁剪方法的遮罩用途