HTML5画布canvas实战(1)--折线图

左手的ㄟ右手 2022-02-23 06:34 756阅读 0赞

画布基本教程

画布基础知识和绘制
Canvas MDN

唠唠叨叨

canvas 是 HTML5 新增的元素,可用于通过使用JavaScript中的脚本来绘制图形。例如,它可以用于绘制图形,制作照片,创建动画,甚至可以进行实时视频处理或渲染。

HTML结构

  1. <style> canvas { border: 1px solid #000; } </style>
  2. <canvas width="600" height="600"></canvas>

绘制网格线

绘制个普通网格线即可(想展示强大的画工也可以绘制个蜘蛛网出来)

  1. // 获取画布,渲染上下文,绘制工具箱
  2. let myCan = document.querySelector('canvas')
  3. let cxt = myCan.getContext('2d')
  4. // 设置网格的大小
  5. let gridSize = 10
  6. // 获取画布的宽高
  7. let w = cxt.canvas.width
  8. let h = cxt.canvas.height
  9. // 计算出每一行能放多少网格线
  10. let lineTotalX = Math.floor(w / gridSize)
  11. let lineTotalY = Math.floor(h / gridSize)
  12. // 先将X轴的线画出来(记得要去掉1px的不饱和填充)
  13. for (var i = 0; i < lineTotalX;i++){
  14. cxt.moveTo(i*gridSize - 0.5,0)
  15. cxt.lineTo(i*gridSize - 0.5,h)
  16. cxt.strokeStyle = '#eee'
  17. cxt.stroke()
  18. }
  19. for (var i = 0; i < lineTotalY;i++){
  20. cxt.moveTo(0,i*gridSize - 0.5)
  21. cxt.lineTo(w,i*gridSize - 0.5)
  22. cxt.strokeStyle = '#eee'
  23. cxt.stroke()
  24. }

绘制坐标

新建一个html文件,重新绘制

  1. let myCan = document.querySelector('canvas')
  2. let cxt = myCan.getContext('2d')
  3. // 获取画布的宽高
  4. let w = cxt.canvas.width
  5. let h = cxt.canvas.height
  6. // 设置坐标系原点的空间
  7. let space = 20
  8. // 初始化三角形的长度(高)
  9. let arrowSize = 10
  10. // 设置原点坐标x,y
  11. let x = space
  12. let y = h - space
  13. // 绘制X轴
  14. cxt.beginPath()
  15. cxt.moveTo(x,y)
  16. cxt.lineTo(w - space,y)
  17. // 绘制三角形
  18. cxt.lineTo(w - space - arrowSize,y + arrowSize/2)
  19. cxt.lineTo(w - space - arrowSize,y - arrowSize/2)
  20. cxt.lineTo(w - space,y)
  21. cxt.fill()
  22. cxt.stroke()
  23. // 绘制y轴
  24. cxt.beginPath()
  25. cxt.moveTo(x,y)
  26. cxt.lineTo(x,space)
  27. // 绘制三角形
  28. cxt.lineTo(x-arrowSize/2,space+arrowSize)
  29. cxt.lineTo(x+arrowSize/2,space+arrowSize)
  30. cxt.lineTo(x,space)
  31. cxt.fill()
  32. cxt.stroke()

绘制点

  1. var myCan = document.querySelector('canvas')
  2. var cxt = myCan.getContext('2d')
  3. let coordinate = {
  4. x:100,
  5. y:100
  6. }
  7. // 绘制一个大小为10的正方形
  8. let dottedSize = 10
  9. cxt.beginPath()
  10. cxt.moveTo(coordinate.x - dottedSize/2,coordinate.y - dottedSize/2)
  11. cxt.lineTo(coordinate.x + dottedSize/2,coordinate.y - dottedSize/2)
  12. cxt.lineTo(coordinate.x + dottedSize/2,coordinate.y + dottedSize/2)
  13. cxt.lineTo(coordinate.x - dottedSize/2,coordinate.y + dottedSize/2)
  14. cxt.closePath()
  15. cxt.fill()

构造函数实现折线图

一大波代码即将来袭…一步一步重新实现折线图(根据上面的步骤来初始化我们的变量)…接下来要运用我的不锈钢脑子思考…写下我的思路

  1. 初始化一些必要的变量(设置网格的大小、坐标系原点、点的大小,获取画布宽高…),为了方便我把思路写在代码注释里面

    function LineChart(cxt) {

    1. this.canvas = document.querySelector('canvas')
    2. // 1.1 获取渲染上下文,绘制工具箱
    3. this.cxt = cxt || this.canvas.getContext('2d')
    4. // 1.2 设置网格的大小
    5. this.gridSize = 10
    6. // 1.3 设置网格坐标系的原点距离
    7. this.space = 20
    8. // 1.4 设置网格的坐标系的箭头长度
    9. this.arrowSize = 10
    10. // 1.5 设置点的大小
    11. this.dottedSize = 6
    12. // 1.6 获取画布的宽高
    13. this.w = this.cxt.canvas.width
    14. this.h = this.cxt.canvas.height
    15. // 1.7 设置原点x,y坐标
    16. this.x = this.space
    17. this.y = this.h - this.space
    18. }
  2. 使用构造函数的原型来实现网格,坐标系,绘制点

  3. 实现网格,前面定义了网格的距离gridSize,根据画布的宽高来画网格即可(注意加上0.5,否则线会看起来模糊,是因为画布的对齐点是1px绘制线的中线,计算机会帮我们延展,填充更浅的颜色)

    LineChart.prototype.gridding = function () {

    1. // 3.1 使用for循环先绘制竖线
    2. for (var i = 1;i<this.w/this.gridSize;i++){
    3. this.cxt.beginPath()
    4. this.cxt.moveTo(this.gridSize*i + 0.5,0)
    5. this.cxt.lineTo(this.gridSize*i + 0.5,this.h)
    6. // 因为线会有1px不饱和显示,因为中线是基于对齐点对齐,所以+0.5;可以看上面的参考文档
    7. this.cxt.strokeStyle = '#eee'
    8. this.cxt.stroke()
    9. }
    10. // 3.2 画横线
    11. for (var i = 1;i<this.h/this.gridSize;i++){
    12. this.cxt.beginPath()
    13. this.cxt.moveTo(0,this.gridSize*i + 0.5)
    14. this.cxt.lineTo(this.w,this.gridSize*i + 0.5)
    15. this.cxt.strokeStyle = '#eee'
    16. this.cxt.stroke()
    17. }
    18. }
  4. 测试

    let lineChart = new LineChart()

    1. lineChart.gridding()
  5. 绘制x,y轴

    LineChart.prototype.coordinate = function(){

    1. // 绘制x轴的坐标系
    2. this.cxt.beginPath()
    3. this.cxt.moveTo(this.x,this.y + 0.5)
    4. this.cxt.lineTo(this.w - this.space,this.y + 0.5)
    5. // 绘制x轴的三角形
    6. this.cxt.lineTo(this.w -this.space - this.arrowSize,this.y + this.arrowSize/2)
    7. this.cxt.lineTo(this.w -this.space - this.arrowSize,this.y - this.arrowSize/2)
    8. this.cxt.lineTo(this.w - this.space,this.y)
    9. // 绘制y轴的坐标系
    10. // this.cxt.beginPath()
    11. this.cxt.moveTo(this.x+0.5,this.y)
    12. this.cxt.lineTo(this.x+0.5,this.space)
    13. this.cxt.lineTo(this.x+this.arrowSize/2,this.space+this.arrowSize)
    14. this.cxt.lineTo(this.x-this.arrowSize/2,this.space+this.arrowSize)
    15. this.cxt.lineTo(this.x+0.5,this.space)
    16. this.cxt.fill()
    17. this.cxt.strokeStyle = '#000'
    18. this.cxt.stroke()
    19. }
  6. 测试

    lineChart.coordinate()

  7. 初始化一个点,到后面调用即可(其实就是一个边长为dottedSize,中心为坐标的正方形)

    LineChart.prototype.drawDotted = function(x,y){

    1. this.cxt.beginPath()
    2. this.cxt.moveTo(x-this.dottedSize/2,y-this.dottedSize/2)
    3. this.cxt.lineTo(x+this.dottedSize/2,y-this.dottedSize/2)
    4. this.cxt.lineTo(x+this.dottedSize/2,y+this.dottedSize/2)
    5. this.cxt.lineTo(x-this.dottedSize/2,y+this.dottedSize/2)
    6. this.cxt.closePath()
    7. this.cxt.fill()
    8. }
  8. 绘制点(因为画布原来的坐标原点是左上角,现在我们的原点是我们的坐标系的原点,所以需要换算完在绘制点)

    LineChart.prototype.line = function(data){

    1. if(!data.length){
    2. return
    3. }
    4. data.forEach(function (item,i) {
    5. item.x += this.x
    6. item.y = this.y - item.y
    7. this.drawDotted(item.x,item.y)
    8. }.bind(this))//使得this指向我们的构造函数
    9. }
  9. 测试

    lineChart.line([{ x:111,y:80}])

  10. 根据点画折线

    LineChart.prototype.ligature = function (data) {

    1. console.log(data)
    2. for (var i = 1;i<data.length;i++){
    3. this.cxt.beginPath()
    4. this.cxt.moveTo(data[i-1].x,data[i-1].y)
    5. this.cxt.lineTo(data[i].x,data[i].y)
    6. this.cxt.stroke()
    7. }
    8. }

总结

  1. 后面有整体的代码
  2. 将所有的量放在构造函数里面,方便我们维护,如果需要修改的在里面一改即可
  3. 我们有时候需要对数据进行冒泡排序,才能使得折线从左往右排序
  4. 重新绘制时需要使用beginPath(),这样才不会让线粗细
  5. 其实文章基本都是画线,主要是与画布坐标换算的问题

    function LineChart(cxt) {

    1. this.canvas = document.querySelector('canvas')
    2. this.cxt = cxt || this.canvas.getContext('2d')
    3. this.gridSize = 10
    4. this.space = 20
    5. this.arrowSize = 10
    6. this.dottedSize = 6
    7. this.w = this.cxt.canvas.width
    8. this.h = this.cxt.canvas.height
    9. this.x = this.space
    10. this.y = this.h - this.space
    11. }
    12. LineChart.prototype.gridding = function () {
    13. for (var i = 1;i<this.w/this.gridSize;i++){
    14. this.cxt.beginPath()
    15. this.cxt.moveTo(this.gridSize*i + 0.5,0)
    16. this.cxt.lineTo(this.gridSize*i + 0.5,this.h)
    17. this.cxt.strokeStyle = '#eee'
    18. this.cxt.stroke()
    19. }
    20. for (var i = 1;i<this.h/this.gridSize;i++){
    21. this.cxt.beginPath()
    22. this.cxt.moveTo(0,this.gridSize*i + 0.5)
    23. this.cxt.lineTo(this.w,this.gridSize*i + 0.5)
    24. this.cxt.strokeStyle = '#eee'
    25. this.cxt.stroke()
    26. }
    27. }
    28. LineChart.prototype.coordinate = function(){
    29. this.cxt.beginPath()
    30. this.cxt.moveTo(this.x,this.y + 0.5)
    31. this.cxt.lineTo(this.w - this.space,this.y + 0.5)
    32. this.cxt.lineTo(this.w -this.space - this.arrowSize,this.y + this.arrowSize/2)
    33. this.cxt.lineTo(this.w -this.space - this.arrowSize,this.y - this.arrowSize/2)
    34. this.cxt.lineTo(this.w - this.space,this.y)
    35. this.cxt.moveTo(this.x+0.5,this.y)
    36. this.cxt.lineTo(this.x+0.5,this.space)
    37. this.cxt.lineTo(this.x+this.arrowSize/2,this.space+this.arrowSize)
    38. this.cxt.lineTo(this.x-this.arrowSize/2,this.space+this.arrowSize)
    39. this.cxt.lineTo(this.x+0.5,this.space)
    40. this.cxt.fill()
    41. this.cxt.strokeStyle = '#000'
    42. this.cxt.stroke()
    43. }
    44. // 绘制点
    45. LineChart.prototype.drawDotted = function(x,y){
    46. this.cxt.beginPath()
    47. this.cxt.moveTo(x-this.dottedSize/2,y-this.dottedSize/2)
    48. this.cxt.lineTo(x+this.dottedSize/2,y-this.dottedSize/2)
    49. this.cxt.lineTo(x+this.dottedSize/2,y+this.dottedSize/2)
    50. this.cxt.lineTo(x-this.dottedSize/2,y+this.dottedSize/2)
    51. this.cxt.closePath()
    52. this.cxt.fill()
    53. }
    54. LineChart.prototype.line = function(data){
    55. if(!data.length){
    56. return
    57. }
    58. data.forEach(function (item,i) {
    59. item.x += this.x
    60. item.y = this.y - item.y
    61. this.drawDotted(item.x,item.y)
    62. }.bind(this))
    63. }
    64. LineChart.prototype.ligature = function (data) {
    65. console.log(data)
    66. for (var i = 1;i<data.length;i++){
    67. this.cxt.beginPath()
    68. this.cxt.moveTo(data[i-1].x,data[i-1].y)
    69. this.cxt.lineTo(data[i].x,data[i].y)
    70. this.cxt.stroke()
    71. }
    72. }
    73. LineChart.prototype.init = function (data) {
    74. this.gridding()
    75. this.coordinate()
    76. this.line(data)
    77. this.ligature(data)
    78. }
    79. var analogData = [
    80. {
    81. x: 50,
    82. y: 120
    83. },
    84. {
    85. x: 70,
    86. y: 160
    87. },
    88. {
    89. x: 90,
    90. y: 240
    91. },
    92. {
    93. x: 110,
    94. y: 20
    95. },
    96. {
    97. x: 300,
    98. y: 80
    99. }
    100. ];
    101. let lineChart = new LineChart()
    102. lineChart.init(analogData)

发表评论

表情:
评论列表 (有 0 条评论,756人围观)

还没有评论,来说两句吧...

相关阅读

    相关 html5 canvas 画布基础

    canvas 画布基础 学习整理的笔记,内容丰富 有绘制矩形,绘制线条,绘制二次贝塞尔曲线,绘制弧线等。知识点在代码注释中 效果图: ![Center][]