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