• Canvas中的剪切clip()方法


    Canvas中的剪切

    接下来我们要聊的不是图像的合成,而是Canvas中的另一个有用的功能:剪切区域。它是Canvas之中由路径所定义的一块区域,浏览器会将所有的绘图操作都限制在本区域内执行。在默认情况下,剪辑区域的大小与Canvas画布大小一致。除非你通过创建路径并调用Canvas绘图环境对象的clip()方法来显式的设定剪辑区域,否则默认的剪辑区域不会影响Canvas之中所绘制的内容。然而,一旦设置好剪辑区域,那么你在Canvas之中绘制的所有内容都将局限在该区域内。这也意味着在剪辑区域以外进行绘制是没有任何效果的

    简单点讲,Canvas的裁切路径和普通的Canvas图形差不多,不同的是它的作用是遮罩,用来隐藏没有遮罩的部分。如下图所示,红边五角星就是裁切路径,所有在路径以外的部分都不会在Canvas上绘制出来。

    从上图所示的效果来看,跟上一节介绍的globalCompositeOperationsource-insource-atop差不多的效果。最重要的区别是裁切路径不会在Canvas上绘制东西,而且它永远不受新图形的影响。这些特性使得它在特定区域里绘制图形时相当好用。

    clip()使用

    上面也说了,Canvas中的clip()方法是裁切区可用于限制图像描绘的区域,具体的用法:

    • 使用Canvas的绘制函数比如,rect()arc()之类的方法选择好绘图区域(注意:fillRect方法不起作用;需要结合closePath方法)
    • 使用clip()函数将该区域(由rect()arc()方法指定的绘图区域)设定为裁选区

    设定裁选区之后,无论在Canvas上绘制什么,只有落在裁选区内的那部分才能得以显示,其余都会被遮蔽掉

    先来看一个示例,绘制一个四个圆而且未使用裁选区:

    ctx.save(); 
    // 绘制第一个圆 
    ctx.beginPath(); 
    ctx.fillStyle = 'tomato'; 
    ctx.arc(cx, cy, radius, 0, Math.PI * 2, false); 
    ctx.fill(); 
    // 绘制第二个圆 
    ctx.beginPath(); 
    ctx.fillStyle = '#333'; 
    ctx.arc(cx + 100, cy, radius, 0, Math.PI * 2, false); 
    ctx.fill(); 
    // 绘制第三个圆 
    ctx.beginPath(); 
    ctx.fillStyle = 'cornsilk'; 
    ctx.arc(cx, cy + 100, radius, 0, Math.PI * 2, false); 
    ctx.fill(); 
    // 绘制第四个圆 
    ctx.beginPath(); 
    ctx.strokeStyle = '#ccc';
    ctx.lineWidth = 10; 
    ctx.arc(cx, cy, radius, 0, Math.PI * 2, false); 
    ctx.stroke(); 
    ctx.restore();

    看到的效果如下:

    接下来我们分别来看看加上clip()的效果,先来看看在第三个圆后面添加:

    // 绘制第三个圆 
    ctx.beginPath();
    ctx.fillStyle = 'cornsilk'; 
    ctx.arc(cx, cy + 100, radius, 0, Math.PI * 2, false);
    ctx.fill(); 
    ctx.clip();

    从效果图上,可以看出第四个圆(灰色的,只有边框的圆)只有部分绘制出来。接着往下,把clip()往上移,放到第二个圆的后面。

    原理同样的,第二个圆成为裁剪区域,第三个圆和第四个圆与第二个圆有交集的地方才会绘制出来,所以看到的效果如下:

    继续按类似的方法操作,把clip()放置在第一个圆的后面。

    最终的效果,或许你已经可以猜得到了:

    取消裁切区

    当使用裁切区clip()进行绘图后,可能需要取消该裁选区或者重新定义裁切区。在Canvas中,可以通过save()函数和restore()函数来实现——在构建裁切区之前保存状态,完成裁切区内的绘图之后进行状态读取

    同样拿上面的示例来举例,依旧在第三个圆后面做clip(),并且同时做restore()

    // 绘制第三个圆
    ctx.beginPath(); 
    ctx.fillStyle = 'cornsilk'; 
    ctx.arc(cx, cy + 100, radius, 0, Math.PI * 2, false); 
    ctx.fill(); 
    ctx.clip(); 
    ctx.restore(); 
    // 绘制第四个圆 
    ctx.beginPath(); 
    ctx.strokeStyle = '#ccc'; 
    ctx.lineWidth = 10; 
    ctx.arc(cx, cy, radius, 0, Math.PI * 2, false); 
    ctx.stroke();

    和前面的示例效果不一样,第四个灰色的边框圆,他并没有仅在第三个圆(裁切区)绘制,而是整个绘制出来了。接着往下看,把clip()往上提,提到第二个圆之后,而restore()位置不变:

    如果把clip()移动第一个圆之后,然后restore()继续放置在第三个圆之后,看到的效果如下:

    制作探照灯

    通过前面的介绍,我们了解了:Canvas中的clip()方法用于从原始画布中剪切任意形状和尺寸。一旦剪切了某个区域,则所有之后的绘图都会被限制在被剪切的区域内(不能访问画布上的其他区域)。也可以在使用clip()方法前通过使用save()方法对当前画布区域进行保存,并在以后的任意时间通过restore()方法对其进行恢复

    根据这个原理,我们就可以很轻松的实现下个探照灯的效果。

    • 使用arc()绘制一个圆形的区域,然后在其后调用clip(),设置剪切区域
    • 使用drawImage()在画布中绘制一个图像
    • 动态改变arc()的位置,从而看到一个类似探照灯的效果

    该方法实现的效果没有光圈的感觉,不知道大家有什么解决办法吗?我尝试了绘制圆的时候使用径向渐变变化圆的透明度,但是没有效果。

    具体的实现效果以及代码可以看下面:

     这个探照灯的效果是使用clip()方法来实现的,如果你感兴趣的话,可以把这个效果的实现原理与文章《Canvas学习:globalCompositeOperation详解》中提供的示例(图像合成制作探照灯效果)对比,看看这两者制作方案有何不同之处。

    总结

    这篇文章主要介绍了Canvas中的clip()方法的特性。clip()方法将剪切区域设置为当前剪切区域与当前路径的交集。在第一次调用clip()方法之前,剪切区域与整个Canvas画布大小一致。因为clip()方法会将剪切区域设置为当前剪切区域与当前路径的交集,所以对该方法的调用一般都是嵌入save()restore()方法之间的。否则,剪切区域将会越变越小,这通常不是我们想要的效果。合理的运用好clip()save()以及restore()方法我们就可制作出不同的效果,比如文章中介绍的探照灯的效果。

    原文: https://www.w3cplus.com/canvas/clip.html 

  • 相关阅读:
    python while循环语句
    Python if条件语句
    推荐一款java的验证码组件——kaptcha
    Linux硬链接和符号链接(转)
    推荐一款好用的java反编译软件——JavaDecompiler
    数据库性能优化之冗余字段的作用
    通过设置代理,解决服务器禁止抓取,报“java.io.IOException: Server returned HTTP response code: 403 for URL”错误的方法
    浏览器在同域名下有并发加载的限制
    XCODE快捷键和功能汇总篇(不断更新)
    队列应用场景,自己实现队列
  • 原文地址:https://www.cnblogs.com/fangsmile/p/10180344.html
Copyright © 2020-2023  润新知