Created
June 12, 2025 10:07
-
-
Save youssef22222/afed15882f46407fe6cd3ed0775a8fe5 to your computer and use it in GitHub Desktop.
Speed Violation Map - 1692 EDD/New (Afzal) - 1749722845
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 - 1692 EDD/New (Afzal)</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" /> | |
<style> | |
html, body { height: 100%; margin: 0; padding: 0; } | |
#map { height: 100%; } | |
.number-icon { | |
background-color: #4285F4; | |
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); | |
} | |
.start-icon { | |
background-color: #00C853; | |
} | |
.end-icon { | |
background-color: #FF6F00; /* Orange for violation/end point */ | |
width: 30px; | |
height: 30px; | |
line-height: 26px; | |
font-size: 14px; | |
} | |
.popup-content { | |
min-width: 250px; | |
} | |
.popup-content table { | |
width: 100%; | |
border-collapse: collapse; | |
} | |
.popup-content td { | |
padding: 2px 5px; | |
border-bottom: 1px solid #eee; | |
} | |
.popup-content td:first-child { | |
font-weight: bold; | |
width: 40%; | |
} | |
.speed-ok { color: green; } | |
.speed-violation { color: red; font-weight: bold; } | |
.legend-toggle { | |
position: absolute; | |
top: 90px; | |
right: 10px; | |
z-index: 1000; | |
background: white; | |
padding: 8px; | |
border: 2px solid #ccc; | |
border-radius: 5px; | |
cursor: pointer; | |
font-size: 14px; | |
font-family: Arial, sans-serif; | |
box-shadow: 0 1px 5px rgba(0,0,0,0.4); | |
} | |
</style> | |
</head> | |
<body> | |
<div id="map"></div> | |
<div id="legend-toggle" class="legend-toggle">Hide Legend</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.67030875, 49.897912625], 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.864942, 49.770333], | |
[26.830917, 49.797538], | |
[26.748077, 49.86894], | |
[26.656478, 49.926685], | |
[26.651943, 49.92752], | |
[26.558905, 49.953805], | |
[26.55443, 49.955117], | |
[26.496778, 49.983363] | |
]; | |
var pathData = [{"latitude": 26.864942, "longitude": 49.770333, "time": "06/12/25,12:40:55", "speed": 206, "speed_limit": 120, "street_name": "Dhahran Jubail Expressway", "street_name_ar": "\u0637\u0631\u064a\u0642 \u0627\u0644\u0638\u0647\u0631\u0627\u0646 \u0627\u0644\u062c\u0628\u064a\u0644 \u0627\u0644\u0633\u0631\u064a\u0639", "distance_to_segment": 7.55, "vehicle_direction": 129, "segment_bearing": 132.4, "nearest_segment": [[26.8667993, 49.7679405], [26.863677, 49.7717739]], "closest_point": [26.864887059454407, 49.77028825098724], "angle_difference": 3.4}, {"latitude": 26.830917, "longitude": 49.797538, "time": "06/12/25,12:43:37", "speed": 201, "speed_limit": 120, "street_name": "Dhahran Jubail Expressway", "street_name_ar": "\u0637\u0631\u064a\u0642 \u0627\u0644\u0638\u0647\u0631\u0627\u0646 \u0627\u0644\u062c\u0628\u064a\u0644 \u0627\u0644\u0633\u0631\u064a\u0639", "distance_to_segment": 2.01, "vehicle_direction": 149, "segment_bearing": 149.5, "nearest_segment": [[26.8329402, 49.7961802], [26.8305947, 49.7977272]], "closest_point": [26.830906255762233, 49.797521710013136], "angle_difference": 0.5}, {"latitude": 26.748077, "longitude": 49.86894, "time": "06/12/25,12:50:19", "speed": 206, "speed_limit": 120, "street_name": "Dhahran Jubail Expressway", "street_name_ar": "\u0637\u0631\u064a\u0642 \u0627\u0644\u0638\u0647\u0631\u0627\u0646 \u0627\u0644\u062c\u0628\u064a\u0644 \u0627\u0644\u0633\u0631\u064a\u0639", "distance_to_segment": 0.39, "vehicle_direction": 156, "segment_bearing": 156.2, "nearest_segment": [[26.7502086, 49.8678813], [26.7471033, 49.8694173]], "closest_point": [26.748075279543855, 49.86893652178876], "angle_difference": 0.2}, {"latitude": 26.656478, "longitude": 49.926685, "time": "06/12/25,12:56:45", "speed": 213, "speed_limit": 120, "street_name": "Dhahran Jubail Expressway", "street_name_ar": "\u0637\u0631\u064a\u0642 \u0627\u0644\u0638\u0647\u0631\u0627\u0646 \u0627\u0644\u062c\u0628\u064a\u0644 \u0627\u0644\u0633\u0631\u064a\u0639", "distance_to_segment": 5.66, "vehicle_direction": 170, "segment_bearing": 170.6, "nearest_segment": [[26.6593496, 49.9260945], [26.6545753, 49.9269804]], "closest_point": [26.656467657429527, 49.92662926172908], "angle_difference": 0.6}, {"latitude": 26.651943, "longitude": 49.92752, "time": "06/12/25,12:57:02", "speed": 217, "speed_limit": 120, "street_name": "Dhahran Jubail Expressway", "street_name_ar": "\u0637\u0631\u064a\u0642 \u0627\u0644\u0638\u0647\u0631\u0627\u0646 \u0627\u0644\u062c\u0628\u064a\u0644 \u0627\u0644\u0633\u0631\u064a\u0639", "distance_to_segment": 7.74, "vehicle_direction": 171, "segment_bearing": 170.9, "nearest_segment": [[26.6542951, 49.9270189], [26.6486678, 49.9280291]], "closest_point": [26.651929285840918, 49.92744360553614], "angle_difference": 0.1}, {"latitude": 26.558905, "longitude": 49.953805, "time": "06/12/25,13:02:47", "speed": 211, "speed_limit": 120, "street_name": "Dhahran Jubail Expressway", "street_name_ar": "\u0637\u0631\u064a\u0642 \u0627\u0644\u0638\u0647\u0631\u0627\u0646 \u0627\u0644\u062c\u0628\u064a\u0644 \u0627\u0644\u0633\u0631\u064a\u0639", "distance_to_segment": 3.36, "vehicle_direction": 152, "segment_bearing": 160.9, "nearest_segment": [[26.559338, 49.9536017], [26.5588739, 49.9537814]], "closest_point": [26.55889299869117, 49.95377400496702], "angle_difference": 8.9}, {"latitude": 26.55443, "longitude": 49.955117, "time": "06/12/25,13:03:04", "speed": 208, "speed_limit": 120, "street_name": "Dhahran Jubail Expressway", "street_name_ar": "\u0637\u0631\u064a\u0642 \u0627\u0644\u0638\u0647\u0631\u0627\u0646 \u0627\u0644\u062c\u0628\u064a\u0644 \u0627\u0644\u0633\u0631\u064a\u0639", "distance_to_segment": 2.32, "vehicle_direction": 160, "segment_bearing": 168.5, "nearest_segment": [[26.5552019, 49.9549171], [26.553759, 49.9552464]], "closest_point": [26.55442485107079, 49.955094438840106], "angle_difference": 8.5}, {"latitude": 26.496778, "longitude": 49.983363, "time": "06/12/25,13:07:10", "speed": 198, "speed_limit": 120, "street_name": "", "street_name_ar": "To Road 95", "distance_to_segment": 0.95, "vehicle_direction": 147, "segment_bearing": 147.8, "nearest_segment": [[26.4978788, 49.9825766], [26.496404, 49.9836152]], "closest_point": [26.49677273574902, 49.98335552482443], "angle_difference": 0.8}]; | |
// Draw the polyline (straight lines between points) | |
var polyline = L.polyline(latlngs, { | |
color: 'blue', | |
weight: 4, | |
opacity: 0.6, | |
dashArray: '10, 5' | |
}).addTo(map); | |
// Add directional arrows | |
var decorator = L.polylineDecorator(polyline, { | |
patterns: [ | |
{ | |
offset: 25, | |
repeat: 50, | |
symbol: L.Symbol.arrowHead({ | |
pixelSize: 12, | |
polygon: false, | |
pathOptions: { | |
stroke: true, | |
color: 'blue', | |
weight: 2, | |
opacity: 0.8 | |
} | |
}) | |
} | |
] | |
}).addTo(map); | |
// Function to create numbered div icons | |
function createNumberedIcon(number, extraClass = '') { | |
return L.divIcon({ | |
className: 'number-icon ' + extraClass, | |
html: number.toString(), | |
iconSize: [24, 24] | |
}); | |
} | |
// Function to create popup content | |
function createPopupContent(pointNum, data) { | |
var lat = data.latitude; | |
var lon = data.longitude; | |
var isViolation = data.speed && data.speed_limit && (data.speed > data.speed_limit); | |
var speedClass = isViolation ? 'speed-violation' : 'speed-ok'; | |
var html = '<div class="popup-content">'; | |
html += '<h4 style="margin: 0 0 5px 0;">Point ' + pointNum + '</h4>'; | |
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) { // This is street_name_en | |
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.angle_difference !== undefined) { | |
html += '<tr><td>Direction Diff:</td><td>' + data.angle_difference.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 (isViolation) { | |
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; | |
} | |
// Add markers for all points | |
for (var i = 0; i < pathData.length; i++) { | |
var iconClass = ''; | |
var icon; | |
var data = pathData[i]; | |
data.device_name = "1692 EDD/New (Afzal)"; // Add device name to each point's data | |
if (i === 0) { | |
iconClass = 'start-icon'; | |
icon = createNumberedIcon('S', iconClass); | |
} else if (i === latlngs.length - 1) { | |
iconClass = 'end-icon'; // End point is the violation point | |
icon = createNumberedIcon('V', iconClass); | |
} else { | |
icon = createNumberedIcon(i + 1); | |
} | |
var popupContent = createPopupContent(i + 1, data); | |
var vehicleMarker = L.marker([data.latitude, data.longitude], {icon: icon}) | |
.addTo(map) | |
.bindPopup(popupContent); | |
// Draw the nearest street segment for each point if available | |
if (data.nearest_segment && data.nearest_segment.length === 2) { | |
L.polyline(data.nearest_segment, { | |
color: 'red', | |
weight: 6, | |
opacity: 0.8 | |
}).addTo(map).bindPopup('Nearest Street Segment for Point ' + (i + 1)); | |
// Add start and end circles for the segment | |
L.circleMarker(data.nearest_segment[0], { radius: 4, color: 'black', fillColor: 'red', fillOpacity: 1 }).addTo(map); | |
L.circleMarker(data.nearest_segment[1], { radius: 4, color: 'black', fillColor: 'red', fillOpacity: 1 }).addTo(map); | |
} | |
// Draw the closest point on the segment and a line to it | |
if (data.closest_point && data.closest_point.length === 2) { | |
// Draw a small yellow circle at the closest point on the segment | |
L.circleMarker(data.closest_point, { radius: 4, color: 'black', fillColor: 'yellow', fillOpacity: 1 }).addTo(map); | |
// Draw a dashed line from the vehicle to the closest point | |
var line_to_closest = [ | |
[data.latitude, data.longitude], | |
data.closest_point | |
]; | |
L.polyline(line_to_closest, { | |
color: 'grey', | |
weight: 2, | |
opacity: 0.8, | |
dashArray: '5, 5' | |
}).addTo(map); | |
} | |
} | |
// Fit the map to show all points | |
map.fitBounds(polyline.getBounds().pad(0.1)); | |
// Add a legend | |
var legend = L.control({position: 'bottomright'}); | |
legend.onAdd = function (map) { | |
var div = L.DomUtil.create('div', 'legend'); | |
div.style.background = 'white'; | |
div.style.padding = '10px'; | |
div.style.border = '2px solid #ccc'; | |
div.style.borderRadius = '5px'; | |
div.style.fontSize = '12px'; | |
div.innerHTML = '<h4 style="margin: 0 0 5px 0;">Legend</h4>' + | |
'<p style="margin: 2px 0;"><span style="color: #00C853; font-weight: bold;">S</span> Start Point</p>' + | |
'<p style="margin: 2px 0;"><span style="color: #4285F4; font-weight: bold;">1-9</span> Path Points</p>' + | |
'<p style="margin: 2px 0;"><span style="color: #FF6F00; font-weight: bold;">V</span> Violation Location</p>' + | |
'<p style="margin: 2px 0;"><span style="background: #9b59b6; display: inline-block; width: 30px; height: 6px; border-radius: 3px; margin-right: 5px;"></span> Nearest Street Segment</p>' + | |
'<p style="margin: 2px 0;"><span style="color: blue;">- - →</span> Vehicle Path</p>' + | |
'<hr style="margin: 5px 0;">' + | |
'<p style="margin: 2px 0; font-style: italic; font-size: 11px;">Note: Lines show direct paths<br>between GPS points, not<br>actual street routes.</p>'; | |
return div; | |
}; | |
legend.addTo(map); | |
var legendContainer = legend.getContainer(); | |
// Add info control | |
var info = L.control({position: 'topleft'}); | |
info.onAdd = function (map) { | |
var div = L.DomUtil.create('div', 'info'); | |
div.style.background = 'rgba(255,255,255,0.9)'; | |
div.style.padding = '8px'; | |
div.style.border = '2px solid #ccc'; | |
div.style.borderRadius = '5px'; | |
div.style.fontSize = '14px'; | |
var violationCount = 0; | |
for (var i = 0; i < pathData.length; i++) { | |
var d = pathData[i]; | |
if (d.speed && d.speed_limit && d.speed > d.speed_limit) { | |
violationCount++; | |
} | |
} | |
div.innerHTML = '<b>Vehicle:</b> 1692 EDD/New (Afzal)<br>' + | |
'<b>Total Points:</b> ' + latlngs.length + '<br>' + | |
'<b>Violations on Path:</b> ' + violationCount; | |
return div; | |
}; | |
info.addTo(map); | |
// Legend toggle logic | |
var toggleButton = document.getElementById('legend-toggle'); | |
var legendVisible = true; | |
toggleButton.addEventListener('click', function() { | |
if (legendVisible) { | |
legendContainer.style.display = 'none'; | |
toggleButton.innerHTML = 'Show Legend'; | |
} else { | |
legendContainer.style.display = 'block'; | |
toggleButton.innerHTML = 'Hide Legend'; | |
} | |
legendVisible = !legendVisible; | |
}); | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment