prishasinghai commited on
Commit
17aeb1b
Β·
verified Β·
1 Parent(s): 7eccbfd

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +126 -88
index.html CHANGED
@@ -42,7 +42,7 @@
42
  display: flex;
43
  flex-wrap: wrap;
44
  gap: 20px;
45
- max-width: 1400px;
46
  margin: 0 auto;
47
  }
48
 
@@ -140,7 +140,7 @@
140
 
141
  <header>
142
  <h1>🏎️ SILVERSTONE BRITISH GP β€” CROWD FLOW OPTIMISER</h1>
143
- <p>Real-time crowd simulation, dynamic bottleneck detection & Google Maps style rerouting</p>
144
  </header>
145
 
146
  <div class="dashboard">
@@ -156,32 +156,33 @@
156
  </div>
157
 
158
  <div class="slider-group">
159
- <label for="becketts">Becketts GS: <span id="becketts-val" class="value-badge">50</span> fans/min</label>
160
- <input type="range" id="becketts" min="10" max="100" value="50" oninput="updateSimulation()">
161
  </div>
162
 
163
  <div class="slider-group">
164
- <label for="stowe">Stowe GS: <span id="stowe-val" class="value-badge">30</span> fans/min</label>
165
- <input type="range" id="stowe" min="10" max="100" value="30" oninput="updateSimulation()">
166
  </div>
167
 
168
  <div class="slider-group">
169
- <label for="village">Village GS: <span id="village-val" class="value-badge">40</span> fans/min</label>
170
- <input type="range" id="village" min="10" max="100" value="40" oninput="updateSimulation()">
171
  </div>
172
 
173
  <div class="slider-group">
174
- <label for="club">Club GS: <span id="club-val" class="value-badge">45</span> fans/min</label>
175
- <input type="range" id="club" min="10" max="100" value="45" oninput="updateSimulation()">
176
  </div>
177
 
178
  <hr style="border-color: #333; margin: 20px 0;">
179
 
180
  <div style="font-size: 12px; color: #aaa; line-height: 1.4;">
181
- <p><strong>πŸ’‘ How It Works:</strong></p>
182
- <p>β€’ <strong>Main Gate 1 Limit:</strong> 60 fans/min</p>
183
- <p>β€’ When crowd load exceeds 60, walking paths turn <span class="badge badge-red">RED</span>.</p>
184
- <p>β€’ The system instantly activates <span class="badge badge-purple">PURPLE</span> Google Maps detours to South Gate 2 and West Gate 4.</p>
 
185
  </div>
186
  </div>
187
 
@@ -189,7 +190,7 @@
189
  <!-- RIGHT PANEL: HTML5 CANVAS MAP & TEXT ANALYSIS REPORT -->
190
  <!-- ============================================================== -->
191
  <div class="map-panel">
192
- <canvas id="silverstoneCanvas" width="850" height="500"></canvas>
193
  <div id="reportBox" class="report-box">
194
  <!-- Dynamic Text Report Injected Here -->
195
  </div>
@@ -200,8 +201,9 @@
200
  <!-- 2. JAVASCRIPT SIMULATION & CANVAS DRAWING LOGIC -->
201
  <!-- ================================================================== -->
202
  <script>
203
- // Gate Capacity Limit before bottleneck occurs
204
- const GATE_1_CAPACITY = 60;
 
205
 
206
  function updateSimulation() {
207
  // 1. READ SLIDER VALUES FROM HTML INPUTS
@@ -219,23 +221,28 @@
219
  document.getElementById('club-val').innerText = clubCrowd;
220
 
221
  // 2. MATHEMATICAL TRAFFIC LOAD CALCULATIONS
222
- const gate1Load = Math.round(hamiltonCrowd * 0.5 + beckettsCrowd * 0.3 + villageCrowd * 0.2);
223
- const gate2Load = Math.round(hamiltonCrowd * 0.2 + stoweCrowd * 0.2 + clubCrowd * 0.4);
224
- const gate3Load = Math.round(stoweCrowd * 0.7 + beckettsCrowd * 0.5);
225
- const gate4Load = Math.round(villageCrowd * 0.6 + hamiltonCrowd * 0.3);
226
 
227
- // Check if bottleneck occurs at Main Gate 1
228
- const isBottleneck = gate1Load > GATE_1_CAPACITY;
229
- const excessCrowd = isBottleneck ? (gate1Load - GATE_1_CAPACITY) : 0;
 
 
230
 
231
  // 3. DRAW MAP ON HTML5 CANVAS
232
- drawCanvasMap(hamiltonCrowd, beckettsCrowd, stoweCrowd, villageCrowd, clubCrowd, gate1Load, isBottleneck);
 
 
 
233
 
234
  // 4. UPDATE TEXT REPORT
235
- updateReport(gate1Load, gate2Load, gate3Load, gate4Load, isBottleneck, excessCrowd);
236
  }
237
 
238
- function drawCanvasMap(hamilton, becketts, stowe, village, club, gate1Load, isBottleneck) {
239
  const canvas = document.getElementById('silverstoneCanvas');
240
  const ctx = canvas.getContext('2d');
241
 
@@ -246,8 +253,8 @@
246
  // Map coordinate converter
247
  function toCanvas(x, y) {
248
  return {
249
- x: x * 65 + 400,
250
- y: -y * 50 + 250
251
  };
252
  }
253
 
@@ -260,18 +267,18 @@
260
  {x: 1, y: 4}, {x: 3, y: 4}, {x: 4, y: 2}, {x: 2, y: 0}, {x: -1, y: 0}
261
  ];
262
 
263
- // Draw outer dark grey track
264
  ctx.beginPath();
265
  trackPoints.forEach((pt, idx) => {
266
  const c = toCanvas(pt.x, pt.y);
267
  if (idx === 0) ctx.moveTo(c.x, c.y);
268
  else ctx.lineTo(c.x, c.y);
269
  });
270
- ctx.strokeStyle = '#444444';
271
  ctx.lineWidth = 14;
272
  ctx.stroke();
273
 
274
- // Draw center dashed line (racing line)
275
  ctx.beginPath();
276
  ctx.setLineDash([6, 6]);
277
  trackPoints.forEach((pt, idx) => {
@@ -279,13 +286,13 @@
279
  if (idx === 0) ctx.moveTo(c.x, c.y);
280
  else ctx.lineTo(c.x, c.y);
281
  });
282
- ctx.strokeStyle = '#ffffff';
283
  ctx.lineWidth = 1.5;
284
  ctx.stroke();
285
  ctx.setLineDash([]); // Reset dash
286
 
287
  // -------------------------------------------------------------
288
- // B. DEFINE MAP NODES (Grandstands, Food Stalls, Gates)
289
  // -------------------------------------------------------------
290
  const nodes = {
291
  // Grandstands
@@ -301,38 +308,42 @@
301
  "Village Plaza": { pos: toCanvas(-1.8, 2.2), type: "food", label: "πŸ• Village Plaza" },
302
  "Club Eats": { pos: toCanvas(0.2, -2.2), type: "food", label: "🍦 Club Eats" },
303
 
 
 
 
 
 
304
  // Gates
305
- "Main Gate 1": { pos: toCanvas(-3.2, 0), type: "gate", label: "πŸšͺ Main Gate 1" },
306
  "South Gate 2": { pos: toCanvas(1, -4.2), type: "gate", label: "πŸšͺ South Gate 2" },
307
- "East Gate 3": { pos: toCanvas(4.2, -1), type: "gate", label: "πŸšͺ East Gate 3" },
308
- "West Gate 4": { pos: toCanvas(-3.8, 2.8), type: "gate", label: "πŸšͺ West Gate 4" }
309
  };
310
 
311
  // -------------------------------------------------------------
312
- // C. DRAW PEDESTRIAN WALKING PATHS
313
  // -------------------------------------------------------------
314
  const paths = [
315
- // Hamilton & Main Gate Paths
316
- { start: "Hamilton GS", end: "Main Fan Zone", color: "#00cc66" },
317
- { start: "Main Fan Zone", end: "Main Gate 1", color: isBottleneck ? "#ff4444" : "#00cc66" },
318
-
319
- // Becketts Paths
320
- { start: "Becketts GS", end: "Becketts Food", color: "#00cc66" },
321
- { start: "Becketts Food", end: "Main Gate 1", color: isBottleneck ? "#ff4444" : "#00cc66" },
322
- { start: "Becketts GS", end: "East Gate 3", color: "#00cc66" },
323
-
324
- // Stowe & East Gate Paths
325
- { start: "Stowe GS", end: "East Gate 3", color: "#00cc66" },
326
-
327
- // Village & West Gate Paths
 
328
  { start: "Village GS", end: "Village Plaza", color: "#00cc66" },
329
  { start: "Village Plaza", end: "West Gate 4", color: "#00cc66" },
330
- { start: "Village Plaza", end: "Main Gate 1", color: isBottleneck ? "#ff4444" : "#00cc66" },
331
-
332
- // Club & South Gate Paths
333
  { start: "Club GS", end: "Club Eats", color: "#00cc66" },
334
- { start: "Club Eats", end: "South Gate 2", color: "#00cc66" },
335
- { start: "Hamilton GS", end: "Club Eats", color: "#00cc66" }
336
  ];
337
 
338
  paths.forEach(p => {
@@ -345,28 +356,43 @@
345
  });
346
 
347
  // -------------------------------------------------------------
348
- // D. DRAW GOOGLE MAPS PURPLE DETOUR PATHS (If Bottlenecked)
349
  // -------------------------------------------------------------
350
- if (isBottleneck) {
351
- // Detour to South Gate 2
352
  ctx.beginPath();
353
- ctx.setLineDash([8, 8]);
354
  ctx.moveTo(nodes["Main Fan Zone"].pos.x, nodes["Main Fan Zone"].pos.y);
 
355
  ctx.lineTo(nodes["Club Eats"].pos.x, nodes["Club Eats"].pos.y);
356
  ctx.lineTo(nodes["South Gate 2"].pos.x, nodes["South Gate 2"].pos.y);
357
- ctx.strokeStyle = "#a020f0"; // Purple
358
  ctx.lineWidth = 5;
359
  ctx.stroke();
360
 
361
- // Secondary Detour to West Gate 4
362
  ctx.beginPath();
363
- ctx.moveTo(nodes["Village Plaza"].pos.x, nodes["Village Plaza"].pos.y);
 
364
  ctx.lineTo(nodes["West Gate 4"].pos.x, nodes["West Gate 4"].pos.y);
365
  ctx.strokeStyle = "#a020f0";
366
  ctx.lineWidth = 5;
367
  ctx.stroke();
368
-
369
- ctx.setLineDash([]); // Reset dash
 
 
 
 
 
 
 
 
 
 
 
 
 
370
  }
371
 
372
  // -------------------------------------------------------------
@@ -376,12 +402,17 @@
376
  const n = nodes[key];
377
  ctx.font = "bold 11px Arial";
378
  const textWidth = ctx.measureText(n.label).width;
379
- const boxPadding = 8;
380
 
381
- let boxColor = "#3498db"; // Blue for Grandstand
382
- if (n.type === "food") boxColor = "#f39c12"; // Orange for Food Court
 
383
  if (n.type === "gate") {
384
- boxColor = (key === "Main Gate 1" && isBottleneck) ? "#ff4444" : "#00cc66";
 
 
 
 
385
  }
386
 
387
  // Draw background rounded box
@@ -399,7 +430,7 @@
399
  ctx.lineWidth = 1;
400
  ctx.stroke();
401
 
402
- // Draw white text
403
  ctx.fillStyle = "#ffffff";
404
  ctx.textAlign = "center";
405
  ctx.textBaseline = "middle";
@@ -410,34 +441,41 @@
410
  ctx.font = "11px Arial";
411
  ctx.fillStyle = "#ffffff";
412
  ctx.textAlign = "left";
413
- ctx.fillText("🟒 Clear Path", 20, 30);
414
- ctx.fillText("πŸ”΄ Congested Path", 120, 30);
415
- ctx.fillText("🟣 Google Maps Detour", 240, 30);
416
  }
417
 
418
- function updateReport(gate1, gate2, gate3, gate4, isBottleneck, excess) {
419
  const reportDiv = document.getElementById('reportBox');
420
 
421
- if (isBottleneck) {
422
  reportDiv.className = "report-box alert";
423
- reportDiv.innerHTML = `
424
- <h3 style="color: #ff4444;">πŸ”΄ BOTTLENECK ALERT AT MAIN GATE 1</h3>
425
- <p>β€’ <strong>Gate 1 Load:</strong> <code>${gate1}</code> fans/min (Limit: <code>${GATE_1_CAPACITY}</code>)</p>
426
- <p>β€’ <strong>Queue Overflow:</strong> <code>${excess}</code> fans facing delay risks.</p>
 
 
 
 
 
 
427
  <hr style="border-color: #552222; margin: 10px 0;">
428
- <h4 style="color: #a020f0;">πŸ”„ Dynamic Rerouting Active:</h4>
429
- <p>1. <strong>Google Maps Rerouting:</strong> Diverting crowd overflow along <span class="badge badge-purple">PURPLE DETOURS</span> to <strong>South Gate 2</strong> and <strong>West Gate 4</strong>.</p>
430
- <p>2. <strong>Staggering Notice:</strong> Directing Village Grandstand pedestrian traffic directly toward West Gate 4 bypass.</p>
431
  `;
 
432
  } else {
433
  reportDiv.className = "report-box";
434
  reportDiv.innerHTML = `
435
- <h3 style="color: #00cc66;">🟒 ALL PEDESTRIAN PATHWAYS CLEAR</h3>
436
- <p>β€’ <strong>Main Gate 1:</strong> <code>${gate1}</code> / ${GATE_1_CAPACITY} fans/min (Safe)</p>
437
- <p>β€’ <strong>South Gate 2:</strong> <code>${gate2}</code> / 50 fans/min (Safe)</p>
438
- <p>β€’ <strong>East Gate 3:</strong> <code>${gate3}</code> / 40 fans/min (Safe)</p>
439
- <p>β€’ <strong>West Gate 4:</strong> <code>${gate4}</code> / 45 fans/min (Safe)</p>
440
- <p style="margin-top: 5px; color: #aaa;"><em>Status: No detour required. Crowd distribution across all 4 gates is balanced.</em></p>
441
  `;
442
  }
443
  }
 
42
  display: flex;
43
  flex-wrap: wrap;
44
  gap: 20px;
45
+ max-width: 1450px;
46
  margin: 0 auto;
47
  }
48
 
 
140
 
141
  <header>
142
  <h1>🏎️ SILVERSTONE BRITISH GP β€” CROWD FLOW OPTIMISER</h1>
143
+ <p>Real-time interconnected crowd routing, dynamic bottleneck propagation & multi-path detours</p>
144
  </header>
145
 
146
  <div class="dashboard">
 
156
  </div>
157
 
158
  <div class="slider-group">
159
+ <label for="becketts">Becketts GS: <span id="becketts-val" class="value-badge">60</span> fans/min</label>
160
+ <input type="range" id="becketts" min="10" max="100" value="60" oninput="updateSimulation()">
161
  </div>
162
 
163
  <div class="slider-group">
164
+ <label for="stowe">Stowe GS: <span id="stowe-val" class="value-badge">40</span> fans/min</label>
165
+ <input type="range" id="stowe" min="10" max="100" value="40" oninput="updateSimulation()">
166
  </div>
167
 
168
  <div class="slider-group">
169
+ <label for="village">Village GS: <span id="village-val" class="value-badge">55</span> fans/min</label>
170
+ <input type="range" id="village" min="10" max="100" value="55" oninput="updateSimulation()">
171
  </div>
172
 
173
  <div class="slider-group">
174
+ <label for="club">Club GS: <span id="club-val" class="value-badge">50</span> fans/min</label>
175
+ <input type="range" id="club" min="10" max="100" value="50" oninput="updateSimulation()">
176
  </div>
177
 
178
  <hr style="border-color: #333; margin: 20px 0;">
179
 
180
  <div style="font-size: 12px; color: #aaa; line-height: 1.4;">
181
+ <p><strong>πŸ’‘ Dynamic Flow Rules:</strong></p>
182
+ <p>β€’ <strong>Gate 1 Threshold:</strong> 50 fans/min</p>
183
+ <p>β€’ <strong>Gate 3 Threshold:</strong> 45 fans/min</p>
184
+ <p>β€’ Bottlenecks cause cascading <span class="badge badge-red">RED</span> corridor congestions.</p>
185
+ <p>β€’ Active rerouting renders complex multi-node <span class="badge badge-purple">PURPLE</span> Google Maps detours.</p>
186
  </div>
187
  </div>
188
 
 
190
  <!-- RIGHT PANEL: HTML5 CANVAS MAP & TEXT ANALYSIS REPORT -->
191
  <!-- ============================================================== -->
192
  <div class="map-panel">
193
+ <canvas id="silverstoneCanvas" width="900" height="520"></canvas>
194
  <div id="reportBox" class="report-box">
195
  <!-- Dynamic Text Report Injected Here -->
196
  </div>
 
201
  <!-- 2. JAVASCRIPT SIMULATION & CANVAS DRAWING LOGIC -->
202
  <!-- ================================================================== -->
203
  <script>
204
+ // Gate Capacity Limits
205
+ const GATE_1_CAPACITY = 50;
206
+ const GATE_3_CAPACITY = 45;
207
 
208
  function updateSimulation() {
209
  // 1. READ SLIDER VALUES FROM HTML INPUTS
 
221
  document.getElementById('club-val').innerText = clubCrowd;
222
 
223
  // 2. MATHEMATICAL TRAFFIC LOAD CALCULATIONS
224
+ const gate1Load = Math.round(hamiltonCrowd * 0.5 + beckettsCrowd * 0.3 + villageCrowd * 0.3);
225
+ const gate2Load = Math.round(hamiltonCrowd * 0.2 + clubCrowd * 0.4);
226
+ const gate3Load = Math.round(stoweCrowd * 0.6 + beckettsCrowd * 0.4);
227
+ const gate4Load = Math.round(villageCrowd * 0.4 + hamiltonCrowd * 0.2);
228
 
229
+ // Bottleneck flags
230
+ const isGate1Bottleneck = gate1Load > GATE_1_CAPACITY;
231
+ const isGate3Bottleneck = gate3Load > GATE_3_CAPACITY;
232
+ const excessGate1 = isGate1Bottleneck ? (gate1Load - GATE_1_CAPACITY) : 0;
233
+ const excessGate3 = isGate3Bottleneck ? (gate3Load - GATE_3_CAPACITY) : 0;
234
 
235
  // 3. DRAW MAP ON HTML5 CANVAS
236
+ drawCanvasMap(
237
+ hamiltonCrowd, beckettsCrowd, stoweCrowd, villageCrowd, clubCrowd,
238
+ gate1Load, gate3Load, isGate1Bottleneck, isGate3Bottleneck
239
+ );
240
 
241
  // 4. UPDATE TEXT REPORT
242
+ updateReport(gate1Load, gate2Load, gate3Load, gate4Load, isGate1Bottleneck, isGate3Bottleneck, excessGate1, excessGate3);
243
  }
244
 
245
+ function drawCanvasMap(hamilton, becketts, stowe, village, club, gate1Load, gate3Load, isGate1Bottleneck, isGate3Bottleneck) {
246
  const canvas = document.getElementById('silverstoneCanvas');
247
  const ctx = canvas.getContext('2d');
248
 
 
253
  // Map coordinate converter
254
  function toCanvas(x, y) {
255
  return {
256
+ x: x * 65 + 430,
257
+ y: -y * 48 + 260
258
  };
259
  }
260
 
 
267
  {x: 1, y: 4}, {x: 3, y: 4}, {x: 4, y: 2}, {x: 2, y: 0}, {x: -1, y: 0}
268
  ];
269
 
270
+ // Outer track border
271
  ctx.beginPath();
272
  trackPoints.forEach((pt, idx) => {
273
  const c = toCanvas(pt.x, pt.y);
274
  if (idx === 0) ctx.moveTo(c.x, c.y);
275
  else ctx.lineTo(c.x, c.y);
276
  });
277
+ ctx.strokeStyle = '#333333';
278
  ctx.lineWidth = 14;
279
  ctx.stroke();
280
 
281
+ // Racing line
282
  ctx.beginPath();
283
  ctx.setLineDash([6, 6]);
284
  trackPoints.forEach((pt, idx) => {
 
286
  if (idx === 0) ctx.moveTo(c.x, c.y);
287
  else ctx.lineTo(c.x, c.y);
288
  });
289
+ ctx.strokeStyle = '#aaaaaa';
290
  ctx.lineWidth = 1.5;
291
  ctx.stroke();
292
  ctx.setLineDash([]); // Reset dash
293
 
294
  // -------------------------------------------------------------
295
+ // B. DEFINE MAP NODES (Grandstands, Food, Hubs, Gates)
296
  // -------------------------------------------------------------
297
  const nodes = {
298
  // Grandstands
 
308
  "Village Plaza": { pos: toCanvas(-1.8, 2.2), type: "food", label: "πŸ• Village Plaza" },
309
  "Club Eats": { pos: toCanvas(0.2, -2.2), type: "food", label: "🍦 Club Eats" },
310
 
311
+ // Intermediate Junction Hubs
312
+ "Arena Crossroad": { pos: toCanvas(-1.2, 0.8), type: "hub", label: "πŸ“ Arena Hub" },
313
+ "Becketts Interchange": { pos: toCanvas(0.5, 2.2), type: "hub", label: "πŸ“ Becketts Hub" },
314
+ "South Bypass": { pos: toCanvas(-0.8, -1.5), type: "hub", label: "πŸ“ South Hub" },
315
+
316
  // Gates
317
+ "Main Gate 1": { pos: toCanvas(-3.5, 0), type: "gate", label: "πŸšͺ Main Gate 1" },
318
  "South Gate 2": { pos: toCanvas(1, -4.2), type: "gate", label: "πŸšͺ South Gate 2" },
319
+ "East Gate 3": { pos: toCanvas(4.5, -1), type: "gate", label: "πŸšͺ East Gate 3" },
320
+ "West Gate 4": { pos: toCanvas(-4.0, 2.8), type: "gate", label: "πŸšͺ West Gate 4" }
321
  };
322
 
323
  // -------------------------------------------------------------
324
+ // C. INTERCONNECTED STANDARD PEDESTRIAN PATHS (GREEN / RED)
325
  // -------------------------------------------------------------
326
  const paths = [
327
+ // Network towards Gate 1 (Turns Red on Gate 1 Bottleneck)
328
+ { start: "Hamilton GS", end: "Arena Crossroad", color: isGate1Bottleneck ? "#ff4444" : "#00cc66" },
329
+ { start: "Arena Crossroad", end: "Main Fan Zone", color: isGate1Bottleneck ? "#ff4444" : "#00cc66" },
330
+ { start: "Main Fan Zone", end: "Main Gate 1", color: isGate1Bottleneck ? "#ff4444" : "#00cc66" },
331
+ { start: "Village GS", end: "Arena Crossroad", color: isGate1Bottleneck ? "#ff4444" : "#00cc66" },
332
+
333
+ // Network towards Becketts & Gate 3
334
+ { start: "Becketts GS", end: "Becketts Interchange", color: isGate3Bottleneck ? "#ff4444" : "#00cc66" },
335
+ { start: "Becketts Interchange", end: "Becketts Food", color: isGate3Bottleneck ? "#ff4444" : "#00cc66" },
336
+ { start: "Becketts Interchange", end: "Main Fan Zone", color: isGate1Bottleneck ? "#ff4444" : "#00cc66" },
337
+ { start: "Becketts Food", end: "Stowe GS", color: isGate3Bottleneck ? "#ff4444" : "#00cc66" },
338
+ { start: "Stowe GS", end: "East Gate 3", color: isGate3Bottleneck ? "#ff4444" : "#00cc66" },
339
+
340
+ // West & South Paths
341
  { start: "Village GS", end: "Village Plaza", color: "#00cc66" },
342
  { start: "Village Plaza", end: "West Gate 4", color: "#00cc66" },
343
+ { start: "Hamilton GS", end: "South Bypass", color: "#00cc66" },
344
+ { start: "South Bypass", end: "Club Eats", color: "#00cc66" },
 
345
  { start: "Club GS", end: "Club Eats", color: "#00cc66" },
346
+ { start: "Club Eats", end: "South Gate 2", color: "#00cc66" }
 
347
  ];
348
 
349
  paths.forEach(p => {
 
356
  });
357
 
358
  // -------------------------------------------------------------
359
+ // D. EXPANDED GOOGLE MAPS MULTI-NODE DETOURS (PURPLE)
360
  // -------------------------------------------------------------
361
+ if (isGate1Bottleneck) {
362
+ // Multi-leg Detour 1: Fan Zone -> South Bypass -> Club Eats -> South Gate 2
363
  ctx.beginPath();
364
+ ctx.setLineDash([8, 6]);
365
  ctx.moveTo(nodes["Main Fan Zone"].pos.x, nodes["Main Fan Zone"].pos.y);
366
+ ctx.lineTo(nodes["South Bypass"].pos.x, nodes["South Bypass"].pos.y);
367
  ctx.lineTo(nodes["Club Eats"].pos.x, nodes["Club Eats"].pos.y);
368
  ctx.lineTo(nodes["South Gate 2"].pos.x, nodes["South Gate 2"].pos.y);
369
+ ctx.strokeStyle = "#a020f0";
370
  ctx.lineWidth = 5;
371
  ctx.stroke();
372
 
373
+ // Multi-leg Detour 2: Arena Hub -> Village Plaza -> West Gate 4
374
  ctx.beginPath();
375
+ ctx.moveTo(nodes["Arena Crossroad"].pos.x, nodes["Arena Crossroad"].pos.y);
376
+ ctx.lineTo(nodes["Village Plaza"].pos.x, nodes["Village Plaza"].pos.y);
377
  ctx.lineTo(nodes["West Gate 4"].pos.x, nodes["West Gate 4"].pos.y);
378
  ctx.strokeStyle = "#a020f0";
379
  ctx.lineWidth = 5;
380
  ctx.stroke();
381
+ ctx.setLineDash([]);
382
+ }
383
+
384
+ if (isGate3Bottleneck) {
385
+ // Detour 3: Becketts Interchange -> Arena Hub -> South Bypass -> South Gate 2
386
+ ctx.beginPath();
387
+ ctx.setLineDash([8, 6]);
388
+ ctx.moveTo(nodes["Becketts Interchange"].pos.x, nodes["Becketts Interchange"].pos.y);
389
+ ctx.lineTo(nodes["Arena Crossroad"].pos.x, nodes["Arena Crossroad"].pos.y);
390
+ ctx.lineTo(nodes["South Bypass"].pos.x, nodes["South Bypass"].pos.y);
391
+ ctx.lineTo(nodes["South Gate 2"].pos.x, nodes["South Gate 2"].pos.y);
392
+ ctx.strokeStyle = "#a020f0";
393
+ ctx.lineWidth = 5;
394
+ ctx.stroke();
395
+ ctx.setLineDash([]);
396
  }
397
 
398
  // -------------------------------------------------------------
 
402
  const n = nodes[key];
403
  ctx.font = "bold 11px Arial";
404
  const textWidth = ctx.measureText(n.label).width;
405
+ const boxPadding = 7;
406
 
407
+ let boxColor = "#3498db"; // Blue for Grandstands
408
+ if (n.type === "food") boxColor = "#f39c12"; // Orange for Food
409
+ if (n.type === "hub") boxColor = "#7f8c8d"; // Grey for Hubs
410
  if (n.type === "gate") {
411
+ if ((key === "Main Gate 1" && isGate1Bottleneck) || (key === "East Gate 3" && isGate3Bottleneck)) {
412
+ boxColor = "#ff4444";
413
+ } else {
414
+ boxColor = "#00cc66";
415
+ }
416
  }
417
 
418
  // Draw background rounded box
 
430
  ctx.lineWidth = 1;
431
  ctx.stroke();
432
 
433
+ // Draw label text
434
  ctx.fillStyle = "#ffffff";
435
  ctx.textAlign = "center";
436
  ctx.textBaseline = "middle";
 
441
  ctx.font = "11px Arial";
442
  ctx.fillStyle = "#ffffff";
443
  ctx.textAlign = "left";
444
+ ctx.fillText("🟒 Clear Pathway", 20, 25);
445
+ ctx.fillText("πŸ”΄ Congested Network Segment", 140, 25);
446
+ ctx.fillText("🟣 Google Maps Active Multi-Leg Detour", 330, 25);
447
  }
448
 
449
+ function updateReport(gate1, gate2, gate3, gate4, isG1Alert, isG3Alert, excess1, excess3) {
450
  const reportDiv = document.getElementById('reportBox');
451
 
452
+ if (isG1Alert || isG3Alert) {
453
  reportDiv.className = "report-box alert";
454
+ let alertsHtml = `<h3 style="color: #ff4444;">πŸ”΄ NETWORK BOTTLENECK ALERT ACTIVATED</h3>`;
455
+
456
+ if (isG1Alert) {
457
+ alertsHtml += `<p>β€’ <strong>Main Gate 1 Bottleneck:</strong> Load <code>${gate1}</code> fans/min (Max limit: ${GATE_1_CAPACITY}). Overflow: <code>${excess1}</code> fans.</p>`;
458
+ }
459
+ if (isG3Alert) {
460
+ alertsHtml += `<p>β€’ <strong>East Gate 3 Bottleneck:</strong> Load <code>${gate3}</code> fans/min (Max limit: ${GATE_3_CAPACITY}). Overflow: <code>${excess3}</code> fans.</p>`;
461
+ }
462
+
463
+ alertsHtml += `
464
  <hr style="border-color: #552222; margin: 10px 0;">
465
+ <h4 style="color: #a020f0;">πŸ”„ Dynamic Rerouting Protocol:</h4>
466
+ <p>β€’ Activating interconnected <span class="badge badge-purple">PURPLE DETOURS</span> across <strong>Arena Hub</strong>, <strong>South Bypass</strong>, and <strong>Becketts Interchange</strong>.</p>
467
+ <p>β€’ Directing overflow pedestrian traffic to under-utilized exit points at <strong>South Gate 2</strong> and <strong>West Gate 4</strong>.</p>
468
  `;
469
+ reportDiv.innerHTML = alertsHtml;
470
  } else {
471
  reportDiv.className = "report-box";
472
  reportDiv.innerHTML = `
473
+ <h3 style="color: #00cc66;">🟒 ALL INTERCONNECTED PATHWAYS OPTIMAL</h3>
474
+ <p>β€’ <strong>Main Gate 1 Load:</strong> <code>${gate1}</code> / ${GATE_1_CAPACITY} fans/min (Safe)</p>
475
+ <p>β€’ <strong>South Gate 2 Load:</strong> <code>${gate2}</code> / 50 fans/min (Safe)</p>
476
+ <p>β€’ <strong>East Gate 3 Load:</strong> <code>${gate3}</code> / ${GATE_3_CAPACITY} fans/min (Safe)</p>
477
+ <p>β€’ <strong>West Gate 4 Load:</strong> <code>${gate4}</code> / 45 fans/min (Safe)</p>
478
+ <p style="margin-top: 5px; color: #aaa;"><em>Status: Grid flow is balanced across all junctions. No purple detour routing required.</em></p>
479
  `;
480
  }
481
  }