diff --git a/index.html b/index.html new file mode 100644 index 0000000..85b6022 --- /dev/null +++ b/index.html @@ -0,0 +1,63 @@ + + + + + + 磁盘调度算法可视化 + + + +
+

磁盘调度算法可视化

+ +
+
+ + + + + +
+ +
+ + + + + + +
+
+ +
+ +
+ +
+
+ 总寻道时间: + 0 +
+
+ 当前位置: + 0 +
+
+
+ + + diff --git a/script.js b/script.js new file mode 100644 index 0000000..b1ac06a --- /dev/null +++ b/script.js @@ -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; diff --git a/styles.css b/styles.css new file mode 100644 index 0000000..6f08ac7 --- /dev/null +++ b/styles.css @@ -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); } +} \ No newline at end of file