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

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +250 -4
index.html CHANGED
@@ -83,6 +83,123 @@
83
  font-weight: bold;
84
  }
85
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
86
  /* Right Panel: Interactive Canvas Map & Report */
87
  .map-panel {
88
  flex: 2;
@@ -140,12 +257,12 @@
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">
147
  <!-- ============================================================== -->
148
- <!-- LEFT PANEL: USER SLIDER INPUTS -->
149
  <!-- ============================================================== -->
150
  <div class="controls-panel">
151
  <h2>βš™οΈ Grandstand Crowd Inputs</h2>
@@ -175,7 +292,20 @@
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>
@@ -197,6 +327,39 @@
197
  </div>
198
  </div>
199
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
200
  <!-- ================================================================== -->
201
  <!-- 2. JAVASCRIPT SIMULATION & CANVAS DRAWING LOGIC -->
202
  <!-- ================================================================== -->
@@ -205,6 +368,10 @@
205
  const GATE_1_CAPACITY = 50;
206
  const GATE_3_CAPACITY = 45;
207
 
 
 
 
 
208
  function updateSimulation() {
209
  // 1. READ SLIDER VALUES FROM HTML INPUTS
210
  const hamiltonCrowd = parseInt(document.getElementById('hamilton').value);
@@ -242,6 +409,67 @@
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');
@@ -396,7 +624,7 @@
396
  }
397
 
398
  // -------------------------------------------------------------
399
- // E. DRAW NODE BOXES AND LABELS
400
  // -------------------------------------------------------------
401
  for (let key in nodes) {
402
  const n = nodes[key];
@@ -435,6 +663,24 @@
435
  ctx.textAlign = "center";
436
  ctx.textBaseline = "middle";
437
  ctx.fillText(n.label, n.pos.x, n.pos.y);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
438
  }
439
 
440
  // Draw Legend
 
83
  font-weight: bold;
84
  }
85
 
86
+ /* Online Ordering Section inside Controls Panel */
87
+ .order-btn {
88
+ width: 100%;
89
+ padding: 12px;
90
+ background-color: #e10600;
91
+ color: white;
92
+ border: none;
93
+ border-radius: 6px;
94
+ font-weight: bold;
95
+ font-size: 14px;
96
+ cursor: pointer;
97
+ margin-top: 10px;
98
+ transition: background 0.2s;
99
+ }
100
+
101
+ .order-btn:hover {
102
+ background-color: #ff1e1e;
103
+ }
104
+
105
+ .active-orders-list {
106
+ margin-top: 15px;
107
+ max-height: 180px;
108
+ overflow-y: auto;
109
+ background: #141414;
110
+ padding: 10px;
111
+ border-radius: 6px;
112
+ border: 1px solid #333;
113
+ }
114
+
115
+ .order-card {
116
+ background: #252525;
117
+ padding: 8px;
118
+ margin-bottom: 8px;
119
+ border-radius: 4px;
120
+ border-left: 3px solid #f39c12;
121
+ font-size: 12px;
122
+ }
123
+
124
+ .order-card.ready {
125
+ border-left-color: #00cc66;
126
+ }
127
+
128
+ /* Modal Overlay */
129
+ .modal {
130
+ display: none;
131
+ position: fixed;
132
+ z-index: 1000;
133
+ left: 0;
134
+ top: 0;
135
+ width: 100%;
136
+ height: 100%;
137
+ background-color: rgba(0, 0, 0, 0.8);
138
+ justify-content: center;
139
+ align-items: center;
140
+ }
141
+
142
+ .modal-content {
143
+ background-color: #1e1e1e;
144
+ padding: 25px;
145
+ border-radius: 10px;
146
+ border: 1px solid #444;
147
+ width: 400px;
148
+ max-width: 90%;
149
+ }
150
+
151
+ .modal-content h3 {
152
+ color: #e10600;
153
+ margin-bottom: 15px;
154
+ }
155
+
156
+ .form-group {
157
+ margin-bottom: 12px;
158
+ }
159
+
160
+ .form-group label {
161
+ display: block;
162
+ font-size: 13px;
163
+ margin-bottom: 5px;
164
+ color: #ccc;
165
+ }
166
+
167
+ .form-group select, .form-group input {
168
+ width: 100%;
169
+ padding: 8px;
170
+ background: #2b2b2b;
171
+ border: 1px solid #444;
172
+ color: white;
173
+ border-radius: 4px;
174
+ }
175
+
176
+ .modal-actions {
177
+ display: flex;
178
+ gap: 10px;
179
+ margin-top: 20px;
180
+ }
181
+
182
+ .btn-submit {
183
+ flex: 1;
184
+ background: #00cc66;
185
+ color: black;
186
+ padding: 10px;
187
+ border: none;
188
+ border-radius: 4px;
189
+ font-weight: bold;
190
+ cursor: pointer;
191
+ }
192
+
193
+ .btn-cancel {
194
+ flex: 1;
195
+ background: #444;
196
+ color: white;
197
+ padding: 10px;
198
+ border: none;
199
+ border-radius: 4px;
200
+ cursor: pointer;
201
+ }
202
+
203
  /* Right Panel: Interactive Canvas Map & Report */
204
  .map-panel {
205
  flex: 2;
 
257
 
258
  <header>
259
  <h1>🏎️ SILVERSTONE BRITISH GP β€” CROWD FLOW OPTIMISER</h1>
260
+ <p>Real-time interconnected crowd routing, dynamic bottleneck propagation & online ordering integration</p>
261
  </header>
262
 
263
  <div class="dashboard">
264
  <!-- ============================================================== -->
265
+ <!-- LEFT PANEL: USER SLIDER INPUTS & ONLINE ORDERING -->
266
  <!-- ============================================================== -->
267
  <div class="controls-panel">
268
  <h2>βš™οΈ Grandstand Crowd Inputs</h2>
 
292
  <input type="range" id="club" min="10" max="100" value="50" oninput="updateSimulation()">
293
  </div>
294
 
295
+ <hr style="border-color: #333; margin: 15px 0;">
296
+
297
+ <!-- ONLINE ORDERING SECTION -->
298
+ <h2 style="color: #f39c12;">πŸ” Click & Collect Food Express</h2>
299
+ <button class="order-btn" onclick="openOrderModal()">πŸ›’ Place Express Food/Merch Order</button>
300
+
301
+ <div style="margin-top: 15px;">
302
+ <span style="font-size: 13px; font-weight: bold; color: #aaa;">Active Mobile Orders:</span>
303
+ <div id="ordersContainer" class="active-orders-list">
304
+ <p style="color: #666; font-size: 12px; text-align: center;">No active mobile orders</p>
305
+ </div>
306
+ </div>
307
+
308
+ <hr style="border-color: #333; margin: 15px 0;">
309
 
310
  <div style="font-size: 12px; color: #aaa; line-height: 1.4;">
311
  <p><strong>πŸ’‘ Dynamic Flow Rules:</strong></p>
 
327
  </div>
328
  </div>
329
 
330
+ <!-- ONLINE ORDER MODAL DIALOG -->
331
+ <div id="orderModal" class="modal">
332
+ <div class="modal-content">
333
+ <h3>πŸ” Place Online Pickup Order</h3>
334
+ <div class="form-group">
335
+ <label for="pickupLocation">Select Pickup Location:</label>
336
+ <select id="pickupLocation">
337
+ <option value="Main Fan Zone">Main Fan Zone</option>
338
+ <option value="Becketts Food">Becketts Food</option>
339
+ <option value="Village Plaza">Village Plaza</option>
340
+ <option value="Club Eats">Club Eats</option>
341
+ </select>
342
+ </div>
343
+ <div class="form-group">
344
+ <label for="itemSelect">Select Express Menu Item:</label>
345
+ <select id="itemSelect">
346
+ <option value="F1 Burger & Chips Combo (Β£14.00)">F1 Burger & Chips Combo (Β£14.00)</option>
347
+ <option value="Woodfired Pizza Slices (Β£11.50)">Woodfired Pizza Slices (Β£11.50)</option>
348
+ <option value="Grid Soft Drink & Fries (Β£7.00)">Grid Soft Drink & Fries (Β£7.00)</option>
349
+ <option value="Silverstone Official Cap (Β£30.00)">Silverstone Official Cap (Β£30.00)</option>
350
+ </select>
351
+ </div>
352
+ <div class="form-group">
353
+ <label for="custName">Customer Name / Ticket ID:</label>
354
+ <input type="text" id="custName" placeholder="e.g. John - Row C" value="Seat 14B">
355
+ </div>
356
+ <div class="modal-actions">
357
+ <button class="btn-submit" onclick="submitOrder()">Confirm Order</button>
358
+ <button class="btn-cancel" onclick="closeOrderModal()">Cancel</button>
359
+ </div>
360
+ </div>
361
+ </div>
362
+
363
  <!-- ================================================================== -->
364
  <!-- 2. JAVASCRIPT SIMULATION & CANVAS DRAWING LOGIC -->
365
  <!-- ================================================================== -->
 
368
  const GATE_1_CAPACITY = 50;
369
  const GATE_3_CAPACITY = 45;
370
 
371
+ // Active Orders State Management
372
+ let activeOrders = [];
373
+ let orderCounter = 101;
374
+
375
  function updateSimulation() {
376
  // 1. READ SLIDER VALUES FROM HTML INPUTS
377
  const hamiltonCrowd = parseInt(document.getElementById('hamilton').value);
 
409
  updateReport(gate1Load, gate2Load, gate3Load, gate4Load, isGate1Bottleneck, isGate3Bottleneck, excessGate1, excessGate3);
410
  }
411
 
412
+ /* --- ONLINE ORDERING FUNCTIONS --- */
413
+ function openOrderModal() {
414
+ document.getElementById('orderModal').style.display = 'flex';
415
+ }
416
+
417
+ function closeOrderModal() {
418
+ document.getElementById('orderModal').style.display = 'none';
419
+ }
420
+
421
+ function submitOrder() {
422
+ const location = document.getElementById('pickupLocation').value;
423
+ const item = document.getElementById('itemSelect').value;
424
+ const customer = document.getElementById('custName').value || 'Guest';
425
+
426
+ const newOrder = {
427
+ id: `#ORD-${orderCounter++}`,
428
+ location: location,
429
+ item: item,
430
+ customer: customer,
431
+ status: 'Preparing'
432
+ };
433
+
434
+ activeOrders.push(newOrder);
435
+ closeOrderModal();
436
+ renderOrdersUI();
437
+ updateSimulation(); // Refresh Canvas Map Badges
438
+
439
+ // Automatically transition order status to Ready after 8 seconds
440
+ setTimeout(() => {
441
+ newOrder.status = 'Ready for Pickup';
442
+ renderOrdersUI();
443
+ updateSimulation();
444
+ }, 8000);
445
+ }
446
+
447
+ function completeOrder(orderId) {
448
+ activeOrders = activeOrders.filter(o => o.id !== orderId);
449
+ renderOrdersUI();
450
+ updateSimulation();
451
+ }
452
+
453
+ function renderOrdersUI() {
454
+ const container = document.getElementById('ordersContainer');
455
+ if (activeOrders.length === 0) {
456
+ container.innerHTML = `<p style="color: #666; font-size: 12px; text-align: center;">No active mobile orders</p>`;
457
+ return;
458
+ }
459
+
460
+ container.innerHTML = activeOrders.map(o => `
461
+ <div class="order-card ${o.status === 'Ready for Pickup' ? 'ready' : ''}">
462
+ <div style="display:flex; justify-space-between; font-weight:bold;">
463
+ <span>${o.id} - ${o.customer}</span>
464
+ <span style="color: ${o.status === 'Ready for Pickup' ? '#00cc66' : '#f39c12'}">${o.status}</span>
465
+ </div>
466
+ <div style="color: #aaa; margin-top:3px;">πŸ“ ${o.location}</div>
467
+ <div style="color: #ddd;">πŸ” ${o.item}</div>
468
+ ${o.status === 'Ready for Pickup' ? `<button onclick="completeOrder('${o.id}')" style="margin-top:5px; background:#00cc66; color:black; border:none; padding:2px 6px; border-radius:3px; cursor:pointer; font-size:10px; font-weight:bold;">Collect Order</button>` : ''}
469
+ </div>
470
+ `).join('');
471
+ }
472
+
473
  function drawCanvasMap(hamilton, becketts, stowe, village, club, gate1Load, gate3Load, isGate1Bottleneck, isGate3Bottleneck) {
474
  const canvas = document.getElementById('silverstoneCanvas');
475
  const ctx = canvas.getContext('2d');
 
624
  }
625
 
626
  // -------------------------------------------------------------
627
+ // E. DRAW NODE BOXES, LABELS & ORDER BADGES
628
  // -------------------------------------------------------------
629
  for (let key in nodes) {
630
  const n = nodes[key];
 
663
  ctx.textAlign = "center";
664
  ctx.textBaseline = "middle";
665
  ctx.fillText(n.label, n.pos.x, n.pos.y);
666
+
667
+ // DRAW PENDING ORDERS OVERLAY BADGE FOR FOOD STALLS
668
+ if (n.type === "food") {
669
+ const pendingCount = activeOrders.filter(o => o.location === key).length;
670
+ if (pendingCount > 0) {
671
+ ctx.fillStyle = "#e10600";
672
+ ctx.beginPath();
673
+ ctx.arc(n.pos.x + textWidth / 2 + 5, n.pos.y - 10, 10, 0, Math.PI * 2);
674
+ ctx.fill();
675
+ ctx.strokeStyle = "#ffffff";
676
+ ctx.lineWidth = 1.5;
677
+ ctx.stroke();
678
+
679
+ ctx.fillStyle = "#ffffff";
680
+ ctx.font = "bold 10px Arial";
681
+ ctx.fillText(pendingCount, n.pos.x + textWidth / 2 + 5, n.pos.y - 10);
682
+ }
683
+ }
684
  }
685
 
686
  // Draw Legend