《JavaScript 高级程序设计》第十八章 动画与Canvas图形 学习记录

221 阅读8分钟

1、使用requestAnimationFrame

  • 浏览器通过最优方式决定重绘时序。

1、早期定时动画

  • 无法保证时间精度。

2、时间间隔问题

3、requestAnimationFrame

  • 接收一个参数,是要在重绘屏幕前调用的函数。为了实现循环动画,可以多把个requestAnimationFrame()串联起来。

    function updateProgress() {
      let div = document.getElementById('status')
      div.style.width = (parseInt(div.style.width, 10)+5)+ '%'
      if(div.style.left != '100%'){
        requestAnimationFrame(updateProgress)
      }
    }
    requestAnimationFrame(updateProgress)
    
    • 只会调用一次所以需要循环调用,控制什么时候结束。
    • 传入的函数可以接受一个参数,是DOMHighResTimeStamp实例
      • performance.now()的返回值。表示下次重绘的时间。

4、cancelAnimationFrame

  • 返回一个请求ID,一用于通过另一个cancelAnimationFrame()方法来取消重绘任务。
let requestID = window.requestAnimationFrame(()=>{
  console.log('Repaint!')
})
window.cancelAnimationFrame(requestID)

5、通过requestAnimationFrame节流

  • 递归地向队列中加入回调函数,可以保证每次重绘最多只调用一次回调函数

    let enabled = true
    function expensiveOperation() {
      console.log("Invoked at", Date.now())
    }
    
    window.addEventListener('scroll', ()=> {
      if(enabled) {
        enabled = false
        window.requestAnimationFrame(expensiveOperation)
        window.setTimeout(()=> enabled = true, 50)
      }
    })
    

2、基本画布功能

  • widthheight属性,设置画布大小。

  • getContext() :获取对绘图上下文的引用,平面图形传入"2d"参数。

  • toDataURL():导出<canvas>上的图像

    • 参数: MIME类型
    let drawing = document.getElementById("drawing")
    if(drawing.getContext){
      let imgURI = drawing.toDataURL("image/png")
      let image = document.createElement("img")
      img.src = imgURI
      document.body.appendChild(image)
    }
    
  • 如果画布中的图像是其他域绘制过来的,该方法会抛出错误。

3、2D绘图上下文

1、填充和描边

  • 填充以指定样式(颜色、渐变或图像)自动填充形状,描边只为边界着色。
  • fillStyle:填充
  • strokeStyle:描边
    • 属性可以是字符串、渐变对象或图案对象
    • 默认"#000000"
    • 字符串表示颜色可以是css任意格式
let drawing = document.getElementById("drawing")
if(drawing.getContext){
  let context = drawing.getContext("2d")
  context.strokeStyle = "red"
  context.fillStyle = "#0000ff"
}
  • 后面所有与描边和填充的相关操作都会用这两种样式,触发再次修改。

2、绘制矩形

  • fillRect():用来以指定颜色在画布上绘制并填充矩形

  • strokeRect():用来以指定颜色在画布上绘制矩形轮廓

    • 描边宽度:lineWidth,整数
    • 端点状态:lineCap(butt平头、round出圆头、squre出方头)
    • 线条交点形状:lineJoin(round圆转、bevel取平、miter出尖)
  • clearRect():擦除画布中某个区域

    • 参数:矩形x坐标,矩形y坐标,矩形宽度,矩形高度

3、绘制路径

  • 绘制路径要先调用befinPath()表示要开始绘制路径
  • arc(x, y, radius, startAngle, endAngle, counterclockwise)
    • 以坐标(x, y) 为圆心,以radius为半径绘制一条弧线,起始角度startAngle,结束角度endAngle(弧度)。counterclockwise表示是否逆时针计算起始角度和结束角度(默认顺时针)
  • arcTo(x1, y1, x2, y2, radius)
    • 以给定半径radius,经由(x1, y1)绘制一条从上一点到(x2, y2)的弧线
  • bezierCurveTo(c1x, c1y, c2x, c2y, x, y)
    • 以(c1x, c1y),(c2x, c2y)为控制点绘制一条从上一点到(x,y)的弧线(三次贝塞尔曲线)
  • lineTo(x, y)
    • 绘制一条从上一点到(x, y)的直线
  • moveTo(x, y)
    • 不绘制线条,只把绘制光标移动到(x, y)
  • quadraticCurveTo(cx, cy, x, y)
    • 以(cx, cy) 为控制点,绘制一条从上一点到(x, y)的弧线(二次贝塞尔曲线)
  • rect(x, y, width, height)
    • 以给定的宽度和高度,在坐标点(x, y)绘制一个矩形。
    • 与strokeRect和fillRect区别是创建的是一条路径而不是独立图形
  • 创建路径后通过closePath()方法绘制一条返回起点的线。如果路径已完成,可以
    • 指定fillStyle属性并调用fill()方法来填充路径
    • 指定strokeStyle属性并调用stroke()方法来描画路径
    • 调用clip()方法基于已有路径创建一个新剪切区域
  • isPointInPath(x, y)
    • (x, y)点是否在路径上

4、绘制文本

  • fillText()strokeText()
    • 参数:要绘制的字符串、x坐标、y坐标、可选的最大像素宽度
  • 基于属性
    • font CSS语法指定的字体样式、大小、字体族等
    • textAlign:指定文本对其方式
      • start、end、left、right、center
    • textBaseLine:文本的基线
      • top、hanging、middle、alphabetic、ideographic和bottom
  • measureText()用来辅助确定文本大小,接收一个参数,即要绘制的文本,返回一个TextMetrics对象,包含width属性。
    • 使用属性计算绘制指定文本后的大小
  • 第四个参数:最大像素宽度如果超出最大宽度限制,字符会水平压缩。

5、变换

  • 会以默认初始值变化矩阵。

  • rotate(angle):围绕原点把图像旋转angle角度

  • scale(scaleX, scaleY):通过在x轴乘以scaleX, 在y轴乘以scaleY来缩放图像,默认1.0

  • translate(x, y):把原点移到(x, y)。坐标(0, 0)会变成(x, y)

  • transform(m1_1, m1_2, m2_1, m2_2, dx, dy):通过矩阵乘法修改矩阵

    m1_1 m1_2 dx
    m2_1 m2_2 dy
    0    0    1
    
  • setTransform(m1_1, m1_2, m2_1, m2_2, dx, dy):把矩阵重置为默认值,在以传入的参数调用transform

  • 所有的变换包括fillStylestrokeStyle属性,会一直保留在上下文直到再次修改。通过save()方法保存当前的状态,使用restore()方法回到之前保存的设置

  • 只保存应用到绘图上下文的设置和变换,不保存绘图上下文的内容。

6、绘制图像

  • drawImage()
  • 三个参数:在画布上定位图像
    • img,一个<img>元素,或<canvas>元素
    • x,表示绘制目标的x坐标
    • y,表示绘制目标的y坐标
context.drawImage(img,x,y);
  • 五个参数:在画布上定位图像,并规定图像的宽度和高度
    • img,一个<img>元素,或<canvas>元素
    • x,表示绘制目标的x坐标
    • y,表示绘制目标的y坐标
    • width,目标宽度
    • height,目标高度
context.drawImage(img,x,y,width,height);
  • 九个参数:剪切图像,并在画布上定位被剪切的部分
    • img,一个<img>元素,或<canvas>元素
    • sx,源图像x坐标
    • sy,源图像y坐标
    • swidth,源图像宽度
    • sheight,源图像高度
    • x,表示绘制目标的x坐标
    • y,表示绘制目标的y坐标
    • width,目标宽度
    • height,目标高度
context.drawImage(img,sx,sy,swidth,sheight,x,y,width,height);

7、阴影

  • 属性设置
  • shadowColor:要绘制的阴影颜色,默认黑色
  • shadowOffsetX:阴影相对于形状或路径的x坐标的偏移量,默认0
  • shadowOffsetY:阴影相对于形状或路径的y坐标的偏移量,默认0
  • shadowBlur:像素,表示阴影的模糊量,默认0

8、渐变

  • createLineGradient()创建线性渐变
    • 参数:起点x坐标、起点y坐标、终点x坐标、终点y坐标
    • 返回gradient实例
      • 实例使用addColorStop()为渐变指定色标
        • 参数:色标位置(0 ~ 1),CSS字符串
      • 设置完毕后把该实例赋给fillStyle或strokeStyle来绘制图形。
  • createRadialGradient()创建径向渐变
    • 参数:起点圆形中心x,y和半径,终点x,y和半径
    • 返回gradient实例
      • 实例使用addColorStop()为渐变指定色标
        • 参数:色标位置(0 ~ 1),CSS字符串
      • 设置完毕后把该实例赋给fillStyle或strokeStyle来绘制图形。

9、图案

  • 图案用于填充和描画图形的重复图像
  • createPattern()传入两个参数
    • <img>元素(或<video><canvas>)
    • 如何重复图像:repeat、repeat-x、repeat-y、no-repeat
  • 图案的起点是画布原点(0, 0)

10、图像数据

  • getImageData()获取原始图像数据
    • 四个参数:
      • 要取得图像数据中第一个像素的左上角坐标
      • 要取得的像素宽度及高度
    • 返回ImageData的实例,包含width、height、data三个属性
      • data是包含图像的元素像素信息的数组,由红、绿、蓝和透明度表示(第一个像素占据0 - 3 四个值)

11、合成

  • globalAlpha

    • 范围 0 - 1 指定所有绘制内容的透明度,默认0
  • globalCompositionOperation,表示新绘制的形状如何与上下文中已有的形状融合

    • source-over:默认值,新图形绘制在原有图形上面。

    • source-in:新图形只绘制出与原有图形重叠的部分,画布上其余部分全部透明。

    • source-out:新图形只绘制出不与原有图形重叠的部分,画布上其余部分全部透明。

    • source-atop:新图形只绘制出与原有图形重叠的部分,原有图形不受影响。

    • destination-over:新图形绘制在原有图形下面,重叠部分只有原图形透明像素下的部分可见。

    • destination-in:新图形绘制在原有图形下面,画布上只剩下二者重叠的部分,其余部分完全透明。

    • destination-out:新图形与原有图形重叠的部分完全透明,原图形其余部分不受影响。

    • destination-atop:新图形绘制在原有图形下面,原有图形与新图形不重叠的部分完全透明。

    • lighter:新图形与原有图形重叠部分的像素值相加,使该部分变亮。

    • copy:新图形将擦除并完全取代原有图形。

    • xor:新图形与原有图形重叠部分的像素执行“异或”计算

4、WebGL

1、WebGL上下文

let drawing = document.getElementById("drawing")
if(drawing.getContext) {
  let gl = drawing.getContext("webgl")
  if(gl) {
    ...
  }
}

2、WebGL基础

3、WebGL1与WebGL2