合成与裁切

在之前的例子里面,我们总是将一个图形画在另一个之上,对于其他更多的情况,仅仅这样是远远不够的。比如,对合成的图形来说,绘制顺序会有限制。不过,我们可以利用 globalCompositeOperation 属性来改变这种状况。此外, clip 属性允许我们隐藏不想看到的部分图形。

合成

我们不仅可以在已有图形后面再画新图形,还可以用来遮盖指定区域,清除画布中的某些部分(清除区域不仅限于矩形,像 clearRect()方法做的那样)以及更多其他操作。

globalCompositeOperation = type

这个属性设定了在画新图形时采用的遮盖策略,其值是一个用于标识不同遮盖方式的字符串。

source-over

这是默认设置,并在现有画布上下文之上绘制新图形。

canvas合成方式 source-over

source-atop

新图形只在与现有画布内容重叠的地方绘制。

canvas合成方式 source-atop

source-in

新图形只在新图形和目标画布重叠的地方绘制。其他的都是透明的。

canvas合成方式 source-in

source-out

在不与现有画布内容重叠的地方绘制新图形。

canvas合成方式 source-out

destination-over

在现有的画布内容后面绘制新的图形。

canvas合成方式 destination-over

destination-atop

现有的画布只保留与新图形重叠的部分,新的图形是在画布内容后面绘制的。

canvas合成方式 destination-atop

destination-in

现有的画布内容保持在新图形和现有画布内容重叠的位置。其他的都是透明的。

canvas合成方式 destination-in

destination-out

现有内容保持在新图形不重叠的地方。

canvas合成方式 destination-out

lighter

两个重叠图形的颜色是通过颜色值相加来确定的。

canvas合成方式 lighter

copy

只显示新图形。

canvas合成方式 copy

xor

图像中,那些重叠和正常绘制之外的其他地方是透明的。

canvas合成方式 xor

举例

  1. <template>
  2. <div class="page">
  3. <text class=glo-type>{{globalCompositeOperation}}</text>
  4. <canvas id="cavs" class="canvas"></canvas>
  5. <input class="btn" value="切换合成方式" type="button" onclick="changeGlobalCompositeOperation"></input>
  6. </div>
  7. </template>
  8. <style>
  9. .page {
  10. flex-direction: column;
  11. align-items: center;
  12. }
  13. .glo-type {
  14. margin: 20px;
  15. }
  16. .canvas {
  17. width: 320px;
  18. height: 320px;
  19. border: 1px solid red;
  20. }
  21. .btn {
  22. width: 500px;
  23. height: 80px;
  24. text-align: center;
  25. border-radius: 5px;
  26. margin: 20px;
  27. color: #ffffff;
  28. font-size: 30px;
  29. background-color: #0faeff;
  30. }
  31. </style>
  32. <script>
  33. export default {
  34. private: {
  35. globalCompositeOperation: 'source-over'
  36. },
  37. onShow () {
  38. this.draw()
  39. },
  40. draw () {
  41. const ctx = this.$element('cavs').getContext('2d')
  42. // 清除画布
  43. ctx.clearRect(0, 0, 320, 320)
  44. // 正常绘制第一个矩形
  45. ctx.globalCompositeOperation = 'source-over'
  46. ctx.fillStyle = 'skyblue'
  47. ctx.fillRect(10, 10, 200, 200)
  48. // 设置canvas的合成方式
  49. ctx.globalCompositeOperation = this.globalCompositeOperation
  50. // 绘制第二个矩形
  51. ctx.fillStyle = 'rgba(255, 0, 0, 0.5)'
  52. ctx.fillRect(110, 110, 200, 200)
  53. },
  54. // 切换canvas合成方式
  55. changeGlobalCompositeOperation () {
  56. const globalCompositeOperationArr = ['source-over', 'source-atop',
  57. 'source-in', 'source-out',
  58. 'destination-over', 'destination-atop',
  59. 'destination-in', 'destination-out',
  60. 'lighter', 'copy', 'xor']
  61. const index = globalCompositeOperationArr.indexOf(this.globalCompositeOperation)
  62. if (index < globalCompositeOperationArr.length - 1) {
  63. this.globalCompositeOperation = globalCompositeOperationArr[index + 1]
  64. }
  65. else {
  66. this.globalCompositeOperation = globalCompositeOperationArr[0]
  67. }
  68. this.draw()
  69. }
  70. }
  71. </script>

裁切

裁切路径,就是用 clip 绘制一个不可见的图形。一旦设置好裁切路径,那么你在画布上新绘制的所有内容都将局限在该区域内,区域以外进行绘制是没有任何效果的。

已有的内容不受影响。

要取消裁切路径的效果,可以绘制一个和画布等大的矩形裁切路径。

//绘制一个红色矩形
ctx.fillStyle = 'rgb(200,0,0)'
ctx.fillRect(20, 20, 200, 200)

//使用裁切路径绘制一个圆
ctx.beginPath()
ctx.arc(120, 120, 120, 0, Math.PI * 2, true)
ctx.clip()

//绘制一个蓝色矩形,超出圆形裁切路径之外的部分无法绘制
ctx.fillStyle = 'rgba(0, 0, 200)'
ctx.fillRect(80, 80, 200, 200)

运行效果如下

叠加效果