koesan commited on
Commit
e5dcade
·
verified ·
1 Parent(s): 470ff46

Update templates/index.html

Browse files
Files changed (1) hide show
  1. templates/index.html +229 -91
templates/index.html CHANGED
@@ -31,21 +31,6 @@
31
  border-radius: 10px;
32
  margin-bottom: 20px;
33
  }
34
- .slider-container {
35
- margin: 15px 0;
36
- }
37
- .slider-label {
38
- font-weight: 600;
39
- color: #495057;
40
- margin-bottom: 5px;
41
- }
42
- .slider-value {
43
- display: inline-block;
44
- min-width: 30px;
45
- text-align: center;
46
- font-weight: bold;
47
- color: #667eea;
48
- }
49
  .btn-find {
50
  width: 100%;
51
  padding: 12px;
@@ -53,15 +38,24 @@
53
  font-weight: bold;
54
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
55
  border: none;
56
- margin-top: 20px;
57
  }
58
  .btn-find:hover {
59
  transform: translateY(-2px);
60
  box-shadow: 0 5px 15px rgba(102, 126, 234, 0.4);
61
  }
62
- #resultImage {
63
- max-width: 100%;
 
 
 
 
 
 
 
64
  border-radius: 10px;
 
 
65
  box-shadow: 0 5px 20px rgba(0,0,0,0.1);
66
  }
67
  .info-box {
@@ -76,7 +70,7 @@
76
  font-weight: bold;
77
  }
78
  .algorithm-btn {
79
- margin: 5px;
80
  }
81
  .loading {
82
  display: none;
@@ -86,13 +80,54 @@
86
  .spinner-border {
87
  color: #667eea;
88
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
89
  </style>
90
  </head>
91
  <body>
92
  <div class="container">
93
  <div class="header">
94
  <h1>🗺️ Path Finding Algorithms Visualizer</h1>
95
- <p class="text-muted">Select start and goal positions, choose an algorithm, and visualize the shortest path!</p>
 
 
 
 
 
 
96
  </div>
97
 
98
  <div class="row">
@@ -101,12 +136,12 @@
101
  <h5 class="mb-3">⚙️ Settings</h5>
102
 
103
  <!-- Algorithm Selection -->
104
- <div class="mb-4">
105
- <label class="slider-label">🎯 Algorithm</label>
106
  <div class="btn-group-vertical w-100" role="group">
107
  <input type="radio" class="btn-check" name="algorithm" id="astar" value="A*" checked>
108
  <label class="btn btn-outline-primary algorithm-btn" for="astar">
109
- A* (Fastest)
110
  </label>
111
 
112
  <input type="radio" class="btn-check" name="algorithm" id="dijkstra" value="Dijkstra">
@@ -118,53 +153,42 @@
118
  <label class="btn btn-outline-danger algorithm-btn" for="bellman">
119
  Bellman-Ford (Robust)
120
  </label>
121
- </div>
122
- </div>
123
 
124
- <!-- Start Position -->
125
- <h6 class="mt-4">📍 Start Position</h6>
126
- <div class="slider-container">
127
- <label class="slider-label">
128
- X: <span class="slider-value" id="startXValue">0</span>
129
- </label>
130
- <input type="range" class="form-range" id="startX" min="0" max="11" value="0">
131
- </div>
132
- <div class="slider-container">
133
- <label class="slider-label">
134
- Y: <span class="slider-value" id="startYValue">7</span>
135
- </label>
136
- <input type="range" class="form-range" id="startY" min="0" max="7" value="7">
137
  </div>
138
 
139
- <!-- Goal Position -->
140
- <h6 class="mt-4">🎯 Goal Position</h6>
141
- <div class="slider-container">
142
- <label class="slider-label">
143
- X: <span class="slider-value" id="goalXValue">11</span>
144
- </label>
145
- <input type="range" class="form-range" id="goalX" min="0" max="11" value="11">
146
- </div>
147
- <div class="slider-container">
148
- <label class="slider-label">
149
- Y: <span class="slider-value" id="goalYValue">0</span>
150
- </label>
151
- <input type="range" class="form-range" id="goalY" min="0" max="7" value="0">
152
  </div>
153
 
154
- <!-- Find Path Button -->
155
- <button class="btn btn-primary btn-find" onclick="findPath()">
156
  🔍 Find Path
157
  </button>
 
 
 
158
 
159
  <!-- Info Box -->
160
  <div class="info-box">
161
- <h6>📝 Grid Info</h6>
162
  <ul class="small mb-0">
163
- <li><strong>Size:</strong> 12x8 cells</li>
 
 
 
164
  <li><strong>Cost Range:</strong> 1-9</li>
165
- <li><strong>Green:</strong> Start</li>
166
- <li><strong>Red:</strong> Goal</li>
167
- <li><strong>Blue/Orange/Red:</strong> Path</li>
168
  </ul>
169
  </div>
170
  </div>
@@ -172,15 +196,15 @@
172
 
173
  <div class="col-lg-8">
174
  <div class="visualization-panel">
175
- <h5 class="mb-3">🗺️ Visualization</h5>
176
  <div id="loading" class="loading">
177
  <div class="spinner-border" role="status">
178
  <span class="visually-hidden">Loading...</span>
179
  </div>
180
  <p class="mt-3">Calculating path...</p>
181
  </div>
182
- <div id="imageContainer">
183
- <img id="resultImage" src="" alt="Path visualization will appear here">
184
  </div>
185
  </div>
186
  </div>
@@ -189,36 +213,143 @@
189
 
190
  <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
191
  <script>
192
- // Update slider values
193
- document.getElementById('startX').addEventListener('input', function() {
194
- document.getElementById('startXValue').textContent = this.value;
195
- });
196
- document.getElementById('startY').addEventListener('input', function() {
197
- document.getElementById('startYValue').textContent = this.value;
198
- });
199
- document.getElementById('goalX').addEventListener('input', function() {
200
- document.getElementById('goalXValue').textContent = this.value;
201
- });
202
- document.getElementById('goalY').addEventListener('input', function() {
203
- document.getElementById('goalYValue').textContent = this.value;
204
- });
205
 
206
- // Load initial visualization
207
  window.onload = function() {
208
- findPath();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
209
  };
210
 
211
- // Find Path function
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
212
  async function findPath() {
213
- const startX = document.getElementById('startX').value;
214
- const startY = document.getElementById('startY').value;
215
- const goalX = document.getElementById('goalX').value;
216
- const goalY = document.getElementById('goalY').value;
 
217
  const algorithm = document.querySelector('input[name="algorithm"]:checked').value;
218
 
219
  // Show loading
220
  document.getElementById('loading').style.display = 'block';
221
- document.getElementById('imageContainer').style.display = 'none';
222
 
223
  try {
224
  const response = await fetch('/find_path', {
@@ -227,31 +358,38 @@
227
  'Content-Type': 'application/json',
228
  },
229
  body: JSON.stringify({
230
- start_x: startX,
231
- start_y: startY,
232
- goal_x: goalX,
233
- goal_y: goalY,
234
  algorithm: algorithm
235
  })
236
  });
237
 
238
  const data = await response.json();
239
 
240
- // Hide loading, show image
241
  document.getElementById('loading').style.display = 'none';
242
- document.getElementById('imageContainer').style.display = 'block';
243
 
244
  if (data.error) {
245
  alert('Error: ' + data.error);
246
- console.error('Server error:', data.error);
247
  } else {
248
- document.getElementById('resultImage').src = data.image;
 
 
 
 
 
 
 
 
249
  }
250
  } catch (error) {
251
  console.error('Error:', error);
252
  alert('An error occurred: ' + error.message);
253
  document.getElementById('loading').style.display = 'none';
254
- document.getElementById('imageContainer').style.display = 'block';
255
  }
256
  }
257
  </script>
 
31
  border-radius: 10px;
32
  margin-bottom: 20px;
33
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
34
  .btn-find {
35
  width: 100%;
36
  padding: 12px;
 
38
  font-weight: bold;
39
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
40
  border: none;
41
+ margin-top: 10px;
42
  }
43
  .btn-find:hover {
44
  transform: translateY(-2px);
45
  box-shadow: 0 5px 15px rgba(102, 126, 234, 0.4);
46
  }
47
+ .btn-clear {
48
+ width: 100%;
49
+ padding: 12px;
50
+ font-size: 18px;
51
+ font-weight: bold;
52
+ margin-top: 10px;
53
+ }
54
+ #mapCanvas {
55
+ border: 3px solid #667eea;
56
  border-radius: 10px;
57
+ cursor: crosshair;
58
+ max-width: 100%;
59
  box-shadow: 0 5px 20px rgba(0,0,0,0.1);
60
  }
61
  .info-box {
 
70
  font-weight: bold;
71
  }
72
  .algorithm-btn {
73
+ margin: 5px 0;
74
  }
75
  .loading {
76
  display: none;
 
80
  .spinner-border {
81
  color: #667eea;
82
  }
83
+ .point-indicator {
84
+ padding: 10px;
85
+ border-radius: 5px;
86
+ margin: 5px 0;
87
+ font-weight: bold;
88
+ }
89
+ .start-indicator {
90
+ background: #d4edda;
91
+ color: #155724;
92
+ }
93
+ .goal-indicator {
94
+ background: #f8d7da;
95
+ color: #721c24;
96
+ }
97
+ .github-link {
98
+ display: inline-flex;
99
+ align-items: center;
100
+ gap: 8px;
101
+ color: #667eea;
102
+ text-decoration: none;
103
+ font-weight: 600;
104
+ font-size: 1.em;
105
+ padding: 10px 20px;
106
+ background: white;
107
+ border: 2px solid #667eea;
108
+ border-radius: 8px;
109
+ transition: all 0.3s;
110
+ margin: 10px 0;
111
+ }
112
+ .github-link:hover {
113
+ transform: translateY(-2px);
114
+ box-shadow: 0 4px 12px rgba(102, 126, 234, 0.3);
115
+ background: #667eea;
116
+ color: white;
117
+ }
118
  </style>
119
  </head>
120
  <body>
121
  <div class="container">
122
  <div class="header">
123
  <h1>🗺️ Path Finding Algorithms Visualizer</h1>
124
+ <p class="text-muted">Click on the map to set start (green) and goal (red) points!</p>
125
+ <a href="https://github.com/koesan/Path_Finding" target="_blank" class="github-link">
126
+ <svg width="24" height="24" viewBox="0 0 24 24" fill="currentColor">
127
+ <path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"/>
128
+ </svg>
129
+ View on GitHub
130
+ </a>
131
  </div>
132
 
133
  <div class="row">
 
136
  <h5 class="mb-3">⚙️ Settings</h5>
137
 
138
  <!-- Algorithm Selection -->
139
+ <div class="mb-3">
140
+ <label class="form-label fw-bold">🎯 Algorithm</label>
141
  <div class="btn-group-vertical w-100" role="group">
142
  <input type="radio" class="btn-check" name="algorithm" id="astar" value="A*" checked>
143
  <label class="btn btn-outline-primary algorithm-btn" for="astar">
144
+ A* (Heuristic)
145
  </label>
146
 
147
  <input type="radio" class="btn-check" name="algorithm" id="dijkstra" value="Dijkstra">
 
153
  <label class="btn btn-outline-danger algorithm-btn" for="bellman">
154
  Bellman-Ford (Robust)
155
  </label>
 
 
156
 
157
+ <input type="radio" class="btn-check" name="algorithm" id="qlearning" value="Q-Learning">
158
+ <label class="btn btn-outline-success algorithm-btn" for="qlearning">
159
+ Q-Learning (ML)
160
+ </label>
161
+ </div>
 
 
 
 
 
 
 
 
162
  </div>
163
 
164
+ <!-- Selected Points -->
165
+ <div class="mb-3">
166
+ <label class="form-label fw-bold">📍 Selected Points</label>
167
+ <div id="startPoint" class="point-indicator start-indicator">
168
+ 🟢 Start: Click on map
169
+ </div>
170
+ <div id="goalPoint" class="point-indicator goal-indicator">
171
+ 🔴 Goal: Click on map
172
+ </div>
 
 
 
 
173
  </div>
174
 
175
+ <!-- Buttons -->
176
+ <button class="btn btn-primary btn-find" onclick="findPath()" id="findBtn" disabled>
177
  🔍 Find Path
178
  </button>
179
+ <button class="btn btn-secondary btn-clear" onclick="clearPoints()">
180
+ 🗑️ Clear Points
181
+ </button>
182
 
183
  <!-- Info Box -->
184
  <div class="info-box">
185
+ <h6>📝 How to Use</h6>
186
  <ul class="small mb-0">
187
+ <li><strong>First Click:</strong> Set Start (Green)</li>
188
+ <li><strong>Second Click:</strong> Set Goal (Red)</li>
189
+ <li><strong>Path:</strong> Blue line</li>
190
+ <li><strong>Grid Size:</strong> 12x8 cells</li>
191
  <li><strong>Cost Range:</strong> 1-9</li>
 
 
 
192
  </ul>
193
  </div>
194
  </div>
 
196
 
197
  <div class="col-lg-8">
198
  <div class="visualization-panel">
199
+ <h5 class="mb-3">🗺️ Map (Click to set points)</h5>
200
  <div id="loading" class="loading">
201
  <div class="spinner-border" role="status">
202
  <span class="visually-hidden">Loading...</span>
203
  </div>
204
  <p class="mt-3">Calculating path...</p>
205
  </div>
206
+ <div id="canvasContainer" style="position: relative;">
207
+ <canvas id="mapCanvas"></canvas>
208
  </div>
209
  </div>
210
  </div>
 
213
 
214
  <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
215
  <script>
216
+ const COLS = 12;
217
+ const ROWS = 8;
218
+ let canvas, ctx;
219
+ let startPoint = null;
220
+ let goalPoint = null;
221
+ let mapImage = null;
222
+ let clickCount = 0;
 
 
 
 
 
 
223
 
224
+ // Initialize canvas
225
  window.onload = function() {
226
+ canvas = document.getElementById('mapCanvas');
227
+ ctx = canvas.getContext('2d');
228
+
229
+ // Load background image
230
+ mapImage = new Image();
231
+ mapImage.crossOrigin = 'anonymous';
232
+ mapImage.onload = function() {
233
+ canvas.width = mapImage.width;
234
+ canvas.height = mapImage.height;
235
+ drawCanvas();
236
+ };
237
+ mapImage.src = '/static/images/map.jpg';
238
+
239
+ // Add click listener
240
+ canvas.addEventListener('click', handleCanvasClick);
241
  };
242
 
243
+ function handleCanvasClick(event) {
244
+ const rect = canvas.getBoundingClientRect();
245
+ const scaleX = canvas.width / rect.width;
246
+ const scaleY = canvas.height / rect.height;
247
+
248
+ const clickX = (event.clientX - rect.left) * scaleX;
249
+ const clickY = (event.clientY - rect.top) * scaleY;
250
+
251
+ // Calculate grid cell
252
+ const cellX = Math.floor(clickX / (canvas.width / COLS));
253
+ const cellY = Math.floor(clickY / (canvas.height / ROWS));
254
+
255
+ if (cellX < 0 || cellX >= COLS || cellY < 0 || cellY >= ROWS) return;
256
+
257
+ if (clickCount === 0) {
258
+ // First click - set start
259
+ startPoint = { x: cellX, y: cellY };
260
+ document.getElementById('startPoint').textContent = `🟢 Start: (${cellX}, ${cellY})`;
261
+ clickCount = 1;
262
+ } else {
263
+ // Second click - set goal
264
+ goalPoint = { x: cellX, y: cellY };
265
+ document.getElementById('goalPoint').textContent = `🔴 Goal: (${cellX}, ${cellY})`;
266
+ clickCount = 0;
267
+ document.getElementById('findBtn').disabled = false;
268
+ }
269
+
270
+ drawCanvas();
271
+ }
272
+
273
+ function drawCanvas() {
274
+ if (!mapImage || !mapImage.complete) return;
275
+
276
+ // Clear canvas
277
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
278
+
279
+ // Draw background image
280
+ ctx.drawImage(mapImage, 0, 0, canvas.width, canvas.height);
281
+
282
+ const cellWidth = canvas.width / COLS;
283
+ const cellHeight = canvas.height / ROWS;
284
+
285
+ // Draw start point (green)
286
+ if (startPoint) {
287
+ ctx.fillStyle = '#00FF00';
288
+ ctx.beginPath();
289
+ ctx.arc(
290
+ (startPoint.x + 0.5) * cellWidth,
291
+ (startPoint.y + 0.5) * cellHeight,
292
+ cellWidth * 0.4,
293
+ 0, 2 * Math.PI
294
+ );
295
+ ctx.fill();
296
+ ctx.strokeStyle = 'white';
297
+ ctx.lineWidth = 3;
298
+ ctx.stroke();
299
+
300
+ // Draw 'S'
301
+ ctx.fillStyle = 'white';
302
+ ctx.font = 'bold ' + (cellWidth * 0.6) + 'px Arial';
303
+ ctx.textAlign = 'center';
304
+ ctx.textBaseline = 'middle';
305
+ ctx.fillText('S', (startPoint.x + 0.5) * cellWidth, (startPoint.y + 0.5) * cellHeight);
306
+ }
307
+
308
+ // Draw goal point (red)
309
+ if (goalPoint) {
310
+ ctx.fillStyle = '#FF0000';
311
+ ctx.beginPath();
312
+ ctx.arc(
313
+ (goalPoint.x + 0.5) * cellWidth,
314
+ (goalPoint.y + 0.5) * cellHeight,
315
+ cellWidth * 0.4,
316
+ 0, 2 * Math.PI
317
+ );
318
+ ctx.fill();
319
+ ctx.strokeStyle = 'white';
320
+ ctx.lineWidth = 3;
321
+ ctx.stroke();
322
+
323
+ // Draw 'G'
324
+ ctx.fillStyle = 'white';
325
+ ctx.font = 'bold ' + (cellWidth * 0.6) + 'px Arial';
326
+ ctx.textAlign = 'center';
327
+ ctx.textBaseline = 'middle';
328
+ ctx.fillText('G', (goalPoint.x + 0.5) * cellWidth, (goalPoint.y + 0.5) * cellHeight);
329
+ }
330
+ }
331
+
332
+ function clearPoints() {
333
+ startPoint = null;
334
+ goalPoint = null;
335
+ clickCount = 0;
336
+ document.getElementById('startPoint').textContent = '🟢 Start: Click on map';
337
+ document.getElementById('goalPoint').textContent = '🔴 Goal: Click on map';
338
+ document.getElementById('findBtn').disabled = true;
339
+ drawCanvas();
340
+ }
341
+
342
  async function findPath() {
343
+ if (!startPoint || !goalPoint) {
344
+ alert('Please select both start and goal points!');
345
+ return;
346
+ }
347
+
348
  const algorithm = document.querySelector('input[name="algorithm"]:checked').value;
349
 
350
  // Show loading
351
  document.getElementById('loading').style.display = 'block';
352
+ document.getElementById('canvasContainer').style.display = 'none';
353
 
354
  try {
355
  const response = await fetch('/find_path', {
 
358
  'Content-Type': 'application/json',
359
  },
360
  body: JSON.stringify({
361
+ start_x: startPoint.x,
362
+ start_y: startPoint.y,
363
+ goal_x: goalPoint.x,
364
+ goal_y: goalPoint.y,
365
  algorithm: algorithm
366
  })
367
  });
368
 
369
  const data = await response.json();
370
 
371
+ // Hide loading
372
  document.getElementById('loading').style.display = 'none';
373
+ document.getElementById('canvasContainer').style.display = 'block';
374
 
375
  if (data.error) {
376
  alert('Error: ' + data.error);
 
377
  } else {
378
+ // Load result image
379
+ const resultImg = new Image();
380
+ resultImg.onload = function() {
381
+ canvas.width = resultImg.width;
382
+ canvas.height = resultImg.height;
383
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
384
+ ctx.drawImage(resultImg, 0, 0);
385
+ };
386
+ resultImg.src = data.image;
387
  }
388
  } catch (error) {
389
  console.error('Error:', error);
390
  alert('An error occurred: ' + error.message);
391
  document.getElementById('loading').style.display = 'none';
392
+ document.getElementById('canvasContainer').style.display = 'block';
393
  }
394
  }
395
  </script>