canvas学习笔记

1 篇文章 0 订阅

canvas笔记
1.初识canvas
  • 什么是canvas?

html5新增加的绘图工具,如何使用?先获得canvas画布对象,创建绘制上下文,调用不同的绘制方法和属性进行图像的绘制,案例:如下代码

<html>
    <body>
        <canvas width="600" height="400"></canvas>
        <script>
            // 获取canvas对象
        	const canvas = document.querySelector('canvas')
            // 创建绘制上下文
    		const ctx  = canvas.getContext('2d')
        </script>
    </body>
</html>
2.绘制矩形
  • 绘制填充矩形
<html lang="en">
<body>
  <canvas width="600" height="400"></canvas>
  <script>
    const canvas = document.querySelector('canvas')
    const ctx  = canvas.getContext('2d')
    ctx.fillStyle = 'red'
    // 设置画笔的落点,起始点,x和y 以及矩形的宽和高
    ctx.fillRect(100,50,300,10)
  </script>
</body>
</html>
  • 绘制矩形路径
<html lang="en">
<body>
  <canvas width="600" height="400"></canvas>
  <script>
    const canvas = document.querySelector('canvas')
    const ctx  = canvas.getContext('2d')
    ctx.fillStyle = 'red'
    // 设置画笔的落点,起始点,x和y
    // 绘制矩形路径
    ctx.strokeRect(20,20,100,100)
    // 清楚画布 要清楚的起始位置,要清楚的宽高
    setTimeout(() => {
      ctx.clearRect(20,20,100,100)
    }, 1000);
  </script>
</body>
</html>
  • 绘制api拆开来写
<html lang="en">
<body>
  <canvas width="600" height="400"></canvas>
  <script>
    const canvas = document.querySelector('canvas')
    const ctx  = canvas.getContext('2d')
    ctx.fillStyle = 'red'
    // 定义矩形路径 但是不填充,也不绘制
    ctx.beginPath()  // 开始一个路径
    ctx.rect(10,10,100,100)
    // 填充矩形
    ctx.fill()
    ctx.closePath() // 结束或者说断开一个路径
    ctx.rect(10,120,100,100)
    ctx.stroke()
  </script>
</body>
</html>
矩形绘制api整理
属性/方法名称使用说明属性类型备注
fillStyle设置或返回当前填充颜色String
strokeStyle设置或返回当前绘制颜色String
beginPath()开始一个路径Function
closePath()结束一个路径Function
rect(x,y,width,height)定义矩形路径 但是不填充,也不绘制Function
fill()填充一个已经定义的路径Function
stroke()绘制一个已经定义的路径Function
fillRect(x,y,width,height)定义并填充一个矩形Function
strokeRect(x,y,width,height)定义并绘制一个矩形Function
clearRect(x,y,width,height)清除画布,从起始点开始,清除固定的宽高Function
3.绘制弧形和圆形
  • 弧形绘制
<html lang="en">
<body>
  <canvas width="500" height="500"></canvas>
  <script>
    const canvas = document.querySelector('canvas')
    const ctx = canvas.getContext('2d')
    // ctx.arc(圆心x,圆心y, 半径, 开始的角度(默认是从3点方向开始), 结束的角度, 是否逆时针(默认是false))
    // 传入pi 函数内会计算,pi直接等于180度
    // .arc(250,250,100,0,Math.PI,true) // 绘制半弧形
    ctx.arc(250,250,100,0,Math.PI/2,true)
    // ctx.fill() // 如果填充,那么默认会从开始点到结束点进行闭合连接
    ctx.stroke()
  </script>
</body>
</html>
  • 绘制一个笑脸
<html lang="en">
<body>
  <canvas width="500" height="500"></canvas>
  <script>
    const canvas = document.querySelector('canvas')
    const ctx = canvas.getContext('2d')
    // 绘制整个头部
    ctx.arc(250,250,200,0,Math.PI*2)
    ctx.stroke()
    ctx.beginPath()
    // 绘制嘴巴
    ctx.arc(250,280,100,0,Math.PI)
    ctx.stroke()
    // 绘制左眼睛
    ctx.beginPath()
    ctx.arc(150,150,30,0,Math.PI*2)
    ctx.stroke()
    // 绘制右眼
    ctx.beginPath()
    ctx.arc(350,150,30,0,Math.PI*2)
    ctx.stroke()
  </script>
</body>
</html>
  • 使用moveTo绘制不连续的路径 移动画笔到指定的位置
<html lang="en">
<body>
  <canvas width="500" height="500"></canvas>
  <script>
    const canvas = document.querySelector('canvas')
    const ctx = canvas.getContext('2d')
    // ctx.moveTo 绘制一条不连续的额路径
    // 绘制整个头部
    ctx.arc(250,250,200,0,Math.PI*2)
    ctx.moveTo(350,250) // 移动画笔到指定位置
    // 绘制嘴巴
    ctx.arc(250,250,100,0,Math.PI)
    // 绘制左眼睛
    ctx.moveTo(180,150)
    ctx.moveTo(120,150)
    ctx.arc(150,150,30,0,Math.PI*2)
    // 绘制右眼
    ctx.moveTo(380,150)
    ctx.moveTo(320,150)
    ctx.arc(350,150,30,0,Math.PI*2)
    ctx.fillStyle = 'yellow'
    ctx.fill()
    ctx.strokeStyle = 'red'
    ctx.stroke()
  </script>
</body>
</html>
  • 使用arcTo绘制
<html lang="en">
<body>
  <canvas width="500" height="500"></canvas>
  <script>
    const canvas = document.querySelector('canvas')
    const ctx = canvas.getContext('2d')
    ctx.moveTo(250,250)
    ctx.arcTo(250,300,200,250,20)
    ctx.stroke()
    ctx.moveTo(250,250)
    ctx.lineTo(250,300)
    ctx.lineTo(200,250)
    ctx.stroke()
  </script>
</body>
</html>
弧形绘制api整理
属性/方法名称使用说明属性类型备注
arc(x,y,r,起始角度(0是从3点位置开始),结束的角度,是否逆时针(默认是false))定义弧形路径Function
fill()填充Function
stroke()绘制Function
beginPath()开始一个新的绘制点Function
moveTo()将画笔移动到指定的位置Function
arcTo(x1,y1,x2,y2,r)根据三个点形成的内角绘制圆弧
4.绘制直线
<html lang="en">
<body>
  <canvas width="500" height="500"></canvas>
  <script>
    const canvas = document.querySelector('canvas')
    const ctx = canvas.getContext('2d')
    // //  将画笔移动到指定的位置
    // ctx.moveTo(250,250)
    // // 连接到指定位置
    // ctx.lineTo(400,250)
    // // 绘制路径
    // ctx.stroke()

    // 绘制一个三角形
    ctx.moveTo(250,250)
    ctx.lineTo(350,250)
    ctx.lineTo(300,300)
    ctx.lineTo(250,250)
    ctx.fill() // 如果不连接第三条线 在填充时也会自动的闭合
    ctx.stroke()
  </script>
</body>
</html>
直线绘制api整理
属性/方法名称使用说明属性类型备注
moveTo(x,y)画笔移动到指定位置
lineTo(x,y)从当前点连接到指定的点
fill()填充
stroke()绘制
5.贝塞尔曲线
  • 二次贝塞尔曲线

什么是二次贝塞尔曲线?由一个起点p1,一个控制点p1和一个终点p2组成的路径,并根据这个路径绘制一个弧形线段

绘制一个贝塞尔曲线

<html lang="en">
<body>
  <canvas width="600" height="400"></canvas>
  <script>
    const canvas = document.querySelector('canvas')
    const ctx = canvas.getContext('2d')
    ctx.moveTo(200,300)
    ctx.quadraticCurveTo(150,300,150,200)
    ctx.stroke()
  </script>
</body>
</html>

效果

大致的绘制及基点位置

  • 使用二次贝塞尔曲线绘制一个聊天气泡图案
<html lang="en">
<body>
  <canvas width="600" height="400"></canvas>
  <script>
    const canvas = document.querySelector('canvas')
    const ctx = canvas.getContext('2d')
    ctx.moveTo(200,300)
    ctx.quadraticCurveTo(150,300,150,200)
    // 当前的起点就是上一个曲线的终点
    ctx.quadraticCurveTo(150,150,300,150)
    ctx.quadraticCurveTo(350,150,350,250)
    ctx.quadraticCurveTo(350,300,250,300)
    ctx.quadraticCurveTo(250,350,180,380)
    ctx.quadraticCurveTo(250,300,200,300)
    ctx.stroke()
  </script>
</body>
</html>

效果

  • 贝塞尔三次曲线

什么是贝塞尔三次曲线?通过一个起点p0,控制点p1,途径点p2,结束点p3,根据这几个节点绘制弧形线段

  • 绘制一个贝塞尔三次曲线
<html lang="en">
<body>
  <canvas width="1280" height="800"></canvas>
  <script>
    const canvas = document.querySelector('canvas')
    const ctx = canvas.getContext('2d')
    ctx.moveTo(300,300)
    ctx.bezierCurveTo(400,200,600,400,300,600)
    ctx.stroke()
  </script>
</body>
</html>

效果

大致的绘制及基点位置

  • 使用三次贝塞尔曲线和二次贝塞尔曲线绘制桃心
<html lang="en">
<body>
  <canvas width="1280" height="800"></canvas>
  <script>
    const canvas = document.querySelector('canvas')
    const ctx = canvas.getContext('2d')
    ctx.moveTo(300,300)
    ctx.bezierCurveTo(400,200,600,400,300,600)
    ctx.moveTo(300,300)
    ctx.bezierCurveTo(200,200,0,400,300,600)
    ctx.strokeStyle = 'red'
    ctx.stroke()
    ctx.closePath()
    ctx.beginPath()
    ctx.moveTo(400,350)
    ctx.quadraticCurveTo(450,250,500,350)
    ctx.moveTo(500,350)
    ctx.bezierCurveTo(600,275,700,350,300,600)
    ctx.strokeStyle = 'pink'
    ctx.stroke()
    ctx.closePath()
    ctx.beginPath()
    ctx.moveTo(50,500)
    ctx.quadraticCurveTo(300,350,650,450)
    ctx.strokeStyle = 'red'
    ctx.stroke()
    ctx.closePath()
    ctx.beginPath()
    ctx.moveTo(625,425)
    ctx.lineTo(650,450)
    ctx.lineTo(625,465)
    ctx.stroke()
  </script>
</body>
</html>

效果

贝塞尔曲线api整理
属性/方法名称使用说明属性类型备注
quadraticCurveTo(x1,y1,x2,y2)根据两个点绘制弧线
bezierCurveTo(x1,y1,x2,y2,x3,y3)根据三个点绘制弧线
6.路径封装 Path2D
  • 将需要绘制的路径先存储到一个对象中,最后在交给绘制上下文进行绘制
<html lang="en">
<body>
  <canvas width="1280" height="800"></canvas>
  <script>
    const canvas = document.querySelector('canvas')
    const ctx = canvas.getContext('2d')
    const bardPath = new Path2D()
    console.log(bardPath);
    // 先进行路径存储
    bardPath.moveTo(300,300)
    bardPath.bezierCurveTo(400,200,600,400,300,600)
    bardPath.moveTo(300,300)
    bardPath.bezierCurveTo(200,200,0,400,300,600)
    // 最后就行绘制
    ctx.stroke(bardPath)
  </script>
</body>
</html>
7.颜色设置
属性/方法名称使用说明属性类型备注
globalAlpha设置或返回全局的透明度Number
fillStyle设置或返回填充颜色,支持单位:16进制,rgba,颜色单词String
strokeStyle设置或返回路径绘制颜色String
8.渐变色设置

canvas的渐变需要先创建渐变对象,然后将渐变对象设置给渲染style

创建一个渐变

ctx.createLinearGradient(x,y,width,height)

将渐变对象设置给渲染style

ctx.fillStyle = jianbian

线性渐变
<body>
    <canvas width="1280" height="800"></canvas>
    <script>
    	const canvas = document.querySelector('canvas')
    	const ctx = canvas.getContext('2d')
        // 想要使用家变必须先创建一个渐变 , 然后把渐变对象赋值给画笔的style
        // 创建一个线性渐变
        // const jianbian = ctx.createLinearGradient(x,y,width,height)
        // const jianbian = ctx.createLinearGradient(100,200,400,500)
        // 设置对0到1不同区域的颜色
        // jianbian.addColorStop(0,'red')
        // jianbian.addColorStop(0.5,'pink')
        // jianbian.addColorStop(1,'blue')
        // ctx.fillStyle = jianbian
        // ctx.fillRect(100,200,300,300)
        
        // 过度效果
        let index =0
        function render(){
          ctx.clearRect(0,0,1200,800)
          index+=0.01
          if(index>=1){
            index=0
          }
          const jianbian = ctx.createLinearGradient(100,200,400,500)
          jianbian.addColorStop(0,'red')
          jianbian.addColorStop(index,'pink')
          jianbian.addColorStop(1,'blue')
          ctx.fillStyle = jianbian
          ctx.fillRect(100,200,300,300)
          requestAnimationFrame(render)
        }
        requestAnimationFrame(render)
    </script>
</body>
镜像渐变
<html lang="en">
<body>
  <canvas width="600" height="400"></canvas>
  <script>
    const canvas = document.querySelector('canvas')
    const ctx = canvas.getContext('2d')
    // 想要使用家变必须先创建一个渐变 , 然后把渐变对象赋值给画笔的style
    // 创建一个镜像渐变
    // const jianbian = ctx.createRadialGradient(x,y,r,x1,y1,r)
    const jianbian = ctx.createRadialGradient(250,150,10,300,200,100)
    jianbian.addColorStop(0,'pink')
    jianbian.addColorStop(1,'red')
    ctx.fillStyle = jianbian
    ctx.arc(300,200,100,0,Math.PI*2)
    ctx.fill()
  </script>
</body>
</html>
圆锥渐变
< lang="en">
<body>
  <canvas width="600" height="400"></canvas>
  <script>
    const canvas = document.querySelector('canvas')
    const ctx = canvas.getContext('2d')
    // 想要使用家变必须先创建一个渐变 , 然后把渐变对象赋值给画笔的style
    // 创建一个圆锥渐变
    // const jianbian = ctx.createConicGradient(角度,x,y)
    const jianbian = ctx.createConicGradient(0,300,200)
    jianbian.addColorStop(0,'pink')
    jianbian.addColorStop(0.5,'yellow')
    jianbian.addColorStop(1,'red')
    ctx.fillStyle = jianbian
    ctx.arc(300,200,100,0,Math.PI*2)
    ctx.fill()
  </script>
</body>
</html>
渐变api整理
属性/方法名称使用说明属性类型备注
ctx.createLinearGradient(x,y,width,height)创建线性渐变返回渐变对象
ctx.createRadialGradient(x,y,r,x1,y1,r)创建镜像渐变返回渐变对象
ctx.createConicGradient(角度(Math.PI默认3点方向),x,y)创建圆锥渐变返回渐变对象
9.填充图片为背景
<html lang="en">
<body>
  <canvas width="600" height="400"></canvas>
  <script>
    const canvas = document.querySelector('canvas')
    const ctx = canvas.getContext('2d')
    // 用图片作为填充背景
    const img = new Image()
    img.src = '../img/2.jpg'
    // 在图片加载完成后
    img.onload = function(){
      // ctx.createPattern(img/canvas对象,'平铺方式-同css')
      const imgBg = ctx.createPattern(img,'no-repeat')
      ctx.fillStyle = imgBg
      ctx.fillRect(0,0,600,400)
    }
  </script>
</body>
</html>
填充图片为背景api整理
属性/方法名称使用说明属性类型备注
ctx.createPattern(img/canvas对象,‘平铺方式-同css’)创建图片为填充背景返回style对象
10 线条样式
<html lang="en">
<body>
  <canvas width="600" height="400"></canvas>
  <script>
    const canvas = document.querySelector('canvas')
    const ctx = canvas.getContext('2d')
    ctx.moveTo(300,200)
    ctx.lineTo(400,300)
    ctx.lineTo(500,200)
    // 设置线段的粗细
    ctx.lineWidth = 10
    // 设置线段两端的点的样式. butt平齐,round半圆, square正方形
    ctx.lineCap = 'square'
    // 设置两个线段连接点的样式 (mitter默认,round带有一点圆润效果, bevel把尖角弄平)
    ctx.lineJoin = 'bevel'
    ctx.stroke()

    ctx.lineWidth = 1
    ctx.moveTo(100,100)
    ctx.lineTo(400,100)
    
    // 设置虚线
    ctx.setLineDash([20,5])
    ctx.lineDashOffset = 40
    ctx.stroke()
  </script>
</body>
</html>
  • 带有过度效果的偏移
<html lang="en">
<body>
  <canvas width="600" height="400"></canvas>
  <script>
    const canvas = document.querySelector('canvas')
    const ctx = canvas.getContext('2d')
    let index = 0
    function render(){
      ctx.clearRect(0,0,600,400)
      index++
      if(index>40)index = 0
      ctx.moveTo(100,100)
      ctx.lineTo(400,100)
      
      // 设置虚线
      ctx.setLineDash([20,5])
      ctx.lineDashOffset = index
      ctx.stroke()
      requestAnimationFrame(render)
    }
    render()
  </script>
</body>
</html>
线条样式api整理
属性/方法名称使用说明属性类型备注
lineWidth设置或返回线条的粗细Number
lineCap设置线段两端的点的样式. butt平齐,round半圆, square正方形String
lineJoin设置两个线段连接点的样式 (mitter默认,round带有一点圆润效果, bevel把尖角弄平)String
setLineDash([虚线的长度,空格部分的宽度])设置虚线Function
lineDashOffset设置或返回线段的偏移Number
11.阴影设置
<html lang="en">
<body>
  <canvas width="600" height="400"></canvas>
  <script>
    const canvas = document.querySelector('canvas')
    const ctx = canvas.getContext('2d')
    ctx.shadowOffsetX = 10 // 设置阴影的x方向偏移
    ctx.shadowOffsetY = 10 // 设置阴影y方向的偏移
    ctx.shadowColor = 'red' // 设置阴影y方向的偏移
    ctx.shadowBlur = 5 // 设置阴影的模糊程度
    ctx.strokeRect(300,200,200,200)
   </script>
</body>
</html>
阴影绘制api整理
属性/方法名称使用说明属性类型备注
shadowOffsetX设置阴影的x方向偏移Number
shadowOffsetY设置阴影y方向的偏移Number
shadowColor设置阴影y方向的偏移String
shadowBlur设置阴影的模糊程度Number
12.绘制图像及视频
绘制图像
<html lang="en">
  <body>
    <canvas width="600" height="800"></canvas>
    <script>
      const canvas = document.querySelector('canvas')
      const ctx = canvas.getContext('2d')
      const img = new Image()
      img.src = '../img/1.png'
      img.onload = function(){
        // 第一种绘制图片的方式
        // ctx.drawImage(imgDom,x,y)
        // ctx.drawImage(img,0,0)
        // 第二种方式
         // ctx.drawImage(imgDom,x,y,width,height)
        ctx.drawImage(img,0,0,600,800)
        // 第三种方式 裁剪
        // ctx.drawImage(img,裁剪的x,裁剪的y,要裁剪的宽,要裁剪的高,绘制x,绘制y,绘制width,绘制的height)
        // ctx.drawImage(img,500,600,1000,1500,0,0,700,500)
      }
    </script>
  </body>
</html>

绘制视频
<html lang="en">
</html>
  <body>
    <canvas width="600" height="400"></canvas>
    <video id="video" width="500" height="500" controls hidden src="../img/4.mp4"></video>
    <button id="btn">播放</button>
    <script>
      const canvas = document.querySelector('canvas')
      const ctx = canvas.getContext('2d')
      const video = document.getElementById('video')
      const img = new Image()
      img.src = '../img/2.jpg'
      btn.onclick = function(){
        if(video.paused){
          video.play()
          render()
        }else{
          video.pause()
        }
      }
      function render(){
        ctx.drawImage(video,0,0,600,400)
        ctx.drawImage(img,0,0,50,50) // 同时绘制一个icon图标
        requestAnimationFrame(render)
      }
    </script>
  </body>
</html>

图像视频绘制api整理
属性/方法名称使用说明属性类型备注
drawImage(imgDom,x,y)绘制图像Function方案一,同时可以渲染canvas
drawImage(imgDom,x,y,width,height)绘制图像Function方案二
drawImage(img,裁剪的x,裁剪的y,要裁剪的宽,要裁剪的高,绘制x,绘制y,绘制width,绘制的height)绘制图像Function方案三
drawImage(video,x,y,width,height)绘制视频
toDataURL(‘image/jpeg’, 0.5)将canvas导出为可访问路径Function返回base64地址
toBlob(file=>)将canvas导出为文件对象Functione为文件对象
13.绘制文字
<html lang="en">
</html>
  <body>
    <canvas width="600" height="600"></canvas>
    <script>
      const canvas = document.querySelector('canvas')
      const ctx = canvas.getContext('2d')
      ctx.strokeStyle = 'red'
      // 设置文字样式 同css
      ctx.font = '50px 微软雅黑'
      // 设置文字水平对齐方式 (基于对峙中心点),同css
      ctx.textAlign = 'center'
      // 设置垂直对齐方式 支持top,button,middle 
      ctx.textBaseline = 'middle'
      // 文本方向
      ctx.direction = 'rtl'
      // 返回一个文本的预设参数,包括文字的占比宽度等等信息
      const textInfo = ctx.measureText('你好')
      // ctx.fillText(要绘制的文字,x,x,绘制文字的最大宽度)
      // 填充文字
      // ctx.fillText('小明大门',100,100)
      // 绘制文字 轮廓
      ctx.strokeText('小明大门!',200,200)
      ctx.arc(200,200,5,0,Math.PI*2)
      ctx.fill()
    </script>
  </body>
</html>
	
文字绘制api整理
属性/方法名称使用说明属性类型备注
font设置或返回文字样式,同cssString
textAlign设置文件对其方式,基于绘制起点String
textBaseline设置垂直对齐方式 支持top,button,middleString
direction文本方向,支持 rtl (基本没啥用)String
measureText(‘text’)返回一个文本的预设参数,包括文字的占比宽度等等信息Function
fillText(要绘制的文字,x,y,绘制文字的最大宽度)填充文字Function
strokeText(‘文字!’,x,y)绘制文字 轮廓Function
14.2D转换
位移
<html lang="en">
  <body>
    <canvas width="600" height="600"></canvas>
    <script>
      const canvas = document.querySelector('canvas')
      const ctx = canvas.getContext('2d')
      // 位移 移动的是坐标,也就是绘制起点
      ctx.translate(100,100)
      ctx.fillRect(0,0,100,100)
      // 从上一个坐标系开始位移
      ctx.translate(100,100)
      ctx.fillRect(0,0,100,100)
    </script>
  </body>
</html>

缩放
<html lang="en">
</html>
  <body>
    <canvas width="600" height="600"></canvas>
    <script>
      const canvas = document.querySelector('canvas')
      const ctx = canvas.getContext('2d')
      // 缩放 拉伸坐标系
      ctx.scale(2,2)
      ctx.fillRect(100,100,100,100)
    </script>
  </body>
</html>

旋转
<html lang="en">
  <body>
    <canvas width="600" height="600"></canvas>
    <script>
      const canvas = document.querySelector('canvas')
      const ctx = canvas.getContext('2d')
      // 旋转。旋转坐标系x,y
      ctx.arc(200,200,10,0,Math.PI*2)
      ctx.fill()
      ctx.rotate(Math.PI/6)
      ctx.fillRect(200,200,100,100)
    </script>
  </body>
</html>

使用transform
<html lang="en">
  <body>
    <canvas width="600" height="600"></canvas>
    <script>
      const canvas = document.querySelector('canvas')
      const ctx = canvas.getContext('2d')
      // 位移
      ctx.transform(1,0,0,1,100,100)
      ctx.fillRect(0,0,100,100)
    </script>
  </body>
</html>

一起使用
<html lang="en">
  <body>
    <canvas width="600" height="600"></canvas>
    <script>
      const canvas = document.querySelector('canvas')
      const ctx = canvas.getContext('2d')
      ctx.translate(300,300)
      ctx.rotate(Math.PI/4)
      ctx.scale(2,1)
      ctx.fillRect(-250,-25,500,50)
    </script>
  </body>
</html>

转换api整理
属性/方法名称使用说明属性类型备注
translate(x,y)位移,移动的起始点Function
scale(x,y)缩放 拉伸坐标系x,yFunction
rotate(Math.pi)旋转。旋转坐标系x,yFunction
transform()复合使用
15.合成图层
  • 更多参数参考地址:https://developer.mozilla.org/zh-CN/docs/Web/API/CanvasRenderingContext2D/globalCompositeOperation
合成图层的设置
<html lang="en">
  <body>
    <canvas width="600" height="600"></canvas>
    <script>
      const canvas = document.querySelector('canvas')
      const ctx = canvas.getContext('2d')
      ctx.fillStyle = 'red'
      ctx.fillRect(100,100,100,100)
      // 设置图层相交时的显示样式
      // 更多参数 https://developer.mozilla.org/zh-CN/docs/Web/API/CanvasRenderingContext2D/globalCompositeOperation
      ctx.globalCompositeOperation ="source-in"
      ctx.fillStyle = 'pink'
      ctx.fillRect(150,150,100,100)
    </script>
  </body>
</html>

刮刮卡案例实现
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <style>
      *{
        margin: 0;
        padding: 0;
      }
      div{
        width: 500px;
        height: 200px;
        text-align: center;
        line-height: 200px;
      }
      canvas{
        position: absolute;
        top: 0;
        left: 0;
        z-index: 10;
      }
    </style>
  </head>
  <body>
    <div>谢谢惠顾</div>
    <canvas width="500" height="200"></canvas>
    <script>
      const canvas = document.querySelector('canvas')
      const ctx = canvas.getContext('2d')
      // 设置图层相交时的显示样式
      // 更多参数 https://developer.mozilla.org/zh-CN/docs/Web/API/CanvasRenderingContext2D/globalCompositeOperation
      // ctx.globalCompositeOperation ="source-in"
      
      const img = new Image()
      img.src = '../img/5.jpg'
      img.onload = function(){
        ctx.drawImage(img,0,0,500,200)
      }
      // 是否可以刮
      let isgua = false
      // 监听canvas的鼠标事件
      canvas.onmousedown = function(){
        isgua=true
      }
      canvas.onmouseup = function(){
        isgua =false
      }
      canvas.onmousemove = function(e){
        if(!isgua)return
        ctx.globalCompositeOperation = 'destination-out'
        const x = e.pageX
        const y = e.pageY
        ctx.closePath()
        ctx.beginPath()
        ctx.arc(x,y,20,0,Math.PI*2)
        ctx.fill()
      }
    </script>
  </body>
</html>

合成图层api整理
属性/方法名称使用说明属性类型备注
globalCompositeOperation设置/返回合成图层的方式String
16.裁剪
  • 什么是裁剪?

在一个画布上有多个图层时,只是显示有裁剪路径的部分

案例

<html lang="en">
<body>
  <canvas width="600" height="600"></canvas>
  <script>
    const canvas = document.querySelector('canvas')
    const ctx = canvas.getContext('2d')
     // 用于存储绘制路径
    const path2d = new Path2D()
    path2d.moveTo(300,300)
    path2d.bezierCurveTo(400,200,600,400,300,600)
    path2d.moveTo(300,300)
    path2d.bezierCurveTo(200,200,0,400,300,600)
    ctx.strokeStyle = 'red'
    //  当canvas上有其它的图层时只绘制裁剪出来的部分内容
    // ctx.clip(裁剪路径  如果不传绘制路径的话默认会以开始路径和结束路径作为裁剪路径)
    ctx.clip(path2d)
    const img = new Image()
      img.src = '../img/1.png'
      img.onload = function(){
        ctx.drawImage(img,0,0,600,600)
        ctx.lineWidth = 10
        ctx.stroke(path2d)
      }
  </script>
</body>
</html>
裁剪api整理
属性/方法名称使用说明属性类型备注
clip(裁剪路径 如果不传绘制路径的话默认会以开始路径和结束路径作为裁剪路径)裁剪路径Function
17.状态的保存与恢复
  • 什么是状态缓存和恢复

状态保存 可以保存多个,就像一个数组,每次保存就往数组中添加一项,恢复时取出数组中最前面的一个

案例

<body>
  <canvas width="600" height="600"></canvas>
  <script>
    const canvas = document.querySelector('canvas')
    const ctx = canvas.getContext('2d')
    
    // 状态保存 可以保存多个,就像一个数组,每次保存就往数组中添加一项,恢复时取出数组中最前面的一个
    ctx.fillStyle='red'
    ctx.fillRect(0,0,100,100)
    // 保存当前的状态   会保存颜色,位移等等参数
    ctx.save()
    ctx.fillStyle = 'blue'
    ctx.fillRect(100,100,100,100)
    ctx.save()
    ctx.fillStyle = 'pink'
    ctx.fillRect(200,200,100,100)

    // 如果继续画那么默认会以pink为颜色
    // 那么现在恢复一个状态,取出数组中的最前面一项就是blue的颜色
    ctx.restore()
    ctx.fillRect(300,300,100,100)
    // 在恢复一下,取出红色
    ctx.restore()
    ctx.fillRect(400,400,100,100)
  </script>
</body>
属性/方法名称使用说明属性类型备注
save()保存状态Function
restore()恢复上一次保存的状态Function
18.像素的操作

对每个像素进行操作后在绘制回去

用案例说话

<html lang="en">
  <body>
    <canvas width="600" height="800"></canvas>
    <script>
      const canvas = document.querySelector('canvas')
      const ctx = canvas.getContext('2d')
      const img = new Image()
      img.src = '../img/1.png'
      img.onload = function(){
        ctx.drawImage(img,0,0,600,800)
        // 获取固定区域的所有像素信息
        const imageData = ctx.getImageData(0,0,300,300)
        console.log(imageData);
        // 对每个像素进行操作后在绘制回去、

        // 置灰操作
        // for(var i =0; i<imageData.data.length;i+=4){
        //   // 每个像素由rgba组成,所以数组中的每4个值为一组 ,所以在循环时i必须+=4
        //   const amv = (imageData.data[i]+imageData.data[i+1]+imageData.data[i+2])/3
        //   imageData.data[i] = amv
        //   imageData.data[i+1] = amv
        //   imageData.data[i+2] = amv
        //   imageData.data[i+3] = 255
        // }
        // 反向取色
        for(var i =0; i<imageData.data.length;i+=4){
          // 每个像素由rgba组成,所以数组中的每4个值为一组 ,所以在循环时i必须+=4
          // imageData.data[i] = 255-imageData.data[i]
          // imageData.data[i+1] = 255-imageData.data[i+1]
          // imageData.data[i+2] = 255-imageData.data[i+2]
          if(i%30==0){
            imageData.data[i+3] = 150
          }else{
            imageData.data[i+3] = 255
          }
          
        }
        // 把处理完的像素信息在绘制回去
        ctx.putImageData(imageData,0,0)
      }
    </script>
  </body>
</html>

像素操作api整理
属性/方法名称使用说明属性类型备注
getImageData(x,y,width,height)返回指定位置和高宽的像素信息Function
putImageData(橡树对象,x,y)绘制像素信息Function
isPointInPath(绘制路径对象,x,y)判断某个点是否在需要绘制的路径上
19.封装绘制物体
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    canvas{
      border: 1px solid red;
      margin: 100px;
    }
  </style>
</head>
<body>
  <canvas width="800" height="800"></canvas>
  <script>
    const canvas = document.querySelector('canvas')
    const ctx = canvas.getContext('2d')
     // 用于存储绘制路径
    // const path2d = new Path2D()
    // path2d.moveTo(300,300)
    // path2d.bezierCurveTo(400,200,600,400,300,600)
    // path2d.moveTo(300,300)
    // path2d.bezierCurveTo(200,200,0,400,300,600)
    // ctx.fillStyle = 'red'
    // ctx.fill(path2d)
    
    class Love {
      path2d = {}
      constructor(x,y){
        this.x = x
        this.y = y
        canvas.onmousemove = (e)=>{
          // 判断某个点是否在需要绘制的路径上
          const isIn = ctx.isPointInPath(this.path2d,e.offsetX,e.offsetY)
          console.log(isIn);
        }
      }
      setMoveTo(x,y){
        this.x = x
        this.y = y
        return this
      }
      deaw(){
        const path2d = new Path2D()
        path2d.moveTo(this.x,this.y)
        path2d.bezierCurveTo(this.x+100,this.y-100,this.x+300,this.y+100,this.x,this.y+300)
        path2d.moveTo(this.x,this.y)
        path2d.bezierCurveTo(this.x-100,this.y-100,this.x-300,this.y+100,this.x,this.y+300)
        ctx.fillStyle = 'red'
        ctx.save()
        ctx.fill(path2d)
        this.path2d = path2d
        ctx.restore()
      }
    }
    requestAnimationFrame(()=>{
      console.log(11);
    })
    const love = new Love(400,300)
    love.deaw()
  </script>
</body>
</html>
20.制作画笔,手绘签名
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    canvas{
      border: 1px solid red;
    }
    .option{
      width: 800px;
      margin-top: 10px;
      text-align: center;
    }
  </style>
</head>
<body>
  <canvas width="800" height="400"></canvas>
  <br />
  <div class="option">
    <button class="wide">粗线条</button>
    <button class="thin">细线条</button>
    <button class="preserve">保存签名</button>
    <input type="color" />
    <button class="xpc">橡皮差</button>
    <button class="clonsRect">清空画布</button>
  </div>
  <script>
    const canvas = document.querySelector('canvas')
    const {width,height} = canvas
    const ctx = canvas.getContext('2d')
    // 线段连接处样式
    ctx.lineJoin ="round"
    // 线段两端样式
    ctx.lineCap ="round"
    const wide= document.querySelector('.wide')
    const thin= document.querySelector('.thin')
    const color = document.querySelector('[type=color]')
    const xpc= document.querySelector('.xpc')
    const clonsRect= document.querySelector('.clonsRect')
    const preserve = document.querySelector('.preserve')
    wide.onclick = function(){
      ctx.globalCompositeOperation ="source-over"
      ctx.lineWidth = 10
    }
    thin.onclick = function(){
      ctx.globalCompositeOperation ="source-over"
      ctx.lineWidth = 1
    }
    clonsRect.onclick = function(){
      ctx.clearRect(0,0,width,height)
    }
    // 橡皮擦
    xpc.onclick = function(){
      // 原理:在选中橡皮擦时,把合成图层改为的相交的变透明
      ctx.globalCompositeOperation ="destination-out"
      ctx.lineWidth = 20
    }
    color.onchange = function(e){
      ctx.strokeStyle = e.target.value
      console.log(e);
    }
    preserve.onclick = function(){
      // 得到一个base64
      const imgUrl = canvas.toDataURL()
      // const img = new Image()
      // img.src = imgUrl
      // document.body.append(img)
      const a = document.createElement('a')
      a.download = '签名'
      a.href = imgUrl
      a.click()
    }
    // 判断是否开始画,当鼠标按下并移动时
    let isin = false

    // 当鼠标按下时移动画笔到指定位置,并开发可以绘制变量
    canvas.onmousedown = function(e){
      isin=true
      ctx.beginPath()
      var x = e.offsetX
      var y = e.offsetY
      ctx.moveTo(x,y)
    }
    // 当鼠标放开时。停止绘制,
    canvas.onmouseup = function(e){
      isin = false
    }
    // 当鼠标移出canvas区域时也停止绘制
    canvas.onmouseleave = function (e){
      isin = false
    } 
    // 当鼠标在canvas上移动时,并且鼠标处于按下状态并开始绘制
    canvas.onmousemove = function(e){
      if(!isin)return
      var x = e.offsetX
      var y = e.offsetY
      ctx.lineTo(x,y)
      ctx.stroke()
    }
  </script>
</body>
</html>
21.制作时钟
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <canvas width="800" height="600"></canvas>
    <script>
      const canvas = document.querySelector('canvas')
      const ctx = canvas.getContext('2d')
      function render() {
        ctx.clearRect(0,0,800,600)
        ctx.save()
        // 移动坐标点
        ctx.translate(400, 300)
        // 旋转坐标系
        ctx.rotate(-Math.PI / 2)
        // 缓存上面位移及旋转操作
        ctx.save()
        // 绘制小时刻度
        for (var i = 0; i < 12; i++) {
          ctx.beginPath()
          ctx.moveTo(170, 0)e
          ctx.lineTo(190, 0)
          ctx.lineWidth = 6
          ctx.strokeStyle = 'gray'
          ctx.stroke()
          ctx.closePath()
          // 每一次旋转都是基于上一次的位置尔旋转
          ctx.rotate((2 * Math.PI) / 12)
        }
        // 小时刻度绘制完成后恢复之前的操作,不在保留,以就是说不在保留之前绘制小时刻度的rotate旋转
        ctx.restore()

        // 同理可得绘制分钟刻度的方法

        ctx.save()
        for (var i = 0; i < 60; i++) {
          ctx.beginPath()
          ctx.moveTo(180, 0)
          ctx.lineTo(190, 0)
          ctx.lineWidth = 2
          ctx.strokeStyle = 'gray'
          ctx.stroke()
          ctx.closePath()
          // 每一次旋转都是基于上一次的位置尔旋转
          ctx.rotate((2 * Math.PI) / 60)
        }
        ctx.restore()

        // 获取时间
        const date = new Date()
        let h = date.getHours()
        const m = date.getMinutes()
        const s = date.getSeconds()
        // 小时是24小时的,表盘只有12小时,需要处理一下
        h = h >= 12 ? h - 12 : h

        ctx.save()
        // 先绘制秒帧
        // 先按现在的秒数进行旋转
        ctx.rotate(((2 * Math.PI) / 60) * s)
        ctx.beginPath()
        ctx.moveTo(-30, 0)
        ctx.lineTo(190, 0)
        ctx.lineWidth = 2
        ctx.strokeStyle = 'red'
        ctx.stroke()
        ctx.closePath()
        ctx.restore()
        // 同上道理 绘制分针和时针
        // 先按现在的秒数进行旋转
        ctx.save()
        ctx.rotate(((2 * Math.PI) / 60) * m + ((2 * Math.PI) / 60 / 60) * s)
        ctx.beginPath()
        ctx.moveTo(-20, 0)
        ctx.lineTo(150, 0)
        ctx.lineWidth = 4
        ctx.strokeStyle = 'blue'
        ctx.stroke()
        ctx.closePath()
        ctx.restore()

        // 绘制时针
        ctx.save()
        ctx.rotate(((2 * Math.PI) / 12) * h + ((2 * Math.PI) / 12 / 60) * m)
        ctx.beginPath()
        ctx.moveTo(-10, 0)
        ctx.lineTo(130, 0)
        ctx.lineWidth = 6
        ctx.strokeStyle = '#000'
        ctx.stroke()
        ctx.closePath()
        ctx.restore()
        // 一定要多恢复一次,把所有的缓存都清除调
        ctx.restore()
        requestAnimationFrame(render)
      }
      render()
    </script>
  </body>
</html>

  • 22
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Canvas红包雨是一种基于HTML5 Canvas技术开发的节日效果,通过JavaScript控制红包的下落和动画效果,实现一个红包雨的动态效果。 下面是Canvas红包雨的开发流程: 1. HTML页面中添加Canvas画布,并设置画布的宽高和样式。 ```html <canvas id="canvas"></canvas> ``` ```css #canvas { width: 100%; height: 100%; position: absolute; top: 0; left: 0; z-index: 999; } ``` 2. 在JavaScript中获取Canvas画布对象,并设置画布的宽高。 ```javascript var canvas = document.getElementById('canvas'); var ctx = canvas.getContext('2d'); canvas.width = window.innerWidth; canvas.height = window.innerHeight; ``` 3. 定义红包对象,包括红包的位置、速度、大小和颜色等属性。 ```javascript function RedPacket(x, y, vx, vy, size, color) { this.x = x; this.y = y; this.vx = vx; this.vy = vy; this.size = size; this.color = color; } ``` 4. 在Canvas画布上绘制红包,并实现红包的下落和动画效果。 ```javascript var redPackets = []; // 存储红包对象的数组 function drawRedPacket(redPacket) { ctx.beginPath(); ctx.arc(redPacket.x, redPacket.y, redPacket.size, 0, 2 * Math.PI); ctx.fillStyle = redPacket.color; ctx.fill(); } function updateRedPacket(redPacket) { redPacket.x += redPacket.vx; redPacket.y += redPacket.vy; redPacket.vy += gravity; } function animate() { ctx.clearRect(0, 0, canvas.width, canvas.height); for (var i = 0; i < redPackets.length; i++) { drawRedPacket(redPackets[i]); updateRedPacket(redPackets[i]); } requestAnimationFrame(animate); } requestAnimationFrame(animate); ``` 5. 实现红包的自动生成和动态效果,可以通过setInterval或setTimeout定时调用生成红包的函数。 ```javascript function createRedPacket() { var x = Math.random() * canvas.width; var y = -20; var vx = Math.random() * 6 - 3; var vy = Math.random() * 2 + 2; var size = Math.random() * 10 + 10; var color = '#' + Math.floor(Math.random() * 16777215).toString(16); // 随机生成颜色 var redPacket = new RedPacket(x, y, vx, vy, size, color); redPackets.push(redPacket); } setInterval(createRedPacket, 500); // 每500ms生成一个红包 ``` 6. 实现红包的点击事件,当用户点击红包时,可以实现红包爆炸效果,并显示红包金额或祝福语。 ```javascript function explodeRedPacket(redPacket) { var particles = []; // 存储爆炸粒子的数组 for (var i = 0; i < 20; i++) { var particle = { x: redPacket.x, y: redPacket.y, vx: Math.random() * 6 - 3, vy: Math.random() * 6 - 3, size: Math.random() * 3 + 1, color: redPacket.color }; particles.push(particle); } for (var i = 0; i < particles.length; i++) { drawRedPacket(particles[i]); } } canvas.addEventListener('click', function(event) { var x = event.clientX; var y = event.clientY; for (var i = 0; i < redPackets.length; i++) { var redPacket = redPackets[i]; if (x > redPacket.x - redPacket.size && x < redPacket.x + redPacket.size && y > redPacket.y - redPacket.size && y < redPacket.y + redPacket.size) { explodeRedPacket(redPacket); redPackets.splice(i, 1); break; } } }); ``` 上述就是Canvas红包雨的开发流程,通过Canvas技术和JavaScript实现红包的下落、动画、自动生成和点击事件等效果,可以增加网站的趣味性和用户互动性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值