canvas基础

MDN:Canvas - Web API 接口参考 | MDN

目录

MDN:Canvas - Web API 接口参考 | MDN

1. 初始canvas

2. 绘制图形也可以分开写

3.绘制圆形(笑脸)

4.绘制直线(三角形)

5. 绘制圆弧

6. 贝塞曲线(二次贝塞曲线)

7. 贝塞曲线(三次贝塞曲线)

8. 封装路径Path2d

9. 颜色设置

10. 渐变(线型渐变-径向渐变)

11. 图案样式:pattern

12.绘制图片 

13.绘制视频

 14.文本绘制

15.位移、缩放、旋转

16.合成与裁剪

17.状态的保存和恢复

 18.像素

19. 高级封装和元素交互

 20.在线画板

 20.动态时钟


1. 初始canvas

<body>
  <!-- 
      id:标识元素的唯一性
      width:画布的宽度
      height:画布的高度
   -->
   <canvas id="c1" width="800" height="600"></canvas>
   <script >
    // 1. 找到画布
    let c1 = document.getElementById('c1')
    // 2. 获取画笔,上下文对象
    let ctx = c1.getContext('2d')
    // 3. 绘制图形
        // 设置颜色
    ctx.fillStyle = 'skyblue'
        // 3.1 绘制矩形fillRect(位置X,位置Y,宽度,高度)-填充模式
    ctx.fillRect(10,20,300,200)
        // 3.2 绘制矩形strokeRect(位置X,位置Y,宽度,高度)-路径模式
    ctx.strokeRect(360,200,300,200)
        //3.3 清除模式
          //3.3.1 立即清除
          // ctx.clearRect(0, 0, c1.clientWidth, c1.clientHeight)
         // 3.3.2 计时器清除
         let height = 0;
         let timer = setInterval(() => {
           height++;
           if (height > c1.clientHeight) {
             clearInterval(timer)
             return
           }
           ctx.clearRect(0, 0, c1.clientWidth, height)
         }, 10)
   </script>
</body>

2. 绘制图形也可以分开写

    // 1. 找到画布
    let c1 = document.getElementById('c1')
    // 2. 获取画笔,上下文对象
    let ctx = c1.getContext('2d')
    // 3. 绘制图形
    // 绘制图形也可以分开写(但是需要写开始和结束的路径,不然他会以为画笔是一次性的,会全部都是后面写的那种模式)
    ctx.beginPath()
    ctx.rect(10, 260, 300, 200)
    ctx.fill()
    ctx.closePath()
    
    ctx.beginPath()
    ctx.rect(360, 10, 300, 200)
    ctx.stroke()
    ctx.closePath()

3.绘制圆形(笑脸)

<body>
  <!-- 
      id:标识元素的唯一性
      width:画布的宽度
      height:画布的高度
   -->
  <canvas id="c1" width="800" height="600"></canvas>
  <script>
    // 1. 找到画布
    let c1 = document.getElementById('c1')
    // 2. 获取画笔,上下文对象
    let ctx = c1.getContext('2d')
    // 3. 绘制图形
    //3.1 绘制圆弧arc(圆心x,圆心y,半径,开始的角度,结束的角度,逆时针还是顺时针:默认顺时针false)
    // ctx.beginPath()
    // ctx.arc(200, 100, 50,0,Math.PI*2)
    // // 3.2 填充
    // ctx.stroke()
    // ctx.closePath()
    // ctx.beginPath()
    // ctx.arc(180,85,8,0,Math.PI*2)
    // ctx.stroke()
    // ctx.closePath()
    // ctx.beginPath()
    // ctx.arc(220,85,8,0,Math.PI*2)
    // ctx.stroke()
    // ctx.closePath()
    // ctx.beginPath()
    // ctx.arc(200,100,30,0,Math.PI)
    // ctx.stroke()
    // ctx.closePath()

    // 使用moveTo-移动(绘制一条不连续的路径)
    ctx.beginPath()
    ctx.arc(200, 100, 50, 0, Math.PI * 2)
    // 3.2 填充
    ctx.stroke()
    ctx.moveTo(230, 100)
    // 嘴巴
    ctx.arc(200, 100, 30, 0, Math.PI)
    ctx.stroke()
    ctx.moveTo(188, 85)
    // 左眼
    ctx.arc(180, 85, 8, 0, Math.PI * 2)
    ctx.stroke()
    ctx.moveTo(228, 85)
    // 右眼
    ctx.arc(220, 85, 8, 0, Math.PI * 2)
    ctx.stroke()
    ctx.closePath()
  </script>
</body>

4.绘制直线(三角形)

<body>
  <canvas id="c1" width="800" height="600"></canvas>
  <script>
    // 1. 找到画布
    let c1 = document.getElementById('c1')
    // 2. 获取画笔,上下文对象
    let ctx = c1.getContext('2d')
    ctx.fillStyle = 'skyblue'
    // 3. 绘制路径
    // 3.1 绘制三角形--路径
    ctx.beginPath()
    ctx.moveTo(300, 200)
    ctx.lineTo(350, 250)
    ctx.lineTo(350, 200)
    ctx.lineTo(300, 200)
    ctx.stroke()
    ctx.closePath()

    //3.2 绘制三角形--填充
    ctx.beginPath()
    ctx.moveTo(100, 100)
    ctx.lineTo(150, 150)
    ctx.lineTo(150, 100)
    ctx.fill()
    ctx.closePath()

  </script>
</body>

5. 绘制圆弧

<body>
  <canvas id="c1" width="800" height="600"></canvas>
  <script>
    // 1. 找到画布
    let c1 = document.getElementById('c1')
    // 2. 获取画笔,上下文对象
    let ctx = c1.getContext('2d')
    ctx.fillStyle = 'skyblue'
    // 3. 绘制圆弧
    // arcTo()
    // 3.1 绘制三角形--路径
    ctx.beginPath()
    // 绘制第一个点
    ctx.moveTo(300, 200)
    // 绘制第二个点和第三个点,以及圆弧半径
    ctx.arcTo(300, 250, 250, 250, 50)
    ctx.stroke()
    ctx.closePath()
  </script>
</body>

6. 贝塞曲线(二次贝塞曲线)

<body>
  <canvas id="c1" width="800" height="600"></canvas>
  <script>
    // 1. 找到画布
    let c1 = document.getElementById('c1')
    // 2. 获取画笔,上下文对象
    let ctx = c1.getContext('2d')
    ctx.fillStyle = 'skyblue'
    // 3. 绘制圆弧
    // 3.2 贝塞曲线--(二次贝塞曲线--气泡聊天框)
    ctx.beginPath()
    // 绘制第一个点
    ctx.moveTo(200, 300)
    // 绘制第二个点和第三个点,以及圆弧半径
    ctx.quadraticCurveTo(150, 300, 150, 200)
    ctx.quadraticCurveTo(150, 100, 300, 100)
    ctx.quadraticCurveTo(450, 100, 450, 200)
    ctx.quadraticCurveTo(450, 300, 250, 300)
    ctx.quadraticCurveTo(250, 350, 150, 350)
    ctx.quadraticCurveTo(200, 350, 200, 300)
    ctx.stroke()
    ctx.closePath()
  </script>
</body>

7. 贝塞曲线(三次贝塞曲线)

<body>
  <canvas id="c1" width="800" height="600"></canvas>
  <script>
    // 1. 找到画布
    let c1 = document.getElementById('c1')
    // 2. 获取画笔,上下文对象
    let ctx = c1.getContext('2d')
    // 3. 贝塞曲线(三次杯赛曲线)
    ctx.fillStyle='red'
    ctx.beginPath()
    ctx.moveTo(300,200)
    ctx.bezierCurveTo(350,150,400,200,300,300)
    ctx.bezierCurveTo(200,200,250,150,300,200)
    ctx.fill()
    ctx.closePath()
  </script>
</body>

8. 封装路径Path2d

<body>
  <canvas id="c1" width="800" height="600"></canvas>
  <script>
    // 1. 找到画布
    let c1 = document.getElementById('c1')
    // 2. 获取画笔,上下文对象
    let ctx = c1.getContext('2d')
    // 3. 封装路径Path2d
    ctx.fillStyle='red'
    let heartPath= new Path2D()
    heartPath.moveTo(300,200)
    heartPath.bezierCurveTo(350,150,400,200,300,300)
    heartPath.bezierCurveTo(200,200,250,150,300,200)
    ctx.fill(heartPath)
    // 绘制一条折线
    let polyPath=new Path2D('M10 10 h 80 v 80 h -80 z')
    ctx.stroke(polyPath)
  </script>
</body>

9. 颜色设置

// 路径颜色
ctx.strokeStyle='skyblue'
ctx.strokeStyle='rgb(135,206,235)'
ctx.strokeStyle='rbga(135,206,235,0.8)'
ctx.strokeStyle='#87CEEB'

// 颜色填充
ctx.fillStyle='red'

// 全局透明度
ctx.globalAlpha = 0.5

10. 渐变(线型渐变-径向渐变)

<body>
  <canvas id="c1" width="800" height="600"></canvas>
  <script>
    // 1. 找到画布
    let c1 = document.getElementById('c1')
    // 2. 获取画笔,上下文对象
    let ctx = c1.getContext('2d')
    // 3. 线性渐变
    let linearGradient = ctx.createLinearGradient(200, 200, 400, 400)
    linearGradient.addColorStop(0,'red')
    linearGradient.addColorStop(0.5,'pink')
    linearGradient.addColorStop(1,'blue')
    ctx.fillStyle= linearGradient
    ctx.fillRect(200, 200, 200, 200)
  </script>
</body>
<body>
  <canvas id="c1" width="800" height="600"></canvas>
  <script>
    // 1. 找到画布
    let c1 = document.getElementById('c1')
    // 2. 获取画笔,上下文对象
    let ctx = c1.getContext('2d')
    // 3. 线性渐变
    let index = 0
    function render() {
      ctx.clearRect(200, 200, 400, 400)
      index += 0.01
      if (index > 1) {
        index = 0
      }
      let linearGradient = ctx.createLinearGradient(200, 200, 400, 400)
      linearGradient.addColorStop(0, 'red')
      linearGradient.addColorStop(index, 'pink')
      linearGradient.addColorStop(1, 'blue')
      ctx.fillStyle = linearGradient
      ctx.fillRect(200, 200, 200, 200)
      requestAnimationFrame(render)
    }
    // 动画效果
    requestAnimationFrame(render)
  </script>
</body>

<body>
  <canvas id="c1" width="800" height="600"></canvas>
  <script>
    // 1. 找到画布
    let c1 = document.getElementById('c1')
    // 2. 获取画笔,上下文对象
    let ctx = c1.getContext('2d')
    // 3. 径向渐变
      let radiaGradient = ctx.createRadialGradient(300, 200, 0, 300, 200, 100)
      radiaGradient.addColorStop(0, 'red')
      radiaGradient.addColorStop(0.5, 'pink')
      radiaGradient.addColorStop(1, 'blue')
      ctx.fillStyle = radiaGradient
      ctx.fillRect(0, 0, 600, 400)
  </script>
</body>
<body>
  <canvas id="c1" width="800" height="600"></canvas>
  <script>
    // 1. 找到画布
    let c1 = document.getElementById('c1')
    // 2. 获取画笔,上下文对象
    let ctx = c1.getContext('2d')
    // 3. 径向渐变
    let index = 0
    function render() {
      ctx.clearRect(200, 200, 400, 400)
      index += 0.01
      if (index > 1) {
        index = 0
      }
      let radiaGradient = ctx.createRadialGradient(300, 200, 0, 300, 200, 100)
      radiaGradient.addColorStop(0, 'red')
      radiaGradient.addColorStop(index, 'pink')
      radiaGradient.addColorStop(1, 'blue')
      ctx.fillStyle = radiaGradient
      ctx.fillRect(0, 0, 600, 400)
      requestAnimationFrame(render)
    }
    requestAnimationFrame(render)
  </script>
</body>

<body>
  <canvas id="c1" width="800" height="600"></canvas>
  <script>
    // 1. 找到画布
    let c1 = document.getElementById('c1')
    // 2. 获取画笔,上下文对象
    let ctx = c1.getContext('2d')
    // 3. 径向渐变
    let radiaGradient = ctx.createRadialGradient(250, 150, 10, 300, 200, 100)
    radiaGradient.addColorStop(1, 'red')
    radiaGradient.addColorStop(0, 'pink')
    ctx.fillStyle = radiaGradient
    ctx.arc(300, 200, 100, 0, Math.PI * 2)
    ctx.fill()
  </script>
</body>

11. 图案样式:pattern

<body>
  <canvas id="c1" width="800" height="600"></canvas>
  <script>
    // 1. 找到画布
    let c1 = document.getElementById('c1')
    // 2. 获取画笔,上下文对象
    let ctx = c1.getContext('2d')
    // 3. pattern
    var img = new Image();
    img.src = 'https://img0.baidu.com/it/u=1685203771,1473174621&fm=253&fmt=auto&app=138&f=JPEG?w=224&h=219';
    img.onload = function () {

      // createPattern(图片,重复方式:重复:repeat;不重复:no-repeat;水平重复:repeat-x,垂直重复:repeat-y)
      var pattern = ctx.createPattern(img, 'repeat');
      ctx.fillStyle = pattern;
      ctx.fillRect(0, 0, 500, 500);
    }
  </script>
</body>

12.绘制图片 

<body>
  <canvas id="c1" width="800" height="600"></canvas>
  <script>
    // 1. 找到画布
    let c1 = document.getElementById('c1')
    // 2. 获取画笔,上下文对象
    let ctx = c1.getContext('2d')
    // 3. 绘制图片
    var img = new Image();
    img.src = 'https://img0.baidu.com/it/u=1685203771,1473174621&fm=253&fmt=auto&app=138&f=JPEG?w=224&h=219';
    img.onload = function () {
      // 第一种:drawImage(图片,将图片渲染到画布的x位置,将图片渲染到画布的y位置)
      // ctx.drawImage(img,0,0)
      // 第二种:drawImage(图片,将图片渲染到画布的x位置,将图片渲染到画布的y位置,图片的宽,图片的高)
      // ctx.drawImage(img,0,0,800,600)
      // 第三种:drawImage(图片,裁剪的起点x,裁剪的起点y,裁剪的宽,裁剪的高,将图片渲染到画布的x位置,将图片渲染到画布的y位置,图片的宽,图片的高)
      ctx.drawImage(img,155,0,50,50,0,0,100,100)
    }
  </script>
</body>

13.绘制视频

<body>
  <canvas id="c1" width="800" height="600"></canvas>
  <video src="视频地址"  style="width: 400px;height:400px"></video>
  <button id="btn">播放/暂停</button>
  <script>
    // 1. 找到画布
    let c1 = document.getElementById('c1')
    // 2. 获取画笔,上下文对象
    let ctx = c1.getContext('2d')
    // 3. 绘制视频
    // 获取绘制视频对象
    let video = document.querySelector('video')
    // 获取按钮
    let btn = document.getElementById('btn')
    btn.onclick = function () {
      if (video.paused) {
        video.play()
        render()
      } else {
        video.pause()
      }
    }
    // 添加水印
    let image = new Image()
    image.src = 'https://img0.baidu.com/it/u=1685203771,1473174621&fm=253&fmt=auto&app=138&f=JPEG?w=224&h=219'
    // 播放
    function render() {
      ctx.drawImage(video, 0, 0, 600, 400)
      ctx.drawImage(image, 480, 350, 100, 20)
      requestAnimationFrame(render)
    }
  </script>
</body>

 14.文本绘制

<body>
  <canvas id="c1" width="600" height="400"></canvas>
  <script>
    // 1. 找到画布
    let c1 = document.getElementById('c1')
    // 2. 获取画笔,上下文对象
    let ctx = c1.getContext('2d')
    // 3.  文字  大小/字体
    ctx.font = '100px Microsoft YaHei'
    ctx.strokeStyle = 'pink'
    // ctx.fillStyle = 'skyblue'
    // 文本对齐(start(默认),end,left,right,center)
    ctx.textAlign = 'center'
    // 文本基线对齐(middle,top,bottom,alphabetic)
    ctx.textBaseline = 'middle'
    // 文本方向(ltr, rtl, inherit)
    // ctx.direction = 'rtl'
    // 预测量文本的宽度
    let text = ctx.measureText('Wlop!')
    console.log(text);
    // 填充渲染文字--ctx.fillText('渲染的文字',位置x,位置y,绘制文本的最大宽度)
    // ctx.fillText('Wlop', 300, 200)
    ctx.strokeText('Wlop!', 300, 200)
    ctx.arc(300, 200, 5, 0, Math.PI * 2)
    ctx.fill()

  </script>
</body>

15.位移、缩放、旋转

<body>
  <canvas id="c1" width="600" height="400"></canvas>
  <script>
    // 1. 找到画布
    let c1 = document.getElementById('c1')
    // 2. 获取画笔,上下文对象
    let ctx = c1.getContext('2d')
    // 位移(*x *是左右偏移量,y 是上下偏移量)
    ctx.translate(100, 100)
    ctx.fillRect(0, 0, 50, 50)
    ctx.translate(100, 100)
    ctx.fillRect(0, 0, 50, 50)


    // 矩阵控制变换(a,b,c,d,e,f)(水平方向的缩放,竖直方向的倾斜偏移,水平方向的倾斜偏移,竖直方向的缩放,水平方向的移动.竖直方向的移动)
    // 初始值:ctx.transform(1, 0, 0, 1, 0, 0);
    // ctx.transform(1, 0, 0, 1, 0, 0)
    // ctx.fillRect(0, 0, 50, 50)
    //  ctx.transform(1, 0, 0, 1, 100, 100)
    // ctx.fillRect(0, 0, 50, 50)

  </script>
</body>
<body>
  <canvas id="c1" width="600" height="400"></canvas>
  <script>
    // 1. 找到画布
    let c1 = document.getElementById('c1')
    // 2. 获取画笔,上下文对象
    let ctx = c1.getContext('2d')
    // 缩放(*x *是水平放大,y 是垂直放大)
    // ctx.scale(5, 2)
    // ctx.fillRect(0, 0, 50, 50)
    // 旋转(角度)
    // ctx.rotate(Math.PI / 6)
    // ctx.fillRect(0, 100, 200, 50)


    // 先移动,在旋转
    ctx.translate(300, 200)
    ctx.rotate(Math.PI / 4)
    ctx.scale(5, 2)
    ctx.fillRect(-100, -25, 200, 50)

    // 矩阵控制变换(a,b,c,d,e,f)(水平方向的缩放,竖直方向的倾斜偏移,水平方向的倾斜偏移,竖直方向的缩放,水平方向的移动.竖直方向的移动)
    // 初始值:ctx.transform(1, 0, 0, 1, 0, 0);
    // ctx.transform(1, 1, -1, 1, 0, 0)
    // ctx.fillRect(0, 0, 200, 50)

  </script>
</body>

16.合成与裁剪

<body>
  <div id="ggk">谢谢惠顾</div>
  <canvas id="c1" width="600" height="400"></canvas>
  <script>
    // 1. 找到画布
    let c1 = document.getElementById('c1')
    let ctx = c1.getContext('2d')
    let img = new Image()
    img.src = 'https://img0.baidu.com/it/u=3313956622,100749147&fm=253&fmt=auto&app=138&f=JPEG?w=480&h=240'
    img.onload = function () {
      ctx.drawImage(img, 0, 0, 600, 400)
    }
    let isDraw = false
    c1.onmousedown = function () {
      isDraw = true
    }
    c1.onmouseup = function () {
      isDraw = false
    }
    c1.onmousemove = function (e) {
      if (isDraw) {
        var x = e.pageX
        var y = e.pageY
        ctx.globalCompositeOperation = 'destination-out'
        ctx.arc(x, y, 20, 0, 2 * Math.PI)
        ctx.fill()
      }
    }
    let ran = Math.random()
    if (ran < 0.1) {
      var ggkDiv = document.getElementById('ggk')
      ggkDiv.innerHTML = '恭喜您获得内马尔合影机会一次!!'
    }
  </script>
</body>
  <style>
    * {
      padding: 0;
      margin: 0;
    }

    #ggk {
      width: 600px;
      height: 400px;
      font-size: 30px;
      font-weight: 400;
      text-align: center;
      line-height: 400px;
      overflow: hidden;
      position: absolute;
      left: 0;
      top: 0;
      color: #f00;
    }

    canvas {
      position: absolute;
      left: 0;
      top: 0;
      z-index: 10;
    }
  </style>

 

<body>
  <canvas id="c1" width="800" height="600"></canvas>
  <script>
    // 1. 找到画布
    let c1 = document.getElementById('c1')
    // 2. 获取画笔,上下文对象
    let ctx = c1.getContext('2d')
    // 3. 绘制圆弧
    let heartPath = new Path2D()
    // 绘制第一个点
    heartPath.moveTo(200, 300)
    // 绘制第二个点和第三个点,以及圆弧半径
    heartPath.quadraticCurveTo(150, 300, 150, 200)
    heartPath.quadraticCurveTo(150, 100, 300, 100)
    heartPath.quadraticCurveTo(450, 100, 450, 200)
    heartPath.quadraticCurveTo(450, 300, 250, 300)
    heartPath.quadraticCurveTo(250, 350, 150, 350)
    heartPath.quadraticCurveTo(200, 350, 200, 300)
    // 裁剪
    ctx.clip(heartPath)
    ctx.stroke(heartPath)
    let img = new Image()
    img.src = 'https://img0.baidu.com/it/u=3313956622,100749147&fm=253&fmt=auto&app=138&f=JPEG?w=480&h=240'
    img.onload = function () {
      ctx.drawImage(img, 0, 0, 600, 400)
    }
  </script>
</body>

17.状态的保存和恢复

<body>
  <canvas id="c1" width="800" height="800"></canvas>
  <script>
    let c1 = document.getElementById('c1')
    let ctx = c1.getContext('2d')
    ctx.fillStyle = 'red'
    ctx.fillRect(0, 0, 100, 100)
    ctx.save()

    ctx.fillStyle = 'Orange'
    ctx.fillRect(100, 100, 100, 100)
    ctx.save()

    ctx.fillStyle = 'green'
    ctx.fillRect(200, 200, 100, 100)
    ctx.save()
    ctx.fillStyle = 'Purple'
    ctx.fillRect(300, 300, 100, 100)


    ctx.restore()
    ctx.fillRect(400, 400, 100, 100)
    ctx.restore()
    ctx.fillRect(500, 500, 100, 100)
    ctx.restore()
    ctx.fillRect(600, 600, 100, 100)
  </script>
</body>

 18.像素

<body>
  <canvas id="c1" width="800" height="600"></canvas>
  <script>
    // 1. 找到画布
    let c1 = document.getElementById('c1')
    // 2. 获取画笔,上下文对象
    let ctx = c1.getContext('2d')
    // 3. 绘制图片
    var img = new Image();
    //解决报错--:DOMException: Failed to execute 'getImageData' on 'CanvasRenderingContext2D': The canvas has been tainted by cross-origin data.
    img.crossOrigin = ''
    img.src = 'https://img2.baidu.com/it/u=1694308595,2732789570&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=500';
    img.onload = function () {
      // 第一种:drawImage(图片,将图片渲染到画布的x位置,将图片渲染到画布的y位置)
      // ctx.drawImage(img,0,0)
      // 第二种:drawImage(图片,将图片渲染到画布的x位置,将图片渲染到画布的y位置,图片的宽,图片的高)
      // ctx.drawImage(img,0,0,800,600)
      // 第三种:drawImage(图片,裁剪的起点x,裁剪的起点y,裁剪的宽,裁剪的高,将图片渲染到画布的x位置,将图片渲染到画布的y位置,图片的宽,图片的高)
      ctx.drawImage(img, 0, 0, 600, 400)
      //获取像素数据
      let imageData = ctx.getImageData(0, 0, 600, 400)
      console.log(imageData);
      // 修改数据
      for (let i = 0; i < imageData.data.length; i += 4) {
        // 计算当前像素的平均值
        let avg = (imageData.data[i] + imageData.data[i + 1] + imageData.data[i + 2]) / 3
        imageData.data[i] = avg
        imageData.data[i + 1] = avg
        imageData.data[i + 2] = avg
        imageData.data[i + 3] = 255
      }
      // 将修改的数据重新渲染到画布上
      // ctx.putImageData(imageData, 0, 0)  // 全部成灰色
      ctx.putImageData(imageData, 0, 0,0,0,300,200)  // 局部灰色
    }
  </script>
</body>

19. 高级封装和元素交互

标鼠标滑上变成粉色,鼠标离开恢复红色
<body>
  <canvas id="c1" width="800" height="600"></canvas>
  <script>
    // 1. 找到画布
    let c1 = document.getElementById('c1')
    // 2. 获取画笔,上下文对象
    let ctx = c1.getContext('2d')
    // 3. 高级封装
    // class Heat {
    //   constructor(x, y) {
    //     this.x = x;
    //     this.y = y;
    //     this.heartPath = new Path2D();
    //     this.heartPath.moveTo(this.x, this.y);
    //     this.heartPath.bezierCurveTo(this.x + 50, this.y - 50, this.x + 100, this.y, this.x, this.y + 100);
    //     this.heartPath.bezierCurveTo(this.x - 100, this.y, this.x - 50, this.y - 50, this.x, this.y)
    //   }
    //   draw() {
    //     ctx.save()
    //     ctx.fillStyle = 'red'
    //     ctx.fill(this.heartPath)
    //     ctx.restore()
    //   }
    // }
    // let heart = new Heat(100, 100)
    // heart.draw()


    // 4. 交互
    class Heat2 {
      constructor(x, y) {
        this.x = x;
        this.y = y;
        this.color = 'red';
        this.isIn = false;
        this.eventMapList = {
          hover: [],
          leave: []
        }
        c1.onmousemove = (e) => {
          let x = e.offsetX;
          let y = e.offsetY;
          this.isIn = ctx.isPointInPath(this.heartPath, x, y)
          if (this.isIn) {
            // this.color = 'skyblue'
            this.eventMapList.hover.forEach(item => {
              item()
            })
          } else {
            // this.color = 'red'
            this.eventMapList.leave.forEach(item => {
              item()
            })
          }
        }
      }
      // 鼠标划上事件
      onHover(fn) {
        this.eventMapList.hover.push(fn)
      }
      // 鼠标离开事件
      onLeave(fn) {
        this.eventMapList.leave.push(fn)
      }
      // 改变位置
      setPosition(x, y) {
        this.x = x;
        this.y = y
      }
      draw() {
        this.heartPath = new Path2D();
        this.heartPath.moveTo(this.x, this.y);
        this.heartPath.bezierCurveTo(this.x + 50, this.y - 50, this.x + 100, this.y, this.x, this.y + 100);
        this.heartPath.bezierCurveTo(this.x - 100, this.y, this.x - 50, this.y - 50, this.x, this.y)
        ctx.save()
        ctx.fillStyle = this.color
        ctx.fill(this.heartPath)
        ctx.restore()
      }
    }
    let heart2 = new Heat2(100, 100)
    heart2.onHover(() => {
      heart2.color = 'pink'
    })
    heart2.onLeave(() => {
      heart2.color = 'red'
    })
    function render() {
      ctx.clearRect(0, 0, c1.width, c1.height)
      heart2.draw()
      requestAnimationFrame(render)
    }
    render()
  </script>
</body>

 20.在线画板

<style>
    button.active {
      color: #fff;
      background-color: orange;
    }
  </style>
<body>
  <canvas id="c1" width="800" height="600"></canvas>
  <hr>
  <button id="boldBtn" type="button">粗线条</button>
  <button id="thinBtn" type="button">细线条</button>
  <button id="saveBtn" type="button">保存签名</button>
  <input type="color" name="" id="color" value="" />
  <button id="clearBtn">橡皮擦</button>
  <button id="nullBtn">清空画布</button>

  <script>
    // 获取画布
    let canvas = document.getElementById('c1')
    let ctx = canvas.getContext('2d')
    // 连接处圆润
    ctx.lineJoin = 'round'
    // 开端和结束端也是圆的
    ctx.lineCap = 'round'
    // 获取画笔(输入框和按钮)
    let boldBtn = document.getElementById('boldBtn')
    let thinBtn = document.getElementById('thinBtn')
    // 保存签名
    let saveBtn = document.getElementById('saveBtn')
    // 颜色
    let inputColor = document.getElementById('color')
    // 橡皮擦
    let clearBtn = document.getElementById('clearBtn')
    // 清空画布
    let nullBtn = document.getElementById('nullBtn')
    // 设置允许绘制的变量
    let isDraw = false
    // 鼠标按下事件
    canvas.onmousedown = function (event) {
      isDraw = true
      // 开始画
      ctx.beginPath()
      // 开始绘制的点
      var x = event.pageX - canvas.offsetLeft
      var y = event.pageY - canvas.offsetTop
      ctx.moveTo(x, y)
    }
    // 鼠标抬起
    canvas.onmouseup = function () {
      isDraw = false
      ctx.closePath()
    }
    // 鼠标离开
    canvas.onmouseleave = function () {
      isDraw = false
      ctx.closePath()
    }
    // 鼠标移动
    canvas.onmousemove = function (event) {
      if (isDraw) {
        var x = event.pageX - canvas.offsetLeft
        var y = event.pageY - canvas.offsetTop
        ctx.lineTo(x, y)
        ctx.stroke()
      }
    }
    // 切换粗线条
    boldBtn.onclick = function () {
      ctx.globalCompositeOperation = 'source-over';
      ctx.lineWidth = 20
      boldBtn.classList.add('active')
      thinBtn.classList.remove('active')
      clearBtn.classList.remove('active')
    }
    // 切换细线条
    thinBtn.onclick = function () {
      ctx.globalCompositeOperation = 'source-over';
      ctx.lineWidth = 2
      thinBtn.classList.add('active')
      boldBtn.classList.remove('active')
      clearBtn.classList.remove('active')
    }
    // 切换橡皮擦
    clearBtn.onclick = function () {
      ctx.globalCompositeOperation = 'destination-out';
      ctx.lineWidth = 30
      clearBtn.classList.add('active')
      thinBtn.classList.remove('active')
      boldBtn.classList.remove('active')
    }
    // 清空画布
    nullBtn.onclick = function () {
      ctx.clearRect(0, 0, 800, 600)
    }
    // 保存签名
    saveBtn.onclick = function () {
      let urlData = canvas.toDataURL()
      // let img = new Image()
      // img.src = urlData
      // document.body.appendChild(img)
      let downLoadA = document.createElement('a')
      downLoadA.setAttribute('download', '签名')
      downLoadA.href = urlData
      downLoadA.click()
    }
    // 切换颜色
    inputColor.onchange = function () {
      ctx.strokeStyle = inputColor.value
    }
  </script>
</body>

 20.动态时钟

<body>
  <canvas id="c1" width="800" height="600"></canvas>
  <script>
    // 获取画布
    let canvas = document.getElementById('c1')
    let ctx = canvas.getContext('2d')
    //保存当前坐标位置和上下文对象的状态
    function rander() {
      ctx.clearRect(0, 0, 800, 600)
      ctx.save()
      // 移动
      ctx.translate(400, 300)
      ctx.rotate(-Math.PI / 2)

      ctx.save()
      for (let i = 0; i < 12; i++) {
        // 开始画--绘制小时的刻度
        ctx.beginPath()
        ctx.moveTo(170, 0)
        ctx.lineTo(190, 0)
        ctx.lineWidth = 8
        ctx.strokeStyle = 'gray'
        ctx.stroke()
        ctx.closePath()
        ctx.rotate(2 * Math.PI / 12)
      }

      ctx.restore()
      ctx.save()
      for (let 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()
      ctx.save()
      // 获取时间
      let time = new Date()
      let hour = time.getHours()
      let min = time.getMinutes()
      let sec = time.getSeconds()
      hour = hour >= 12 ? hour - 12 : hour

      // 绘制秒针
      ctx.rotate(2 * Math.PI / 60 * sec)
      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 * min + 2 * Math.PI / 60 / 60 * sec)
      ctx.beginPath()
      ctx.moveTo(-20, 0)
      ctx.lineTo(130, 0)
      ctx.lineWidth = 4
      ctx.strokeStyle = '#888'
      ctx.stroke()
      ctx.closePath()
      ctx.restore()
      ctx.save()

      // 绘制时针
      ctx.rotate(2 * Math.PI / 12 * hour + 2 * Math.PI / 12 / 60 * min + 2 * Math.PI / 12 / 60 / 60 * sec)
      ctx.beginPath()
      ctx.moveTo(-15, 0)
      ctx.lineTo(110, 0)
      ctx.lineWidth = 8
      ctx.strokeStyle = '#333'
      ctx.stroke()
      ctx.closePath()
      ctx.restore()
      // 动起来
      ctx.restore()
      requestAnimationFrame(rander)
    }
    rander()
  </script>
</body>

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值