当前位置: 首页 > article >正文

canvas的基本用法

canvas

canvas元素简介

1.是个container元素<canvas width='100' height='100'></canvas>,有开闭标签

2.有且只有widthheight两个attribute,不需要写单位

canvas的基本使用

const canvasEl = document.getElementById('canvas01')
const ctx = canvasEl.getContext('2d')   //ctx包含了各种属性和画图的函数
ctx.fillStyle='#d55'
ctx.fillRect(200,20,200,50)   //填充矩形
ctx.strokeStyle='#55d'
ctx.lineWidth=10
ctx.strokeRect(100,60,-20,-50)   //描边矩形
ctx.lineWidth=2
ctx.strokeStyle='#5dd'
ctx.strokeRect(150,100,-20,-50)

canvas路径绘制

画多线段

ctx.beginPath()
ctx.moveTo(100,100)//用moveTo将画笔移动到下一个开始绘制的点,和之前绘制的尾部不连接
ctx.lineCap='round'
ctx.lineJoin='bevel'
ctx.lineWidth=5
ctx.lineTo(150,100)
ctx.lineTo(200,120)
ctx.moveTo(220,100)
ctx.lineTo(220,150)
ctx.stroke()
ctx.closePath()

线条的属性:

1.ctx.lineCap:线条端点样式,可以设置'round'|'butt'|'square' 圆角|截断|方角

2.ctx.lineJoin: 线条连接处样式 'round'|'bevel'|'miter' 圆角|倒角|默认

画三角形描边(stroke):需要用到ctx.closePath()

ctx.beginPath()
ctx.moveTo(200,200)
ctx.lineTo(200,250)
ctx.lineTo(300,100)
ctx.stroke()
ctx.closePath()

画三角填充(fill):可以没有ctx.closePath()

ctx.beginPath()
ctx.moveTo(200,200)
ctx.lineTo(200,250)
ctx.lineTo(300,100)
ctx.fill()
ctx.closePath()

画弧

CanvasPath.arc(x: number, y: number, radius: number, startAngle: number, endAngle: number, counterclockwise?: boolean)

ctx.beginPath()
ctx.arc(300,300,20,0,Math.PI*2,false)
ctx.moveTo(370,350)
ctx.arc(350,350,20,0,Math.PI,false)
ctx.stroke()
ctx.closePath()

画矩形

ctx.beginPath()
ctx.fillStyle='#e00'
ctx.rect(20,300,20,50)
ctx.fill()
ctx.closePath()

ctx.beginPath()
ctx.lineStyle='#e00'
ctx.lineWidth=3
ctx.rect(20,400,50,80)
ctx.stroke()
ctx.closePath()

canvas绘制文字

ctx.font = "50px 仿宋"
ctx.textAlign = 'center'
ctx.textBaseline = 'bottom'
ctx.fillStyle = '#d00'
ctx.fillText("哈哈哈", 250, 90,200);
ctx.font = "20px 黑体"
ctx.strokeStyle = '#d000dd'
ctx.strokeText("嘿嘿嘿", 250, 200,200);

canvas绘制图片

1.ctx.drawImage(image, dx, dy)

2.ctx.drawImage(image, dx, dy, dWidth, dHeight)

3.ctx.drawImage(image,sx,sy,swidth,sheight,dx,dy,dwidth,dheight)

s开头的是裁剪坐标,d开头的是绘制坐标

示例:

const dogImage = new Image(200,200)
dogImage.src = './dog.jpg'
dogImage.onload = function(){
  ctx.drawImage(dogImage,10,10,300,300,0,0,100,100)
}
   

补充:

canvas绘制的图都是栅格图

canvas绘制状态

保存绘图状态,在进行复杂的绘图以后,可以随时返回当前的状态,主要是保存某个绘图时期的字体,颜色,线条宽度,坐标变换等状态,这样不用重复设置绘图样式,被保存的绘图状态会被推入一个栈中,每次调用restore()就会弹出到栈最顶层的状态,也就是让canvas的各类属性设置回到上一次保存的设置

ctx.save()

ctx.restore()

ctx.fillRect(0,0,100,100)
ctx.save()
ctx.translate(10,150)
ctx.fillRect(0,0,100,100)
ctx.restore()

canvas变形

1.ctx.translate(dx,dy) 平移画布

2.ctx.rotate(deg) 旋转画布

3.ctx.scale(sx,sy)缩放画布,只能在原坐标系统缩放

ctx.save()
ctx.beginPath()
ctx.translate(100,150)
ctx.scale(2, 2)
ctx.rotate(45)
ctx.fillRect(-50,-100,100,100)
ctx.restore()

canvas动画

1.通过setInterval,setTimeoutrequestAnimationFrame三种方法来控制时间

2.画一帧的步骤

1.ctx.clearRect()
2.ctx.save()
3.绘制动画图形
4.ctx.resotre()

示例:绘制表盘

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    .container{
      position: relative;
      width: 500px;
      height: 500px;
      border-radius: 5px;
      margin: 50px auto;
      box-shadow: 1px 1px 10px 5px #d5d5d5;
    }
    canvas{
      position: absolute;
      top: 0;
      left: 0;
    }
  </style>
</head>
<body>
  <div class="container">
    <canvas id="canvas01" width="500" height="500"></canvas>
  </div>
  <script>
    const canvasEl = document.getElementById('canvas01')
    const ctx = canvasEl.getContext('2d')
    
    function drawClock(pHours,pMinutes,pSeconds){
      let oldHours = pHours <= 12?(pHours/12)*60-15:((pHours-12)/12)*60-15
      let minutes = pMinutes - 15
      let seconds = pSeconds -15
      let hours = oldHours+Math.round((pMinutes/12))

      ctx.clearRect(0,0,500,500)
      ctx.save()

      //表盘
      ctx.beginPath()
      ctx.arc(250,250,105,0,Math.PI*2,false)
      ctx.fillStyle='#fff'
      ctx.fill()
      ctx.closePath()

      //表外框线条
      ctx.beginPath()
      ctx.strokeStyle= '#000'
      ctx.lineWidth = 5
      ctx.moveTo(356,250)
      ctx.arc(250,250,106,0,Math.PI*2,false)
      ctx.stroke()
      ctx.closePath()

      //表内框线
      ctx.beginPath()
      ctx.strokeStyle= '#000'
      ctx.lineWidth = 1
      ctx.moveTo(351,250)
      ctx.arc(250,250,101,0,Math.PI*2,false)
      ctx.stroke()
      ctx.closePath()

      //刻度线
      ctx.beginPath()
      ctx.lineWidth=1
      for(let j = 0;j<60;j++ ){
        ctx.save()
        ctx.translate(250,250)
        ctx.rotate(Math.PI*2/60*j)
        
        if(j%5===0){
          ctx.moveTo(95,0)
          ctx.lineTo(100,0)
        }
        else if(j%15===0){
          ctx.moveTo(90,0)
          ctx.lineTo(100,0)
        }else{
          ctx.moveTo(98,0)
          ctx.lineTo(100,0)
        }
        ctx.restore()
      }
      ctx.stroke()
      ctx.closePath()

      //刻度数字
      const numbers = [3,4,5,6,7,8,9,10,11,0,1,2]
      ctx.save()
      ctx.translate(247,254)
      for(let i = 0; i<numbers.length;i++){
        let x = Math.cos(Math.PI*2/12*i)*83
        let y = Math.sin(Math.PI*2/12*i)*83
        ctx.fillStyle='#000'
        ctx.textAlign = 'left'
        ctx.fillText(numbers[i],x,y)
      }
      ctx.restore()
    
      //秒针
      ctx.beginPath()
      ctx.strokeStyle= '#d33'
      ctx.lineCap = 'round'
      ctx.lineWidth = 1
      ctx.moveTo(250,250)
      ctx.arc(250,250,96,Math.PI*2/60*seconds,Math.PI*2/60*seconds,true)
      ctx.stroke()
      ctx.closePath()

      //分针
      ctx.beginPath()
      ctx.strokeStyle= '#111'
      ctx.lineCap = 'round'
      ctx.lineWidth = 2
      ctx.moveTo(250,250)
      ctx.arc(250,250,80,Math.PI*2/60*minutes,Math.PI*2/60*minutes,true)
      ctx.stroke()
      ctx.closePath()

      //时针
      ctx.beginPath()
      ctx.strokeStyle= '#222'
      ctx.lineCap = 'round'
      ctx.lineWidth = 4
      ctx.moveTo(250,250)
      ctx.arc(250,250,50,Math.PI*2/60*hours,Math.PI*2/60*hours,true)
      ctx.stroke()
      ctx.closePath()

      //表心
      ctx.beginPath()
      ctx.moveTo(250,250)
      ctx.fillStyle= '#fff'
      ctx.arc(250,250,1,0,Math.PI*2)
      ctx.fill()
      ctx.closePath()
    }

    let lastSecond = -1;

    function playAnimation(){
      const date = new Date()
      const seconds = date.getSeconds()
      const minutes = date.getMinutes()
      const hours = date.getHours()
      if(lastSecond !== seconds){
        drawClock(hours,minutes,seconds)
        lastSecond = seconds
      }
      requestAnimationFrame(()=>{
        playAnimation()
      })
    }

    playAnimation()

  </script>
</body>
</html>

http://www.kler.cn/a/527856.html

相关文章:

  • 网站结构优化:加速搜索引擎收录的关键
  • 项目测试之MockMvc
  • PCA9685 一款由 NXP Semiconductors 生产的 16 通道、12 位 PWM(脉宽调制)控制器芯片
  • 基于Django的Boss直聘IT岗位可视化分析系统的设计与实现
  • LMI Gocator GO_SDK VS2019引用配置
  • openssl 生成证书 windows导入证书
  • @EventListener底层原理(超详细)| @TransactionalEventListener底层原理 | 事务同步
  • 列表导出功能
  • 深度解析:网站快速收录与服务器性能的关系
  • DeepSeek的介绍
  • 2025:影刀RPA使用新实践--CSDN博客下载
  • 【AIGC专栏】AI在自然语言中的应用场景
  • 用QT做一个网络调试助手
  • 芯片AI深度实战:让verilog不再是 AI 的小众语言
  • 开发过程中如何减少属性注释?
  • Cursor 背后的技术栈:从 VS Code 到 AI 集成
  • 数据结构 树1
  • LeetCode题练习与总结:不含连续1的非负整数--600
  • level-icmp(ping)详细过程_6
  • 输入一行字符,分别统计出其中英文字母,空格,数字和其他字符的个数。
  • 团体程序设计天梯赛-练习集——L1-028 判断素数
  • 课程设计|结构力学
  • 蓝桥杯真题k倍区间
  • C# Winform enter键怎么去关联button
  • 分层多维度应急管理系统的设计
  • 疯狂拆单词01