287 lines
10 KiB
HTML
287 lines
10 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="ar" dir="rtl">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Intaleq Premium Map V3 - خرائط انطلاقة الذكية</title>
|
|
|
|
<link href="https://unpkg.com/maplibre-gl@4.7.1/dist/maplibre-gl.css" rel="stylesheet" />
|
|
<script src="https://unpkg.com/maplibre-gl@4.7.1/dist/maplibre-gl.js"></script>
|
|
|
|
<style>
|
|
@import url('https://fonts.googleapis.com/css2?family=Outfit:wght@400;600;800&family=Noto+Sans+Arabic:wght@400;700&display=swap');
|
|
|
|
:root {
|
|
--primary: #c0a048; /* Warm primary from style v3 */
|
|
--primary-dark: #b89038;
|
|
--accent: #2563eb;
|
|
--bg-glass: rgba(255, 255, 255, 0.85);
|
|
--shadow: 0 12px 40px rgba(0,0,0,0.12);
|
|
}
|
|
|
|
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
body {
|
|
font-family: 'Outfit', 'Noto Sans Arabic', sans-serif;
|
|
background: #F2EDE4;
|
|
overflow: hidden;
|
|
color: #342C20;
|
|
}
|
|
|
|
#map { width: 100%; height: 100vh; position: absolute; top: 0; left: 0; }
|
|
|
|
.controls {
|
|
position: absolute; top: 24px; right: 24px; z-index: 100;
|
|
background: var(--bg-glass);
|
|
backdrop-filter: blur(12px) saturate(180%);
|
|
-webkit-backdrop-filter: blur(12px) saturate(180%);
|
|
border-radius: 24px; padding: 28px; width: 380px;
|
|
box-shadow: var(--shadow);
|
|
border: 1px solid rgba(255, 255, 255, 0.3);
|
|
transition: all 0.3s ease;
|
|
}
|
|
|
|
.branding {
|
|
position: absolute; bottom: 32px; left: 32px; z-index: 100;
|
|
background: var(--bg-glass);
|
|
backdrop-filter: blur(8px);
|
|
padding: 10px 20px; border-radius: 12px;
|
|
display: flex; align-items: center; gap: 12px;
|
|
box-shadow: 0 8px 24px rgba(0,0,0,0.1);
|
|
border: 1px solid rgba(255, 255, 255, 0.4);
|
|
}
|
|
|
|
.badge {
|
|
display: inline-block; padding: 4px 10px; border-radius: 6px;
|
|
font-size: 11px; font-weight: 800; background: var(--primary); color: white;
|
|
margin-bottom: 12px; text-transform: uppercase; letter-spacing: 1px;
|
|
}
|
|
|
|
h2 { font-size: 22px; font-weight: 800; margin-bottom: 8px; color: #18100A; }
|
|
p { font-size: 14px; color: #584840; margin-bottom: 24px; line-height: 1.5; }
|
|
|
|
.btn-group { display: flex; flex-direction: column; gap: 12px; }
|
|
|
|
.btn {
|
|
position: relative; padding: 16px 20px; border: none; border-radius: 16px;
|
|
font-size: 15px; font-weight: 700; cursor: pointer;
|
|
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
|
display: flex; align-items: center; justify-content: space-between;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.btn-primary {
|
|
background: linear-gradient(135deg, var(--primary) 0%, var(--primary-dark) 100%);
|
|
color: white;
|
|
box-shadow: 0 4px 15px rgba(192, 160, 72, 0.3);
|
|
}
|
|
.btn-primary:hover {
|
|
transform: translateY(-3px);
|
|
box-shadow: 0 8px 25px rgba(192, 160, 72, 0.4);
|
|
}
|
|
|
|
.btn-secondary {
|
|
background: white;
|
|
color: #342C20;
|
|
border: 1px solid rgba(0,0,0,0.05);
|
|
box-shadow: 0 4px 10px rgba(0,0,0,0.03);
|
|
}
|
|
.btn-secondary:hover {
|
|
background: #fdfaf5;
|
|
transform: translateY(-2px);
|
|
box-shadow: 0 6px 15px rgba(0,0,0,0.05);
|
|
}
|
|
|
|
.btn span.icon { font-size: 18px; }
|
|
|
|
.info-box {
|
|
background: rgba(253, 250, 245, 0.6);
|
|
border-radius: 16px; padding: 18px; font-size: 14px;
|
|
color: #342C20; margin-top: 24px;
|
|
border: 1px dashed var(--primary);
|
|
line-height: 1.6; display: none;
|
|
animation: fadeIn 0.4s ease-out;
|
|
}
|
|
|
|
@keyframes fadeIn { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } }
|
|
|
|
#loading {
|
|
display: none; position: fixed; inset: 0;
|
|
background: rgba(242, 237, 228, 0.6);
|
|
z-index: 2000; align-items: center; justify-content: center;
|
|
backdrop-filter: blur(6px);
|
|
}
|
|
.spinner {
|
|
width: 40px; height: 40px; border: 4px solid rgba(192, 160, 72, 0.1);
|
|
border-top: 4px solid var(--primary); border-radius: 50%;
|
|
animation: spin 1s linear infinite;
|
|
}
|
|
@keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }
|
|
|
|
/* Custom Scrollbar for better look */
|
|
::-webkit-scrollbar { width: 6px; }
|
|
::-webkit-scrollbar-track { background: transparent; }
|
|
::-webkit-scrollbar-thumb { background: var(--primary); border-radius: 10px; }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
|
|
<div id="map"></div>
|
|
|
|
<div id="loading">
|
|
<div style="text-align: center;">
|
|
<div class="spinner" style="margin: 0 auto 15px;"></div>
|
|
<strong style="color: var(--primary-dark);">جاري حساب المسار الذكي...</strong>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="branding">
|
|
<img src="/intaleq-logo.png" alt="Logo" style="height: 24px;" onerror="this.style.display='none'">
|
|
<span style="font-size: 13px; font-weight: 800; color: #18100A; letter-spacing: 0.5px;">INTALEQ PREMIUM MAPS</span>
|
|
</div>
|
|
|
|
<div class="controls">
|
|
<div class="badge">Version 3.0.0</div>
|
|
<h2>🗺️ خرائط انطلاقة الذكية</h2>
|
|
<p>حلول جغرافية متقدمة لمنطقة الشرق الأوسط وشمال أفريقيا بدقة متناهية ونظام عرض ثلاثي الأبعاد.</p>
|
|
|
|
<div class="btn-group">
|
|
<button class="btn btn-primary" onclick="handleRoute('LEVANT')">
|
|
<div style="text-align: right;">
|
|
<div style="font-size: 12px; opacity: 0.8; margin-bottom: 2px;">المسار المقترح - سوريا</div>
|
|
<span>عمان ➔ دمشق</span>
|
|
</div>
|
|
<span class="icon">🚀</span>
|
|
</button>
|
|
|
|
<button class="btn btn-secondary" onclick="handleRoute('EGYPT')">
|
|
<div style="text-align: right;">
|
|
<div style="font-size: 12px; opacity: 0.7; margin-bottom: 2px;">المسار المقترح - مصر</div>
|
|
<span>شبرا ➔ الزمالك</span>
|
|
</div>
|
|
<span class="icon">🇪🇬</span>
|
|
</button>
|
|
</div>
|
|
|
|
<div id="status" class="info-box"></div>
|
|
</div>
|
|
|
|
<script>
|
|
const TILES_URL = 'https://tiles.intaleqapp.com';
|
|
const API_KEY = 'intaleq_secret_2026';
|
|
|
|
const COORDS = {
|
|
LEVANT: {
|
|
from: [35.9106, 31.9539], // Amman
|
|
to: [36.2765, 33.5138], // Damascus
|
|
center: [36.09, 32.73],
|
|
zoom: 8
|
|
},
|
|
EGYPT: {
|
|
from: [31.2427, 30.0931], // Shoubra
|
|
to: [31.2201, 30.0619], // Zamalek
|
|
center: [31.23, 30.07],
|
|
zoom: 13
|
|
}
|
|
};
|
|
|
|
maplibregl.setRTLTextPlugin('https://unpkg.com/@mapbox/mapbox-gl-rtl-text@0.2.3/mapbox-gl-rtl-text.js', null, true);
|
|
|
|
const map = new maplibregl.Map({
|
|
container: 'map',
|
|
center: COORDS.LEVANT.center,
|
|
zoom: COORDS.LEVANT.zoom,
|
|
attributionControl: false,
|
|
style: './style.json?v=' + Date.now(),
|
|
pitch: 45,
|
|
bearing: -10
|
|
});
|
|
|
|
let mapLoaded = false;
|
|
map.on('load', () => {
|
|
mapLoaded = true;
|
|
console.log('Intaleq Style v3 Loaded');
|
|
});
|
|
|
|
function decodePoly(str) {
|
|
let index = 0, lat = 0, lng = 0, coordinates = [];
|
|
while (index < str.length) {
|
|
let byte, shift = 0, result = 0;
|
|
do { byte = str.charCodeAt(index++) - 63; result |= (byte & 0x1f) << shift; shift += 5; } while (byte >= 0x20);
|
|
lat += ((result & 1) ? ~(result >> 1) : (result >> 1));
|
|
shift = 0; result = 0;
|
|
do { byte = str.charCodeAt(index++) - 63; result |= (byte & 0x1f) << shift; shift += 5; } while (byte >= 0x20);
|
|
lng += ((result & 1) ? ~(result >> 1) : (result >> 1));
|
|
coordinates.push([lng / 1e5, lat / 1e5]);
|
|
}
|
|
return coordinates;
|
|
}
|
|
|
|
async function handleRoute(region) {
|
|
if (!mapLoaded) return;
|
|
|
|
const config = COORDS[region];
|
|
const l = document.getElementById('loading');
|
|
const s = document.getElementById('status');
|
|
|
|
l.style.display = 'flex';
|
|
s.style.display = 'none';
|
|
|
|
try {
|
|
const url = `https://map-saas.intaleqapp.com/api/maps/route?fromLat=${config.from[1]}&fromLng=${config.from[0]}&toLat=${config.to[1]}&toLng=${config.to[0]}`;
|
|
const res = await fetch(url, { headers: { 'x-api-key': API_KEY } });
|
|
const data = await res.json();
|
|
|
|
if (data.statusCode >= 400) throw new Error(data.message || 'Routing API Error');
|
|
|
|
let coords = typeof data.points === 'string' ? decodePoly(data.points) : data.points;
|
|
if (!coords || coords.length === 0) throw new Error('No valid route points found');
|
|
|
|
// Add/Update Route Source
|
|
if (map.getSource('route')) {
|
|
map.getSource('route').setData({ type: 'Feature', geometry: { type: 'LineString', coordinates: coords } });
|
|
} else {
|
|
map.addSource('route', { type: 'geojson', data: { type: 'Feature', geometry: { type: 'LineString', coordinates: coords } } });
|
|
map.addLayer({
|
|
id: 'route-line',
|
|
type: 'line',
|
|
source: 'route',
|
|
layout: { 'line-join': 'round', 'line-cap': 'round' },
|
|
paint: {
|
|
'line-color': region === 'EGYPT' ? '#2563eb' : '#c0a048',
|
|
'line-width': 8,
|
|
'line-opacity': 0.85
|
|
}
|
|
});
|
|
}
|
|
|
|
// Fit bounds
|
|
const bounds = coords.reduce((b, c) => b.extend(c), new maplibregl.LngLatBounds(coords[0], coords[0]));
|
|
map.fitBounds(bounds, { padding: 120, duration: 2000 });
|
|
|
|
setTimeout(() => {
|
|
s.style.display = 'block';
|
|
s.innerHTML = `
|
|
<div style="font-weight: 700; margin-bottom: 8px; color: var(--primary-dark);">🏁 ملخص الرحلة الذكي</div>
|
|
<div style="display: flex; justify-content: space-between;">
|
|
<span>المسافة الفاصلة:</span>
|
|
<span style="font-weight: 800;">${(data.distance/1000).toFixed(1)} كم</span>
|
|
</div>
|
|
<div style="display: flex; justify-content: space-between;">
|
|
<span>الوقت المتوقع:</span>
|
|
<span style="font-weight: 800;">${(data.duration/60).toFixed(0)} دقيقة</span>
|
|
</div>
|
|
`;
|
|
}, 500);
|
|
|
|
} catch (e) {
|
|
console.error(e);
|
|
alert('عذراً، فشل في حساب المسار: ' + e.message);
|
|
} finally {
|
|
l.style.display = 'none';
|
|
}
|
|
}
|
|
</script>
|
|
</body>
|
|
</html>
|
|
|