Initial commit

This commit is contained in:
xixu-me committed 2024-11-27 10:13:38 +08:00
1 parent d38ac87454
commit 07cb6335c4
3 files changed
+406

No files matched your search

+63
View File
@@ -0,0 +1,63 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>磁盘调度算法可视化</title>
<link rel="stylesheet" href="styles.css" />
</head>
<body>
<div class="container">
<h1>磁盘调度算法可视化</h1>
<div class="controls">
<div class="input-row">
<label>磁头初始位置:</label>
<input
type="number"
id="initialHead"
value="50"
min="0"
max="199"
/>
<label>请求队列:</label>
<input
type="text"
id="requestQueue"
value="82,170,43,140,24,16,190"
placeholder="用逗号分隔的数字"
/>
</div>
<div class="buttons-row">
<button onclick="reset()">重置</button>
<button onclick="startFCFS()">开始 FCFS</button>
<button onclick="startSSTF()">开始 SSTF</button>
<button onclick="startSCAN()">开始 SCAN</button>
<label>SCAN 初始方向:</label>
<select id="scanDirection">
<option value="right">向右</option>
<option value="left">向左</option>
</select>
</div>
</div>
<div class="disk-track" id="diskTrack">
<div class="head" id="head"></div>
</div>
<div id="stats">
<div class="stat-item">
<span>总寻道时间:</span>
<span class="stat-value" id="seekTime">0</span>
</div>
<div class="stat-item">
<span>当前位置:</span>
<span class="stat-value" id="currentPos">0</span>
</div>
</div>
</div>
<script src="script.js"></script>
</body>
</html>
+207
View File
@@ -0,0 +1,207 @@
let head;
let requests = [];
let currentIndex = 0;
let seekTime = 0;
let direction = 1; // 1 for right, -1 for left
let animationInterval;
function initialize() {
head = document.getElementById("head");
const diskTrack = document.getElementById("diskTrack");
const trackWidth = diskTrack.offsetWidth;
const headWidth = 12;
// Clear existing requests
const existingRequests = document.querySelectorAll(".request");
existingRequests.forEach((req) => req.remove());
// Get initial head position and requests
const initialHead = parseInt(document.getElementById("initialHead").value);
const requestInput = document.getElementById("requestQueue").value;
requests = requestInput.split(",").map((x) => parseInt(x.trim()));
// Set initial head position
const headPosition = (initialHead / 199) * trackWidth;
head.style.left = headPosition + "px";
// Place request points
requests.forEach((pos) => {
const request = document.createElement("div");
request.className = "request";
request.style.left = (pos / 199) * trackWidth + "px";
diskTrack.appendChild(request);
});
// Reset statistics
seekTime = 0;
currentIndex = 0;
direction = 1;
updateStats(initialHead);
}
function updateStats(position) {
document.getElementById("seekTime").textContent = seekTime;
document.getElementById("currentPos").textContent = position;
}
function startFCFS() {
reset();
const diskTrack = document.getElementById("diskTrack");
const trackWidth = diskTrack.offsetWidth;
const headWidth = 12;
const initialHead = parseInt(document.getElementById("initialHead").value);
let currentPosition = initialHead;
let currentRequestIndex = 0;
animationInterval = setInterval(() => {
if (currentRequestIndex >= requests.length) {
clearInterval(animationInterval);
return;
}
const targetPosition = requests[currentRequestIndex];
const targetPixel = (targetPosition / 199) * trackWidth;
seekTime += Math.abs(targetPosition - currentPosition);
currentPosition = targetPosition;
head.style.left = targetPixel + "px";
const requestElements = document.querySelectorAll(".request");
requestElements.forEach((req) => {
const reqPos =
((parseFloat(req.style.left) - headWidth / 2) /
(trackWidth - headWidth)) *
199;
if (Math.abs(reqPos - targetPosition) < 1) {
req.classList.add("served");
}
});
direction = currentPosition > targetPosition ? -1 : 1;
updateStats(targetPosition);
currentRequestIndex++;
}, 1000);
}
function startSSTF() {
reset();
const diskTrack = document.getElementById("diskTrack");
const trackWidth = diskTrack.offsetWidth;
const headWidth = 12;
const initialHead = parseInt(document.getElementById("initialHead").value);
let currentPosition = initialHead;
let remainingRequests = [...requests];
animationInterval = setInterval(() => {
if (remainingRequests.length === 0) {
clearInterval(animationInterval);
return;
}
let closestRequest = remainingRequests.reduce((closest, current) => {
let closestDistance = Math.abs(closest - currentPosition);
let currentDistance = Math.abs(current - currentPosition);
return currentDistance < closestDistance ? current : closest;
});
remainingRequests = remainingRequests.filter(
(req) => req !== closestRequest
);
const targetPixel = (closestRequest / 199) * trackWidth;
seekTime += Math.abs(closestRequest - currentPosition);
currentPosition = closestRequest;
head.style.left = targetPixel + "px";
const requests = document.querySelectorAll(".request");
requests.forEach((req) => {
const reqPos =
((parseFloat(req.style.left) - headWidth / 2) /
(trackWidth - headWidth)) *
199;
if (Math.abs(reqPos - closestRequest) < 1) {
req.classList.add("served");
}
});
direction = currentPosition > closestRequest ? -1 : 1;
updateStats(closestRequest);
}, 1000);
}
function startSCAN() {
reset();
const diskTrack = document.getElementById("diskTrack");
const trackWidth = diskTrack.offsetWidth;
const headWidth = 12;
const initialHead = parseInt(document.getElementById("initialHead").value);
const initialDirection = document.getElementById("scanDirection").value;
let currentPosition = initialHead;
let sortedRequests = [...requests].sort((a, b) => a - b);
let headIndex = sortedRequests.findIndex((x) => x >= initialHead);
if (headIndex === -1) headIndex = sortedRequests.length;
let scanOrder;
if (initialDirection === "right") {
scanOrder = [
...sortedRequests.slice(headIndex),
...sortedRequests.slice(0, headIndex).reverse(),
];
direction = 1;
} else {
scanOrder = [
...sortedRequests.slice(0, headIndex).reverse(),
...sortedRequests.slice(headIndex),
];
direction = -1;
}
let currentRequestIndex = 0;
animationInterval = setInterval(() => {
if (currentRequestIndex >= scanOrder.length) {
clearInterval(animationInterval);
return;
}
const targetPosition = scanOrder[currentRequestIndex];
const targetPixel = (targetPosition / 199) * trackWidth;
seekTime += Math.abs(targetPosition - currentPosition);
currentPosition = targetPosition;
head.style.left = targetPixel + "px";
const requests = document.querySelectorAll(".request");
requests.forEach((req) => {
const reqPos =
((parseFloat(req.style.left) - headWidth / 2) /
(trackWidth - headWidth)) *
199;
if (Math.abs(reqPos - targetPosition) < 1) {
req.classList.add("served");
}
});
updateStats(targetPosition);
currentRequestIndex++;
}, 1000);
}
function reset() {
if (animationInterval) {
clearInterval(animationInterval);
}
initialize();
}
function markRequestAsServed(request) {
request.classList.add("served");
request.style.animation = "pulse 0.3s ease";
}
window.onload = initialize;
+136
View File
@@ -0,0 +1,136 @@
body {
font-family: "Segoe UI", system-ui, sans-serif;
max-width: 1200px;
margin: 0 auto;
padding: 20px;
background-color: #f8f9fa;
color: #212529;
}
h1 {
text-align: center;
margin-bottom: 2rem;
}
.container {
background-color: white;
padding: 2rem;
border-radius: 12px;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
}
.disk-track {
position: relative;
width: 100%;
height: 80px;
background: linear-gradient(to right, #e9ecef, #dee2e6);
border-radius: 8px;
margin: 2rem 0;
}
.head {
position: absolute;
width: 12px;
height: 50px;
background: linear-gradient(45deg, #ff4d4d, #ff6b6b);
border-radius: 6px;
top: 15px;
transform: translateX(-50%);
transition: left 0.4s cubic-bezier(0.4, 0, 0.2, 1);
box-shadow: 0 2px 8px rgba(255, 77, 77, 0.3);
}
.request {
position: absolute;
width: 12px;
height: 12px;
background-color: #339af0;
border-radius: 50%;
top: 34px;
transform: translateX(-50%);
transition: background-color 0.3s ease;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
.served {
background-color: #51cf66;
transform: translateX(-50%) scale(1.2);
}
.controls {
background-color: #f8f9fa;
padding: 1.5rem;
border-radius: 8px;
border: 1px solid #dee2e6;
}
.input-row {
display: grid;
grid-template-columns: auto 1fr;
gap: 1rem;
margin-bottom: 1rem;
}
.buttons-row {
display: flex;
flex-wrap: wrap;
gap: 12px;
align-items: center;
}
button {
padding: 10px 20px;
background: linear-gradient(45deg, #339af0, #228be6);
color: white;
border: none;
border-radius: 6px;
cursor: pointer;
font-weight: 500;
transition: transform 0.2s, box-shadow 0.2s;
}
button:hover {
transform: translateY(-1px);
box-shadow: 0 4px 12px rgba(34, 139, 230, 0.2);
}
input,
select {
padding: 8px 12px;
border: 1px solid #dee2e6;
border-radius: 6px;
font-size: 14px;
transition: border-color 0.2s;
}
input:focus,
select:focus {
outline: none;
border-color: #339af0;
box-shadow: 0 0 0 3px rgba(51, 154, 240, 0.1);
}
#stats {
margin-top: 1.5rem;
padding: 1.5rem;
background-color: #f8f9fa;
border-radius: 8px;
border: 1px solid #dee2e6;
}
.stat-item {
display: flex;
justify-content: space-between;
margin-bottom: 0.5rem;
}
.stat-value {
font-weight: 600;
color: #339af0;
}
@keyframes pulse {
0% { transform: translateX(-50%) scale(1); }
50% { transform: translateX(-50%) scale(1.3); }
100% { transform: translateX(-50%) scale(1.2); }
}