三、Canvas基本绘图

Canvas绘图(二)

本章将学习Canvas绘图的以下技巧

  • 裁剪区域
  • 图象合成
  • 简单的Canvas变换

一、设置裁切区域

使用Canvas裁切区域可以限制路径以及子路径的绘制区域,通过rect()函数设置一个用来绘图的矩形区域环境属性;然后调用clip()函数用rect()函数定义的矩形区域设置为裁切区域。那么,无论当前环境绘制什么内容,他只显示裁切区域以内的部分,也可以理解成绘图操作的一种蒙版。例如

drawClip() {
    // 绘制一个大方块
    this.context.fillStyle = "#66ccff";
    this.context.fillRect(10, 10, 200, 200);
    this.context.save();
    this.context.beginPath();

    // 裁切画布从(0,0)点到50 x 50的正方形
    this.context.rect(0, 0, 50, 50);
    this.context.clip();

    // 红色圆
    this.context.beginPath();
    this.context.strokeStyle = "red";
    this.context.lineWidth = 5;
    this.context.arc(100, 100, 100, 0, (Math.PI / 180) * 360, false);

    // 整圆
    this.context.stroke();
    this.context.closePath();

    this.context.restore();

    // 再次裁切整个画布
    this.context.beginPath();
    this.context.rect(0, 0, 500, 500);
    this.context.clip();

    // 裁切一个没有 裁切的 蓝线
    this.context.beginPath();
    this.context.strokeStyle = "blue";
    this.context.lineWidth = 5;
    this.context.arc(100, 100, 50, 0, (Math.PI / 180) * 360, false);
    this.context.stroke();
    this.context.closePath();
}
image-20200927115701655.png

首先,我们创建了50*50的矩形区域作为裁切区域,然后绘制一个红色圆弧形,但是所画的红色圆弧线只能看到在这个矩形以内的部分(有点类似overflow :hidden),最后将裁切区域调整为500 * 500,画一个蓝色圆弧。

二、合成

合成是指如何精细控制画布上对象的透明层与分层效果,有两个属性可以控制。 在Canvas中,默认情况下把Canvas之中的某个物体源绘制到另一个物体(目标)上时,浏览器就会简单的把源物体叠放在目标图像上。

另外,Canvas每次绘制一个图形,就会将原有的Canvas图像作为目标图像,将将要绘制的图像作为源图像

  • globalAlpha : 该属性的默认值为1.0(完全不透明),取值范围为0.,0 ~1.0
  • globalCompositeOperation : 该属性在globalAlpah以及所有变换生效后,控制如何在当前Canvas位图中绘制图形,它由以下枚举值
属性 说明
source-over(默认) 默认。在目标图像上显示源图像。
source-atop 在目标图像顶部显示源图像。源图像位于目标图像之外的部分是不可见的。
source-out 在目标图像之外显示源图像。只会显示目标图像之外源图像部分,目标图像是透明的。
source-in 在目标图像中显示源图像。只有目标图像内的源图像部分会显示,目标图像是透明的。
destination-over 在源图像上方显示目标图像。
destination-atop 在源图像顶部显示目标图像。源图像之外的目标图像部分不会被显示。
destination-in 在源图像中显示目标图像。只有源图像内的目标图像部分会被显示,源图像是透明的
destination-out 在源图像外显示目标图像。只有源图像外的目标图像部分会被显示,源图像是透明的。
copy 显示源图像。忽略目标图像。
xor 使用异或操作对源图像与目标图像进行组合。
lighter 显示源图像 + 目标图像。

A. souce-over

this.context.fillStyle = "black";
this.context.fillRect(10, 10, 200, 200);
// 红色正方形会叠加到黑色上面
this.context.globalCompositeOperation = "source-over";
this.context.fillStyle = "red";
this.context.fillRect(1, 1, 50, 50);
image-20200927143312392.png

B. souce-atop

this.context.globalCompositeOperation = "source-atop";
this.context.fillRect(60, 1, 50, 50);
image-20200927143414050.png

C. source-in

只有目标图像内的源图像部分会显示,目标图像是透明的

this.context.globalCompositeOperation = "source-in";
this.context.fillRect(1, 60, 50, 50);
image-20200927143533513.png

D. destination-over

this.context.globalCompositeOperation = 'destination-over'
this.context.fillRect(1, 1, 50, 50);
image-20200927143654071.png

E. destination-atop

this.context.globalCompositeOperation = 'destination-atop'
this.context.fillRect(1, 1, 50, 50);
image-20200927143920874.png

F. destination-in

this.context.globalCompositeOperation = 'destination-in'
this.context.fillRect(1, 1, 50, 50);
image-20200927144044802.png

G.destination-out

this.context.globalCompositeOperation = 'destination-out'
this.context.fillRect(1, 1, 50, 50);
image-20200927144140182.png

三、简单画布转换

画布变换是指用数学方法调整绘制形状的物理数学,例如缩放与旋转,所有变换依赖后台的数学矩阵运算,我们不必去理解这些运算,我们将讨论如何调整Canvas属性来应用旋转和缩放变换。

这里说一下 Canvas坐标变换的方式 :

  • 平移 : translate
  • 缩放 : scale
  • 旋转 : rotate

而上面三种方式,都可以通过transform()矩阵变换做到,transform(m11,m12,m22,dx,dy),这个之后单独开一章节讲。

A. 旋转和平移变换

例如,我们对一个正方形进行旋转 .

const x = 100,
      y = 100,
      width = 50,
      height = 50,
      angleRadians = (45 * Math.PI) / 180;
this.context.translate(x + 0.5 * width, y + 0.5 * height);
this.context.rotate(angleRadians);
this.context.fillStyle = "red";
this.context.fillRect(-0.5 *width, -0.5 * height, width, height);
image-20200927153307450.png

值得注意以下几点 :

  • translate() : 可以设置画布的原点,默认(0,0),这里设置为红色正方形的中点,那么就可以实现围绕中心点进行旋转了
  • fillRect(-05 * width,-0.5 * height...): 为什么绘制的原点是(-25,-25)呢?是因为原点改变了,现在是(125,125),所以要从(-25,-25)开始绘制

例如绘制多个正方形

drawRotateRects() {
    this.drawRect(50, 100, 40, 40, 45);
    this.drawRect(100, 100, 40, 40, 75);
    this.drawRect(150, 100, 40, 40, 90);
    this.drawRect(200, 100, 40, 40, 120);
}

drawRect(x, y, width, height, angle) {
    this.context.setTransform(1, 0, 0, 1, 0, 0);
    const angleInRadians = (angle * Math.PI) / 180;
    this.context.translate(x + 0.5 * width, y + 0.5 * height);
    this.context.rotate(angleInRadians);
    this.context.fillStyle = "red";
    this.context.fillRect(-0.5 * width, -0.5 * height, width, height);
}
image-20200927164013384.png

this.context.setTransform(1, 0, 0, 1, 0, 0);这段代码你可以理解为重置Canvas变换设置

B. 缩放变换

接口 说明
context.scale(x,y) x为x轴的缩放属性,y为y轴缩放属性,默认为1
如果要把一个对象放大两倍,则可以将两个参数都设为2
drawScaleRect() {
    this.context.fillRect(100, 100, 50, 50);
    this.context.setTransform(1, 0, 0, 1, 0, 0);
    this.context.scale(2, 2);
    this.context.fillStyle = "red";
    this.context.fillRect(100, 100, 50, 50);
}
image-20200927170139949.png

这段代码工作方式与旋转差不多,由于没有平移原点对正方形进行缩放,而仍然用画布左上角作为原点,因此红色的正方形向右下方移动了。可以从中心点进行缩放,代码如下所示

drawScaleRectByCenter() {
    this.context.fillRect(100, 100, 50, 50);
    this.context.globalCompositeOperation = 'destination-over'
    this.context.setTransform(1, 0, 0, 1, 0, 0);
    const x = 100,
    y = 100,
    width = 50,
    height = 50;
    this.context.translate(x + 0.5 * width, y + 0.5 * height);
    this.context.scale(2, 2);
    this.context.fillStyle = "red";
    this.context.fillRect(-0.5 * width, -0.5 * height, width, height);
}
image-20200927170539764.png

最佳实践 : 任何形状的中心点都是(x + 0.5 * width, y + 0.5 * height)

你可能感兴趣的:(三、Canvas基本绘图)