FCFS调度算法可视化求助:修复节点连线及优化代码与输出
FCFS调度算法可视化:修复节点连线并优化效果
问题说明
我们正在开发基于JS、HTML、CSS的FCFS(先来先服务)调度算法可视化系统,当前代码可正常运行,但Canvas绘图中的节点无法实现连线,同时希望对代码和输出效果进行优化。
原代码问题分析
核心问题在于绘制节点时,每次调用ctx.beginPath()会重置当前路径,导致之前构建的连线路径被中断,最终无法形成连续的线条。
修复与优化后的完整代码
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>FCFS Scheduling Algorithm Visualization</title> <style> body { font-family: 'Arial', sans-serif; margin: 0; padding: 2rem; background-color: #f5f5f5; } .container { max-width: 800px; margin: 0 auto; background: white; padding: 2rem; border-radius: 8px; box-shadow: 0 2px 8px rgba(0,0,0,0.1); } h1 { color: #2c3e50; text-align: center; margin-bottom: 1.5rem; } .input-section { margin-bottom: 1.5rem; display: flex; gap: 0.5rem; flex-wrap: wrap; } #burstTimesInput { flex: 1; min-width: 250px; padding: 0.75rem; border: 1px solid #ddd; border-radius: 4px; font-size: 1rem; } button { padding: 0.75rem 1.5rem; background-color: #3498db; color: white; border: none; border-radius: 4px; cursor: pointer; font-size: 1rem; transition: background-color 0.2s; } button:hover { background-color: #2980b9; } canvas { border: 1px solid #eee; border-radius: 4px; width: 100%; height: auto; background-color: #fafafa; } </style> </head> <body> <div class="container"> <h1>FCFS Scheduling Algorithm</h1> <div class="input-section"> <p style="margin:0; flex-basis:100%;">Enter process burst times separated by commas:</p> <input type="text" id="burstTimesInput" placeholder="e.g., 5,3,2,4"> <button onclick="plotGraph()">Plot Graph</button> </div> <canvas id="graphCanvas" width="800" height="400"></canvas> </div> <script> function plotGraph() { const inputElement = document.getElementById('burstTimesInput'); const inputValue = inputElement.value.trim(); // 健壮的输入处理 if (!inputValue) { alert("Please enter at least one positive integer."); return; } const burstTimes = inputValue.split(',') .map(str => str.trim()) .filter(str => str !== '') .map(Number); if (!burstTimes.every(time => Number.isInteger(time) && time > 0)) { alert("Please enter positive integers only, separated by commas."); return; } const canvas = document.getElementById('graphCanvas'); const ctx = canvas.getContext('2d'); const padding = 60; const graphWidth = canvas.width - 2 * padding; const graphHeight = canvas.height - 2 * padding; const processWidth = graphWidth / burstTimes.length; const maxBurstTime = Math.max(...burstTimes); const scaleY = graphHeight / maxBurstTime; // 清空画布 ctx.clearRect(0, 0, canvas.width, canvas.height); // 绘制坐标轴 drawAxes(ctx, canvas.width, canvas.height, padding, graphHeight); // 初始化连线路径 ctx.beginPath(); ctx.strokeStyle = '#3498db'; ctx.lineWidth = 2; ctx.moveTo(padding, canvas.height - padding); // 起始点在坐标轴原点 // 绘制每个进程的节点和连线 burstTimes.forEach((time, index) => { const x = padding + (index + 1) * processWidth; const y = canvas.height - padding - time * scaleY; // 绘制连线(从之前的点到当前点) ctx.lineTo(x, y); // 绘制节点 drawNode(ctx, x, y); // 标注进程信息 drawLabels(ctx, x, y, time, index + 1, canvas.height - padding); }); // 完成连线绘制 ctx.stroke(); } // 绘制坐标轴 function drawAxes(ctx, width, height, padding, graphHeight) { ctx.beginPath(); ctx.strokeStyle = '#2c3e50'; ctx.lineWidth = 2; // X轴 ctx.moveTo(padding, height - padding); ctx.lineTo(width - padding, height - padding); // X轴箭头 ctx.lineTo(width - padding - 10, height - padding - 5); ctx.moveTo(width - padding, height - padding); ctx.lineTo(width - padding - 10, height - padding + 5); // Y轴 ctx.moveTo(padding, height - padding); ctx.lineTo(padding, padding); // Y轴箭头 ctx.lineTo(padding - 5, padding + 10); ctx.moveTo(padding, padding); ctx.lineTo(padding + 5, padding + 10); ctx.stroke(); // 坐标轴标签 ctx.fillStyle = '#2c3e50'; ctx.font = '14px Arial'; ctx.fillText('Processes', width/2 - 40, height - 10); ctx.save(); ctx.translate(15, height/2); ctx.rotate(-Math.PI/2); ctx.fillText('Burst Time', 0, 0); ctx.restore(); } // 绘制节点 function drawNode(ctx, x, y) { ctx.beginPath(); ctx.arc(x, y, 5, 0, Math.PI * 2); ctx.fillStyle = '#e74c3c'; ctx.fill(); ctx.strokeStyle = '#c0392b'; ctx.lineWidth = 1; ctx.stroke(); } // 标注进程编号和时间 function drawLabels(ctx, x, y, time, processNum, baseY) { ctx.fillStyle = '#2c3e50'; ctx.font = '12px Arial'; // 进程编号 ctx.fillText(`P${processNum}`, x - 15, baseY + 20); // Burst时间 ctx.fillText(time, x - 8, y - 10); } </script> </body> </html>
关键修改与优化点
- 修复连线问题:将节点绘制的路径与连线路径分离,仅在初始化连线和绘制节点时单独调用
beginPath(),避免重置连线的主路径,确保线条连续。 - 输入处理优化:增加空输入校验,处理输入中的空格,提升用户输入的容错性。
- 视觉效果优化:
- 美化页面布局,添加阴影、圆角和响应式设计
- 完善坐标轴绘制,添加箭头和标签
- 增大节点尺寸并添加描边,提升辨识度
- 为每个进程添加编号和Burst时间标注
- 使用动态比例计算Y轴刻度,适配不同的Burst时间范围
- 代码结构优化:将坐标轴、节点、标签绘制逻辑拆分为独立函数,提升代码可读性和可维护性。
内容的提问来源于stack exchange,提问作者Oraora Mudamuda
相关产品推荐
相关产品推荐

