• canvas 基础 和 动图案例


      是 HTML5 新增的一种标签,一个可以使用脚本(通常为JavaScript)在其中绘制图的 HTML 元素。它可以用来制作照片集或者制作简单(也不是那么简单)的动画,甚至可以进行实时视频处理和渲染。

     

    目前只支持JS,不支持其他如 jQuery 等等; 需要设置宽高,单位默认是px,如果不设置宽高,默认为 300*150;

    在低版本浏览器不兼容时,可以在标签内,设置不兼容时显示的内容

     一、canvas 获取画布和画笔 画线条

    注意:canvas 标签是行内块元素,如果需要设置他的布局,可以设置为块级元素

    1.设置一个canvas 画布画直线,需要固定执行以下步骤:

    1.1.获取canvas 标签(通过标签选择器来选择)

    1.2.拿到canvas 的上下文对象(通过ctx.getContext('2d')来获取)

    1.3.开启一条路径 beginPath();

    1.4.确定起始点 moveTo(x,y)

    1.5.确定终点  lineTo(x,y) ,这里可以连写lineTo(x,y) 终点位置,实现连笔画,及以上一个结束坐标作为下一个点的开始坐标;

    1.6.进行上色  

    1.7.关闭路劲

    1. /* 1.获取canvas 标签 */
    2. let canvas = document.querySelector('canvas')
    3. /* 2.获取上下文对象,使用getContext('2d')方法 */
    4. let ctx = canvas.getContext('2d');
    5. /* 3.开启一条路径 */
    6. ctx.beginPath();
    7. /* 4.确定起点坐标 坐标是相对于 canvas 的左上角 */
    8. ctx.moveTo(100, 100)
    9. /* 5.确实终点坐标 */
    10. ctx.lineTo(400, 400)
    11. /* 设置颜色和线宽,必须要在上色之前设置颜色和线宽属性 */
    12. ctx.strokeStyle = 'pink'
    13. ctx.lineWidth = 5
    14. /* 6.上色 */
    15. ctx.stroke()
    16. /* 7.关闭路径 */
    17. ctx.closePath();

    2.画虚线(通常可以把重复的代码封装为一个函数来调用)

    2.1 可以使用循环方式连续画出不同的直线,实现虚线效果;原理是,不断的变化每条小的直线的坐标,来实现;

    1. let canvas = document.querySelector('canvas')
    2. let ctx = canvas.getContext('2d')
    3. drawLine(100, 100, 105, 100, 'pink', 5)
    4. // 画虚线
    5. for (let i = 0; i < 20; i++) {
    6. drawLine(100 + 10 * i, 100, 105 + 10 * i, 100, 'pink', 5)
    7. }
    8. // 斜角度画虚线
    9. for (let i = 0; i < 20; i++) {
    10. drawLine(100 + 10 * i, 100 + 10 * i, 105 + 10 * i, 105 + 10 * i, 'pink', 5)
    11. }
    12. // 画直线函数
    13. function drawLine(x1, y1, x2, y2, color, width) {
    14. ctx.beginPath();
    15. ctx.moveTo(x1, y1)
    16. ctx.lineTo(x2, y2)
    17. ctx.strokeStyle = color
    18. ctx.lineWidth = width
    19. ctx.stroke()
    20. ctx.closePath();
    21. }

    2.2 通过 ctx.setLineDash([num1,num2]) 方法和   ctx.lineDashOffset = -5; 来定制虚线样式

    (1)setLineDash([num1,num2]) 方法接受一个数组作为参数,num1为 线条长度,num2 为间隔距离

    (2)lineDashOffset = num, 方法设置起始点偏移量;

    1. function draw() {
    2. let canvas = document.querySelector('canvas')
    3. let ctx = canvas.getContext('2d')
    4. ctx.setLineDash([10, 10]); // [实线长度, 间隙长度]
    5. ctx.lineDashOffset = -5;
    6. // ctx.strokeRect(50, 50, 210, 210);
    7. ctx.beginPath()
    8. ctx.moveTo(0, 0)
    9. ctx.lineTo(100, 100)
    10. ctx.stroke()
    11. ctx.closePath()
    12. }
    13. draw();

    3.线条连画(多次调用lineTo(x,y))

    4.画矩形

    4.1 画有填充矩形 方法:fillRect(x,y,width,height)

            x,y表示矩形左上角起始坐标;

            width,height 表示 矩形的长宽;

    1. ctx.fillRect(200, 200, 100, 100)
    2. ctx.fillStyle = 'red'

    4.2 画无填充矩形 方法:ctx.strokeRect(x,y,width,height)

    1. ctx.strokeStyle = '#ccc'
    2. ctx.lineWidth = 3
    3. ctx.strokeRect(300, 300, 100, 100)

    4.3 画有边框的 填充矩形 

    1. let canvas = document.querySelector('canvas')
    2. let ctx = canvas.getContext('2d')
    3. ctx.beginPath()
    4. // 创建矩形,rect(x,y,width,height)
    5. ctx.rect(100, 100, 100, 100)
    6. // 填充色
    7. ctx.fillStyle = 'pink'
    8. // 填充
    9. ctx.fill()
    10. // 描边
    11. ctx.strokeStyle = 'green'
    12. // 描边的宽度
    13. ctx.lineWidth = 5
    14. // 着色
    15. ctx.stroke()

     简单实例如下:

    5.清除画布  方法:ctx.clearRect(x,y,w,h) 

    清除画布在画图过程中很常用,比如实现动态图,就是不断清除画布和重绘画布;

    1. /* 画矩形 */
    2. let canvas = document.querySelector('canvas')
    3. let ctx = canvas.getContext('2d')
    4. ctx.beginPath()
    5. // 创建矩形,rect(x,y,width,height)
    6. ctx.rect(100, 100, 300, 200)
    7. // 填充色
    8. ctx.fillStyle = 'pink'
    9. // 填充
    10. ctx.fill()
    11. // 描边
    12. ctx.strokeStyle = 'green'
    13. // 描边的宽度
    14. ctx.lineWidth = 5
    15. // 着色
    16. ctx.stroke()
    17. // 清除画布 clearRect(x,y,width,height) 坐标x,y依然是矩形的左上角;
    18. ctx.clearRect(120, 120, 150, 100)

    6.画圆 

    方法:arc(x,y,radius,startAngle,endAngle,counterclockwise)

          (1)x,y 表示圆心坐标

          (2)radius 表示圆弧半径

          (3)startAngle 开始角度

          (4)endAngle 结束角度

          (5)counterclockwise 表示画圆弧的顺逆时针方向,false 表示顺时针,true表示逆时针

    1. ctx.beginPath()
    2. ctx.arc(400, 400, 250, 0, Math.PI * 2, false)
    3. ctx.strokeStyle = 'red'
    4. ctx.lineWidth = 3
    5. // 内部填充
    6. ctx.fillStyle = 'gold'
    7. ctx.fill()
    8. // 着色,不可缺,没有着色是不能看到的
    9. ctx.stroke()
    10. // 图像不是封闭的时候,需要设置开始路径和结束路径的,要不然会连笔
    11. ctx.beginPath()
    12. ctx.arc(400, 400, 100, 0, Math.PI, false)
    13. ctx.strokeStyle = 'red'
    14. ctx.lineWidth = 3
    15. // 着色,不可缺,没有着色是不能看到的
    16. ctx.stroke()

     7.画文字

    7.1 绘制文字

          (1).实心字体 方法:fillText('文字内容',x,y,maxWidth)

          (2) 空心字体 方法:ctx.strokeText('文字内容', x, y)

              - x,y 表示文字的开始位置坐标,maxWidth表示文字内容最大宽度,超出会压缩

          (3)线性渐变

             方法:let grd = ctx.createLinearGradient(x1, y, x2, y2);

              grd.addColorStop('0','颜色')

              grd.addColorStop('1','颜色')

              - x1,y1,x2,y2表示渐变开始和结束的坐标

              - addColorStop() 表示,颜色的添加

    1. // 字体的样式需要放在 前面
    2. ctx.font = '50px 微软雅黑'
    3. ctx.fillStyle = 'gold'
    4. // 实心字体
    5. ctx.fillText('hello canvas', 100, 100)
    6. ctx.font = '50px 宋体'
    7. // 空心字体
    8. ctx.strokeStyle = 'pink'
    9. ctx.strokeText('你好', 100, 200)
    10. // 颜色线性渐变
    11. let grd = ctx.createLinearGradient(0, 0, canvas.width, 0);
    12. // 增加渐变颜色以及范围
    13. grd.addColorStop('0', 'yellow')
    14. grd.addColorStop('0.5', 'red')
    15. grd.addColorStop('1.0', 'skyBlue')
    16. // 应用渐变,把渐变的变量 赋值给strokeStyle 属性
    17. ctx.strokeStyle = grd;
    18. ctx.font = '40px 楷体'
    19. ctx.strokeText('今天很冷,要多穿衣服哦!!!', 0, 300, 400)

     

     7.2 文字位置设置

     文字位置属性:

          文字水平方向:start,end, left,right,center

          文字垂直方向:top,bottom,middle

    1. // 画田字格
    2. ctx.beginPath();
    3. ctx.moveTo(250, 0)
    4. ctx.lineTo(250, 500)
    5. ctx.stroke()
    6. ctx.closePath()
    7. ctx.beginPath();
    8. ctx.moveTo(0, 250)
    9. ctx.lineTo(500, 250)
    10. ctx.stroke()
    11. ctx.closePath()
    12. ctx.font = '30px 宋体'
    13. ctx.fillStyle = 'red'
    14. // 水平居中 (参考点都是坐标点)
    15. ctx.textAlign = 'center'
    16. // 垂直居中 (参考点都是坐标点)
    17. ctx.textBaseline = 'middle'
    18. ctx.fillText('风和日丽', 250, 250)

     8. 绘制图片

         全图显示方法:ctx.drawImage(img,x,y)

             - img 为图片对象,采用new Image()方式

                - x,y 为图片左上角的坐标;

        裁剪显示方法:ctx.drawImage(img,xs,ys,sWidth,sHeight,x,y,width,heigth)

             - xs,ys,表示开始裁剪的位置坐标

             - sWidth,sHeight 表示裁剪的宽高

                  - x,y 表示图片在画布上显示的位置坐标

                  - width,height 表示要使用的图像的宽高(sheng)

    1. // 创建图片
    2. let img = new Image()
    3. img.src = './imgs/fengjing.jpeg'
    4. img.onload = function () {
    5. /**
    6. * 获取当前图片的属性,宽高
    7. */
    8. console.log(img.width, img.height);
    9. // ctx.drawImage(img, 100, 100)
    10. ctx.drawImage(img, 0, 0, 100, 100, 100, 100, 50, 50)
    11. }

    9. 像素操作和像素数据

    9.1 获取图片像素对象  getImageData(x,y,width,height)

            - x,y 表获取起始点坐标

            - width,height 表示宽高

          ctx.getImageData(x,y,w,h)返回一个对象,包含了所获取的像素块的像素内容,包含了 该块图像的每一个像素,每一个像素点信息 = rgba(0-255,0-255,0-255,0-255),前三个数据表示红绿蓝,第四个数据表示 透明度(0-255)

    9.2 重新绘制获取的图片对象 putImageData(imgData,x,y,dirtyX,dirtyY,dirtyWidth,dirtyHeight)

            - imgData 表示要放回画布的 ImageData 对象

            - x,y 表示 ImageData 对象左上角的x,y坐标,以像素点计算

            - dirtyX,dirtyY 可选。表示在画布上放置图像的位置

            - dirtyWidth,dirtyHeight 可选。表示在画布上绘制图像所使用的宽高

    1. // 1.创建图片
    2. let img = new Image();
    3. img.src = './imgs/fengjing.jpeg';
    4. img.onload = function () {
    5. // 绘制图片
    6. ctx.drawImage(img, 0, 0);
    7. let copy = ctx.getImageData(0, 0, 100, 100)
    8. console.log(copy);
    9. /*
    10. putImageData(imgData,x,y,dirtyX,dirtyY,dirtyWidth,dirtyHeight)
    11. - imgData 表示要放回画布的 ImageData 对象
    12. - x,y 表示 ImageData 对象左上角的x,y坐标,以像素点计算
    13. - dirtyX,dirtyY 可选。表示在画布上放置图像的位置
    14. - dirtyWidth,dirtyHeight 可选。表示在画布上绘制图像所使用的宽高
    15. */
    16. ctx.putImageData(copy, 0, 650)// 可以在原图片上扣取一部分图片重新绘制到指定地方;
    17. }

    二、动图案例

    1. 小球的碰撞检测

    重要点为:小球碰到边缘如何反弹,本质是小球的速度(也就是坐标的变化距离),当小球的坐标+半径和 到了边缘时,设置小球往方向跑

    1. html>
    2. <html lang="en">
    3. <head>
    4. <meta charset="UTF-8">
    5. <meta http-equiv="X-UA-Compatible" content="IE=edge">
    6. <meta name="viewport" content="width=device-width, initial-scale=1.0">
    7. <title>Documenttitle>
    8. <style>
    9. * {
    10. margin: 0;
    11. padding: 0;
    12. }
    13. canvas {
    14. margin: 50px auto;
    15. display: block;
    16. border: 1px solid #ccc;
    17. }
    18. style>
    19. head>
    20. <body>
    21. <canvas width="600" height="600">默认参数canvas>
    22. <script>
    23. let c = document.querySelector('canvas')
    24. let ctx = c.getContext('2d')
    25. /*
    26. 小球运动的本质就是定时器重新绘制小球
    27. */
    28. let w = h = 600
    29. let x = 100;
    30. let y = 100
    31. let r = 20
    32. let xSpeed = 3;
    33. let ySpeed = 4
    34. setInterval(function () {
    35. ctx.clearRect(0, 0, w, h)
    36. // 小球坐标的变化
    37. drawCircle(x, y, r, 'red')
    38. if (x + r >= w || x - r <= 0) {
    39. xSpeed = -xSpeed;
    40. }
    41. x += xSpeed
    42. if (y + r >= h || y - r <= 0) {
    43. ySpeed = -ySpeed;
    44. }
    45. y += ySpeed
    46. }, 10)
    47. function drawCircle(x, y, r, color = '#000') {
    48. ctx.beginPath();
    49. ctx.arc(x, y, r, 0, Math.PI * 2);
    50. ctx.fillStyle = color;
    51. // ctx.fill()方法是实心着色
    52. ctx.fill()
    53. // 着色,不可缺,没有着色是不能看到的
    54. // ctx.stroke() 是空心着色
    55. // ctx.stroke();
    56. ctx.closePath();
    57. }
    58. script>
    59. body>
    60. html>

    2.面向对象的小球碰撞

    面向对象的本质是对小球对象的封装,小球移动和绘制方法的封装;

    1. <body>
    2. <canvas width="600" height="600">默认参数canvas>
    3. <script>
    4. let c = document.querySelector('canvas')
    5. let ctx = c.getContext('2d')
    6. /*
    7. 小球运动的本质就是定时器重新绘制小球
    8. */
    9. let w = h = 600
    10. // 创建随机数
    11. function ranD(num) {
    12. return Math.random() * num
    13. }
    14. // 创建一个小球对象
    15. class Ball {
    16. constructor() {
    17. this.r = ranD(30) + 20;
    18. this.x = ranD(500) + 60;
    19. this.y = ranD(500) + 60;
    20. this.xSpeed = ranD(3) + 2;
    21. this.ySpeed = ranD(3) + 1;
    22. this.color = "#" + parseInt(ranD(1) * 0xffffff).toString(16)
    23. }
    24. // 小球显示的方法
    25. show() {
    26. ctx.beginPath();
    27. ctx.arc(this.x, this.y, this.r, 0, Math.PI * 2);
    28. ctx.fillStyle = this.color;
    29. ctx.fill()
    30. ctx.closePath();
    31. }
    32. // 小球运动的方法
    33. run() {
    34. if (this.x + this.r >= w || this.x - this.r <= 0) {
    35. this.xSpeed = -this.xSpeed;
    36. }
    37. this.x += this.xSpeed
    38. if (this.y + this.r >= h || this.y - this.r <= 0) {
    39. this.ySpeed = -this.ySpeed;
    40. }
    41. this.y += this.ySpeed
    42. }
    43. }
    44. // 创建小球
    45. let ballArr = []
    46. for (let i = 0; i < 20; i++) {
    47. var ball = new Ball()
    48. ballArr.push(ball)
    49. ball.show()
    50. }
    51. console.log(ballArr);
    52. // 小球运动
    53. setInterval(function () {
    54. ctx.clearRect(0, 0, w, h)
    55. for (let i = 0; i < ballArr.length; i++) {
    56. ballArr[i].show()
    57. ballArr[i].run()
    58. }
    59. }, 10)
    60. script>
    61. body>
    62. html>

    3.小球连线

    小球之间连线的本质是 选取小球之间的圆心,不断动态重新绘制直线

    1. <body>
    2. <canvas width="600" height="600">默认参数canvas>
    3. <script>
    4. let c = document.querySelector('canvas')
    5. let ctx = c.getContext('2d')
    6. /*
    7. 小球运动的本质就是定时器重新绘制小球
    8. */
    9. let w = h = 600
    10. // 创建随机数
    11. function ranD(num) {
    12. return Math.random() * num
    13. }
    14. // 创建一个小球对象
    15. class Ball {
    16. constructor(text) {
    17. this.r = ranD(30) + 20;
    18. this.x = ranD(500) + 50;
    19. this.y = ranD(500) + 50;
    20. this.xSpeed = ranD(3) + 2;
    21. this.ySpeed = ranD(3) + 1;
    22. this.color = "#" + parseInt(ranD(1) * 0xffffff).toString(16);
    23. this.text = text;
    24. }
    25. // 画圆;小球显示的方法
    26. show() {
    27. drawCircle(this.x, this.y, this.r, this.color);// 画圆
    28. drawText(this.r, this.text, this.x + this.r, this.y, this.color);// 画文字
    29. }
    30. // 小球运动的方法
    31. run() {
    32. if (this.x + this.r >= w - 60 || this.x - this.r <= 0) {
    33. this.xSpeed = -this.xSpeed;
    34. }
    35. this.x += this.xSpeed
    36. if (this.y + this.r >= h || this.y - this.r <= 0) {
    37. this.ySpeed = -this.ySpeed;
    38. }
    39. this.y += this.ySpeed
    40. }
    41. }
    42. // 画直线
    43. function drawLine(x1, y1, x2, y2, color = "#000") {
    44. ctx.beginPath();
    45. ctx.moveTo(x1, y1);
    46. ctx.lineTo(x2, y2);
    47. ctx.strokeStyle = color;
    48. ctx.stroke();
    49. ctx.closePath();
    50. }
    51. // 画字体
    52. function drawText(font, text, x, y, color = '#000') {
    53. ctx.font = `${font}px 宋体`;
    54. ctx.textAlign = 'left';
    55. ctx.textBaseline = 'middle';
    56. ctx.fillStyle = color;
    57. ctx.fillText(text, x, y, 60)
    58. }
    59. // 画圆
    60. function drawCircle(x, y, r, color) {
    61. ctx.beginPath();
    62. ctx.arc(x, y, r, 0, Math.PI * 2);
    63. ctx.fillStyle = color;
    64. ctx.fill()
    65. ctx.closePath();
    66. }
    67. // 文字数据
    68. let titleText = 'Java PHP JS GO Vue Angular jQuery CSS HTML Bootstrap webGL ThreeJs ElementUI UI AXIOS ajax'.split(' ')
    69. // 创建小球
    70. let ballArr = []
    71. for (let i = 0; i < 6; i++) {
    72. var ball = new Ball(titleText[i])
    73. ballArr.push(ball)
    74. ball.show()
    75. }
    76. console.log(ballArr);
    77. // 小球运动
    78. setInterval(function () {
    79. ctx.clearRect(0, 0, w, h)
    80. for (let i = 0; i < ballArr.length; i++) {
    81. ballArr[i].show()
    82. ballArr[i].run()
    83. /*
    84. 小球连线
    85. */
    86. for (let j = 0; j < i; j++) {
    87. drawLine(ballArr[i].x, ballArr[i].y, ballArr[j].x, ballArr[j].y, ballArr[i].color)
    88. }
    89. }
    90. }, 10)
    91. script>
    92. body>
    93. html>

     4.跟随鼠标的炫彩炫彩小球

    1. <body>
    2. <canvas>默认参数canvas>
    3. <script>
    4. let c = document.querySelector('canvas')
    5. let ctx = c.getContext('2d')
    6. /*
    7. 小球运动的本质就是定时器重新绘制小球
    8. */
    9. let w = document.documentElement.clientWidth - 10
    10. let h = document.documentElement.clientHeight - 10
    11. c.width = w;
    12. c.height = h
    13. // 创建随机数
    14. function ranD(num) {
    15. return Math.random() * num
    16. }
    17. // 创建一个小球对象
    18. class Ball {
    19. constructor(x, y) {
    20. this.r = 60;
    21. this.x = x;
    22. this.y = y;
    23. this.color = "#" + parseInt(ranD(1) * 0xffffff).toString(16);
    24. }
    25. // 画圆;小球显示的方法
    26. show() {
    27. this.r--;// 小球直径减小
    28. if (this.r <= 0) return
    29. drawCircle(this.x, this.y, this.r, this.color);// 画圆
    30. }
    31. }
    32. // 画圆
    33. function drawCircle(x, y, r, color) {
    34. ctx.beginPath();
    35. ctx.arc(x, y, r, 0, Math.PI * 2);
    36. ctx.fillStyle = color;
    37. ctx.fill()
    38. ctx.closePath();
    39. }
    40. // 创建小球
    41. let ballArr = []
    42. // 小球的坐标跟着鼠标的位置而移动
    43. window.onmousemove = function (event) {
    44. console.log(event.x, event.y);
    45. var ball = new Ball(event.x, event.y)
    46. ballArr.push(ball)
    47. ball.show()
    48. }
    49. // 拿到小球对象集合
    50. console.log(ballArr);
    51. // 小球运动
    52. setInterval(function () {
    53. ctx.clearRect(0, 0, w, h)
    54. for (let i = 0; i < ballArr.length; i++) {
    55. ballArr[i].show()
    56. }
    57. }, 8)
    58. script>
    59. body>
    60. html>

    最后附上写的比较好的大佬的博客,感谢参考!!

    http://t.csdn.cn/l1OK0

  • 相关阅读:
    如何用golang写一个自己的后端框架
    正则表达式.java
    【运维篇】三、SLF4J与Logback
    网络编程 —— Http使用httpClient实现页面爬虫
    Could not read from boot medium. System halted.
    PCBA方案|红外额温枪方案
    如何在VMware workstation虚拟机中安装ensp(完美运行),解决报错40
    解决开发板有IP无法上网
    Spark系列之Spark的RDD详解
    Linux内核优化的一些配置
  • 原文地址:https://blog.csdn.net/weixin_67642008/article/details/127697720