canvas学习笔记

####Canvas

\负责在页面中设定一个区域,然后通过js动态地在这个区域中绘制图形。必须先设置width和height属性,然后去的绘图上下文对象的引用,调用getContext("2d")方法,就可以取得2D上下文对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
<canvas id='drawing' width='1024' height='768'>
当前浏览器不支持Canvas,请更换浏览器再试,并把这个浏览器永远扔进垃圾堆
</canvas>
如果浏览器不支持canvas,会出现以上文字;如果支持,就会忽略
-----
##推荐直接在便签里制定大小,即width和height;不能使用css指定大小,因为元素会被拉伸。
因为canvas默认宽高是300px*150px,如果在css设置宽高,会对默认大小进行拉伸
##这两个属性的大小不带有单位
-----
也可以直接js中设置画布宽高
var canvas = document.getElementById('drawing)
canvas.width = xxx
canvas.height = yyy
  • 填充:fillStyle

  • 描边:strokeStyle

    1
    2
    3
    4
    5
    6
    var context = document.getElementById('drawing').getContext('2d')
    context.fillStyle="red"
    context.strokeStyle="blue"
    #所有涉及描边和填充的操作都将使用这两个样式,直到重新设置这两个值
    -----
    context.canvas //直接获取到canvas对象
  1. 绘制矩形:context.rect(x, y, width, height)

    • fillRect(x, y, width, height):矩形实体(颜色由上面的fillStyle定义)
    • strokeRect(x, y, width, height):矩形边框(颜色由上面的strokeStyle定义)
    • clearRect(x, y, width, height)
  2. 绘制直线

    • ctx.moveTo

    • ctx.lineTo

    • ctx.lineWidth

    • ctx.lineCap: round / square

    • ctx.lineJoin: round / bevel / miter(默认)


    绘制虚线 ctx.setLineDash([x1, x2])

    1
    miter状态下,如果超过默认值miterlimiter = 10,那么会自动转换成bevel的形式

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    #先状态设置
    context.lineWidth = 3
    ------
    context.beginPath()
    context.strokeStyle = 'black'
    context.moveTo(100,200) //moveTo表示起点的位置,不会接连在一起
    context.lineTo(300,400)
    context.lineTo(100,600)
    context.stroke()
    context.beginPath() //重新设置状态并绘制,多段不同样式的路径
    context.moveTo(300,200) //1.绘制路径
    context.lineTo(500,400)
    context.lineTo(300,600)
    context.strokeStyle = 'red' //2.描述状态
    context.stroke() //3.绘制
    context.beginPath()
    context.moveTo(500,200)
    context.lineTo(700,400)
    context.lineTo(500,600)
    context.strokeStyle = 'blue'
    context.stroke()
    #再绘制
    context.stroke()

  3. 绘制多段路径:beginPath() & closePath()

    • baginPath() :表示开辟一条新路径
    • closePath() :表示结束当前路径,如果路径不闭合,会自动帮你闭合。closePath()不一定要和beginPath()成对出现

    ⚠️:一般绘制封闭的多边形的时候,可以用closePath()来闭合

  4. 绘制弧线:context.arc(centerx, centery, radius, startingAngle, endingAngle, boolean)

    • 最后一个布尔值:false表示顺时针, true表示逆时针

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      for(var i=0; i++; i<10){
      context.beginPath()
      context.arc(50+ 100*i, 100 , 40 , 0, Math.PI*2*(i+1/10))
      context.closePath()
      context.stroke()
      }
      --------------
      for(var i=0; i++; i<10){
      context.beginPath()
      context.arc(50+ 100*i, 100 , 40 , 0, Math.PI*2*(i+1/10),true)
      context.stroke()
      }

#####实例demo:

图形变换:对图形所有的顶点进行再计算
  • 位移translate(x, y)
  • 旋转rotate( deg )
  • 缩放scale( sx, sy ) :副作用是左上角的原点坐标,图像的stroke宽度也会随之放大缩小。
状态的存储: 在多次进行图形变换中,是叠加的,相互影响,可以用以下api隔离开来。
  • save()
  • restore()

设置变换矩阵 transform(a, b, c, d, e, f) : 多次调用状态会在之前叠加,并且图形原点的位置也会被参数影响。

忽略前面的transform的效果,setTransform(1, 0, 0, 1, 50, 50) ,以这个效果为准。

1
2
3
4
5
6
7
8
9
10
11
12
a c e
b d f
0 0 1
-------
a, d 水平,垂直缩放
b, c 水平,垂直倾斜
e, f 水平,垂直位移
----
context.save()
context.transform(1, 0, 0, 1, 0, 0) 表示原始大小
context.fill()
context.restore()
填充样式
  • 线性渐变色:创建一个填充样式的对象,最后赋值给fillStyle就完事。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    1. var grd = context.createLinearGradient(xstart, ystart, xend, yend)
    2. grd.addColorStop( stop, color) //stop是0.0~1.0之间的数
    ---------eg
    var grd = context.createLinearGradient(0,0,0,canvas.height)
    grd.addColorStop( 0.0, 'black')
    grd.addColorStop( 0.5, 'yellow')
    grd.addColorStop( 1.0, 'white')
    context.fillStyle = grd
    context.fillRect(0,0, 100, 100)
  • 径向渐变色:

    1
    2
    1. var grd = context.createRadialGradient(x0,y0,r0,x1,y1,r1)
    2. grd.addColorStop( stop, color)

实例demo:

星空渐变色背景

使用图片、画布或者video

主要用于背景纹理和图案

createPattern( img , repeat-style ) : no-repeat / repeat-x / repeat-y / repeat

createPattern( canvas, repeat-style) :第一个参数也可以是画布


1
2
3
4
5
6
fillStyle = color
gradient //createLinearGradient(x0, y0, x1, y1)
// createRadialGradient(x0, y0, r0, x1, y1, r1)
image
canvas //createPattern(img/canvas/video , repeat-style)
video
圆弧绘制

context.arcTo(x1, y1, x2, y2, radius)

1
2
3
contest.moveTo(x0, y0)
context.arcTo(x1, y1, x2, y2, radius)
# 三个点确定一段圆弧

实例demo:

绘制弯月

贝塞尔曲线
  • 二次曲线:quadraticCurveTo()

    1
    2
    3
    context.moveTo(x0, y0) //x0,y0是起始点的坐标
    context.quadraticCurveTo(x1, y1, x2, y2)
    //x2, y2是终止点的坐标,x1, y1是控制点
  • 三次曲线:bezierCurveTo()

    1
    2
    context.moveTo(x0, y0) //x0,y0是起始点的坐标
    context.bezierCurveTo(x1, y1, x2, y2, x3, y3)

贝塞尔曲线二次

贝塞尔曲线三次

文字渲染
1
2
3
4
5
6
7
8
9
context.font = "bold 40px Arial"
context.fillText(string , x, y, [maxlength])
context.strokeText(string , x, y, [maxlength])
-----------
context.textAlign = left / center / right
-----------
context.textBaseline = top / middle / bottom
--------测量文本宽度
context.measureText(string).width
  • 文本阴影
1
2
3
4
context.shadowColor
context.shadowOffsetX
context.shadowOffsetY
context.shadowBlur
  • 整体透明度:context.globalAlpha = 0~1

  • context.globalCompositeOperation = ‘destination-over’ :先绘制的图形覆盖后绘制的图形

    ​ = ‘source-over’ :默认,后绘制的图形覆盖前面的

裁剪区域

context.clip():下面的所有绘图都在clip的封闭区域内绘制

探照灯demo

非零环绕原则

对于复杂的图形,画一条射线,如果与图片相交的点的方向相反,则为此区域在图形的外面。

非零环绕demo

#####isPointInPath(x, y) :检测这个坐标点是否在所规划的路径内,可以用来进行一定的交互应用

isPointInPath-demo

图像处理

  • context.drawImage(image/canvas, dx, dy) :图片原始大小

  • context.drawImage(image/canvas, dx, dy, dw, dh) :dw和dh可以缩放指定大小

  • context.drawImage(image/canvas, sx, sy, sw, wh, dx, dy, dw, dh) :截取图片中某一部分绘制到画布的指定位置

    image-20180618173750660

#####离屏canvas:将第二个canvas中的内容加载到第一个canvas上

图像像素级别操作:先getImageData拿到图像的相关像素信息,然后修改后,用putImageData来把处理过的imageData放进去
1
2
3
4
5
6
7
8
9
imageDate = context.getImageData(x, y, w, h)
imageDate对象有widt, height, data属性,data中存储了像素信息
------
context.putImageData(
imageData,
dx, dy,
dirtyX, dirtyY,
dirtyW, dirtyH
)

⚠️imageData是一个数组