160 lines
7.3 KiB
HTML
Executable File
160 lines
7.3 KiB
HTML
Executable File
<!DOCTYPE html>
|
|
<html lang="ar" dir="rtl">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>خريطة الكثافة الحرارية (Grid Heatmap) - OpenStreetMap</title>
|
|
|
|
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" />
|
|
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
|
|
|
|
<style>
|
|
body { margin: 0; padding: 0; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; }
|
|
#map { height: 100vh; width: 100%; }
|
|
.info-box {
|
|
position: absolute;
|
|
top: 10px;
|
|
right: 10px;
|
|
z-index: 1000;
|
|
background: white;
|
|
padding: 15px;
|
|
border-radius: 8px;
|
|
box-shadow: 0 0 10px rgba(0,0,0,0.2);
|
|
max-width: 300px;
|
|
}
|
|
.legend {
|
|
margin-top: 10px;
|
|
line-height: 1.5;
|
|
}
|
|
.legend i {
|
|
width: 18px;
|
|
height: 18px;
|
|
float: right;
|
|
margin-left: 8px;
|
|
opacity: 0.7;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
|
|
<div class="info-box">
|
|
<h3>تحليل كثافة الرحلات</h3>
|
|
<p>هذه الخريطة تقسم المنطقة إلى مربعات جغرافية وتحسب عدد الرحلات في كل مربع.</p>
|
|
<div class="legend">
|
|
<div><i style="background: #bd0026"></i> طلبات عالية جداً (+5)</div>
|
|
<div><i style="background: #f03b20"></i> طلبات عالية (3-4)</div>
|
|
<div><i style="background: #fd8d3c"></i> طلبات متوسطة (2)</div>
|
|
<div><i style="background: #feb24c"></i> طلب واحد (1)</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div id="map"></div>
|
|
|
|
<script>
|
|
// 1. تهيئة الخريطة (مركزها دمشق مبدئياً)
|
|
var map = L.map('map').setView([33.513, 36.276], 13);
|
|
|
|
// 2. إضافة طبقة OpenStreetMap
|
|
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
|
|
attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
|
|
}).addTo(map);
|
|
|
|
// 3. البيانات المستخرجة من ملفك (ride.json)
|
|
// ملاحظة: قمت بوضع البيانات هنا لمحاكاتها، في الواقع سيقوم السكربت بطلبها من ملف heatmap.json
|
|
var rawData = [
|
|
{"type":"header","version":"5.2.2","comment":"Export to JSON plugin for PHPMyAdmin"},
|
|
{"type":"database","name":"intaleq-ridesDB"},
|
|
{"type":"table","name":"ride","database":"intaleq-ridesDB","data": [
|
|
// ... تم نسخ عينة من بياناتك هنا لتعمل الصفحة ...
|
|
{"start_location":"33.4323,36.2432"}, {"start_location":"34.68947,36.36329"},
|
|
{"start_location":"33.5445,36.30571"}, {"start_location":"33.4323,36.24326"},
|
|
{"start_location":"33.43222,36.24319"}, {"start_location":"33.51326,36.27646"},
|
|
{"start_location":"33.50895,36.29209"}, {"start_location":"33.49631,36.3221"},
|
|
{"start_location":"33.55463,36.32338"}, {"start_location":"33.53447,36.29727"},
|
|
{"start_location":"33.5727,36.192"}, {"start_location":"33.52811,36.37998"},
|
|
{"start_location":"33.54115,36.21846"}, {"start_location":"33.4323,36.24309"},
|
|
{"start_location":"33.50312,36.25959"}, {"start_location":"33.52518,36.35682"},
|
|
{"start_location":"33.51814,36.3119"}, {"start_location":"33.50142,36.27113"},
|
|
{"start_location":"33.49593,36.30942"}, {"start_location":"33.55189,36.32245"},
|
|
{"start_location":"33.5322,36.29513"}, {"start_location":"33.53994,36.22878"},
|
|
{"start_location":"33.52441,36.28758"}, {"start_location":"33.46744,36.19679"},
|
|
{"start_location":"33.52842,36.23082"}, {"start_location":"33.50236,36.27406"},
|
|
{"start_location":"33.4323,36.24331"}, {"start_location":"33.51246,36.29807"}
|
|
// (ملاحظة: البيانات هنا هي عينة لتعمل الصفحة، يمكنك استبدالها ببياناتك الكاملة)
|
|
]}
|
|
];
|
|
|
|
// في حال أردت استخدام بياناتك الكاملة، الصق محتوى المصفوفة "data" من ملفك داخل المتغير أدناه
|
|
// سأقوم الآن باستخراج البيانات من الهيكل المعقد الذي أرسلته
|
|
var rides = rawData[2].data;
|
|
|
|
// 4. خوارزمية الشبكة (Grid Algorithm)
|
|
var grid = {};
|
|
var precision = 0.005; // حجم المربع (تقريباً 500 متر). صغّر الرقم لـ 0.002 لدقة أعلى
|
|
|
|
rides.forEach(function(ride) {
|
|
if(ride.start_location) {
|
|
var coords = ride.start_location.split(',');
|
|
var lat = parseFloat(coords[0]);
|
|
var lng = parseFloat(coords[1]);
|
|
|
|
// استثناء القيم الصفرية أو البعيدة جداً
|
|
if(lat > 32 && lat < 38 && lng > 35 && lng < 39) {
|
|
|
|
// حساب مفتاح الشبكة (تقريب الإحداثيات)
|
|
// Math.floor(lat / precision) * precision -> يقوم بتوحيد الأرقام القريبة
|
|
var gridLat = Math.floor(lat / precision) * precision;
|
|
var gridLng = Math.floor(lng / precision) * precision;
|
|
var key = gridLat.toFixed(3) + "_" + gridLng.toFixed(3);
|
|
|
|
if(!grid[key]) {
|
|
grid[key] = {
|
|
lat: gridLat,
|
|
lng: gridLng,
|
|
count: 0
|
|
};
|
|
}
|
|
grid[key].count++;
|
|
}
|
|
}
|
|
});
|
|
|
|
// 5. دالة تحديد اللون بناءً على العدد
|
|
function getColor(d) {
|
|
return d > 5 ? '#bd0026' : // أحمر داكن (حار جداً)
|
|
d > 3 ? '#f03b20' : // أحمر
|
|
d > 1 ? '#fd8d3c' : // برتقالي
|
|
'#feb24c'; // أصفر (بارد)
|
|
}
|
|
|
|
// 6. رسم المربعات على الخريطة
|
|
var bounds = []; // لتحديد حدود الخريطة النهائية
|
|
|
|
for (var key in grid) {
|
|
var zone = grid[key];
|
|
|
|
// تحديد زوايا المربع
|
|
var southWest = [zone.lat, zone.lng];
|
|
var northEast = [zone.lat + precision, zone.lng + precision];
|
|
var zoneBounds = [southWest, northEast];
|
|
|
|
// رسم المستطيل
|
|
L.rectangle(zoneBounds, {
|
|
color: getColor(zone.count),
|
|
weight: 1,
|
|
fillOpacity: 0.6
|
|
}).bindPopup("<b>عدد الرحلات:</b> " + zone.count)
|
|
.addTo(map);
|
|
|
|
bounds.push(southWest);
|
|
bounds.push(northEast);
|
|
}
|
|
|
|
// 7. تحريك الكاميرا لتشمل كل النقاط
|
|
if(bounds.length > 0) {
|
|
map.fitBounds(bounds);
|
|
}
|
|
|
|
</script>
|
|
</body>
|
|
</html> |