2026/1/22 1:33:19
网站建设
项目流程
建设银行官网首页网站招聘,2024年还有新冠吗,wordpress5.2多站点设置方法,有哪些可以做策划方案的网站在日常运维、演示或监控系统中#xff0c;我们经常需要一种**“像真实终端一样滚动的日志界面”**#xff0c;用于#xff1a;
运维大屏 / NOC 展示Demo / 产品演示系统状态背景动画DevOps / 云原生场景模拟
本文将完整解析一个基于 HTML Canvas 的终端日志流可视化方案我们经常需要一种**“像真实终端一样滚动的日志界面”**用于运维大屏 / NOC 展示Demo / 产品演示系统状态背景动画DevOps / 云原生场景模拟本文将完整解析一个基于 HTML Canvas 的终端日志流可视化方案支持多 Pane 并行日志流Docker / Kubernetes / System 日志配置错误率、速度实时调节隐藏式 Ops 运维控制面板无需任何第三方库纯前端实现。一、整体效果与设计思路核心目标只有一个在浏览器中低成本、高性能地模拟“真实系统日志滚动”。设计原则使用Canvas而非 DOM避免频繁节点重排日志按 Pane 独立渲染支持横向扩展配置统一由全局config控制运维参数通过隐藏面板动态调整二、整体架构说明逻辑结构可以抽象为四层Config全局参数 ↓ Profile日志模板 ↓ LogPane单个 Canvas 日志面板 ↓ Pane Manager多 Pane 管理 主循环三、HTML 与 CSS终端级视觉基础1. 全屏终端布局html, body{margin:0;height:100%;background:#050607;overflow:hidden;font-family:JetBrains Mono,Consolas,monospace;}深色背景贴近 Linux / Ops 场景使用等宽字体保证日志对齐2. 多 Pane 网格容器#container{display:grid;grid-template-columns:repeat(var(--panes,2),1fr);gap:1px;}通过 CSS 变量--panes实现14 个日志窗口动态切换。四、日志 Profile模拟真实系统日志constprofiles{docker:{info:[container started,image pulled],warn:[restart policy triggered],error:[container exited with code 137]},k8s:{info:[pod scheduled],warn:[node pressure detected],error:[pod evicted]}};这样设计的好处一行代码即可切换“系统类型”可快速扩展真实日志语料非硬编码适合产品化五、LogPaneCanvas 日志核心类这是整个系统最关键的部分。1. 日志写入逻辑push(){constpprofiles[config.profile];letlevelinfo;if(Math.random()config.errorRate)levelerror;elseif(Math.random()0.2)levelwarn;this.logs.push({time:newDate().toISOString().slice(11,19),level,msg:p[level][Math.random()*p[level].length|0],highlight:true});}特点错误率可控适合演示系统“不稳定性”每条日志带高亮标记时间戳模拟真实终端格式2. Canvas 绘制与滚动效果draw(){ctx.fillStylergba(5,6,7,0.35);ctx.fillRect(0,0,w,h);}这里使用半透明覆盖而非清屏形成轻微拖影类似真实终端刷新残影高性能无闪烁不同级别日志颜色区分INFO绿色WARN黄色ERROR红色六、多 Pane 管理与自适应functionrebuildPanes(){container.innerHTML;for(leti0;iconfig.panes;i){constcanvasdocument.createElement(canvas);container.appendChild(canvas);panes.push(newLogPane(canvas));}}支持运行中动态切换1 Pane单终端2 Pane常见演示4 Pane监控大屏七、隐藏式运维控制面板Ops Mode这是一个非常“工程味”的设计。快捷键触发Ctrl Shift L面板可调参数日志速度Log Speed错误率Error RatePane 数量日志 Profile适合内部演示运维人员调试不暴露给普通用户八、主循环与性能控制functionanimate(){panes.forEach(p{if(Math.random()0.6*config.speed)p.push();p.draw();});requestAnimationFrame(animate);}优势使用requestAnimationFrame不阻塞主线程低端设备也可流畅运行九、典型应用场景DevOps 产品官网背景工业互联网 / IoT 数据演示云平台控制台动效运维培训或售前 Demo科技风网站首页视觉十、可扩展方向如果你打算进一步工程化可以考虑接入 WebSocket 实时日志支持 ANSI 终端颜色解析增加日志搜索 / 过滤与真实 Docker / K8s API 对接封装为 Vue / React 组件总结本文展示了一个纯前端、零依赖、高性能的终端日志流可视化方案非常适合用于技术展示运维演示工业 / 云原生产品视觉层如果你正在做DevOps、工业数据采集、云平台、系统监控相关产品这个实现可以直接作为基础组件使用。!DOCTYPEhtmlhtmllangzh-CNheadmetacharsetUTF-8/titleTerminal Log Stream — Ops Mode/titlestylehtml, body{margin:0;height:100%;background:#050607;overflow:hidden;font-family:JetBrains Mono,Consolas,monospace;}#container{position:fixed;inset:0;display:grid;grid-template-columns:repeat(var(--panes,2),1fr);gap:1px;background:#000;}canvas{width:100%;height:100%;background:#050607;}/* 运维面板隐藏 */.panel{position:fixed;top:16px;right:16px;width:260px;background:rgba(10,20,30,0.85);border:1px solidrgba(120,180,255,0.25);border-radius:10px;padding:14px;color:#cfe6ff;font-size:12px;opacity:0;transform:translateY(-8px);pointer-events:none;transition:0.25s;}.panel.active{opacity:1;transform:translateY(0);pointer-events:auto;}.panel h3{margin:0 0 10px;font-size:14px;}.panel label{display:block;margin-top:10px;}.panel input[typerange], .panel select{width:100%;}/style/headbodydividcontainer/divdivclasspanelh3Ops Control/h3labelLog Speedinputtyperangeidspeedmin0.2max2step0.1value1//labellabelError Rateinputtyperangeiderrormin0max0.2step0.01value0.05//labellabelPanesselectidpanesoptionvalue11/optionoptionvalue2selected2/optionoptionvalue33/optionoptionvalue44/option/select/labellabelProfileselectidprofileoptionvaluedockerDocker/optionoptionvaluek8sKubernetes/optionoptionvaluesystemSystem/option/select/label/divscript/* 全局配置 */constconfig{speed:1,errorRate:0.05,panes:2,profile:docker,};/* 日志模板 */constprofiles{docker:{info:[container started,image pulled,health check ok],warn:[restart policy triggered],error:[container exited with code 137],},k8s:{info:[pod scheduled,service synced],warn:[node pressure detected],error:[pod evicted],},system:{info:[service started,job completed],warn:[high cpu usage],error:[kernel panic detected],},};/* Pane 类 */classLogPane{constructor(canvas){this.canvascanvas;this.ctxcanvas.getContext(2d);this.logs[];this.fontSize12;this.lineHeight16;}resize(){this.canvas.widththis.canvas.clientWidth;this.canvas.heightthis.canvas.clientHeight;this.maxLinesMath.floor(this.canvas.height/this.lineHeight);}push(){constpprofiles[config.profile];letlevelinfo;if(Math.random()config.errorRate){levelerror;}elseif(Math.random()0.2){levelwarn;}constmsgp[level][Math.floor(Math.random()*p[level].length)];this.logs.push({time:newDate().toISOString().slice(11,19),level,msg,highlight:true,});if(this.logs.lengththis.maxLines){this.logs.shift();}}draw(){constctxthis.ctx;ctx.fillStylergba(5, 6, 7, 0.35);ctx.fillRect(0,0,this.canvas.width,this.canvas.height);ctx.font${this.fontSize}px monospace;this.logs.forEach((l,i){constcolorl.levelerror?255,80,80:l.levelwarn?255,200,80:180,220,180;ctx.fillStylergba(${color},${l.highlight?1:0.85});l.highlightfalse;ctx.fillText([${l.time}]${l.level.toUpperCase()}${l.msg},8,(i1)*this.lineHeight);});}}/* Pane 管理 */constcontainerdocument.getElementById(container);letpanes[];functionrebuildPanes(){container.innerHTML;container.style.setProperty(--panes,config.panes);panes[];for(leti0;iconfig.panes;i){constcanvasdocument.createElement(canvas);container.appendChild(canvas);constpanenewLogPane(canvas);pane.resize();panes.push(pane);}}rebuildPanes();window.addEventListener(resize,()panes.forEach((p)p.resize()));/* 运维面板绑定 */document.getElementById(speed).oninput(e)(config.speede.target.value);document.getElementById(error).oninput(e)(config.errorRatee.target.value);document.getElementById(panes).onchange(e){config.panese.target.value;rebuildPanes();};document.getElementById(profile).onchange(e)(config.profilee.target.value);/* 隐藏式运维模式 */constpaneldocument.querySelector(.panel);letpanelVisiblefalse;document.addEventListener(keydown,(e){if(e.ctrlKeye.shiftKeye.codeKeyL){panelVisible!panelVisible;panel.classList.toggle(active,panelVisible);}});/* 主循环 */functionanimate(){panes.forEach((p){if(Math.random()0.6*config.speed){p.push();}p.draw();});requestAnimationFrame(animate);}animate();/script/body/html