You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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>

关键修改与优化点

  1. 修复连线问题:将节点绘制的路径与连线路径分离,仅在初始化连线和绘制节点时单独调用beginPath(),避免重置连线的主路径,确保线条连续。
  2. 输入处理优化:增加空输入校验,处理输入中的空格,提升用户输入的容错性。
  3. 视觉效果优化:
    • 美化页面布局,添加阴影、圆角和响应式设计
    • 完善坐标轴绘制,添加箭头和标签
    • 增大节点尺寸并添加描边,提升辨识度
    • 为每个进程添加编号和Burst时间标注
    • 使用动态比例计算Y轴刻度,适配不同的Burst时间范围
  4. 代码结构优化:将坐标轴、节点、标签绘制逻辑拆分为独立函数,提升代码可读性和可维护性。

内容的提问来源于stack exchange,提问作者Oraora Mudamuda

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 09:54:54