| <!DOCTYPE html> |
| <html> |
| <head> |
| <meta charset="utf-8"> |
| <title>原生JS实现动态折线图</title> |
| </head> |
| <body> |
| <canvas id="canvas"></canvas> |
| <script> |
| let N = new CreateMovingLineDiagram(); |
| |
| N.play(); |
| |
| function CreateMovingLineDiagram() { |
| let _this = this; |
| |
| _this.SetData = { |
| canvasid: "#canvas", |
| canvaswidth: 600, |
| canvasheight: 400, |
| segmentationNum: 50, |
| MoveSpeed: 100, |
| IsShowsegmentationBool: true, |
| IsCurveBool: true |
| } |
| _this.play = function() { |
| let canvas = document.querySelector(_this.SetData.canvasid); |
| canvas.width = _this.SetData.canvaswidth; |
| canvas.height = _this.SetData.canvasheight; |
| |
| let context = canvas.getContext("2d"); |
| let segmentation = _this.SetData.segmentationNum |
| let Speed = _this.SetData.MoveSpeed |
| let XYAttr = []; |
| let XZ = canvas.width / segmentation |
| let XW = 0; |
| let IsShowsegmentation = _this.SetData.IsShowsegmentationBool; |
| let IsCurve = _this.SetData.IsCurveBool; |
| |
| |
| for (var i = 0; i < segmentation + 1; i++) { |
| XYAttr.push({ |
| "X": XW, |
| "Y": canvas.height / 2 |
| }) |
| if (XW != canvas.width) { |
| XW += XZ; |
| } |
| } |
| |
| setInterval(function() { |
| canvas.height = canvas.height; |
| if (IsShowsegmentation) { |
| for (var i = 0; i < segmentation + 1; i++) { |
| |
| context.moveTo((i * XZ), 0); |
| context.lineTo((i * XZ), canvas.height) |
| context.strokeStyle = "#aaa"; |
| context.stroke(); |
| context.beginPath(); |
| } |
| } |
| |
| for (var i = 0; i < XYAttr.length; i++) { |
| if (IsCurve) { |
| |
| if (i > 0) { |
| context.beginPath(); |
| context.moveTo(XYAttr[i - 1].X, XYAttr[i - 1].Y); |
| context.quadraticCurveTo(XYAttr[i - 1].X, XYAttr[i].Y, XYAttr[i].X, XYAttr[i].Y); |
| |
| } |
| |
| } else { |
| |
| if (i > 0) { |
| context.beginPath(); |
| context.moveTo(XYAttr[i - 1].X, XYAttr[i - 1].Y); |
| context.lineTo(XYAttr[i].X, XYAttr[i].Y) |
| } |
| } |
| |
| context.strokeStyle = "coral"; |
| context.stroke(); |
| } |
| |
| XYAttr.splice(0, 1); |
| |
| round = Math.floor(Math.random() * canvas.height); |
| |
| for (var i = 0; i < XYAttr.length; i++) { |
| XYAttr[i].X = XYAttr[i].X - (XZ * 2) |
| } |
| |
| XYAttr.push({ |
| "X": XW, |
| "Y": round |
| }) |
| |
| }, Speed) |
| } |
| } |
| |
| |
| </script> |
| </body> |
| |
| </html> |
请看效果

【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性