wasmdashai commited on
Commit
f47b0f9
·
verified ·
1 Parent(s): f7a3016

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +554 -317
index.html CHANGED
@@ -1,9 +1,10 @@
 
1
  <!DOCTYPE html>
2
  <html lang="en">
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>AI-Powered Maritime Route Generation Platform</title>
7
  <link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" />
8
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
9
  <style>
@@ -36,7 +37,7 @@
36
  }
37
 
38
  .container {
39
- max-width: 1800px;
40
  margin: 0 auto;
41
  padding: 20px;
42
  }
@@ -90,6 +91,8 @@
90
  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
91
  border: 1px solid var(--border);
92
  overflow-y: auto;
 
 
93
  }
94
 
95
  .map-container {
@@ -99,6 +102,8 @@
99
  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
100
  border: 1px solid var(--border);
101
  position: relative;
 
 
102
  }
103
 
104
  #map {
@@ -179,6 +184,10 @@
179
  background: linear-gradient(135deg, var(--danger) 0%, #dc2626 100%);
180
  }
181
 
 
 
 
 
182
  .model-cards {
183
  display: grid;
184
  grid-template-columns: 1fr 1fr;
@@ -544,6 +553,132 @@
544
  color: var(--dark);
545
  opacity: 0.8;
546
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
547
  </style>
548
  </head>
549
  <body>
@@ -552,8 +687,8 @@
552
  <div class="logo">
553
  <i class="fas fa-ship"></i>
554
  <div class="logo-text">
555
- <h1>AI-Powered Maritime Route Generation</h1>
556
- <p>Advanced route prediction and anomaly detection</p>
557
  </div>
558
  </div>
559
  <div class="header-controls">
@@ -563,157 +698,188 @@
563
 
564
  <div class="app-container">
565
  <div class="control-panel">
566
- <div class="panel-section">
567
- <div class="section-title">
568
- <i class="fas fa-brain"></i>
569
- <h3>AI Model Selection</h3>
570
- </div>
571
- <div class="model-cards">
572
- <div class="model-card active" data-model="TrAISformer">
573
- <div class="model-name">TrAISformer</div>
574
- <div class="model-desc">Transformer-based model</div>
 
 
575
  </div>
576
- <div class="model-card" data-model="EnhcTrAISformer">
577
- <div class="model-name">EnhcTrAISformer</div>
578
- <div class="model-desc">Enhanced Transformer</div>
 
 
579
  </div>
580
- <div class="model-card" data-model="eDQTI-GRU">
581
- <div class="model-name">eDQTI-GRU</div>
582
- <div class="model-desc">GRU with DQTI</div>
 
 
 
 
 
 
 
 
 
 
 
583
  </div>
584
- <div class="model-card" data-model="eDQTI-LSTM">
585
- <div class="model-name">eDQTI-LSTM</div>
586
- <div class="model-desc">LSTM with DQTI</div>
 
 
 
 
 
 
 
 
 
 
587
  </div>
588
- <div class="model-card" data-model="eDQTI-HYPER">
589
- <div class="model-name">eDQTI-HYPER</div>
590
- <div class="model-desc">Advanced hybrid model</div>
 
591
  </div>
592
- </div>
593
 
594
- <div class="form-group">
595
- <label for="anomalyModel"><i class="fas fa-exclamation-triangle"></i> Anomaly Detection Model</label>
596
- <select id="anomalyModel">
597
- <option value="auto">Auto (Based on main model)</option>
598
- <option value="isolation-forest">Isolation Forest</option>
599
- <option value="local-outlier">Local Outlier Factor</option>
600
- <option value="svm">One-Class SVM</option>
601
- <option value="autoencoder">Autoencoder</option>
602
- </select>
603
  </div>
604
  </div>
605
 
606
- <div class="panel-section">
607
- <div class="section-title">
608
- <i class="fas fa-route"></i>
609
- <h3>Generation Settings</h3>
610
- </div>
611
-
612
- <div class="form-group">
613
- <label for="contextInput"><i class="fas fa-code"></i> Context Data</label>
614
- <textarea id="contextInput" class="context-input" placeholder="Enter route context data here...">Historical route from Bab el Mandeb to Suez Canal with AIS data</textarea>
615
- </div>
616
-
617
- <div class="form-group">
618
- <label><i class="fas fa-map-marker-alt"></i> Start Point</label>
619
- <div class="coordinates-input">
620
- <div class="input-group">
621
- <label>Latitude</label>
622
- <input type="number" id="startLat" step="0.0001" value="12.6" placeholder="12.6">
623
  </div>
624
- <div class="input-group">
625
- <label>Longitude</label>
626
- <input type="number" id="startLon" step="0.0001" value="43.0" placeholder="43.0">
627
  </div>
628
- </div>
629
- </div>
630
-
631
- <div class="form-group">
632
- <label><i class="fas fa-flag-checkered"></i> End Point</label>
633
- <div class="coordinates-input">
634
- <div class="input-group">
635
- <label>Latitude</label>
636
- <input type="number" id="endLat" step="0.0001" value="30.5" placeholder="30.5">
637
  </div>
638
- <div class="input-group">
639
- <label>Longitude</label>
640
- <input type="number" id="endLon" step="0.0001" value="32.3" placeholder="32.3">
641
  </div>
642
  </div>
643
- </div>
644
 
645
- <div class="form-group">
646
- <label for="hours"><i class="fas fa-clock"></i> Hours to Generate</label>
647
- <input type="number" id="hours" min="1" max="168" value="24" placeholder="24">
648
- </div>
 
 
 
649
 
650
- <div class="form-group">
651
- <label for="pointsPerHour"><i class="fas fa-map-pin"></i> Points per Hour</label>
652
- <input type="number" id="pointsPerHour" min="1" max="10" value="2" placeholder="2">
 
 
 
 
 
653
  </div>
654
 
655
- <button id="generateBtn"><i class="fas fa-play"></i> Generate Route</button>
656
- </div>
657
-
658
- <div class="panel-section">
659
- <div class="section-title">
660
- <i class="fas fa-chart-bar"></i>
661
- <h3>Generation Results</h3>
662
- </div>
663
- <div class="stats-grid">
664
- <div class="stat-card">
665
- <div class="stat-label">Model Used</div>
666
- <div class="stat-value" id="usedModel">TrAISformer</div>
667
- <div class="stat-label">Model</div>
668
- </div>
669
- <div class="stat-card">
670
- <div class="stat-label">Total Points</div>
671
- <div class="stat-value" id="totalPoints">48</div>
672
- <div class="stat-label">Points</div>
673
  </div>
674
- <div class="stat-card">
675
- <div class="stat-label">Total Distance</div>
676
- <div class="stat-value" id="totalDistance">1,845</div>
677
- <div class="stat-label">km</div>
678
  </div>
679
- <div class="stat-card">
680
- <div class="stat-label">Anomaly Level</div>
681
- <div class="stat-value" id="anomalyLevel">3.2%</div>
682
- <div class="stat-label">Ratio</div>
683
  </div>
 
 
684
  </div>
 
685
 
686
- <div class="performance-metrics">
687
- <div class="metric">
688
- <div class="metric-value" id="accuracy">94.7%</div>
689
- <div class="metric-label">Accuracy</div>
690
- </div>
691
- <div class="metric">
692
- <div class="metric-value" id="confidence">87%</div>
693
- <div class="metric-label">Confidence</div>
694
- </div>
695
- <div class="metric">
696
- <div class="metric-value" id="generationTime">2.3s</div>
697
- <div class="metric-label">Generation Time</div>
698
  </div>
699
- <div class="metric">
700
- <div class="metric-value" id="modelScore">92</div>
701
- <div class="metric-label">Model Score</div>
702
- </div>
703
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
704
 
705
- <div class="anomaly-indicator anomaly-low" id="anomalyIndicator">
706
- <i class="fas fa-check-circle"></i>
707
- <span>Route Normal - No Significant Anomalies</span>
708
  </div>
709
 
710
- <div class="generation-results">
711
- <h4>Generation Details:</h4>
712
- <div id="generationDetails">
713
- <p>• Model: TrAISformer</p>
714
- <p>• Generation Time: 2.3 seconds</p>
715
- <p>• Accuracy: 94.7%</p>
716
- <p>• Anomaly Points: 2 of 48 points</p>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
717
  </div>
718
  </div>
719
  </div>
@@ -747,6 +913,9 @@
747
  <div class="control-btn" id="locateRedSea">
748
  <i class="fas fa-crosshairs"></i>
749
  </div>
 
 
 
750
  </div>
751
  </div>
752
 
@@ -763,14 +932,10 @@
763
  </div>
764
  <div class="legend-item">
765
  <div class="legend-color" style="background: #3b82f6;"></div>
766
- <span>Context Point</span>
767
- </div>
768
- <div class="legend-item">
769
- <div class="legend-color" style="background: #ef4444;"></div>
770
- <span>Generated Point</span>
771
  </div>
772
  <div class="legend-item">
773
- <div class="legend-color" style="background: #f59e0b;"></div>
774
  <span>Anomaly Point</span>
775
  </div>
776
  </div>
@@ -806,7 +971,7 @@
806
  const suezCanal = [30.5, 32.3]; // Suez Canal
807
 
808
  // Add start and end points
809
- L.marker(babMandeb, {
810
  icon: L.divIcon({
811
  className: 'ship-marker',
812
  html: '🚢',
@@ -814,7 +979,7 @@
814
  })
815
  }).addTo(map).bindPopup('<div class="route-popup"><div class="popup-title">Bab el Mandeb</div><div>Starting point for Red Sea navigation</div></div>').openPopup();
816
 
817
- L.marker(suezCanal, {
818
  icon: L.divIcon({
819
  className: 'ship-marker',
820
  html: '⚓',
@@ -822,15 +987,26 @@
822
  })
823
  }).addTo(map).bindPopup('<div class="route-popup"><div class="popup-title">Suez Canal</div><div>End point for Red Sea navigation</div></div>');
824
 
825
- // Variables to store routes
826
  let contextRoute = [];
827
- let generatedRoute = [];
 
828
  let routeLayers = [];
829
  let currentModel = 'TrAISformer';
 
 
830
 
831
  // UI Elements
 
 
832
  const modelCards = document.querySelectorAll('.model-card');
 
 
833
  const generateBtn = document.getElementById('generateBtn');
 
 
 
 
834
  const contextInput = document.getElementById('contextInput');
835
  const startLat = document.getElementById('startLat');
836
  const startLon = document.getElementById('startLon');
@@ -838,52 +1014,101 @@
838
  const endLon = document.getElementById('endLon');
839
  const hours = document.getElementById('hours');
840
  const pointsPerHour = document.getElementById('pointsPerHour');
841
- const usedModelElem = document.getElementById('usedModel');
842
- const totalPointsElem = document.getElementById('totalPoints');
843
- const totalDistanceElem = document.getElementById('totalDistance');
844
- const anomalyLevelElem = document.getElementById('anomalyLevel');
845
- const anomalyIndicator = document.getElementById('anomalyIndicator');
846
- const generationDetails = document.getElementById('generationDetails');
847
  const generationHistory = document.getElementById('generationHistory');
848
  const zoomInBtn = document.getElementById('zoomIn');
849
  const zoomOutBtn = document.getElementById('zoomOut');
850
  const locateRedSeaBtn = document.getElementById('locateRedSea');
851
- const accuracyElem = document.getElementById('accuracy');
852
- const confidenceElem = document.getElementById('confidence');
853
- const generationTimeElem = document.getElementById('generationTime');
854
- const modelScoreElem = document.getElementById('modelScore');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
855
 
856
  // Model selection handling
857
  modelCards.forEach(card => {
858
  card.addEventListener('click', () => {
859
- modelCards.forEach(c => c.classList.remove('active'));
860
- card.classList.add('active');
861
- currentModel = card.getAttribute('data-model');
862
- usedModelElem.textContent = currentModel;
863
- updateModelMetrics(currentModel);
 
 
864
  });
865
  });
866
 
867
- // Update metrics based on selected model
868
- function updateModelMetrics(model) {
869
- const metrics = {
870
- 'TrAISformer': { accuracy: '94.7%', confidence: '87%', score: 92 },
871
- 'EnhcTrAISformer': { accuracy: '96.2%', confidence: '91%', score: 95 },
872
- 'eDQTI-GRU': { accuracy: '92.1%', confidence: '84%', score: 88 },
873
- 'eDQTI-LSTM': { accuracy: '93.5%', confidence: '86%', score: 90 },
874
- 'eDQTI-HYPER': { accuracy: '95.8%', confidence: '89%', score: 93 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
875
  };
876
 
877
- const metric = metrics[model];
878
- accuracyElem.textContent = metric.accuracy;
879
- confidenceElem.textContent = metric.confidence;
880
- modelScoreElem.textContent = metric.score;
881
- }
 
882
 
883
  // Generate context route from coordinates
884
  function generateContextRoute() {
885
- const start = [parseFloat(startLat.value), parseFloat(startLon.value)];
886
- const end = [parseFloat(endLat.value), parseFloat(endLon.value)];
 
 
 
 
 
887
 
888
  const route = [];
889
  const numPoints = 8;
@@ -925,27 +1150,22 @@
925
  // Simulate different model behaviors
926
  switch(model) {
927
  case 'TrAISformer':
928
- // Direct pattern with minor improvements
929
  lat = contextPoint[0] + (Math.random() - 0.5) * 0.3;
930
  lon = contextPoint[1] + (Math.random() - 0.5) * 0.4;
931
  break;
932
  case 'EnhcTrAISformer':
933
- // More precise pattern with less deviation
934
  lat = contextPoint[0] + (Math.random() - 0.5) * 0.2;
935
  lon = contextPoint[1] + (Math.random() - 0.5) * 0.3;
936
  break;
937
  case 'eDQTI-GRU':
938
- // Pattern with medium oscillations
939
  lat = contextPoint[0] + (Math.random() - 0.5) * 0.4;
940
  lon = contextPoint[1] + (Math.random() - 0.5) * 0.5;
941
  break;
942
  case 'eDQTI-LSTM':
943
- // Pattern with larger oscillations
944
  lat = contextPoint[0] + (Math.random() - 0.5) * 0.5;
945
  lon = contextPoint[1] + (Math.random() - 0.5) * 0.6;
946
  break;
947
  case 'eDQTI-HYPER':
948
- // Hybrid pattern with varying behavior
949
  const pattern = Math.sin(progress * Math.PI * 3) * 0.3;
950
  lat = contextPoint[0] + (Math.random() - 0.5) * 0.3 + pattern;
951
  lon = contextPoint[1] + (Math.random() - 0.5) * 0.4 + pattern;
@@ -961,51 +1181,27 @@
961
  return route;
962
  }
963
 
964
- // Detect anomalies in generated route
965
- function detectAnomalies(generatedRoute) {
966
- const anomalies = [];
967
 
968
- // Simulate anomaly detection
969
- for (let i = 0; i < generatedRoute.length; i++) {
970
- // 10% chance of being an anomaly point
971
- if (Math.random() < 0.1) {
972
- anomalies.push(i);
973
- }
974
  }
975
 
976
- return anomalies;
977
- }
978
-
979
- // Calculate distance between two points
980
- function calculateDistance(lat1, lon1, lat2, lon2) {
981
- const R = 6371; // Earth radius in kilometers
982
- const dLat = (lat2 - lat1) * Math.PI / 180;
983
- const dLon = (lon2 - lon1) * Math.PI / 180;
984
- const a =
985
- Math.sin(dLat/2) * Math.sin(dLat/2) +
986
- Math.cos(lat1 * Math.PI / 180) * Math.cos(lat2 * Math.PI / 180) *
987
- Math.sin(dLon/2) * Math.sin(dLon/2);
988
- const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
989
- return R * c;
990
- }
991
-
992
- // Calculate route length
993
- function calculateRouteLength(route) {
994
- let totalDistance = 0;
995
- for (let i = 0; i < route.length - 1; i++) {
996
- totalDistance += calculateDistance(
997
- route[i][0], route[i][1],
998
- route[i+1][0], route[i+1][1]
999
- );
1000
- }
1001
- return Math.round(totalDistance);
1002
  }
1003
 
1004
  // Draw routes on map
1005
- function drawRoutes(contextRoute, generatedRoute, anomalies) {
1006
  // Clear previous routes
1007
  clearRoutes();
1008
 
 
 
1009
  // Draw context route
1010
  const contextPolyline = L.polyline(contextRoute, {
1011
  color: '#1e3a8a',
@@ -1016,63 +1212,65 @@
1016
  }).addTo(map);
1017
  routeLayers.push(contextPolyline);
1018
 
1019
- // Draw context points
1020
- contextRoute.forEach((point, index) => {
1021
- if (index % 2 === 0) { // Fewer points for context
1022
- const pointMarker = L.circleMarker(point, {
1023
- color: '#3b82f6',
1024
- fillColor: '#3b82f6',
1025
- fillOpacity: 0.8,
1026
- radius: 4
1027
- }).addTo(map);
1028
-
1029
- pointMarker.bindPopup(`<div class="route-popup">
1030
- <div class="popup-title">Context Point ${index + 1}</div>
1031
- <div class="popup-details">
1032
- <div class="popup-detail"><span class="popup-label">Latitude:</span> ${point[0].toFixed(4)}</div>
1033
- <div class="popup-detail"><span class="popup-label">Longitude:</span> ${point[1].toFixed(4)}</div>
1034
- <div class="popup-detail"><span class="popup-label">Type:</span> Context</div>
1035
- </div>
1036
- </div>`);
1037
-
1038
- routeLayers.push(pointMarker);
1039
- }
1040
- });
1041
 
1042
- // Draw generated route
1043
- const generatedPolyline = L.polyline(generatedRoute, {
1044
- color: '#dc2626',
1045
- weight: 4,
1046
- opacity: 0.9,
1047
- lineJoin: 'round'
1048
- }).addTo(map);
1049
- routeLayers.push(generatedPolyline);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1050
 
1051
- // Draw generated route points
1052
- generatedRoute.forEach((point, index) => {
1053
- const isAnomaly = anomalies.includes(index);
1054
- const pointMarker = L.circleMarker(point, {
1055
- color: isAnomaly ? '#f59e0b' : '#ef4444',
1056
- fillColor: isAnomaly ? '#f59e0b' : '#ef4444',
1057
- fillOpacity: 0.9,
1058
- radius: isAnomaly ? 6 : 4
 
 
1059
  }).addTo(map);
1060
 
1061
- pointMarker.bindPopup(`<div class="route-popup">
1062
- <div class="popup-title">${isAnomaly ? 'Anomaly Point' : 'Generated Point'} ${index + 1}</div>
1063
  <div class="popup-details">
1064
- <div class="popup-detail"><span class="popup-label">Latitude:</span> ${point[0].toFixed(4)}</div>
1065
- <div class="popup-detail"><span class="popup-label">Longitude:</span> ${point[1].toFixed(4)}</div>
1066
- <div class="popup-detail"><span class="popup-label">Type:</span> ${isAnomaly ? 'Anomaly' : 'Generated'}</div>
1067
- <div class="popup-detail"><span class="popup-label">Model:</span> ${currentModel}</div>
1068
  </div>
1069
  </div>`);
1070
 
1071
- routeLayers.push(pointMarker);
1072
  });
1073
 
1074
  // Adjust map bounds to fit routes
1075
- const allPoints = [...contextRoute, ...generatedRoute];
1076
  const group = L.featureGroup(routeLayers);
1077
  map.fitBounds(group.getBounds().pad(0.1));
1078
  }
@@ -1083,56 +1281,32 @@
1083
  routeLayers = [];
1084
  }
1085
 
1086
- // Update results interface
1087
- function updateResults(generatedRoute, anomalies, generationTime) {
1088
- const totalPoints = generatedRoute.length;
1089
- const anomalyPercentage = ((anomalies.length / totalPoints) * 100).toFixed(1);
1090
- const distance = calculateRouteLength(generatedRoute);
1091
-
1092
- totalPointsElem.textContent = totalPoints;
1093
- totalDistanceElem.textContent = distance.toLocaleString();
1094
- anomalyLevelElem.textContent = `${anomalyPercentage}%`;
1095
- generationTimeElem.textContent = `${generationTime.toFixed(1)}s`;
1096
-
1097
- // Update anomaly indicator
1098
- anomalyIndicator.className = 'anomaly-indicator';
1099
- if (anomalyPercentage < 5) {
1100
- anomalyIndicator.classList.add('anomaly-low');
1101
- anomalyIndicator.innerHTML = '<i class="fas fa-check-circle"></i><span>Route Normal - No Significant Anomalies</span>';
1102
- } else if (anomalyPercentage < 15) {
1103
- anomalyIndicator.classList.add('anomaly-medium');
1104
- anomalyIndicator.innerHTML = '<i class="fas fa-exclamation-triangle"></i><span>Medium Anomaly - Requires Monitoring</span>';
1105
- } else {
1106
- anomalyIndicator.classList.add('anomaly-high');
1107
- anomalyIndicator.innerHTML = '<i class="fas fa-skull-crossbones"></i><span>High Anomaly - Immediate Intervention Required</span>';
1108
- }
1109
-
1110
- // Update generation details
1111
- generationDetails.innerHTML = `
1112
- <p>• Model: ${currentModel}</p>
1113
- <p>• Generation Time: ${generationTime.toFixed(1)} seconds</p>
1114
- <p>• Accuracy: ${(100 - anomalyPercentage).toFixed(1)}%</p>
1115
- <p>• Anomaly Points: ${anomalies.length} of ${totalPoints} points</p>
1116
- <p>• Hours: ${hours.value}</p>
1117
- <p>• Points/Hour: ${pointsPerHour.value}</p>
1118
- `;
1119
-
1120
- // Add to generation history
1121
  const historyItem = document.createElement('div');
1122
  historyItem.className = 'route-item';
1123
  historyItem.innerHTML = `
1124
  <div class="route-header">
1125
- <div class="route-name">Generation ${new Date().toLocaleString()}</div>
1126
- <div class="route-type">${currentModel}</div>
1127
  </div>
1128
  <div class="route-details">
1129
- <span>Points: ${totalPoints}</span>
1130
- <span>Anomaly: ${anomalyPercentage}%</span>
1131
  </div>
1132
  `;
1133
 
1134
  historyItem.addEventListener('click', () => {
1135
- drawRoutes(contextRoute, generatedRoute, anomalies);
 
 
 
 
 
 
 
 
 
1136
  });
1137
 
1138
  generationHistory.insertBefore(historyItem, generationHistory.firstChild);
@@ -1147,26 +1321,86 @@
1147
  generateBtn.addEventListener('click', () => {
1148
  // Generate context route
1149
  contextRoute = generateContextRoute();
 
1150
 
1151
- // Generate route using selected model
1152
- const startTime = performance.now();
1153
- generatedRoute = generateRouteWithModel(
1154
- contextRoute,
1155
- currentModel,
1156
- parseInt(hours.value),
1157
- parseInt(pointsPerHour.value)
1158
- );
1159
- const endTime = performance.now();
1160
- const generationTime = (endTime - startTime) / 1000;
1161
 
1162
- // Detect anomalies
1163
- const anomalies = detectAnomalies(generatedRoute);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1164
 
1165
  // Draw routes
1166
- drawRoutes(contextRoute, generatedRoute, anomalies);
1167
 
1168
- // Update results
1169
- updateResults(generatedRoute, anomalies, generationTime);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1170
  });
1171
 
1172
  // Map control elements
@@ -1182,15 +1416,18 @@
1182
  map.setView([20.0, 38.0], 6);
1183
  });
1184
 
1185
- // Load default data on startup
 
 
 
 
 
 
1186
  window.addEventListener('load', () => {
1187
- // Update metrics for initial model
1188
- updateModelMetrics(currentModel);
1189
-
1190
- // Generate and display initial example
1191
  setTimeout(() => {
1192
- generateBtn.click();
1193
- }, 1000);
1194
  });
1195
  </script>
1196
  </body>
 
1
+
2
  <!DOCTYPE html>
3
  <html lang="en">
4
  <head>
5
  <meta charset="UTF-8">
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
+ <title>Maritime AI Route Generation & Optimization Platform</title>
8
  <link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" />
9
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
10
  <style>
 
37
  }
38
 
39
  .container {
40
+ max-width: 2000px;
41
  margin: 0 auto;
42
  padding: 20px;
43
  }
 
91
  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
92
  border: 1px solid var(--border);
93
  overflow-y: auto;
94
+ display: flex;
95
+ flex-direction: column;
96
  }
97
 
98
  .map-container {
 
102
  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
103
  border: 1px solid var(--border);
104
  position: relative;
105
+ display: flex;
106
+ flex-direction: column;
107
  }
108
 
109
  #map {
 
184
  background: linear-gradient(135deg, var(--danger) 0%, #dc2626 100%);
185
  }
186
 
187
+ .btn-success {
188
+ background: linear-gradient(135deg, var(--success) 0%, #047857 100%);
189
+ }
190
+
191
  .model-cards {
192
  display: grid;
193
  grid-template-columns: 1fr 1fr;
 
553
  color: var(--dark);
554
  opacity: 0.8;
555
  }
556
+
557
+ .file-upload {
558
+ border: 2px dashed var(--border);
559
+ border-radius: 12px;
560
+ padding: 25px;
561
+ text-align: center;
562
+ cursor: pointer;
563
+ transition: all 0.3s ease;
564
+ margin-bottom: 20px;
565
+ }
566
+
567
+ .file-upload:hover {
568
+ border-color: var(--primary);
569
+ background: var(--light);
570
+ }
571
+
572
+ .file-upload i {
573
+ font-size: 3rem;
574
+ margin-bottom: 15px;
575
+ color: var(--primary);
576
+ }
577
+
578
+ .tab-container {
579
+ display: flex;
580
+ gap: 10px;
581
+ margin-bottom: 20px;
582
+ }
583
+
584
+ .tab {
585
+ flex: 1;
586
+ padding: 12px;
587
+ text-align: center;
588
+ background: var(--light);
589
+ border-radius: 8px;
590
+ cursor: pointer;
591
+ transition: all 0.3s ease;
592
+ font-weight: 600;
593
+ }
594
+
595
+ .tab.active {
596
+ background: var(--primary);
597
+ color: white;
598
+ }
599
+
600
+ .tab-content {
601
+ display: none;
602
+ }
603
+
604
+ .tab-content.active {
605
+ display: block;
606
+ }
607
+
608
+ .optimization-panel {
609
+ background: var(--light);
610
+ border-radius: 12px;
611
+ padding: 20px;
612
+ margin-top: 20px;
613
+ border: 1px solid var(--border);
614
+ }
615
+
616
+ .model-comparison {
617
+ display: grid;
618
+ grid-template-columns: 1fr 1fr 1fr;
619
+ gap: 15px;
620
+ margin-top: 15px;
621
+ }
622
+
623
+ .comparison-card {
624
+ background: var(--background);
625
+ border-radius: 12px;
626
+ padding: 15px;
627
+ text-align: center;
628
+ border: 1px solid var(--border);
629
+ transition: all 0.3s ease;
630
+ cursor: pointer;
631
+ }
632
+
633
+ .comparison-card:hover {
634
+ transform: translateY(-3px);
635
+ box-shadow: 0 6px 15px rgba(0, 0, 0, 0.1);
636
+ }
637
+
638
+ .comparison-card.active {
639
+ border-color: var(--success);
640
+ background: linear-gradient(135deg, var(--light) 0%, #d1fae5 100%);
641
+ }
642
+
643
+ .comparison-value {
644
+ font-size: 1.5rem;
645
+ font-weight: bold;
646
+ margin: 10px 0;
647
+ color: var(--success);
648
+ }
649
+
650
+ .comparison-label {
651
+ font-size: 0.9rem;
652
+ color: var(--dark);
653
+ opacity: 0.8;
654
+ }
655
+
656
+ .route-controls {
657
+ display: flex;
658
+ gap: 10px;
659
+ margin-top: 15px;
660
+ }
661
+
662
+ .route-control {
663
+ flex: 1;
664
+ padding: 10px;
665
+ background: var(--light);
666
+ border: 1px solid var(--border);
667
+ border-radius: 8px;
668
+ cursor: pointer;
669
+ text-align: center;
670
+ transition: all 0.3s ease;
671
+ }
672
+
673
+ .route-control:hover {
674
+ background: var(--primary);
675
+ color: white;
676
+ }
677
+
678
+ .route-control.active {
679
+ background: var(--primary);
680
+ color: white;
681
+ }
682
  </style>
683
  </head>
684
  <body>
 
687
  <div class="logo">
688
  <i class="fas fa-ship"></i>
689
  <div class="logo-text">
690
+ <h1>Maritime AI Route Generation & Optimization</h1>
691
+ <p>Professional platform for route prediction and optimization</p>
692
  </div>
693
  </div>
694
  <div class="header-controls">
 
698
 
699
  <div class="app-container">
700
  <div class="control-panel">
701
+ <div class="tab-container">
702
+ <div class="tab active" data-tab="input">Input Data</div>
703
+ <div class="tab" data-tab="generation">Route Generation</div>
704
+ <div class="tab" data-tab="optimization">Route Optimization</div>
705
+ </div>
706
+
707
+ <div class="tab-content active" id="input-tab">
708
+ <div class="panel-section">
709
+ <div class="section-title">
710
+ <i class="fas fa-database"></i>
711
+ <h3>Data Input Methods</h3>
712
  </div>
713
+
714
+ <div class="file-upload" id="fileUpload">
715
+ <i class="fas fa-file-excel"></i>
716
+ <p>Click or drag Excel file here</p>
717
+ <p class="file-format">Supports CSV and Excel files</p>
718
  </div>
719
+ <input type="file" id="fileInput" accept=".csv,.xlsx,.xls" style="display: none;">
720
+
721
+ <div class="form-group">
722
+ <label><i class="fas fa-map-marker-alt"></i> Manual Point Selection</label>
723
+ <div class="coordinates-input">
724
+ <div class="input-group">
725
+ <label>Start Latitude</label>
726
+ <input type="number" id="startLat" step="0.0001" value="12.6" placeholder="12.6">
727
+ </div>
728
+ <div class="input-group">
729
+ <label>Start Longitude</label>
730
+ <input type="number" id="startLon" step="0.0001" value="43.0" placeholder="43.0">
731
+ </div>
732
+ </div>
733
  </div>
734
+
735
+ <div class="form-group">
736
+ <label><i class="fas fa-flag-checkered"></i> End Point</label>
737
+ <div class="coordinates-input">
738
+ <div class="input-group">
739
+ <label>End Latitude</label>
740
+ <input type="number" id="endLat" step="0.0001" value="30.5" placeholder="30.5">
741
+ </div>
742
+ <div class="input-group">
743
+ <label>End Longitude</label>
744
+ <input type="number" id="endLon" step="0.0001" value="32.3" placeholder="32.3">
745
+ </div>
746
+ </div>
747
  </div>
748
+
749
+ <div class="form-group">
750
+ <label for="contextInput"><i class="fas fa-code"></i> Context Data</label>
751
+ <textarea id="contextInput" class="context-input" placeholder="Enter route context data here...">Historical route from Bab el Mandeb to Suez Canal with AIS data</textarea>
752
  </div>
 
753
 
754
+ <button id="saveContextBtn"><i class="fas fa-save"></i> Save Context</button>
 
 
 
 
 
 
 
 
755
  </div>
756
  </div>
757
 
758
+ <div class="tab-content" id="generation-tab">
759
+ <div class="panel-section">
760
+ <div class="section-title">
761
+ <i class="fas fa-brain"></i>
762
+ <h3>AI Model Selection</h3>
763
+ </div>
764
+ <div class="model-cards">
765
+ <div class="model-card active" data-model="TrAISformer">
766
+ <div class="model-name">TrAISformer</div>
767
+ <div class="model-desc">Transformer-based model</div>
 
 
 
 
 
 
 
768
  </div>
769
+ <div class="model-card" data-model="EnhcTrAISformer">
770
+ <div class="model-name">EnhcTrAISformer</div>
771
+ <div class="model-desc">Enhanced Transformer</div>
772
  </div>
773
+ <div class="model-card" data-model="eDQTI-GRU">
774
+ <div class="model-name">eDQTI-GRU</div>
775
+ <div class="model-desc">GRU with DQTI</div>
776
+ </div>
777
+ <div class="model-card" data-model="eDQTI-LSTM">
778
+ <div class="model-name">eDQTI-LSTM</div>
779
+ <div class="model-desc">LSTM with DQTI</div>
 
 
780
  </div>
781
+ <div class="model-card" data-model="eDQTI-HYPER">
782
+ <div class="model-name">eDQTI-HYPER</div>
783
+ <div class="model-desc">Advanced hybrid model</div>
784
  </div>
785
  </div>
 
786
 
787
+ <div class="form-group">
788
+ <label><i class="fas fa-layer-group"></i> Display Mode</label>
789
+ <div class="route-controls">
790
+ <div class="route-control active" data-display="single">Single Model</div>
791
+ <div class="route-control" data-display="compare">Compare All</div>
792
+ </div>
793
+ </div>
794
 
795
+ <div class="form-group">
796
+ <label for="anomalyModel"><i class="fas fa-exclamation-triangle"></i> Anomaly Detection</label>
797
+ <select id="anomalyModel">
798
+ <option value="auto">Auto Detection</option>
799
+ <option value="enabled">Anomaly Detection Enabled</option>
800
+ <option value="disabled">No Anomaly Detection</option>
801
+ </select>
802
+ </div>
803
  </div>
804
 
805
+ <div class="panel-section">
806
+ <div class="section-title">
807
+ <i class="fas fa-route"></i>
808
+ <h3>Generation Parameters</h3>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
809
  </div>
810
+
811
+ <div class="form-group">
812
+ <label for="hours"><i class="fas fa-clock"></i> Hours to Generate</label>
813
+ <input type="number" id="hours" min="1" max="168" value="24" placeholder="24">
814
  </div>
815
+
816
+ <div class="form-group">
817
+ <label for="pointsPerHour"><i class="fas fa-map-pin"></i> Points per Hour</label>
818
+ <input type="number" id="pointsPerHour" min="1" max="10" value="2" placeholder="2">
819
  </div>
820
+
821
+ <button id="generateBtn" class="btn-success"><i class="fas fa-play"></i> Generate Routes</button>
822
  </div>
823
+ </div>
824
 
825
+ <div class="tab-content" id="optimization-tab">
826
+ <div class="panel-section">
827
+ <div class="section-title">
828
+ <i class="fas fa-magic"></i>
829
+ <h3>Route Optimization</h3>
 
 
 
 
 
 
 
830
  </div>
831
+
832
+ <div class="optimization-panel">
833
+ <p>Optimize generated routes using advanced algorithms</p>
834
+
835
+ <div class="model-comparison">
836
+ <div class="comparison-card" data-model="eDQTI-GRU">
837
+ <div class="model-name">eDQTI-GRU</div>
838
+ <div class="comparison-value">92%</div>
839
+ <div class="comparison-label">Optimization Score</div>
840
+ </div>
841
+ <div class="comparison-card" data-model="eDQTI-LSTM">
842
+ <div class="model-name">eDQTI-LSTM</div>
843
+ <div class="comparison-value">88%</div>
844
+ <div class="comparison-label">Optimization Score</div>
845
+ </div>
846
+ <div class="comparison-card" data-model="eDQTI-HYPER">
847
+ <div class="model-name">eDQTI-HYPER</div>
848
+ <div class="comparison-value">95%</div>
849
+ <div class="comparison-label">Optimization Score</div>
850
+ </div>
851
+ </div>
852
 
853
+ <button id="optimizeBtn" class="btn-success"><i class="fas fa-bolt"></i> Optimize Selected Routes</button>
854
+ </div>
 
855
  </div>
856
 
857
+ <div class="panel-section">
858
+ <div class="section-title">
859
+ <i class="fas fa-chart-bar"></i>
860
+ <h3>Optimization Results</h3>
861
+ </div>
862
+ <div class="stats-grid">
863
+ <div class="stat-card">
864
+ <div class="stat-label">Distance Saved</div>
865
+ <div class="stat-value" id="distanceSaved">42</div>
866
+ <div class="stat-label">km</div>
867
+ </div>
868
+ <div class="stat-card">
869
+ <div class="stat-label">Time Saved</div>
870
+ <div class="stat-value" id="timeSaved">3.5</div>
871
+ <div class="stat-label">hours</div>
872
+ </div>
873
+ <div class="stat-card">
874
+ <div class="stat-label">Fuel Efficiency</div>
875
+ <div class="stat-value" id="fuelEfficiency">+12%</div>
876
+ <div class="stat-label">improvement</div>
877
+ </div>
878
+ <div class="stat-card">
879
+ <div class="stat-label">Safety Score</div>
880
+ <div class="stat-value" id="safetyScore">94%</div>
881
+ <div class="stat-label">rating</div>
882
+ </div>
883
  </div>
884
  </div>
885
  </div>
 
913
  <div class="control-btn" id="locateRedSea">
914
  <i class="fas fa-crosshairs"></i>
915
  </div>
916
+ <div class="control-btn" id="clearRoutes">
917
+ <i class="fas fa-trash"></i>
918
+ </div>
919
  </div>
920
  </div>
921
 
 
932
  </div>
933
  <div class="legend-item">
934
  <div class="legend-color" style="background: #3b82f6;"></div>
935
+ <span>Optimized Route</span>
 
 
 
 
936
  </div>
937
  <div class="legend-item">
938
+ <div class="legend-color" style="background: #10b981;"></div>
939
  <span>Anomaly Point</span>
940
  </div>
941
  </div>
 
971
  const suezCanal = [30.5, 32.3]; // Suez Canal
972
 
973
  // Add start and end points
974
+ const startMarker = L.marker(babMandeb, {
975
  icon: L.divIcon({
976
  className: 'ship-marker',
977
  html: '🚢',
 
979
  })
980
  }).addTo(map).bindPopup('<div class="route-popup"><div class="popup-title">Bab el Mandeb</div><div>Starting point for Red Sea navigation</div></div>').openPopup();
981
 
982
+ const endMarker = L.marker(suezCanal, {
983
  icon: L.divIcon({
984
  className: 'ship-marker',
985
  html: '⚓',
 
987
  })
988
  }).addTo(map).bindPopup('<div class="route-popup"><div class="popup-title">Suez Canal</div><div>End point for Red Sea navigation</div></div>');
989
 
990
+ // Variables to store routes and state
991
  let contextRoute = [];
992
+ let generatedRoutes = {};
993
+ let optimizedRoutes = {};
994
  let routeLayers = [];
995
  let currentModel = 'TrAISformer';
996
+ let displayMode = 'single';
997
+ let savedContext = null;
998
 
999
  // UI Elements
1000
+ const tabs = document.querySelectorAll('.tab');
1001
+ const tabContents = document.querySelectorAll('.tab-content');
1002
  const modelCards = document.querySelectorAll('.model-card');
1003
+ const routeControls = document.querySelectorAll('.route-control');
1004
+ const comparisonCards = document.querySelectorAll('.comparison-card');
1005
  const generateBtn = document.getElementById('generateBtn');
1006
+ const optimizeBtn = document.getElementById('optimizeBtn');
1007
+ const saveContextBtn = document.getElementById('saveContextBtn');
1008
+ const fileUpload = document.getElementById('fileUpload');
1009
+ const fileInput = document.getElementById('fileInput');
1010
  const contextInput = document.getElementById('contextInput');
1011
  const startLat = document.getElementById('startLat');
1012
  const startLon = document.getElementById('startLon');
 
1014
  const endLon = document.getElementById('endLon');
1015
  const hours = document.getElementById('hours');
1016
  const pointsPerHour = document.getElementById('pointsPerHour');
 
 
 
 
 
 
1017
  const generationHistory = document.getElementById('generationHistory');
1018
  const zoomInBtn = document.getElementById('zoomIn');
1019
  const zoomOutBtn = document.getElementById('zoomOut');
1020
  const locateRedSeaBtn = document.getElementById('locateRedSea');
1021
+ const clearRoutesBtn = document.getElementById('clearRoutes');
1022
+ const distanceSaved = document.getElementById('distanceSaved');
1023
+ const timeSaved = document.getElementById('timeSaved');
1024
+ const fuelEfficiency = document.getElementById('fuelEfficiency');
1025
+ const safetyScore = document.getElementById('safetyScore');
1026
+
1027
+ // Tab switching
1028
+ tabs.forEach(tab => {
1029
+ tab.addEventListener('click', () => {
1030
+ const tabId = tab.getAttribute('data-tab');
1031
+
1032
+ tabs.forEach(t => t.classList.remove('active'));
1033
+ tabContents.forEach(tc => tc.classList.remove('active'));
1034
+
1035
+ tab.classList.add('active');
1036
+ document.getElementById(`${tabId}-tab`).classList.add('active');
1037
+ });
1038
+ });
1039
 
1040
  // Model selection handling
1041
  modelCards.forEach(card => {
1042
  card.addEventListener('click', () => {
1043
+ if (displayMode === 'single') {
1044
+ modelCards.forEach(c => c.classList.remove('active'));
1045
+ card.classList.add('active');
1046
+ currentModel = card.getAttribute('data-model');
1047
+ } else {
1048
+ card.classList.toggle('active');
1049
+ }
1050
  });
1051
  });
1052
 
1053
+ // Display mode handling
1054
+ routeControls.forEach(control => {
1055
+ control.addEventListener('click', () => {
1056
+ routeControls.forEach(c => c.classList.remove('active'));
1057
+ control.classList.add('active');
1058
+ displayMode = control.getAttribute('data-display');
1059
+
1060
+ if (displayMode === 'single') {
1061
+ // Reset to single model selection
1062
+ modelCards.forEach(c => c.classList.remove('active'));
1063
+ modelCards[0].classList.add('active');
1064
+ currentModel = modelCards[0].getAttribute('data-model');
1065
+ }
1066
+ });
1067
+ });
1068
+
1069
+ // File upload handling
1070
+ fileUpload.addEventListener('click', () => {
1071
+ fileInput.click();
1072
+ });
1073
+
1074
+ fileInput.addEventListener('change', (e) => {
1075
+ const file = e.target.files[0];
1076
+ if (file) {
1077
+ // Simulate file processing
1078
+ alert(`File "${file.name}" loaded successfully!`);
1079
+ // In a real application, you would process the Excel/CSV file here
1080
+ }
1081
+ });
1082
+
1083
+ // Save context
1084
+ saveContextBtn.addEventListener('click', () => {
1085
+ const start = [parseFloat(startLat.value), parseFloat(startLon.value)];
1086
+ const end = [parseFloat(endLat.value), parseFloat(endLon.value)];
1087
+ const context = contextInput.value;
1088
+
1089
+ savedContext = {
1090
+ start,
1091
+ end,
1092
+ context,
1093
+ timestamp: new Date().toLocaleString()
1094
  };
1095
 
1096
+ // Update markers on map
1097
+ startMarker.setLatLng(start);
1098
+ endMarker.setLatLng(end);
1099
+
1100
+ alert('Context saved successfully!');
1101
+ });
1102
 
1103
  // Generate context route from coordinates
1104
  function generateContextRoute() {
1105
+ if (!savedContext) {
1106
+ alert('Please save context first!');
1107
+ return null;
1108
+ }
1109
+
1110
+ const start = savedContext.start;
1111
+ const end = savedContext.end;
1112
 
1113
  const route = [];
1114
  const numPoints = 8;
 
1150
  // Simulate different model behaviors
1151
  switch(model) {
1152
  case 'TrAISformer':
 
1153
  lat = contextPoint[0] + (Math.random() - 0.5) * 0.3;
1154
  lon = contextPoint[1] + (Math.random() - 0.5) * 0.4;
1155
  break;
1156
  case 'EnhcTrAISformer':
 
1157
  lat = contextPoint[0] + (Math.random() - 0.5) * 0.2;
1158
  lon = contextPoint[1] + (Math.random() - 0.5) * 0.3;
1159
  break;
1160
  case 'eDQTI-GRU':
 
1161
  lat = contextPoint[0] + (Math.random() - 0.5) * 0.4;
1162
  lon = contextPoint[1] + (Math.random() - 0.5) * 0.5;
1163
  break;
1164
  case 'eDQTI-LSTM':
 
1165
  lat = contextPoint[0] + (Math.random() - 0.5) * 0.5;
1166
  lon = contextPoint[1] + (Math.random() - 0.5) * 0.6;
1167
  break;
1168
  case 'eDQTI-HYPER':
 
1169
  const pattern = Math.sin(progress * Math.PI * 3) * 0.3;
1170
  lat = contextPoint[0] + (Math.random() - 0.5) * 0.3 + pattern;
1171
  lon = contextPoint[1] + (Math.random() - 0.5) * 0.4 + pattern;
 
1181
  return route;
1182
  }
1183
 
1184
+ // Optimize route (simulated)
1185
+ function optimizeRoute(route, model) {
1186
+ const optimized = [...route];
1187
 
1188
+ // Simulate optimization by smoothing the route
1189
+ for (let i = 1; i < optimized.length - 1; i++) {
1190
+ // Simple smoothing algorithm
1191
+ optimized[i][0] = (optimized[i-1][0] + optimized[i][0] + optimized[i+1][0]) / 3;
1192
+ optimized[i][1] = (optimized[i-1][1] + optimized[i][1] + optimized[i+1][1]) / 3;
 
1193
  }
1194
 
1195
+ return optimized;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1196
  }
1197
 
1198
  // Draw routes on map
1199
+ function drawRoutes() {
1200
  // Clear previous routes
1201
  clearRoutes();
1202
 
1203
+ if (!contextRoute) return;
1204
+
1205
  // Draw context route
1206
  const contextPolyline = L.polyline(contextRoute, {
1207
  color: '#1e3a8a',
 
1212
  }).addTo(map);
1213
  routeLayers.push(contextPolyline);
1214
 
1215
+ // Draw generated routes
1216
+ const modelColors = {
1217
+ 'TrAISformer': '#dc2626',
1218
+ 'EnhcTrAISformer': '#ea580c',
1219
+ 'eDQTI-GRU': '#d97706',
1220
+ 'eDQTI-LSTM': '#059669',
1221
+ 'eDQTI-HYPER': '#7c3aed'
1222
+ };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1223
 
1224
+ Object.keys(generatedRoutes).forEach(model => {
1225
+ if (displayMode === 'single' && model !== currentModel) return;
1226
+
1227
+ const route = generatedRoutes[model];
1228
+ const color = modelColors[model] || '#dc2626';
1229
+
1230
+ const polyline = L.polyline(route, {
1231
+ color: color,
1232
+ weight: 4,
1233
+ opacity: 0.8,
1234
+ lineJoin: 'round'
1235
+ }).addTo(map);
1236
+
1237
+ polyline.bindPopup(`<div class="route-popup">
1238
+ <div class="popup-title">${model} Generated Route</div>
1239
+ <div class="popup-details">
1240
+ <div class="popup-detail"><span class="popup-label">Points:</span> ${route.length}</div>
1241
+ <div class="popup-detail"><span class="popup-label">Model:</span> ${model}</div>
1242
+ <div class="popup-detail"><span class="popup-label">Status:</span> Generated</div>
1243
+ </div>
1244
+ </div>`);
1245
+
1246
+ routeLayers.push(polyline);
1247
+ });
1248
 
1249
+ // Draw optimized routes
1250
+ Object.keys(optimizedRoutes).forEach(model => {
1251
+ const route = optimizedRoutes[model];
1252
+ const color = '#3b82f6';
1253
+
1254
+ const polyline = L.polyline(route, {
1255
+ color: color,
1256
+ weight: 5,
1257
+ opacity: 0.9,
1258
+ lineJoin: 'round'
1259
  }).addTo(map);
1260
 
1261
+ polyline.bindPopup(`<div class="route-popup">
1262
+ <div class="popup-title">${model} Optimized Route</div>
1263
  <div class="popup-details">
1264
+ <div class="popup-detail"><span class="popup-label">Points:</span> ${route.length}</div>
1265
+ <div class="popup-detail"><span class="popup-label">Model:</span> ${model}</div>
1266
+ <div class="popup-detail"><span class="popup-label">Status:</span> Optimized</div>
 
1267
  </div>
1268
  </div>`);
1269
 
1270
+ routeLayers.push(polyline);
1271
  });
1272
 
1273
  // Adjust map bounds to fit routes
 
1274
  const group = L.featureGroup(routeLayers);
1275
  map.fitBounds(group.getBounds().pad(0.1));
1276
  }
 
1281
  routeLayers = [];
1282
  }
1283
 
1284
+ // Add to generation history
1285
+ function addToHistory(model, points, anomalyLevel) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1286
  const historyItem = document.createElement('div');
1287
  historyItem.className = 'route-item';
1288
  historyItem.innerHTML = `
1289
  <div class="route-header">
1290
+ <div class="route-name">${model} - ${new Date().toLocaleString()}</div>
1291
+ <div class="route-type">${model}</div>
1292
  </div>
1293
  <div class="route-details">
1294
+ <span>Points: ${points}</span>
1295
+ <span>Anomaly: ${anomalyLevel}%</span>
1296
  </div>
1297
  `;
1298
 
1299
  historyItem.addEventListener('click', () => {
1300
+ // Switch to single display and show this route
1301
+ routeControls.forEach(c => c.classList.remove('active'));
1302
+ document.querySelector('[data-display="single"]').classList.add('active');
1303
+ displayMode = 'single';
1304
+
1305
+ modelCards.forEach(c => c.classList.remove('active'));
1306
+ document.querySelector(`[data-model="${model}"]`).classList.add('active');
1307
+ currentModel = model;
1308
+
1309
+ drawRoutes();
1310
  });
1311
 
1312
  generationHistory.insertBefore(historyItem, generationHistory.firstChild);
 
1321
  generateBtn.addEventListener('click', () => {
1322
  // Generate context route
1323
  contextRoute = generateContextRoute();
1324
+ if (!contextRoute) return;
1325
 
1326
+ // Clear previous generated routes
1327
+ generatedRoutes = {};
 
 
 
 
 
 
 
 
1328
 
1329
+ // Get selected models
1330
+ const selectedModels = displayMode === 'single'
1331
+ ? [currentModel]
1332
+ : Array.from(document.querySelectorAll('.model-card.active'))
1333
+ .map(card => card.getAttribute('data-model'));
1334
+
1335
+ if (selectedModels.length === 0) {
1336
+ alert('Please select at least one model!');
1337
+ return;
1338
+ }
1339
+
1340
+ // Generate routes for selected models
1341
+ selectedModels.forEach(model => {
1342
+ const route = generateRouteWithModel(
1343
+ contextRoute,
1344
+ model,
1345
+ parseInt(hours.value),
1346
+ parseInt(pointsPerHour.value)
1347
+ );
1348
+
1349
+ generatedRoutes[model] = route;
1350
+
1351
+ // Simulate anomaly detection
1352
+ const anomalyLevel = (Math.random() * 10).toFixed(1);
1353
+
1354
+ // Add to history
1355
+ addToHistory(model, route.length, anomalyLevel);
1356
+ });
1357
 
1358
  // Draw routes
1359
+ drawRoutes();
1360
 
1361
+ alert(`Successfully generated routes for ${selectedModels.length} model(s)!`);
1362
+ });
1363
+
1364
+ // Optimize button handler
1365
+ optimizeBtn.addEventListener('click', () => {
1366
+ if (Object.keys(generatedRoutes).length === 0) {
1367
+ alert('Please generate routes first!');
1368
+ return;
1369
+ }
1370
+
1371
+ // Get selected models for optimization
1372
+ const selectedModels = Array.from(document.querySelectorAll('.comparison-card.active'))
1373
+ .map(card => card.getAttribute('data-model'));
1374
+
1375
+ if (selectedModels.length === 0) {
1376
+ alert('Please select at least one model to optimize!');
1377
+ return;
1378
+ }
1379
+
1380
+ // Optimize selected routes
1381
+ selectedModels.forEach(model => {
1382
+ if (generatedRoutes[model]) {
1383
+ optimizedRoutes[model] = optimizeRoute(generatedRoutes[model], model);
1384
+ }
1385
+ });
1386
+
1387
+ // Update optimization metrics
1388
+ distanceSaved.textContent = Math.floor(Math.random() * 100);
1389
+ timeSaved.textContent = (Math.random() * 5).toFixed(1);
1390
+ fuelEfficiency.textContent = `+${Math.floor(Math.random() * 20)}%`;
1391
+ safetyScore.textContent = `${80 + Math.floor(Math.random() * 20)}%`;
1392
+
1393
+ // Draw routes
1394
+ drawRoutes();
1395
+
1396
+ alert(`Successfully optimized ${selectedModels.length} route(s)!`);
1397
+ });
1398
+
1399
+ // Comparison card selection
1400
+ comparisonCards.forEach(card => {
1401
+ card.addEventListener('click', () => {
1402
+ card.classList.toggle('active');
1403
+ });
1404
  });
1405
 
1406
  // Map control elements
 
1416
  map.setView([20.0, 38.0], 6);
1417
  });
1418
 
1419
+ clearRoutesBtn.addEventListener('click', () => {
1420
+ clearRoutes();
1421
+ generatedRoutes = {};
1422
+ optimizedRoutes = {};
1423
+ });
1424
+
1425
+ // Initialize with example data
1426
  window.addEventListener('load', () => {
1427
+ // Auto-save initial context
 
 
 
1428
  setTimeout(() => {
1429
+ saveContextBtn.click();
1430
+ }, 500);
1431
  });
1432
  </script>
1433
  </body>