Created
June 24, 2025 13:47
-
-
Save youssef22222/820c8ad4c8513d3faab394210145b9e3 to your computer and use it in GitHub Desktop.
Speed Violation Map - 3181 BBD (CTS-OBD) - 1750772828
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<title>Speed Violation Path - 3181 BBD (CTS-OBD)</title> | |
<meta charset="utf-8" /> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" /> | |
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css"> | |
<style> | |
html, body { | |
height: 100%; | |
margin: 0; | |
padding: 0; | |
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Arial, sans-serif; | |
} | |
#map { | |
height: 100%; | |
position: relative; | |
} | |
/* Enhanced marker styles */ | |
.number-icon { | |
background-color: #FF1744; | |
border: 2px solid white; | |
border-radius: 50%; | |
color: white; | |
font-weight: bold; | |
text-align: center; | |
font-size: 12px; | |
line-height: 20px; | |
width: 24px; | |
height: 24px; | |
margin-left: -12px; | |
margin-top: -12px; | |
box-shadow: 0 2px 5px rgba(0,0,0,0.3); | |
} | |
.violation-icon { | |
background-color: #FF1744; | |
border: 3px solid white; | |
width: 32px; | |
height: 32px; | |
line-height: 26px; | |
font-size: 16px; | |
font-weight: bold; | |
margin-left: -16px; | |
margin-top: -16px; | |
position: relative; | |
} | |
/* Pulsing animation for last violation point */ | |
.pulse-ring { | |
border: 3px solid #FF1744; | |
border-radius: 50%; | |
height: 50px; | |
width: 50px; | |
position: absolute; | |
left: 50%; | |
top: 50%; | |
transform: translate(-50%, -50%); | |
animation: pulsate 2s ease-out; | |
animation-iteration-count: infinite; | |
opacity: 0; | |
} | |
@keyframes pulsate { | |
0% { | |
transform: translate(-50%, -50%) scale(0.1, 0.1); | |
opacity: 0; | |
} | |
50% { | |
opacity: 1; | |
} | |
100% { | |
transform: translate(-50%, -50%) scale(1.2, 1.2); | |
opacity: 0; | |
} | |
} | |
/* Enhanced popup styles */ | |
.popup-content { | |
min-width: 280px; | |
font-family: inherit; | |
} | |
.popup-content table { | |
width: 100%; | |
border-collapse: collapse; | |
} | |
.popup-content td { | |
padding: 4px 8px; | |
border-bottom: 1px solid #eee; | |
font-size: 13px; | |
} | |
.popup-content td:first-child { | |
font-weight: 600; | |
width: 45%; | |
color: #555; | |
} | |
.popup-content td:last-child { | |
color: #2c3e50; | |
} | |
.popup-title { | |
font-weight: 600; | |
color: #2c3e50; | |
margin-bottom: 8px; | |
padding-bottom: 8px; | |
border-bottom: 2px solid #e9ecef; | |
font-size: 16px; | |
} | |
.speed-violation { | |
color: #e74c3c; | |
font-weight: bold; | |
} | |
/* Enhanced legend styles */ | |
.legend { | |
position: absolute; | |
bottom: 20px; | |
right: 20px; | |
background: white; | |
padding: 15px 20px; | |
border-radius: 12px; | |
box-shadow: 0 4px 20px rgba(0,0,0,0.15); | |
font-size: 13px; | |
z-index: 1000; | |
transition: transform 0.4s cubic-bezier(0.4, 0, 0.2, 1); | |
transform: translateX(0); | |
min-width: 200px; | |
} | |
.legend.collapsed { | |
transform: translateX(calc(100% + 20px)); | |
} | |
.legend-toggle-btn { | |
position: absolute; | |
left: -35px; | |
top: 50%; | |
width: 35px; | |
height: 50px; | |
background-color: #3498db; | |
color: white; | |
border: none; | |
cursor: pointer; | |
display: flex; | |
align-items: center; | |
justify-content: center; | |
font-size: 16px; | |
box-shadow: 0 2px 8px rgba(0,0,0,0.15); | |
transition: all 0.3s ease; | |
z-index: 1001; | |
border-radius: 8px 0 0 8px; | |
transform: translateY(-50%); | |
} | |
.legend-toggle-btn:hover { | |
background-color: #2980b9; | |
box-shadow: 0 4px 12px rgba(0,0,0,0.2); | |
} | |
.legend-toggle-btn i { | |
transition: transform 0.3s ease; | |
} | |
.legend.collapsed .legend-toggle-btn i { | |
transform: rotate(180deg); | |
} | |
.legend-title { | |
font-weight: 600; | |
margin-bottom: 12px; | |
color: #2c3e50; | |
font-size: 14px; | |
} | |
.legend-item { | |
display: flex; | |
align-items: center; | |
gap: 12px; | |
margin-bottom: 8px; | |
font-size: 12px; | |
} | |
.legend-item:last-child { | |
margin-bottom: 0; | |
} | |
.legend-marker { | |
width: 18px; | |
height: 18px; | |
border-radius: 50%; | |
border: 2px solid white; | |
box-shadow: 0 1px 3px rgba(0,0,0,0.2); | |
flex-shrink: 0; | |
} | |
.legend-line { | |
width: 25px; | |
height: 4px; | |
border-radius: 2px; | |
flex-shrink: 0; | |
} | |
.legend-arrow { | |
width: 25px; | |
height: 4px; | |
background: #3498db; | |
position: relative; | |
flex-shrink: 0; | |
} | |
.legend-arrow::after { | |
content: ''; | |
position: absolute; | |
right: 0; | |
top: -3px; | |
width: 0; | |
height: 0; | |
border-left: 8px solid #3498db; | |
border-top: 5px solid transparent; | |
border-bottom: 5px solid transparent; | |
} | |
/* Info control styles */ | |
.info-control { | |
min-width: 200px; | |
position: absolute; | |
top: 20px; | |
left: 20px; | |
background: rgba(255,255,255,0.95); | |
padding: 15px; | |
border-radius: 10px; | |
box-shadow: 0 2px 10px rgba(0,0,0,0.1); | |
font-size: 14px; | |
z-index: 1000; | |
} | |
.info-control h4 { | |
margin: 0 0 8px 0; | |
color: #2c3e50; | |
font-size: 16px; | |
} | |
.info-control div { | |
margin: 3px 0; | |
} | |
/* Enhanced leaflet popup */ | |
.leaflet-popup-content { | |
margin: 13px 19px; | |
font-size: 14px; | |
line-height: 1.5; | |
} | |
</style> | |
</head> | |
<body> | |
<div id="map"></div> | |
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script> | |
<script src="https://unpkg.com/leaflet-polylinedecorator@1.6.0/dist/leaflet.polylineDecorator.js"></script> | |
<script> | |
// Initialize the map | |
var map = L.map('map').setView([26.26344014814814, 50.186909796296284], 14); | |
// Add OpenStreetMap tile layer | |
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { | |
maxZoom: 19, | |
attribution: '© OpenStreetMap contributors' | |
}).addTo(map); | |
// Define the coordinates and the detailed path data | |
var latlngs = [ | |
[26.181967, 50.182962], | |
[26.185218, 50.185452], | |
[26.219582, 50.197908], | |
[26.181837, 50.18301], | |
[26.239178, 50.195348], | |
[26.277787, 50.183248], | |
[26.285852, 50.17977], | |
[26.286893, 50.179383], | |
[26.288445, 50.180918], | |
[26.28789, 50.183203], | |
[26.287943, 50.183007], | |
[26.287438, 50.18491], | |
[26.288078, 50.188698], | |
[26.292365, 50.186845], | |
[26.29658, 50.185], | |
[26.29755, 50.186255], | |
[26.297498, 50.188777], | |
[26.294935, 50.18992], | |
[26.287462, 50.195782], | |
[26.285898, 50.191387], | |
[26.288252, 50.183185], | |
[26.288762, 50.18157], | |
[26.288982, 50.180658], | |
[26.247775, 50.197408], | |
[26.191442, 50.187808], | |
[26.192178, 50.188452], | |
[26.181925, 50.182892], | |
[26.28577, 50.179802], | |
[26.288147, 50.180002], | |
[26.287375, 50.185008], | |
[26.28932, 50.188128], | |
[26.29328, 50.186458], | |
[26.29778, 50.186902], | |
[26.299695, 50.192598], | |
[26.297788, 50.199213], | |
[26.285727, 50.19193], | |
[26.288502, 50.182342], | |
[26.288967, 50.180568], | |
[26.276548, 50.183443], | |
[26.252535, 50.195902], | |
[26.236332, 50.194452], | |
[26.210365, 50.19697], | |
[26.2086, 50.193113], | |
[26.208527, 50.1915], | |
[26.200445, 50.194977], | |
[26.192077, 50.188225], | |
[26.182207, 50.183087], | |
[26.21024, 50.197573], | |
[26.255402, 50.193758], | |
[26.285608, 50.17979], | |
[26.306643, 50.175115], | |
[26.314975, 50.179677], | |
[26.324393, 50.17936], | |
[26.328808, 50.17948] | |
]; | |
var pathData = [{"latitude": 26.181967, "longitude": 50.182962, "time": "06/19/25,19:37:05", "speed": 63, "speed_limit": 40, "street_name": null, "street_name_ar": null, "distance_to_segment": 4.09, "vehicle_direction": 210, "segment_bearing": 207.6, "nearest_segment": [[26.1822474, 50.1830818], [26.1815841, 50.1826953]], "closest_point": [26.181972240171454, 50.1829214650544]}, {"latitude": 26.185218, "longitude": 50.185452, "time": "06/19/25,19:38:00", "speed": 52, "speed_limit": 40, "street_name": null, "street_name_ar": null, "distance_to_segment": 8.32, "vehicle_direction": 31, "segment_bearing": 29.3, "nearest_segment": [[26.1849846, 50.1853967], [26.1857572, 50.1858795]], "closest_point": [26.185204257836673, 50.18553396324487]}, {"latitude": 26.219582, "longitude": 50.197908, "time": "06/19/25,20:40:49", "speed": 57, "speed_limit": 50, "street_name": null, "street_name_ar": null, "distance_to_segment": 13.33, "vehicle_direction": 99, "segment_bearing": 112.2, "nearest_segment": [[26.2195595, 50.1976306], [26.2194887, 50.1978241]], "closest_point": [26.2194887, 50.1978241]}, {"latitude": 26.181837, "longitude": 50.18301, "time": "06/20/25,14:47:21", "speed": 70, "speed_limit": 40, "street_name": null, "street_name_ar": null, "distance_to_segment": 1.98, "vehicle_direction": 207, "segment_bearing": 36.9, "nearest_segment": [[26.1817345, 50.1829483], [26.182046, 50.183209]], "closest_point": [26.181830044598968, 50.18302826270198]}, {"latitude": 26.239178, "longitude": 50.195348, "time": "06/20/25,14:52:12", "speed": 111, "speed_limit": 110, "street_name": "King Khaled Road", "street_name_ar": "\u0637\u0631\u064a\u0642 \u0627\u0644\u0645\u0644\u0643 \u062e\u0627\u0644\u062f", "distance_to_segment": 11.16, "vehicle_direction": 14, "segment_bearing": 16.8, "nearest_segment": [[26.2379356, 50.1950375], [26.2396139, 50.1956039]], "closest_point": [26.239186197518066, 50.195459551459734]}, {"latitude": 26.277787, "longitude": 50.183248, "time": "06/20/25,14:55:04", "speed": 100, "speed_limit": 60, "street_name": null, "street_name_ar": "\u0637\u0631\u064a\u0642 \u0627\u0644\u0645\u0644\u0643 \u062e\u0627\u0644\u062f \u0627\u0644\u0641\u0631\u0639\u064a", "distance_to_segment": 9.42, "vehicle_direction": 338, "segment_bearing": 339.6, "nearest_segment": [[26.2770537, 50.1836514], [26.2778411, 50.1833248]], "closest_point": [26.277829862729938, 50.18332946099118]}, {"latitude": 26.285852, "longitude": 50.17977, "time": "06/20/25,14:55:53", "speed": 78, "speed_limit": 50, "street_name": null, "street_name_ar": null, "distance_to_segment": 7.28, "vehicle_direction": 341, "segment_bearing": 340.9, "nearest_segment": [[26.2854992, 50.1798305], [26.2863845, 50.179488]], "closest_point": [26.28581949070957, 50.17970658691046]}, {"latitude": 26.286893, "longitude": 50.179383, "time": "06/20/25,14:55:55", "speed": 69, "speed_limit": 50, "street_name": null, "street_name_ar": null, "distance_to_segment": 2.44, "vehicle_direction": 342, "segment_bearing": 349.4, "nearest_segment": [[26.2867917, 50.1793801], [26.2871531, 50.1793045]], "closest_point": [26.28688366288537, 50.17936086246147]}, {"latitude": 26.288445, "longitude": 50.180918, "time": "06/20/25,14:56:22", "speed": 61, "speed_limit": 50, "street_name": null, "street_name_ar": null, "distance_to_segment": 13.6, "vehicle_direction": 75, "segment_bearing": 87.4, "nearest_segment": [[26.2883247, 50.1806874], [26.2883319, 50.1808662]], "closest_point": [26.2883319, 50.1808662]}, {"latitude": 26.28789, "longitude": 50.183203, "time": "06/20/25,14:56:34", "speed": 73, "speed_limit": 50, "street_name": null, "street_name_ar": null, "distance_to_segment": 5.7, "vehicle_direction": 107, "segment_bearing": 108.0, "nearest_segment": [[26.2878493, 50.1831648], [26.287457, 50.1845093]], "closest_point": [26.287847512883715, 50.183170924863234]}, {"latitude": 26.287943, "longitude": 50.183007, "time": "06/20/25,14:56:33", "speed": 77, "speed_limit": 50, "street_name": null, "street_name_ar": null, "distance_to_segment": 5.85, "vehicle_direction": 105, "segment_bearing": 106.2, "nearest_segment": [[26.2882136, 50.1817693], [26.2878493, 50.1831648]], "closest_point": [26.287898844862088, 50.18297501215799]}, {"latitude": 26.287438, "longitude": 50.18491, "time": "06/20/25,14:56:35", "speed": 71, "speed_limit": 50, "street_name": null, "street_name_ar": null, "distance_to_segment": 9.98, "vehicle_direction": 106, "segment_bearing": 108.6, "nearest_segment": [[26.2874331, 50.1846238], [26.2871305, 50.1856285]], "closest_point": [26.28736394453852, 50.18485341201137]}, {"latitude": 26.288078, "longitude": 50.188698, "time": "06/20/25,15:00:05", "speed": 60, "speed_limit": 40, "street_name": "Makkah Al Mukarramah Street", "street_name_ar": "\u0634\u0627\u0631\u0639 \u0645\u0643\u0629 \u0627\u0644\u0645\u0643\u0631\u0645\u0629", "distance_to_segment": 2.26, "vehicle_direction": 340, "segment_bearing": 334.8, "nearest_segment": [[26.2880453, 50.18874], [26.288153, 50.1886836]], "closest_point": [26.288089020976663, 50.18871710432659]}, {"latitude": 26.292365, "longitude": 50.186845, "time": "06/20/25,15:03:08", "speed": 51, "speed_limit": 40, "street_name": "Makkah Al Mukarramah Street", "street_name_ar": "\u0634\u0627\u0631\u0639 \u0645\u0643\u0629 \u0627\u0644\u0645\u0643\u0631\u0645\u0629", "distance_to_segment": 2.93, "vehicle_direction": 340, "segment_bearing": 338.0, "nearest_segment": [[26.2913595, 50.1873294], [26.294309, 50.1860002]], "closest_point": [26.29237864116425, 50.1868701139378]}, {"latitude": 26.29658, "longitude": 50.185, "time": "06/20/25,15:03:44", "speed": 49, "speed_limit": 40, "street_name": "Makkah Al Mukarramah Street", "street_name_ar": "\u0634\u0627\u0631\u0639 \u0645\u0643\u0629 \u0627\u0644\u0645\u0643\u0631\u0645\u0629", "distance_to_segment": 0.76, "vehicle_direction": 338, "segment_bearing": 339.8, "nearest_segment": [[26.2964848, 50.185047], [26.2970144, 50.1848302]], "closest_point": [26.29658346116904, 50.185006611340526]}, {"latitude": 26.29755, "longitude": 50.186255, "time": "06/20/25,15:04:06", "speed": 41, "speed_limit": 40, "street_name": null, "street_name_ar": null, "distance_to_segment": 2.57, "vehicle_direction": 68, "segment_bearing": 249.1, "nearest_segment": [[26.2976593, 50.1866425], [26.2974655, 50.1860774]], "closest_point": [26.29752694708783, 50.186256572846474]}, {"latitude": 26.297498, "longitude": 50.188777, "time": "06/20/25,16:30:12", "speed": 44, "speed_limit": 40, "street_name": null, "street_name_ar": null, "distance_to_segment": 5.02, "vehicle_direction": 159, "segment_bearing": 159.7, "nearest_segment": [[26.2982408, 50.1884176], [26.29745, 50.1887439]], "closest_point": [26.29747516685935, 50.18873351556847]}, {"latitude": 26.294935, "longitude": 50.18992, "time": "06/20/25,16:30:34", "speed": 43, "speed_limit": 40, "street_name": null, "street_name_ar": null, "distance_to_segment": 9.05, "vehicle_direction": 153, "segment_bearing": 159.1, "nearest_segment": [[26.2955248, 50.1895726], [26.2924665, 50.1908772]], "closest_point": [26.294893471292472, 50.18984190413911]}, {"latitude": 26.287462, "longitude": 50.195782, "time": "06/20/25,16:34:51", "speed": 45, "speed_limit": 40, "street_name": null, "street_name_ar": null, "distance_to_segment": 12.42, "vehicle_direction": 120, "segment_bearing": 296.0, "nearest_segment": [[26.2871382, 50.196245], [26.2874143, 50.1956137]], "closest_point": [26.287374687981835, 50.19570427261239]}, {"latitude": 26.285898, "longitude": 50.191387, "time": "06/20/25,16:36:08", "speed": 72, "speed_limit": 60, "street_name": null, "street_name_ar": null, "distance_to_segment": 0.67, "vehicle_direction": 289, "segment_bearing": 288.7, "nearest_segment": [[26.2858077, 50.191704], [26.2859796, 50.1911389]], "closest_point": [26.285902969863756, 50.19139081225109]}, {"latitude": 26.288252, "longitude": 50.183185, "time": "06/20/25,16:37:06", "speed": 79, "speed_limit": 50, "street_name": null, "street_name_ar": null, "distance_to_segment": 2.76, "vehicle_direction": 287, "segment_bearing": 289.5, "nearest_segment": [[26.2878941, 50.1842345], [26.2885052, 50.1823058]], "closest_point": [26.288231653778393, 50.183169144299974]}, {"latitude": 26.288762, "longitude": 50.18157, "time": "06/20/25,16:37:06", "speed": 77, "speed_limit": 50, "street_name": null, "street_name_ar": null, "distance_to_segment": 3.64, "vehicle_direction": 288, "segment_bearing": 288.7, "nearest_segment": [[26.2885052, 50.1823058], [26.2889995, 50.1806786]], "closest_point": [26.288735003907185, 50.181549303348824]}, {"latitude": 26.288982, "longitude": 50.180658, "time": "06/20/25,16:37:06", "speed": 70, "speed_limit": 50, "street_name": null, "street_name_ar": null, "distance_to_segment": 2.52, "vehicle_direction": 285, "segment_bearing": 284.7, "nearest_segment": [[26.2889995, 50.1806786], [26.2891033, 50.1802383]], "closest_point": [26.28900119440345, 50.180671412665504]}, {"latitude": 26.247775, "longitude": 50.197408, "time": "06/20/25,16:40:20", "speed": 113, "speed_limit": 110, "street_name": "King Khaled Road", "street_name_ar": "\u0637\u0631\u064a\u0642 \u0627\u0644\u0645\u0644\u0643 \u062e\u0627\u0644\u062f", "distance_to_segment": 11.31, "vehicle_direction": 172, "segment_bearing": 175.9, "nearest_segment": [[26.2484747, 50.1972433], [26.2471891, 50.1973463]], "closest_point": [26.247738040532163, 50.19730231704182]}, {"latitude": 26.191442, "longitude": 50.187808, "time": "06/20/25,16:44:58", "speed": 41, "speed_limit": 40, "street_name": null, "street_name_ar": null, "distance_to_segment": 6.76, "vehicle_direction": 299, "segment_bearing": 121.5, "nearest_segment": [[26.1913841, 50.1877874], [26.1908701, 50.1887233]], "closest_point": [26.1913841, 50.1877874]}, {"latitude": 26.192178, "longitude": 50.188452, "time": "06/22/25,15:24:40", "speed": 42, "speed_limit": 40, "street_name": null, "street_name_ar": null, "distance_to_segment": 13.23, "vehicle_direction": 210, "segment_bearing": 31.0, "nearest_segment": [[26.1922287, 50.188332], [26.1930344, 50.1888718]], "closest_point": [26.1922287, 50.188332]}, {"latitude": 26.181925, "longitude": 50.182892, "time": "06/22/25,15:26:09", "speed": 79, "speed_limit": 40, "street_name": null, "street_name_ar": null, "distance_to_segment": 0.18, "vehicle_direction": 210, "segment_bearing": 207.6, "nearest_segment": [[26.1822474, 50.1830818], [26.1815841, 50.1826953]], "closest_point": [26.181924766952363, 50.18289380272174]}, {"latitude": 26.28577, "longitude": 50.179802, "time": "06/22/25,15:34:45", "speed": 66, "speed_limit": 50, "street_name": null, "street_name_ar": null, "distance_to_segment": 7.31, "vehicle_direction": 342, "segment_bearing": 340.9, "nearest_segment": [[26.2854992, 50.1798305], [26.2863845, 50.179488]], "closest_point": [26.28573737252638, 50.17973835645762]}, {"latitude": 26.288147, "longitude": 50.180002, "time": "06/22/25,15:35:15", "speed": 51, "speed_limit": 50, "street_name": null, "street_name_ar": null, "distance_to_segment": 3.76, "vehicle_direction": 46, "segment_bearing": 60.9, "nearest_segment": [[26.2881077, 50.1799993], [26.2882226, 50.1802298]], "closest_point": [26.28811479328776, 50.180013529770555]}, {"latitude": 26.287375, "longitude": 50.185008, "time": "06/22/25,15:35:37", "speed": 63, "speed_limit": 50, "street_name": null, "street_name_ar": null, "distance_to_segment": 6.31, "vehicle_direction": 110, "segment_bearing": 108.6, "nearest_segment": [[26.2874331, 50.1846238], [26.2871305, 50.1856285]], "closest_point": [26.287328164077145, 50.18497221128016]}, {"latitude": 26.28932, "longitude": 50.188128, "time": "06/22/25,15:38:06", "speed": 43, "speed_limit": 40, "street_name": "Makkah Al Mukarramah Street", "street_name_ar": "\u0634\u0627\u0631\u0639 \u0645\u0643\u0629 \u0627\u0644\u0645\u0643\u0631\u0645\u0629", "distance_to_segment": 6.94, "vehicle_direction": 340, "segment_bearing": 339.6, "nearest_segment": [[26.2888131, 50.1884117], [26.290195, 50.1878376]], "closest_point": [26.289351582471408, 50.18818798964738]}, {"latitude": 26.29328, "longitude": 50.186458, "time": "06/22/25,15:40:40", "speed": 57, "speed_limit": 40, "street_name": "Makkah Al Mukarramah Street", "street_name_ar": "\u0634\u0627\u0631\u0639 \u0645\u0643\u0629 \u0627\u0644\u0645\u0643\u0631\u0645\u0629", "distance_to_segment": 0.55, "vehicle_direction": 337, "segment_bearing": 338.0, "nearest_segment": [[26.2913595, 50.1873294], [26.294309, 50.1860002]], "closest_point": [26.293282580667427, 50.18646275117793]}, {"latitude": 26.29778, "longitude": 50.186902, "time": "06/22/25,15:41:35", "speed": 47, "speed_limit": 40, "street_name": null, "street_name_ar": null, "distance_to_segment": 3.45, "vehicle_direction": 68, "segment_bearing": 249.1, "nearest_segment": [[26.2978136, 50.1870925], [26.2976593, 50.1866425]], "closest_point": [26.29774900372367, 50.18690411144735]}, {"latitude": 26.299695, "longitude": 50.192598, "time": "06/22/25,17:06:21", "speed": 45, "speed_limit": 40, "street_name": null, "street_name_ar": null, "distance_to_segment": 0.82, "vehicle_direction": 69, "segment_bearing": 248.7, "nearest_segment": [[26.2997671, 50.1927829], [26.2995572, 50.1921815]], "closest_point": [26.299702364425325, 50.192597421017446]}, {"latitude": 26.297788, "longitude": 50.199213, "time": "06/22/25,17:08:08", "speed": 46, "speed_limit": 40, "street_name": null, "street_name_ar": "Abdullah bin Omar Street", "distance_to_segment": 1.37, "vehicle_direction": 158, "segment_bearing": 159.6, "nearest_segment": [[26.2977903, 50.1991976], [26.297339, 50.1993853]], "closest_point": [26.29778175985147, 50.199201151914366]}, {"latitude": 26.285727, "longitude": 50.19193, "time": "06/22/25,17:15:00", "speed": 74, "speed_limit": 60, "street_name": null, "street_name_ar": null, "distance_to_segment": 0.04, "vehicle_direction": 289, "segment_bearing": 291.8, "nearest_segment": [[26.2857096, 50.1919774], [26.2858077, 50.191704]], "closest_point": [26.285726696909705, 50.191929751754444]}, {"latitude": 26.288502, "longitude": 50.182342, "time": "06/22/25,17:15:51", "speed": 67, "speed_limit": 50, "street_name": null, "street_name_ar": null, "distance_to_segment": 0.9, "vehicle_direction": 287, "segment_bearing": 289.5, "nearest_segment": [[26.2878941, 50.1842345], [26.2885052, 50.1823058]], "closest_point": [26.288495367816882, 50.18233683158611]}, {"latitude": 26.288967, "longitude": 50.180568, "time": "06/22/25,17:15:56", "speed": 66, "speed_limit": 50, "street_name": null, "street_name_ar": null, "distance_to_segment": 6.6, "vehicle_direction": 286, "segment_bearing": 284.7, "nearest_segment": [[26.2889995, 50.1806786], [26.2891033, 50.1802383]], "closest_point": [26.289017289313904, 50.180603141133744]}, {"latitude": 26.276548, "longitude": 50.183443, "time": "06/22/25,17:16:58", "speed": 111, "speed_limit": 110, "street_name": "King Khaled Road", "street_name_ar": "\u0637\u0631\u064a\u0642 \u0627\u0644\u0645\u0644\u0643 \u062e\u0627\u0644\u062f", "distance_to_segment": 1.97, "vehicle_direction": 158, "segment_bearing": 158.9, "nearest_segment": [[26.2820518, 50.1810501], [26.2751079, 50.1840428]], "closest_point": [26.276538933193045, 50.18342601861155]}, {"latitude": 26.252535, "longitude": 50.195902, "time": "06/22/25,17:18:57", "speed": 114, "speed_limit": 110, "street_name": "King Khaled Road", "street_name_ar": "\u0637\u0631\u064a\u0642 \u0627\u0644\u0645\u0644\u0643 \u062e\u0627\u0644\u062f", "distance_to_segment": 11.4, "vehicle_direction": 147, "segment_bearing": 147.9, "nearest_segment": [[26.2528193, 50.1955686], [26.2522121, 50.1959932]], "closest_point": [26.252474649895735, 50.195809605179406]}, {"latitude": 26.236332, "longitude": 50.194452, "time": "06/22/25,17:19:43", "speed": 111, "speed_limit": 110, "street_name": "King Khaled Road", "street_name_ar": "\u0637\u0631\u064a\u0642 \u0627\u0644\u0645\u0644\u0643 \u062e\u0627\u0644\u062f", "distance_to_segment": 6.47, "vehicle_direction": 197, "segment_bearing": 187.3, "nearest_segment": [[26.2371349, 50.1945053], [26.2361726, 50.194368]], "closest_point": [26.23631864945483, 50.19438883713221]}, {"latitude": 26.210365, "longitude": 50.19697, "time": "06/22/25,17:21:47", "speed": 63, "speed_limit": 60, "street_name": null, "street_name_ar": null, "distance_to_segment": 1.36, "vehicle_direction": 179, "segment_bearing": 176.0, "nearest_segment": [[26.2109795, 50.1969355], [26.21013, 50.1970012]], "closest_point": [26.210369413267323, 50.196982682851264]}, {"latitude": 26.2086, "longitude": 50.193113, "time": "06/22/25,17:44:39", "speed": 50, "speed_limit": 40, "street_name": null, "street_name_ar": null, "distance_to_segment": 4.22, "vehicle_direction": 270, "segment_bearing": 271.6, "nearest_segment": [[26.2086309, 50.1932976], [26.2086823, 50.1912251]], "closest_point": [26.208635076602008, 50.193129195248424]}, {"latitude": 26.208527, "longitude": 50.1915, "time": "06/22/25,17:56:33", "speed": 53, "speed_limit": 40, "street_name": null, "street_name_ar": null, "distance_to_segment": 4.61, "vehicle_direction": 89, "segment_bearing": 91.5, "nearest_segment": [[26.2086208, 50.189079], [26.2085344, 50.1928748]], "closest_point": [26.208565292950368, 50.19151758465027]}, {"latitude": 26.200445, "longitude": 50.194977, "time": "06/22/25,17:58:22", "speed": 48, "speed_limit": 40, "street_name": null, "street_name_ar": "\u0634\u0627\u0631\u0639 \u0623\u0628\u0648 \u0639\u0628\u062f\u0627\u0644\u0631\u062d\u0645\u0646 \u0628\u0646 \u0639\u0642\u064a\u0644", "distance_to_segment": 14.29, "vehicle_direction": 185, "segment_bearing": 176.6, "nearest_segment": [[26.2008529, 50.195087], [26.2004795, 50.1951116]], "closest_point": [26.20049067955637, 50.19511086344995]}, {"latitude": 26.192077, "longitude": 50.188225, "time": "06/24/25,13:18:23", "speed": 43, "speed_limit": 40, "street_name": null, "street_name_ar": null, "distance_to_segment": 0.84, "vehicle_direction": 215, "segment_bearing": 30.0, "nearest_segment": [[26.1918386, 50.1880805], [26.1922287, 50.188332]], "closest_point": [26.192075472619948, 50.18823321283599]}, {"latitude": 26.182207, "longitude": 50.183087, "time": "06/24/25,13:19:51", "speed": 51, "speed_limit": 40, "street_name": null, "street_name_ar": null, "distance_to_segment": 2.69, "vehicle_direction": 211, "segment_bearing": 207.6, "nearest_segment": [[26.1822474, 50.1830818], [26.1815841, 50.1826953]], "closest_point": [26.182210455233704, 50.18306027226557]}, {"latitude": 26.21024, "longitude": 50.197573, "time": "06/24/25,13:31:57", "speed": 88, "speed_limit": 60, "street_name": null, "street_name_ar": null, "distance_to_segment": 12.91, "vehicle_direction": 357, "segment_bearing": 355.9, "nearest_segment": [[26.2098817, 50.1977254], [26.2103284, 50.1976899]], "closest_point": [26.2102821073148, 50.19769357882846]}, {"latitude": 26.255402, "longitude": 50.193758, "time": "06/24/25,13:35:08", "speed": 112, "speed_limit": 110, "street_name": "King Khaled Road", "street_name_ar": "\u0637\u0631\u064a\u0642 \u0627\u0644\u0645\u0644\u0643 \u062e\u0627\u0644\u062f", "distance_to_segment": 10.92, "vehicle_direction": 324, "segment_bearing": 324.7, "nearest_segment": [[26.2554333, 50.1938674], [26.2563649, 50.193132]], "closest_point": [26.25546188688344, 50.193844833646956]}, {"latitude": 26.285608, "longitude": 50.17979, "time": "06/24/25,13:37:21", "speed": 76, "speed_limit": 50, "street_name": null, "street_name_ar": null, "distance_to_segment": 0.15, "vehicle_direction": 338, "segment_bearing": 340.9, "nearest_segment": [[26.2854992, 50.1798305], [26.2863845, 50.179488]], "closest_point": [26.285607318793392, 50.179788671233275]}, {"latitude": 26.306643, "longitude": 50.175115, "time": "06/24/25,13:45:31", "speed": 97, "speed_limit": 60, "street_name": null, "street_name_ar": "King Saud Road", "distance_to_segment": 7.77, "vehicle_direction": 31, "segment_bearing": 30.5, "nearest_segment": [[26.3045735, 50.1738394], [26.3068764, 50.1753545]], "closest_point": [26.306628069224146, 50.17519111400513]}, {"latitude": 26.314975, "longitude": 50.179677, "time": "06/24/25,13:46:08", "speed": 96, "speed_limit": 60, "street_name": null, "street_name_ar": "King Saud Road", "distance_to_segment": 6.9, "vehicle_direction": 12, "segment_bearing": 7.1, "nearest_segment": [[26.3144986, 50.1796757], [26.3150242, 50.1797492]], "closest_point": [26.314989397625684, 50.17974433307846]}, {"latitude": 26.324393, "longitude": 50.17936, "time": "06/24/25,13:46:48", "speed": 101, "speed_limit": 100, "street_name": "King Saud Road", "street_name_ar": "\u0637\u0631\u064a\u0642 \u0627\u0644\u0645\u0644\u0643 \u0633\u0639\u0648\u062f", "distance_to_segment": 8.11, "vehicle_direction": 356, "segment_bearing": 358.3, "nearest_segment": [[26.3239171, 50.1794536], [26.3271943, 50.179342]], "closest_point": [26.32441771775672, 50.17943654201844]}, {"latitude": 26.328808, "longitude": 50.17948, "time": "06/24/25,13:47:08", "speed": 94, "speed_limit": 40, "street_name": null, "street_name_ar": "King Saud Road", "distance_to_segment": 5.59, "vehicle_direction": 1, "segment_bearing": 1.7, "nearest_segment": [[26.328206, 50.1795136], [26.3289356, 50.1795371]], "closest_point": [26.32882312159297, 50.17953347658482]}]; | |
// Add device name to each point's data | |
pathData.forEach(function(data) { | |
data.device_name = "3181 BBD (CTS-OBD)"; | |
}); | |
// Function to create numbered div icons for violations | |
function createNumberedIcon(number, isLast = false) { | |
if (isLast) { | |
return L.divIcon({ | |
className: 'number-icon violation-icon', | |
html: 'V<div class="pulse-ring"></div>', | |
iconSize: [32, 32] | |
}); | |
} else { | |
return L.divIcon({ | |
className: 'number-icon', | |
html: number.toString(), | |
iconSize: [24, 24] | |
}); | |
} | |
} | |
// Function to create popup content | |
function createPopupContent(pointNum, data, isLast) { | |
var lat = data.latitude; | |
var lon = data.longitude; | |
var speedClass = 'speed-violation'; | |
var html = '<div class="popup-content">'; | |
html += '<div class="popup-title">Violation Point ' + pointNum + (isLast ? ' (Latest)' : '') + '</div>'; | |
html += '<table>'; | |
html += '<tr><td>Latitude:</td><td>' + lat.toFixed(6) + '</td></tr>'; | |
html += '<tr><td>Longitude:</td><td>' + lon.toFixed(6) + '</td></tr>'; | |
if (data.time) { | |
html += '<tr><td>Time:</td><td>' + data.time + '</td></tr>'; | |
} | |
if (data.device_name) { | |
html += '<tr><td>Vehicle:</td><td>' + data.device_name + '</td></tr>'; | |
} | |
if (data.street_name_ar) { | |
html += '<tr><td>Street (AR):</td><td style="direction: rtl;">' + data.street_name_ar + '</td></tr>'; | |
} | |
if (data.street_name) { | |
html += '<tr><td>Street (EN):</td><td>' + data.street_name + '</td></tr>'; | |
} | |
if (data.distance_to_segment !== undefined) { | |
html += '<tr><td>Dist to street:</td><td>' + data.distance_to_segment.toFixed(2) + ' m</td></tr>'; | |
} | |
if (data.vehicle_direction !== undefined) { | |
html += '<tr><td>Vehicle Dir:</td><td>' + data.vehicle_direction.toFixed(1) + '°</td></tr>'; | |
} | |
if (data.segment_bearing !== undefined) { | |
html += '<tr><td>Street Bearing:</td><td>' + data.segment_bearing.toFixed(1) + '°</td></tr>'; | |
} | |
if (data.speed_limit) { | |
html += '<tr><td>Speed Limit:</td><td>' + data.speed_limit + ' km/h</td></tr>'; | |
} | |
if (data.speed) { | |
html += '<tr><td>Vehicle Speed:</td><td class="' + speedClass + '">' + data.speed + ' km/h</td></tr>'; | |
} | |
if (data.speed && data.speed_limit) { | |
var overSpeed = data.speed - data.speed_limit; | |
html += '<tr><td>Over Speed:</td><td class="speed-violation">+' + overSpeed + ' km/h</td></tr>'; | |
} | |
html += '</table>'; | |
html += '</div>'; | |
return html; | |
} | |
// Function to create direction arrow from point | |
function createDirectionArrow(lat, lon, direction) { | |
if (direction === undefined || direction === null) return null; | |
var arrowLength = 0.0002; // Length of arrow in degrees | |
var radians = direction * Math.PI / 180; | |
var endLat = lat + arrowLength * Math.cos(radians); | |
var endLon = lon + arrowLength * Math.sin(radians); | |
var arrow = L.polyline([[lat, lon], [endLat, endLon]], { | |
color: '#3498db', | |
weight: 3, | |
opacity: 0.8 | |
}); | |
var decorator = L.polylineDecorator(arrow, { | |
patterns: [{ | |
offset: '100%', | |
repeat: 0, | |
symbol: L.Symbol.arrowHead({ | |
pixelSize: 12, | |
polygon: false, | |
pathOptions: { | |
stroke: true, | |
color: '#3498db', | |
weight: 2, | |
opacity: 0.9 | |
} | |
}) | |
}] | |
}); | |
return { arrow: arrow, decorator: decorator }; | |
} | |
// Add markers for all points - all are violation points | |
var allBounds = []; | |
for (var i = 0; i < pathData.length; i++) { | |
var data = pathData[i]; | |
var isLast = (i === latlngs.length - 1); | |
var icon = createNumberedIcon(i + 1, isLast); | |
var popupContent = createPopupContent(i + 1, data, isLast); | |
// Add marker to map | |
var vehicleMarker = L.marker([data.latitude, data.longitude], {icon: icon}) | |
.addTo(map) | |
.bindPopup(popupContent); | |
allBounds.push([data.latitude, data.longitude]); | |
// Add direction arrow for each point | |
if (data.vehicle_direction !== undefined && data.vehicle_direction !== null) { | |
var directionArrowData = createDirectionArrow(data.latitude, data.longitude, data.vehicle_direction); | |
if (directionArrowData) { | |
directionArrowData.arrow.addTo(map); | |
directionArrowData.decorator.addTo(map); | |
} | |
} | |
// Draw the nearest street segment for each point if available | |
if (data.nearest_segment && data.nearest_segment.length === 2) { | |
var segmentPolyline = L.polyline(data.nearest_segment, { | |
color: '#9b59b6', | |
weight: 8, | |
opacity: 0.8 | |
}).addTo(map).bindPopup('Nearest Street Segment for Violation ' + (i + 1)); | |
// Add enhanced start and end circles for the segment | |
L.circleMarker(data.nearest_segment[0], { | |
radius: 6, | |
color: '#8e44ad', | |
fillColor: '#9b59b6', | |
fillOpacity: 1, | |
weight: 2 | |
}).addTo(map); | |
L.circleMarker(data.nearest_segment[1], { | |
radius: 6, | |
color: '#8e44ad', | |
fillColor: '#9b59b6', | |
fillOpacity: 1, | |
weight: 2 | |
}).addTo(map); | |
} | |
// Draw the closest point on the segment and a line to it | |
if (data.closest_point && data.closest_point.length === 2) { | |
// Enhanced closest point marker | |
L.circleMarker(data.closest_point, { | |
radius: 8, | |
color: '#e67e22', | |
fillColor: '#f39c12', | |
fillOpacity: 1, | |
weight: 3 | |
}).addTo(map).bindPopup('Closest Point on Street<br>Distance: ' + (data.distance_to_segment ? data.distance_to_segment.toFixed(2) + ' m' : 'N/A')); | |
// Enhanced dashed line from vehicle to closest point | |
var lineToClosest = [ | |
[data.latitude, data.longitude], | |
data.closest_point | |
]; | |
L.polyline(lineToClosest, { | |
color: '#3498db', | |
weight: 3, | |
opacity: 0.7, | |
dashArray: '8, 8' | |
}).addTo(map); | |
} | |
} | |
// Fit the map to show all points | |
if (allBounds.length > 0) { | |
var bounds = L.latLngBounds(allBounds); | |
map.fitBounds(bounds.pad(0.1)); | |
} | |
// Add enhanced legend with toggle functionality | |
var legendHtml = '<button class="legend-toggle-btn" onclick="toggleLegend()"><i class="fas fa-chevron-right"></i></button>'; | |
legendHtml += '<div class="legend-title">Map Legend</div>'; | |
legendHtml += '<div class="legend-item"><div class="legend-marker" style="background: #FF1744;"></div><span>Violation Points</span></div>'; | |
legendHtml += '<div class="legend-item"><div class="legend-marker" style="background: #FF1744; width: 24px; height: 24px;"></div><span>Latest Violation</span></div>'; | |
legendHtml += '<div class="legend-item"><div class="legend-arrow"></div><span>Vehicle Direction</span></div>'; | |
legendHtml += '<div class="legend-item"><div class="legend-line" style="background: #9b59b6; height: 6px;"></div><span>Nearest Street Segment</span></div>'; | |
legendHtml += '<div class="legend-item"><div class="legend-marker" style="background: #f39c12;"></div><span>Closest Point</span></div>'; | |
legendHtml += '<div class="legend-item"><div class="legend-line" style="background: #3498db; border: 2px dashed #3498db; height: 2px;"></div><span>Distance Line</span></div>'; | |
var legendControl = L.control({position: 'bottomright'}); | |
legendControl.onAdd = function (map) { | |
var div = L.DomUtil.create('div', 'legend'); | |
div.id = 'mapLegend'; | |
div.innerHTML = legendHtml; | |
return div; | |
}; | |
legendControl.addTo(map); | |
// Toggle legend function | |
function toggleLegend() { | |
var legend = document.getElementById('mapLegend'); | |
legend.classList.toggle('collapsed'); | |
} | |
// Add info control | |
var infoControl = L.control({position: 'topleft'}); | |
infoControl.onAdd = function (map) { | |
var div = L.DomUtil.create('div', 'info-control'); | |
div.innerHTML = '<h4><i class="fas fa-car" style="margin-right: 8px; color: #3498db;"></i>Vehicle Path Analysis</h4>' + | |
'<div><strong>Vehicle:</strong> 3181 BBD (CTS-OBD)</div>' + | |
'<div><strong>Total Violations:</strong> ' + latlngs.length + '</div>'; | |
return div; | |
}; | |
infoControl.addTo(map); | |
// Add zoom control to top right | |
L.control.zoom({position: 'topright'}).addTo(map); | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment