canvas基础

作者: 邢走在云端 | 来源:发表于2021-10-05 18:18 被阅读0次

    最近在工作中,有个项目一直需要用到canvas相关知识,之前对这块不是很熟练,借着十一假期来进行学习学习

    1. 基础

    1.1 创建canvas

    html

    <canvas id="canvas"></canvas>
    

    在 canvas 上属性 width和height直接指定大小,或用下面的方式

    javascript

    var canvas =  document.getElementById("canvas")
    canvas.width = 1024
    canvas.height = 768
    var ctx = canvas.getContext("2d");
    

    下面所有例子的代码省略了上面的穿件canvas代码

    1.2 坐标

    左上角为原点,向右为x轴正方向,向下为y轴正方向

    image.png

    这个和数学中的坐标系有点区别


    image.png

    2. 绘制线条

    2.1 步骤

    1. 使用moveTo定义笔触开始的点坐标,坐标的表示见 1.2 图形表示
    2. 使用lineTo定义笔触将要到达的点
    3. 使用 stroke 进行绘制
    ctx.moveTo(100, 100)  // 将笔尖移动到 100 100 的位置
    ctx.lineTo(300, 100)  // 将要绘制到的位置
    ctx.stroke() // 绘制
    

    第1,2步是设置状态,第三步才是进行绘制操作。

    此外,对于线的状态设置还有

    ctx.lineWidth = 2
    ctx.strokeStyle = '#f00'
    

    3. 绘制图形

    3.1 根据线->图形。

    在初级数学中,我们都知道线可以组成面,线闭合起来就能形成一个图形,那么有了 2 中的知识,我们就能绘制出一个图形了。just do it

    3.1.1绘制一个三角形

    ctx.moveTo(100, 100)  // 将笔尖移动到 100 100 的位置
    ctx.lineTo(300, 100)  // 将要绘制到的位置 1
    ctx.lineTo(100, 300)  // 将要绘制到的位置 2
    ctx.lineTo(100, 100)  // 将要绘制到的位置 3 回到笔触起点
    ctx.stroke() // 绘制线条
    
    image.png

    3.1.2 填充

    在上面我们在设置状态(确定顶点坐标)之后,用了canvas的 stroke() 这个api,它表示绘制线条,其实我们还有其他的api,填充

    fill

    • stroke
    • fill
    ctx.moveTo(100, 100)  // 将笔尖移动到 100 100 的位置
    ctx.lineTo(300, 100)  // 将要绘制到的位置 1
    ctx.lineTo(100, 300)  // 将要绘制到的位置 2
    ctx.lineTo(100, 100)  // 将要绘制到的位置 3 回到笔触起点
    ctx.fill() // 填充
    
    image.png

    这时候我们就得到一个实心的图形啦!

    哎?怎么是黑色的?因为默认就是黑色的。线条能设置颜色,那么我们填充也能设置颜色,使用下面的api

    • fillStyle
    ctx.moveTo(100, 100)  // 将笔尖移动到 100 100 的位置
    ctx.lineTo(300, 100)  // 将要绘制到的位置 1
    ctx.lineTo(100, 300)  // 将要绘制到的位置 2
    ctx.lineTo(100, 100)  // 将要绘制到的位置 3 回到笔触起点
    ctx.fillStyle = '#f00' // 设置填充样式
    ctx.fill() // 填充
    
    image.png

    所以综上所述,只要我们知道图形的顶点坐标,我们再用线连接起来,就能绘制大部分的图形了!

    3.2 绘制矩形

    矩形,规规矩矩,所以canvas中有特定的api进行绘制,提供以下三个api

    strokeRect(x, y, width, height) // 绘制一个矩形的边框
    fillRect(x, y, width, height) // 绘制一个填充的矩形
    clearRect(x, y, width, height) // 清除指定矩形区域,让清除部分完全透明
    

    我们使用上面三个分别尝试

    3.2.1 strokeRect

    // ctx.strokeStyle = '#f00' // 设置矩形线条颜色
    ctx.strokeRect(100, 100, 200, 200) // 左上角坐标为(100,100),宽高分别为 200, 200 的线状矩形
    
    image.png

    3.2.2 fillRect

    // ctx.fillStyle = '#f00' // 设置矩形线条颜色
    ctx.fillRect(100, 100, 200, 200) // 左上角坐标为(100,100),宽高分别为 200, 200 的填充矩形
    
    image.png

    3.2.3 clearRect

    清除指定矩形区域,让清除部分完全透明

    我们在 3.2.2的基础上写

    // ctx.fillStyle = '#f00' // 设置矩形线条颜色
    ctx.fillRect(100, 100, 200, 200) // 左上角坐标为(100,100),宽高分别为 200, 200 的填充矩形
    ctx.clearRect(100, 100, 150, 150)
    
    image.png

    可以看到,在3.2.2基础上,某个区域被清除了。

    3.2.4 绘制多个图形/线条,状态问题(重要!!!)

    canvas是基于状态进行绘制,先设定状态,再进行绘制。在一个canvas画布上进行多个图形/线条绘制是正常操作,我们看下面代码

    // 绘制一个边线宽为5, 颜色为红色的三角形
    ctx.moveTo(100, 100)  // 将笔尖移动到 100 100 的位置
    ctx.lineTo(300, 100)  // 将要绘制到的位置 1
    ctx.lineTo(100, 300)  // 将要绘制到的位置 2
    ctx.lineTo(100, 100)  // 将要绘制到的位置 3 回到笔触起点
    ctx.strokeStyle = '#f00'
    ctx.lineWidth = 5
    ctx.stroke() // 绘制
    
    
    // 绘制一条绿色的直线,线宽默认
    ctx.moveTo(400, 100)
    ctx.lineTo(100, 400)
    ctx.strokeStyle = '#0f0'
    ctx.stroke()
    

    运行结果如下


    image.png

    哎?从上述代码中,我们明明是先绘制一个边线宽为5, 颜色为红色的三角形,然后再绘制一条绿色的,线宽默认的直线。

    但是我们发现了啥,三角形的边颜色变成了绿色,直线线宽变成了5

    原因如下:

    1. canvas是基于状态进行绘制,先设定状态,再进行绘制
    2. 绘制三角形的时候,我们设置了状态 1.线颜色为红色, 2. 线宽为5
    3. 绘制直线的时候,我们设置了状态 1. 线颜色为绿色
    4. 这时候,我们后面的状态就会将前面的状态进行覆盖!及 1. 线颜色为绿色, 2. 线宽为5

    真相大白!这是新手经常会遇到的问题。这个就类似于作用域,是不是?

    所以我们要对每个图形状态进行状态的限定。用到两个api

    • beginPath
    • closePath

    将每一段状态用beginPath 和 closePath 进行括起来

    直接上代码

    // 绘制一个三角形
    ctx.beginPath()
    ctx.moveTo(100, 100)  // 将笔尖移动到 100 100 的位置
    ctx.lineTo(300, 100)  // 将要绘制到的位置 1
    ctx.lineTo(100, 300)  // 将要绘制到的位置 2
    ctx.lineTo(100, 100)  // 将要绘制到的位置 3 回到笔触起点
    ctx.strokeStyle = '#f00'
    ctx.lineWidth = 5
    ctx.closePath()
    ctx.stroke() // 绘制
    
    
    // 绘制一条直线
    ctx.beginPath()
    ctx.moveTo(400, 100)
    ctx.lineTo(100, 400)
    ctx.strokeStyle = '#0f0'
    ctx.closePath()
    ctx.stroke()
    

    运行结果


    上述代码,其实不需要closePath也能得到同样的效果,closePath会自动将一个不封闭的图形封闭。

    // 绘制一个三角形
    ctx.beginPath()
    ctx.moveTo(100, 100)  // 将笔尖移动到 100 100 的位置
    ctx.lineTo(300, 100)  // 将要绘制到的位置 1
    ctx.lineTo(100, 300)  // 将要绘制到的位置 2
    // ctx.lineTo(100, 100)  // 将要绘制到的位置 3 回到笔触起点  注意此时我注释了这个状态,不是一个封闭的三角形了
    ctx.strokeStyle = '#f00'
    ctx.lineWidth = 5
    ctx.closePath() // 自动封闭图形
    ctx.stroke() // 绘制
    
    
    // 绘制一条直线
    ctx.beginPath()
    ctx.moveTo(400, 100)
    ctx.lineTo(100, 400)
    ctx.strokeStyle = '#0f0'
    // ctx.closePath() // 可以不需要
    ctx.stroke()
    

    3.2.4 绘制圆/圆弧 arc

    1. 重要api
    ctx.arc(centerx, centery, radius, startingAngle, endingAngle, anticlockwise = false)
    

    上面👆的api, 参数分别表示:圆心x, 圆心y,半径r, 起始角度, 结束角度, 逆时针旋转 (默认false)

    1. 角度示意图
    image.png
    1. 例子
      // 圆心x,圆心y,半径r, 起始角度, 结束角度, 逆时针旋转 (默认false)
      ctx.arc(300, 300, 100, 0, 2 * Math.PI, false)
      ctx.stroke()
    
    image.png

    4. 颜色覆盖、透明

    css中使用 rgba来实现颜色及其透明度,在canvas同样适用

    ctx.beginPath()
    ctx.fillStyle = 'rgba(255,100,100, 0.5)'
    ctx.fillRect(100, 100, 100, 100)
    ctx.closePath()
    
    
    ctx.beginPath()
    ctx.fillStyle = 'rgba(100,100,100, 0.5)'
    ctx.fillRect(150, 150, 100, 100)
    ctx.closePath()
    

    运行结果


    image.png

    5. 图形变换和状态保存

    5.1 通过translate讲解 save和restore

    canvas中translate(x,y)可以讲绘制的图形平移到(x,y) 的位置

    ctx.fillStyle = 'rgba(255,100,100, 0.5)'
    ctx.translate(100, 100) // 从0,0 平移到 100,100
    ctx.fillRect(0, 0, 100, 100)
    
    ctx.fillStyle = 'rgba(100,100,100, 0.5)'
    ctx.translate(150, 150) // // 希望从0,0 平移 150,150, 但是和上面的状态叠加了 变成了 translate(250,250)
    ctx.fillRect(0, 0, 100, 100)
    

    结果

    image.png

    第二个灰色的矩形,我们希望从(0,0)平移(150,150)个横纵像素, 按理说和第一个粉色的矩形有重合,但是和上面的状态叠加了 变成了 translate(250,250)。

    这时候我们就需要用到 save和restore这两个api,它们是成对出现的,利用它们更改上面的代码

    ctx.save()
    ctx.fillStyle = 'rgba(255,100,100, 0.5)'
    ctx.translate(100, 100) // 从0,0 平移到 100,100
    ctx.fillRect(0, 0, 100, 100)
    ctx.restore()
    
    ctx.save()
    ctx.fillStyle = 'rgba(100,100,100, 0.5)'
    ctx.translate(150, 150) // // 希望从0,0 平移到 150,150, 但是和上面的状态叠加了 变成了 translate(250,250)
    ctx.fillRect(0, 0, 100, 100)
    ctx.restore()
    

    结果如下:

    image.png

    5.2 tranlate、rotate、scale

    5.2.1 translate

    对图形进行平移

    5.1 章节已经演示过

    5.2.2 rotate

    旋转

    rotate(度数)

    ctx.save()
    ctx.fillStyle = 'rgba(100,100,100, 0.5)'
    ctx.fillRect(200, 200, 100, 100)
    ctx.restore()
    
    ctx.save()
    ctx.fillStyle = 'rgba(255,100,100, 0.5)'
    ctx.rotate(30 / 180 * Math.PI) // 以(0,0)的点为圆心, 以(0,0)到左上角的顶点坐标的距离为半径,顺时针旋转30度
    ctx.fillRect(200, 200, 100, 100)
    ctx.restore()
    

    以(0,0)的点为圆心, 以(0,0)到左上角的顶点坐标的距离为半径,顺时针旋转30度。如图,粉色的图形即为灰色图形旋转后的位置

    image.png

    5.2.3 scale

    缩放

    特性

    scale() 用于修改元素的大小。可以通过向量形式定义的缩放值来放大或缩小元素,同时可以在不同的方向设置不同的缩放值。该变换通过一个二维向量确定在一个方向缩放的多少。如果缩放向量的两个坐标是相等的,那么所讲是均等的,或者说是各向同的,同时元素的形状是被保持的。---- MDN

    我们看下面的代码,蓝色部分可以看作是灰色部分放大两倍的。但是我们看看结果

    ctx.fillStyle = '#98CCFB'
    ctx.fillRect(50, 50, 200, 100)
    
    ctx.fillStyle = '#CCCCCC'
    ctx.scale(2,2)
    ctx.fillRect(50, 50, 200, 100)
    

    结果

    image.png

    我们发现,他们的顶点位置竟然也发生了变化,变成了(100,100),可是咱们代码中,顶点位置都是(50,50)。这就是scale值得注意的地方,它会对起始位置的坐标也会进行缩放操作。下面是示意图:

    image.png

    如图蓝色图形被放大2倍,它的顶点位置也会被相应缩放,当大了两倍。

    副作用

    从上面,我们可以看见scale的副作用之一就是会对起始坐标的位置进行缩放。我们接着上面的例子进行改造下,我们换成strokeRect进行绘制图形。

    ctx.save()
    ctx.fillStyle = '#98CCFB'
    ctx.strokeStyle = '#000'
    ctx.lineWidth = 5
    ctx.strokeRect(50, 50, 200, 100)
    ctx.restore()
    
    ctx.save()
    ctx.fillStyle = '#CCCCCC'
    ctx.strokeStyle = '#000'
    ctx.lineWidth = 5
    ctx.scale(2,2)
    ctx.strokeRect(50, 50, 200, 100)
    ctx.restore()
    

    运行结果如下:

    image.png

    我们会发现,进行放大的图形,它的lineWidth也放大了!这时候我们知道了它的另一个副作用,会缩放边框。

    总结:

    • scale会缩放起始坐标
    • scale会缩放边的粗细

    相关文章

      网友评论

        本文标题:canvas基础

        本文链接:https://www.haomeiwen.com/subject/czpgnltx.html